| // Written in the D programming language. | |
| /** | |
| * Convert Win32 error code to string. | |
| * | |
| * Copyright: Copyright Digital Mars 2006 - 2013. | |
| * License: $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0). | |
| * Authors: $(HTTP digitalmars.com, Walter Bright) | |
| * Credits: Based on code written by Regan Heath | |
| */ | |
| /* Copyright Digital Mars 2006 - 2013. | |
| * Distributed under the Boost Software License, Version 1.0. | |
| * (See accompanying file LICENSE_1_0.txt or copy at | |
| * http://www.boost.org/LICENSE_1_0.txt) | |
| */ | |
| module std.windows.syserror; | |
| import std.traits : isSomeString; | |
| version (StdDdoc) | |
| { | |
| private | |
| { | |
| alias DWORD = uint; | |
| enum LANG_NEUTRAL = 0, SUBLANG_DEFAULT = 1; | |
| } | |
| /** Query the text for a Windows error code, as returned by | |
| $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360.aspx, | |
| $(D GetLastError)), as a D string. | |
| */ | |
| string sysErrorString( | |
| DWORD errCode, | |
| // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) is the user's default language | |
| int langId = LANG_NEUTRAL, | |
| int subLangId = SUBLANG_DEFAULT) @trusted; | |
| /********************* | |
| Thrown if errors that set | |
| $(LINK2 http://msdn.microsoft.com/en-us/library/windows/desktop/ms679360.aspx, | |
| $(D GetLastError)) occur. | |
| */ | |
| class WindowsException : Exception | |
| { | |
| private alias DWORD = int; | |
| final @property DWORD code(); /// $(D GetLastError)'s return value. | |
| this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted; | |
| } | |
| /++ | |
| If $(D !!value) is true, $(D value) is returned. Otherwise, | |
| $(D new WindowsException(GetLastError(), msg)) is thrown. | |
| $(D WindowsException) assumes that the last operation set | |
| $(D GetLastError()) appropriately. | |
| Example: | |
| -------------------- | |
| wenforce(DeleteFileA("junk.tmp"), "DeleteFile failed"); | |
| -------------------- | |
| +/ | |
| T wenforce(T, S)(T value, lazy S msg = null, | |
| string file = __FILE__, size_t line = __LINE__) @safe | |
| if (isSomeString!S); | |
| } | |
| else: | |
| version (Windows): | |
| import core.sys.windows.windows; | |
| import std.array : appender; | |
| import std.conv : to; | |
| import std.format : formattedWrite; | |
| import std.windows.charset; | |
| string sysErrorString( | |
| DWORD errCode, | |
| // MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) is the user's default language | |
| int langId = LANG_NEUTRAL, | |
| int subLangId = SUBLANG_DEFAULT) @trusted | |
| { | |
| auto buf = appender!string(); | |
| if (!putSysError(errCode, buf, MAKELANGID(langId, subLangId))) | |
| { | |
| throw new Exception( | |
| "failed getting error string for WinAPI error code: " ~ | |
| sysErrorString(GetLastError())); | |
| } | |
| return buf.data; | |
| } | |
| bool putSysError(Writer)(DWORD code, Writer w, /*WORD*/int langId = 0) | |
| { | |
| wchar *lpMsgBuf = null; | |
| auto res = FormatMessageW( | |
| FORMAT_MESSAGE_ALLOCATE_BUFFER | | |
| FORMAT_MESSAGE_FROM_SYSTEM | | |
| FORMAT_MESSAGE_IGNORE_INSERTS, | |
| null, | |
| code, | |
| langId, | |
| cast(LPWSTR)&lpMsgBuf, | |
| 0, | |
| null); | |
| scope(exit) if (lpMsgBuf) LocalFree(lpMsgBuf); | |
| if (lpMsgBuf) | |
| { | |
| import std.string : strip; | |
| w.put(lpMsgBuf[0 .. res].strip()); | |
| return true; | |
| } | |
| else | |
| return false; | |
| } | |
| class WindowsException : Exception | |
| { | |
| import core.sys.windows.windows : DWORD; | |
| final @property DWORD code() { return _code; } /// $(D GetLastError)'s return value. | |
| private DWORD _code; | |
| this(DWORD code, string str=null, string file = null, size_t line = 0) @trusted | |
| { | |
| _code = code; | |
| auto buf = appender!string(); | |
| if (str != null) | |
| { | |
| buf.put(str); | |
| if (code) | |
| buf.put(": "); | |
| } | |
| if (code) | |
| { | |
| auto success = putSysError(code, buf); | |
| formattedWrite(buf, success ? " (error %d)" : "Error %d", code); | |
| } | |
| super(buf.data, file, line); | |
| } | |
| } | |
| T wenforce(T, S)(T value, lazy S msg = null, | |
| string file = __FILE__, size_t line = __LINE__) | |
| if (isSomeString!S) | |
| { | |
| if (!value) | |
| throw new WindowsException(GetLastError(), to!string(msg), file, line); | |
| return value; | |
| } | |
| T wenforce(T)(T condition, const(char)[] name, const(wchar)* namez, string file = __FILE__, size_t line = __LINE__) | |
| { | |
| if (condition) | |
| return condition; | |
| string names; | |
| if (!name) | |
| { | |
| static string trustedToString(const(wchar)* stringz) @trusted | |
| { | |
| import core.stdc.wchar_ : wcslen; | |
| import std.conv : to; | |
| auto len = wcslen(stringz); | |
| return to!string(stringz[0 .. len]); | |
| } | |
| names = trustedToString(namez); | |
| } | |
| else | |
| names = to!string(name); | |
| throw new WindowsException(GetLastError(), names, file, line); | |
| } | |
| version (Windows) | |
| @system unittest | |
| { | |
| import std.algorithm.searching : startsWith, endsWith; | |
| import std.exception; | |
| import std.string; | |
| auto e = collectException!WindowsException( | |
| DeleteFileA("unexisting.txt").wenforce("DeleteFile") | |
| ); | |
| assert(e.code == ERROR_FILE_NOT_FOUND); | |
| assert(e.msg.startsWith("DeleteFile: ")); | |
| // can't test the entire message, as it depends on Windows locale | |
| assert(e.msg.endsWith(" (error 2)")); | |
| // Test code zero | |
| e = new WindowsException(0); | |
| assert(e.msg == ""); | |
| e = new WindowsException(0, "Test"); | |
| assert(e.msg == "Test"); | |
| } |