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
|
// *****************************************************************************
// * This file is part of the FreeFileSync project. It is distributed under *
// * GNU General Public License: http://www.gnu.org/licenses/gpl-3.0 *
// * Copyright (C) Zenju (zenju AT freefilesync DOT org) - All Rights Reserved *
// *****************************************************************************
#ifndef SYS_ERROR_H_3284791347018951324534
#define SYS_ERROR_H_3284791347018951324534
#include <string>
#include "utf.h"
#include "i18n.h"
#include "scope_guard.h"
#ifdef ZEN_WIN
#include "win.h" //tame WinINet.h include
#include <WinINet.h>
#elif defined ZEN_LINUX || defined ZEN_MAC
#include <cstring>
#include <cerrno>
#endif
namespace zen
{
//evaluate GetLastError()/errno and assemble specific error message
#ifdef ZEN_WIN
using ErrorCode = DWORD;
#elif defined ZEN_LINUX || defined ZEN_MAC
using ErrorCode = int;
#endif
ErrorCode getLastError();
std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec);
std::wstring formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg);
//A low-level exception class giving (non-translated) detail information only - same conceptional level like "GetLastError()"!
class SysError
{
public:
explicit SysError(const std::wstring& msg) : msg_(msg) {}
const std::wstring& toString() const { return msg_; }
private:
std::wstring msg_;
};
#define DEFINE_NEW_SYS_ERROR(X) struct X : public SysError { X(const std::wstring& msg) : SysError(msg) {} };
#ifdef _MSC_VER
#define THROW_LAST_SYS_ERROR(functionName) \
do \
{ \
const ErrorCode ecInternal = getLastError(); \
throw SysError(formatSystemError(functionName, ecInternal)); \
\
__pragma(warning(suppress: 4127)) /*"conditional expression is constant"*/ \
} while (false)
#else //same thing witout "__pragma":
#define THROW_LAST_SYS_ERROR(functionName) \
do { const ErrorCode ecInternal = getLastError(); throw SysError(formatSystemError(functionName, ecInternal)); } while (false)
#endif
//######################## implementation ########################
inline
ErrorCode getLastError()
{
#ifdef ZEN_WIN
return ::GetLastError();
#elif defined ZEN_LINUX || defined ZEN_MAC
return errno; //don't use "::", errno is a macro!
#endif
}
std::wstring formatSystemErrorRaw(long long) = delete; //intentional overload ambiguity to catch usage errors
inline
std::wstring formatSystemErrorRaw(ErrorCode ec) //return empty string on error
{
const ErrorCode currentError = getLastError(); //not necessarily == lastError
std::wstring errorMsg;
#ifdef ZEN_WIN
ZEN_ON_SCOPE_EXIT(::SetLastError(currentError)); //this function must not change active system error variable!
LPWSTR buffer = nullptr;
const DWORD rv = [&]
{
if (INTERNET_ERROR_BASE <= ec && ec <= INTERNET_ERROR_LAST)
return ::FormatMessage(FORMAT_MESSAGE_FROM_HMODULE |
FORMAT_MESSAGE_MAX_WIDTH_MASK |
FORMAT_MESSAGE_IGNORE_INSERTS |
FORMAT_MESSAGE_ALLOCATE_BUFFER, ::GetModuleHandle(L"WinINet.dll"), ec, 0, reinterpret_cast<LPWSTR>(&buffer), 0, nullptr);
else
return ::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, //_In_ DWORD dwFlags,
nullptr, //_In_opt_ LPCVOID lpSource,
ec, //_In_ DWORD dwMessageId,
0, //_In_ DWORD dwLanguageId,
reinterpret_cast<LPWSTR>(&buffer), //_Out_ LPTSTR lpBuffer,
0, //_In_ DWORD nSize,
nullptr); //_In_opt_ va_list *Arguments
}();
if (rv != 0)
if (buffer) //"don't trust nobody"
{
ZEN_ON_SCOPE_EXIT(::LocalFree(buffer));
errorMsg = buffer;
}
#elif defined ZEN_LINUX || defined ZEN_MAC
ZEN_ON_SCOPE_EXIT(errno = currentError);
errorMsg = utfCvrtTo<std::wstring>(::strerror(ec));
#endif
trim(errorMsg); //Windows messages seem to end with a blank...
return errorMsg;
}
std::wstring formatSystemError(const std::wstring& functionName, long long lastError) = delete; //intentional overload ambiguity to catch usage errors with HRESULT!
inline
std::wstring formatSystemError(const std::wstring& functionName, ErrorCode ec)
{
return formatSystemError(functionName, numberTo<std::wstring>(ec), formatSystemErrorRaw(ec));
}
inline
std::wstring formatSystemError(const std::wstring& functionName, const std::wstring& errorCode, const std::wstring& errorMsg)
{
std::wstring output = replaceCpy(_("Error Code %x:"), L"%x", errorCode);
if (!errorMsg.empty())
{
output += L" ";
output += errorMsg;
}
output += L" (" + functionName + L")";
return output;
}
}
#endif //SYS_ERROR_H_3284791347018951324534
|