1 // Written in the D programming language. 2 3 /** 4 * Convert Win32 error code to string. 5 * 6 * Copyright: Copyright The D Language Foundation" 2006 - 2013. 7 * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). 8 * Authors: $(HTTP digitalmars.com, Walter Bright) 9 * Credits: Based on code written by Regan Heath 10 */ 11 /* Copyright The D Language Foundation" 2006 - 2013. 12 * Distributed under the Boost Software License, Version 1.0. 13 * (See accompanying file LICENSE_1_0.txt or copy at 14 * http://www.boost.org/LICENSE_1_0.txt) 15 */ 16 module std.windows.syserror; 17 import std.traits : isSomeString; 18 19 version (StdDdoc) 20 { 21 private 22 { 23 alias DWORD = uint; 24 enum LANG_NEUTRAL = 0, SUBLANG_DEFAULT = 1; 25 } 26 27 /** Query the text for a Windows error code, as returned by 28 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360.aspx, 29 `GetLastError`), as a D string. 30 */ 31 string sysErrorString( 32 DWORD errCode, 33 // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) is the user's default language 34 int langId = LANG_NEUTRAL, 35 int subLangId = SUBLANG_DEFAULT) @trusted; 36 37 /********************* 38 Thrown if errors that set 39 $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360.aspx, 40 `GetLastError`) occur. 41 */ 42 class WindowsException : Exception 43 { 44 private alias DWORD = int; 45 final @property DWORD code(); /// `GetLastError`'s return value. 46 this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted; 47 } 48 49 /++ 50 If `!!value` is true, `value` is returned. Otherwise, 51 $(D new WindowsException(GetLastError(), msg)) is thrown. 52 `WindowsException` assumes that the last operation set 53 `GetLastError()` appropriately. 54 55 Example: 56 -------------------- 57 wenforce(DeleteFileA("junk.tmp"), "DeleteFile failed"); 58 -------------------- 59 +/ 60 T wenforce(T, S)(T value, lazy S msg = null, 61 string file = __FILE__, size_t line = __LINE__) @safe 62 if (isSomeString!S); 63 } 64 else: 65 66 version (Windows): 67 68 import core.sys.windows.winbase, core.sys.windows.winnt; 69 import std.array : appender; 70 import std.conv : to; 71 import std.format : formattedWrite; 72 import std.windows.charset; 73 74 string sysErrorString( 75 DWORD errCode, 76 // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) is the user's default language 77 int langId = LANG_NEUTRAL, 78 int subLangId = SUBLANG_DEFAULT) @trusted 79 { 80 auto buf = appender!string(); 81 82 if (!putSysError(errCode, buf, MAKELANGID(langId, subLangId))) 83 { 84 throw new Exception( 85 "failed getting error string for WinAPI error code: " ~ 86 sysErrorString(GetLastError())); 87 } 88 89 return buf.data; 90 } 91 92 bool putSysError(Writer)(DWORD code, Writer w, /*WORD*/int langId = 0) 93 { 94 wchar *lpMsgBuf = null; 95 auto res = FormatMessageW( 96 FORMAT_MESSAGE_ALLOCATE_BUFFER | 97 FORMAT_MESSAGE_FROM_SYSTEM | 98 FORMAT_MESSAGE_IGNORE_INSERTS, 99 null, 100 code, 101 langId, 102 cast(LPWSTR)&lpMsgBuf, 103 0, 104 null); 105 scope(exit) if (lpMsgBuf) LocalFree(lpMsgBuf); 106 107 if (lpMsgBuf) 108 { 109 import std..string : strip; 110 w.put(lpMsgBuf[0 .. res].strip()); 111 return true; 112 } 113 else 114 return false; 115 } 116 117 118 class WindowsException : Exception 119 { 120 import core.sys.windows.windef : DWORD; 121 122 final @property DWORD code() { return _code; } /// `GetLastError`'s return value. 123 private DWORD _code; 124 125 this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted 126 { 127 _code = code; 128 129 auto buf = appender!string(); 130 131 if (str != null) 132 { 133 buf.put(str); 134 if (code) 135 buf.put(": "); 136 } 137 138 if (code) 139 { 140 auto success = putSysError(code, buf); 141 formattedWrite(buf, success ? " (error %d)" : "Error %d", code); 142 } 143 144 super(buf.data, file, line); 145 } 146 } 147 148 149 T wenforce(T, S)(T value, lazy S msg = null, 150 string file = __FILE__, size_t line = __LINE__) 151 if (isSomeString!S) 152 { 153 if (!value) 154 throw new WindowsException(GetLastError(), to!string(msg), file, line); 155 return value; 156 } 157 158 T wenforce(T)(T condition, const(char)[] name, const(wchar)* namez, string file = __FILE__, size_t line = __LINE__) 159 { 160 if (condition) 161 return condition; 162 string names; 163 if (!name) 164 { 165 static string trustedToString(const(wchar)* stringz) @trusted 166 { 167 import core.stdc.wchar_ : wcslen; 168 import std.conv : to; 169 auto len = wcslen(stringz); 170 return to!string(stringz[0 .. len]); 171 } 172 173 names = trustedToString(namez); 174 } 175 else 176 names = to!string(name); 177 throw new WindowsException(GetLastError(), names, file, line); 178 } 179 180 version (Windows) 181 @system unittest 182 { 183 import std.algorithm.searching : startsWith, endsWith; 184 import std.exception; 185 import std..string; 186 187 auto e = collectException!WindowsException( 188 DeleteFileA("unexisting.txt").wenforce("DeleteFile") 189 ); 190 assert(e.code == ERROR_FILE_NOT_FOUND); 191 assert(e.msg.startsWith("DeleteFile: ")); 192 // can't test the entire message, as it depends on Windows locale 193 assert(e.msg.endsWith(" (error 2)")); 194 195 // Test code zero 196 e = new WindowsException(0); 197 assert(e.msg == ""); 198 199 e = new WindowsException(0, "Test"); 200 assert(e.msg == "Test"); 201 }