1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "WinErrorHandling.h" 27 #include "Log.h" 28 #include "SysInfo.h" 29 #include "FileUtils.h" 30 31 32 namespace { 33 34 std::string makeMessage(const std::string& msg, const char* label, 35 const void* c, DWORD errorCode) { 36 std::ostringstream err; 37 err << (label ? label : "Some error") << " [" << errorCode << "]"; 38 39 HMODULE hmodule = NULL; 40 if (c) { 41 GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 42 | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, 43 reinterpret_cast<LPCTSTR>(c), &hmodule); 44 45 if (!hmodule) { 46 LOG_WARNING(tstrings::any() << "GetModuleHandleEx() failed for " 47 << c << " address."); 48 } 49 } 50 if (hmodule || !c) { 51 err << "(" << SysError::getSysErrorMessage(errorCode, hmodule) << ")"; 52 } 53 54 return joinErrorMessages(msg, err.str()); 55 } 56 57 58 std::wstring getSystemMessageDescription(DWORD messageId, HMODULE moduleHandle) { 59 LPWSTR pMsg = NULL; 60 std::wstring descr; 61 62 // we always retrieve UNICODE description from system, 63 // convert it to utf8 if UNICODE is not defined 64 65 while (true) { 66 DWORD res = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER 67 | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS 68 | (moduleHandle != NULL ? FORMAT_MESSAGE_FROM_HMODULE : 0), 69 moduleHandle, messageId, 0, (LPWSTR)&pMsg, 0, NULL); 70 if (res > 0) { 71 // replace all non-printed chars with space 72 for (DWORD i=0; i<res; i++) { 73 if (pMsg[i] < L' ') { 74 pMsg[i] = L' '; 75 } 76 } 77 // trim right (spaces and dots) 78 for (DWORD i=res; i>0; i--) { 79 if (pMsg[i] > L' ' && pMsg[i] != L'.') { 80 break; 81 } 82 pMsg[i] = 0; 83 } 84 85 descr = pMsg; 86 87 LocalFree(pMsg); 88 } else { 89 // if we fail to get description for specific moduleHandle, 90 // try to get "common" description. 91 if (moduleHandle != NULL) { 92 moduleHandle = NULL; 93 continue; 94 } 95 descr = L"No description available"; 96 } 97 break; 98 } 99 100 return descr; 101 } 102 103 } // namespace 104 105 106 SysError::SysError(const tstrings::any& msg, const void* caller, DWORD ec, 107 const char* label): 108 109 std::runtime_error(makeMessage(msg.str(), label, caller, ec)) { 110 } 111 112 std::wstring SysError::getSysErrorMessage(DWORD errCode, HMODULE moduleHandle) { 113 tstrings::any msg; 114 msg << "system error " << errCode 115 << " (" << getSystemMessageDescription(errCode, moduleHandle) << ")"; 116 return msg.tstr(); 117 } 118 119 std::wstring SysError::getComErrorMessage(HRESULT hr) { 120 HRESULT hrOrig = hr; 121 // for FACILITY_WIN32 facility we need to reset hiword 122 if(HRESULT_FACILITY(hr) == FACILITY_WIN32) { 123 hr = HRESULT_CODE(hr); 124 } 125 return tstrings::format(_T("COM error 0x%08X (%s)"), hrOrig, 126 getSystemMessageDescription(hr, NULL)); 127 }