summaryrefslogtreecommitdiff
path: root/zen/com_error.h
blob: d891fa1385ca0f93f394efc5e88549afeb5dcac6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
// **************************************************************************
// * 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 (zhnmju123 AT gmx DOT de) - All Rights Reserved    *
// **************************************************************************

#ifndef COM_ERROR_HEADER
#define COM_ERROR_HEADER

#include <string>
#include <cstdio>
#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<LPWSTR>(&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", 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
bgstack15