I'm writing a Win32Exception for an application I'm working on, the header file looks like this:
class Win32Exception : std::exception {
public:
Win32Exception() = default;
explicit Win32Exception(const std::wstring& message);
explicit Win32Exception(const std::string& message);
explicit Win32Exception(const char* message);
virtual ~Win32Exception() throw() override = default;
char const* what() const override;
std::wstring message() const;
};
The implementation for the what
function looks like this:
char const* Win32Exception::what() const
{
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
DWORD errorCode = GetLastError();
DWORD systemLocale = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
LPSTR buffer = nullptr;
DWORD length = FormatMessageA(flags, nullptr, errorCode, systemLocale, (LPSTR)&buffer, 0, nullptr);
if(buffer != nullptr)
{
LocalFree(buffer);
}
else if (length == 0)
{
buffer = "Cannot get an error message. FormatMessage failed.";
}
return buffer;
}
The implementation for the message
function looks like this:
std::wstring Win32Exception::message() const
{
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
DWORD errorCode = GetLastError();
DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
LPWSTR buffer = nullptr;
DWORD length = FormatMessageW(flags, nullptr, errorCode, systemLocale, (LPWSTR)&buffer, 0, nullptr);
if (buffer != nullptr)
{
LocalFree(buffer);
}
else if (length == 0)
{
buffer = L"Cannot get an error message. FormatMessage failed.";
}
return buffer;
}
Now, I would like to get rid of this duplication so I thought I can do something about it with a template, like this:
template <typename TResult, DWORD (*formatMessageVersion)(DWORD, LPCVOID, DWORD, DWORD, TResult, DWORD, va_list*)>
TResult formatMessage(DWORD& systemLocale, DWORD& errorCode, TResult& fallbackMessage) const {
DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER;
TResult buffer = nullptr;
DWORD length = formatMessageVersion(flags, nullptr, errorCode, systemLocale, (TResult)&buffer, 0, nullptr);
if (buffer != nullptr)
{
LocalFree(buffer);
}
else if (length == 0)
{
buffer = fallbackMessage;
}
return buffer;
}
In one of my attempts I tried to pass the function FormatMessageA/W
as an argument to formatMessage
through std::function but I'm not sure why it didn't work...
The way I thought I to use this is as follow:
char const* Win32Exception::what() const
{
DWORD errorCode = GetLastError();
DWORD systemLocale = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
return formatMessage<LPSTR, FormatMessageA>(systemLocale,
errorCode,
"Cannot get an error message. FormatMessage failed.");
}
std::wstring Win32Exception::message() const
{
DWORD errorCode = GetLastError();
DWORD systemLocale = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
return formatMessage<LPWSTR, FormatMessageW>(systemLocale,
errorCode,
L"Cannot get an error message. FormatMessage failed.");
}
But I'm getting bunch of errors:
Severity Code Description Project File Line Suppression State
Error C2664 'TResult Yalla::Win32Exception::formatMessage<LPSTR,DWORD FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const char [51]' to 'LPSTR &' RunBox d:\users\eyal\projects\code\yalla\core\src\runbox\win32\win32-exception.cpp 29
Severity Code Description Project File Line Suppression State
Error C2664 'TResult Yalla::Win32Exception::formatMessage<LPSTR,DWORD FormatMessageA(DWORD,LPCVOID,DWORD,DWORD,LPSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const char [51]' to 'LPSTR &' RunBox d:\users\eyal\projects\code\yalla\core\src\runbox\win32\win32-exception.cpp 29
Severity Code Description Project File Line Suppression State
Error C2664 'TResult Yalla::Win32Exception::formatMessage<LPWSTR,DWORD FormatMessageW(DWORD,LPCVOID,DWORD,DWORD,LPWSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const wchar_t [51]' to 'LPWSTR &' RunBox d:\users\eyal\projects\code\yalla\core\src\runbox\win32\win32-exception.cpp 40
Severity Code Description Project File Line Suppression State
Error C2664 'TResult Yalla::Win32Exception::formatMessage<LPWSTR,DWORD FormatMessageW(DWORD,LPCVOID,DWORD,DWORD,LPWSTR,DWORD,va_list *)>(DWORD &,DWORD &,TResult &) const': cannot convert argument 3 from 'const wchar_t [51]' to 'LPWSTR &' RunBox d:\users\eyal\projects\code\yalla\core\src\runbox\win32\win32-exception.cpp 40
Severity Code Description Project File Line Suppression State
Error (active) no instance of function template "Yalla::Win32Exception::formatMessage" matches the argument list RunBox d:\Users\Eyal\Projects\Code\Yalla\core\src\runbox\win32\win32-exception.cpp 27
Severity Code Description Project File Line Suppression State
Error (active) no instance of function template "Yalla::Win32Exception::formatMessage" matches the argument list RunBox d:\Users\Eyal\Projects\Code\Yalla\core\src\runbox\win32\win32-exception.cpp 38
Bear in my mind that I'm relearning C++ and didn't touch it for many years so if you can tell me how to improve the code or do whatever that I'm trying to do in a better way, I'd be really glad to hear about it! ;)
Update: You can find the final solution at GitHub, thanks to everyone.