| // 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"); |
| } |