阅读文档看起来像ShowWindow
函数没有失败的概念。这令我感到惊讶,因为看起来几乎任何非平凡的代码都可能失败。ShowWindow报告如何失败?
窗口句柄可能无效。显然,这是由调用者承担的联系违规,但是这种情况只是“未定义”或“不关心”,那么呢?
不知道是否支持SetLastError
。
阅读文档看起来像ShowWindow
函数没有失败的概念。这令我感到惊讶,因为看起来几乎任何非平凡的代码都可能失败。ShowWindow报告如何失败?
窗口句柄可能无效。显然,这是由调用者承担的联系违规,但是这种情况只是“未定义”或“不关心”,那么呢?
不知道是否支持SetLastError
。
ShowWindow没有任何错误意识。如果提供的窗口不存在(或不可访问),它只是返回false。
ShowWindow实际上并不仅仅是将WM_SHOW消息发送到目标窗口。由于windows消息队列的性质,ShowWindow不了解其完成状态。尽管正如注释中指出的那样,WM_SHOW是同步处理的,但消息队列本身没有内置的错误报告机制,除了将错误消息发送回发送方。
GetLastError似乎在尝试访问不存在的窗口时报告无效的窗口句柄。对我来说,这是一个未知的行为,因为通常返回值应指示是否使用GetLastError。但是,通过事先手动测试窗口可以很容易地避免这种情况(请参阅:IsWindow)
ShowWindowAsync
虽然本质上是异步的,但它会告诉您操作是否成功启动。根据你在做什么,它可能是一个可用的选择。
虽然ShowWindow()
确实没有错误的概念,但我们可以使用SetWindowPos()
作为支持GetLastError()
的备选方案。
下面我提供一个例子,说明如何将SetWindowPos()
打包成一个函数,以弥合C风格错误报告和C++通过抛出和处理异常来实现它的方式之间的差距。
例子:
#include <windows.h>
#include <iostream>
#include <sstream>
#include <system_error>
// Show or hide the given window by calling SetWindowPos().
//
// \exception Reports any error by throwing std::sytem_error exception.
void MyShowWindow(HWND hwnd, bool show) {
DWORD flags = SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER;
if(show)
flags |= SWP_SHOWWINDOW;
else
flags |= SWP_HIDEWINDOW;
if(!::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, flags)) {
// NOTE: Call GetLastError() IMMEDIATELY when a function's return value indicates
// failure and it is documented that said function supports GetLastError().
// ANY other code (be it your own or library code) before the next line must be
// avoided as it may invalidate the last error value.
DWORD err = ::GetLastError();
std::ostringstream msg;
msg << "Could not change visibility of window (HWND 0x" << hwnd << ")";
throw std::system_error(static_cast<int>(err), std::system_category(), msg.str());
}
}
用法:
当使用包装函数MyShowWindow()
你必须确保赶上由它引发的异常。以下示例显示了如何做到这一点。
int main(){
try{
// Passing an invalid handle to MyShowWindow() will throw
// std::system_error exception. There may be other reasons for the
// function to fail, for instance if you pass the window handle of
// another process to which you don't have access as an argument
// to the function.
HWND anInvalidHandle = 0;
MyShowWindow(anInvalidHandle, true);
}
catch(std::system_error& e){
// Catch the exception thrown by MyShowWindow() and report all
// available error details.
// e.code() outputs the error code retrieved via GetLastError().
std::cout << "Error: " << e.what() << std::endl
<< "Error code: " << e.code() << std::endl;
}
return 0;
}
输出:
Error: Could not change visibility of window (HWND 0x00000000): Ung³ltiges Fensterhandle
Error code: system:1400
该消息表示 “无效窗口句柄”,错误代码对应于ERROR_INVALID_WINDOW_HANDLE。
注意:
虽然提供MyShowWindow()
功能只支持SW_HIDE
和ShowWindow
SW_SHOW
功能,其余的功能可以被propably通过使用附加SetWindowPos
标志设置(例如。SW_SHOWNA
映射到SWP_SHOWWINDOW | SWP_NOACTIVATE
)或调用其他Windows API函数提供此功能,并记录为支持GetLastError()
。
您需要在输入条件后立即调用'GetLastError' **,并返回一个有意义的值。你的'MyShowWindow'实现危险地接近打破那个不变性。它需要一个具有自动存储持续时间的对象,其析构函数在'SetWindowPos'返回值和您对'GetLastError'的调用之间运行。调用'GetLastError'似乎是错误处理中最常见的错误。请不要发布几乎不正确的代码。 – IInspectable
@IInspectable _it带一个具有自动存储持续时间的对象,其析构函数runs_ ...请为您认为具有析构函数的对象命名。我只看到POD数据类型,根据定义它没有析构函数。 – zett42
*“您的执行危险**关闭**”*。和*“[...]通过发布**几乎**不正确的代码。”* – IInspectable
':: SetLastError(0);如果(!:: ShowWindow(0,SW_SHOW)){DWORD err = :: GetLastError(); std :: cout << err; }'...打印1400(ERROR_INVALID_WINDOW_HANDLE) – zett42
只注意到'if(!:: ShowWindow(...'是废话,因为如文档所述,'false'的返回值只是表示窗口是否隐藏,如果发生错误,则不会发生。 – zett42
'SetWindowPos(hwnd,nullptr,0,0,0,0,SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER)'...它有一个BOOL返回值并正式支持'GetLastError )' – zett42