我正在为我正在处理的应用程序编写Win32Exception,头文件看起来像这样:
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;
};
what
函数的实现如下所示:
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;
}
message
函数的实现如下所示:
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;
}
现在,我想摆脱这种重复,所以我想我可以用模板做一些事情,比如:
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;
}
在我的一次尝试中,我尝试通过std :: function将函数FormatMessageA/W
作为参数传递给formatMessage
,但我不确定为什么它不起作用.. 的
我认为我使用它的方式如下:
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.");
}
但是我收到了很多错误:
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
请记住,我正在重新学习C ++并且多年没有触及它,所以如果你能告诉我如何改进代码或做一些我想要做的更好的方式,我真的很高兴听到它! ;)
更新:感谢所有人,您可以在GitHub找到最终解决方案。
答案 0 :(得分:2)
不要通过模板解决重复问题。您已经有一个函数message()
,它调用FormatMessageW
并获取消息文本。这就是你所需要的一切。要实现what()
,您需要一个ANSI字符串。所以先调用message()
然后再转换为ANSI。
换句话说,首先调用what()
来实施message()
。然后将std::wstring
转换为std::string
。然后返回const char*
c_str()
收益率std::string
。您需要将c_str
存储在成员字段中,以便what()
返回的指针仍然有效。
要执行转换,请参阅此处出现的主题的众多问题之一。例如:How to convert wstring into string?
目前,LocalFree
的实现返回一个无效指针,因为它在随后返回的值上调用FormatMessageW
。但如果你按照我的建议完成所有代码的话,那就不要太依赖了。
您对0
的错误处理是错误的。成功或其他方式由返回值表示,如文档所示。值buffer
表示失败。这就是你需要测试的东西。我不能非常强调阅读文档的重要性。我说,我们在这里看到的&gt; 90%的winapi问题在错误处理方面存在错误。
此外,您在释放后再次访问LPWSTR buffer;
DWORD length = FormatMessageW(flags, nullptr, errorCode, systemLocale, (LPWSTR)&buffer,
0, nullptr);
if (length == 0)
return L"Cannot get an error message. FormatMessage failed.";
std::wstring retval = buffer;
LocalFree(buffer);
return retval;
。代码看起来应该更像这样:
SetLastError
您应该允许该类传递错误代码。一些错误代码由API直接返回,例如注册表API。此外,在您设法访问调用GetLastError
的代码之前,有时可能会被调用<!-- The Right navigation drawer -->
<fragment
android:id="@+id/fragment_navigation_filters"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:name="com.ui.newdesign.FilterNavigationFragment"/>
的C ++运行时混淆。
答案 1 :(得分:1)
此处的错误消息中描述了直接问题:
[...] cannot convert argument 3 from 'const char [51]' to 'LPSTR &' [...]
您正在将字符文字传递给期望非const引用的函数。您不能将非const引用绑定到临时引用,因此简单修复只是将最后一个参数类型从TResult&
更改为TResult const&
。这应该可以解决你的问题。