// ************************************************************************** // * This file is part of the FreeFileSync project. It is distributed under * // * GNU General Public License: http://www.gnu.org/licenses/gpl.html * // * Copyright (C) Zenju (zenju AT gmx DOT de) - All Rights Reserved * // ************************************************************************** #ifndef COM_ERROR_HEADER #define COM_ERROR_HEADER #include #include #include "win.h" //includes "windows.h" namespace zen { std::wstring generateErrorMsg(const std::wstring& input, HRESULT hr); std::wstring formatWin32Msg(DWORD dwMessageId); //return empty string on error class ComError { public: explicit ComError(const std::wstring& msg, HRESULT hr = S_OK) : msg_(hr == S_OK ? msg : generateErrorMsg(msg, hr)) {} const std::wstring& toString() const { return msg_; } private: std::wstring msg_; }; #define ZEN_CHECK_COM(func) ZEN_CHECK_COM_ERROR(func, #func) //throw ComError /*Convenience Macro checking for COM errors: Example: ZEN_CHECK_COM(backupComp->InitializeForBackup()); Equivalent to: { HRESULT hrInternal = backupComp->InitializeForBackup(); if (FAILED(hrInternal)) throw ComError(L"Error calling \"backupComp->InitializeForBackup()\".", hrInternal); } */ //################# implementation ##################### std::wstring formatWin32Msg(DWORD dwMessageId) //return empty string on error { std::wstring output; LPWSTR buffer = nullptr; if (::FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_MAX_WIDTH_MASK | FORMAT_MESSAGE_IGNORE_INSERTS | //important: without this flag ::FormatMessage() will fail if message contains placeholders FORMAT_MESSAGE_ALLOCATE_BUFFER, nullptr, dwMessageId, 0, reinterpret_cast(&buffer), 0, nullptr) != 0) { if (buffer) //just to be sure { output = buffer; ::LocalFree(buffer); } } return output; } namespace { std::wstring formatFacility(HRESULT hr) { switch (HRESULT_FACILITY(hr)) { case FACILITY_XPS: return L"XPS"; case FACILITY_WINRM: return L"Windows Resource Manager"; case FACILITY_WINDOWSUPDATE: return L"Windows Update"; case FACILITY_WINDOWS_DEFENDER: return L"Windows Defender Component"; case FACILITY_WINDOWS_CE: return L"Windows CE"; case FACILITY_WINDOWS: return L"Windows Subsystem"; case FACILITY_USERMODE_VOLMGR: return L"User Mode Volume Manager"; case FACILITY_USERMODE_VIRTUALIZATION: return L"User Mode Virtualization Subsystem"; case FACILITY_USERMODE_VHD: return L"User Mode Virtual Hard Disk Support"; case FACILITY_URT: return L".NET CLR"; case FACILITY_UMI: return L"Ubiquitous Memoryintrospection Service"; case FACILITY_UI: return L"UI"; case FACILITY_TPM_SOFTWARE: return L"Trusted Platform Module Applications"; case FACILITY_TPM_SERVICES: return L"Trusted Platform Module Services"; case FACILITY_SXS: return L"Side-by-side Servicing"; case FACILITY_STORAGE: return L"OLE Storage"; case FACILITY_STATE_MANAGEMENT: return L"State Management Services"; case FACILITY_SCARD: return L"Smart-card Subsystem"; case FACILITY_SHELL: return L"User Shell"; case FACILITY_SETUPAPI: return L"Setup API"; case FACILITY_SECURITY: return L"Security API Layer"; case FACILITY_SDIAG: return L"System Diagnostics"; case FACILITY_RPC: return L"RPC Subsystem"; case FACILITY_RAS: return L"RAS"; case FACILITY_PLA: return L"Performance Logs and Alerts"; case FACILITY_OPC: return L"Open Connectivity Service"; case FACILITY_WIN32: return L"Win32"; case FACILITY_CONTROL: return L"Control Mechanism"; case FACILITY_WEBSERVICES: return L"Web Services"; case FACILITY_NDIS: return L"Network Driver Interface"; case FACILITY_METADIRECTORY: return L"Microsoft Identity Server"; case FACILITY_MSMQ: return L"Microsoft Message Queue"; case FACILITY_MEDIASERVER: return L"Windows Media Server"; case FACILITY_MBN: return L"MBN"; case FACILITY_INTERNET: return L"Wininet"; case FACILITY_ITF: return L"COM/OLE Interface Management"; case FACILITY_USERMODE_HYPERVISOR: return L"Usermode Hypervisor Components"; case FACILITY_HTTP: return L"HTTP Support"; case FACILITY_GRAPHICS: return L"Graphics Drivers"; case FACILITY_FWP: return L"Firewall Platform"; case FACILITY_FVE: return L"Full volume encryption"; case FACILITY_USERMODE_FILTER_MANAGER: return L"User Mode Filter Manager"; case FACILITY_DPLAY: return L"Direct Play"; case FACILITY_DISPATCH: return L"COM Dispatch"; case FACILITY_DIRECTORYSERVICE: return L"Active Directory"; case FACILITY_CONFIGURATION: return L"Configuration Services"; case FACILITY_COMPLUS: return L"COM+"; case FACILITY_USERMODE_COMMONLOG: return L"Common Logging Support"; case FACILITY_CMI: return L"Configuration Management Infrastructure"; case FACILITY_CERT: return L"Certificate"; case FACILITY_BCD: return L"Boot Configuration Database"; case FACILITY_BACKGROUNDCOPY: return L"Background Copy Control"; case FACILITY_ACS: return L"Audit Collection Service"; case FACILITY_AAF: return L"Microsoft Agent"; default: return L"Unknown"; } } } inline std::wstring numberToHexString(long number) { wchar_t result[100]; ::swprintf(result, 100, L"0x%08x", static_cast(number)); return std::wstring(result); } inline std::wstring generateErrorMsg(const std::wstring& input, HRESULT hr) { std::wstring output(input); output += L"\n"; //don't use _com_error(hr).ErrorMessage(): internally this is nothing more than a call to ::FormatMessage() std::wstring win32Msg = formatWin32Msg(hr); if (!win32Msg.empty()) //empty string on error output += win32Msg + L"\n" + L"HRESULT: " + numberToHexString(hr); else output += L"HRESULT: " + numberToHexString(hr) + L", " + L"Facility: " + formatFacility(hr); //don't bluntly interpret as Win32 error code HRESULT_CODE(hr), too often misleading! //http://blogs.msdn.com/b/oldnewthing/archive/2006/11/03/942851.aspx return output; } #define ZEN_CHECK_COM_ERROR(func, txt) \ { \ HRESULT hrInternal = func; \ if (FAILED(hrInternal)) \ throw ComError(L"Error calling \"" ## ZEN_CONCAT_SUB(L, txt) ## L"\".", hrInternal); \ } #ifndef ZEN_CONCAT //redeclare those macros: avoid dependency to scope_guard.h #define ZEN_CONCAT_SUB(X, Y) X ## Y #define ZEN_CONCAT(X, Y) ZEN_CONCAT_SUB(X, Y) #endif } #endif //COM_ERROR_HEADER