2017-03-04 263 views
0

阅读文档看起来像ShowWindow函数没有失败的概念。这令我感到惊讶,因为看起来几乎任何非平凡的代码都可能失败。ShowWindow报告如何失败?

窗口句柄可能无效。显然,这是由调用者承担的联系违规,但是这种情况只是“未定义”或“不关心”,那么呢?

不知道是否支持SetLastError

+0

':: SetLastError(0);如果(!:: ShowWindow(0,SW_SHOW)){DWORD err = :: GetLastError(); std :: cout << err; }'...打印1400(ERROR_INVALID_WINDOW_HANDLE) – zett42

+0

只注意到'if(!:: ShowWindow(...'是废话,因为如文档所述,'false'的返回值只是表示窗口是否隐藏,如果发生错误,则不会发生。 – zett42

+0

'SetWindowPos(hwnd,nullptr,0,0,0,0,SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER)'...它有一个BOOL返回值并正式支持'GetLastError )' – zett42

回答

-2

ShowWindow没有任何错误意识。如果提供的窗口不存在(或不可访问),它只是返回false。

ShowWindow实际上并不仅仅是将WM_SHOW消息发送到目标窗口。由于windows消息队列的性质,ShowWindow不了解其完成状态。尽管正如注释中指出的那样,WM_SHOW是同步处理的,但消息队列本身没有内置的错误报告机制,除了将错误消息发送回发送方。

GetLastError似乎在尝试访问不存在的窗口时报告无效的窗口句柄。对我来说,这是一个未知的行为,因为通常返回值应指示是否使用GetLastError。但是,通过事先手动测试窗口可以很容易地避免这种情况(请参阅:IsWindow)

+0

不是,消息并不总是异步的,例如SendMessage是同步的,WM_SHOW不是异步消息,它没有排队,第二个段落错误 –

+0

谢谢你纠正 – Psi

+0

实际上它似乎支持'GetLastError ()',如果窗口不存在则返回1400(ERROR_INVALID_WINDOW_HANDLE)。Win 10下的经验测试。 – zett42

1

ShowWindowAsync虽然本质上是异步的,但它会告诉您操作是否成功启动。根据你在做什么,它可能是一个可用的选择。

1

虽然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_HIDEShowWindowSW_SHOW功能,其余的功能可以被propably通过使用附加SetWindowPos标志设置(例如。SW_SHOWNA映射到SWP_SHOWWINDOW | SWP_NOACTIVATE)或调用其他Windows API函数提供此功能,并记录为支持GetLastError()

+0

您需要在输入条件后立即调用'GetLastError' **,并返回一个有意义的值。你的'MyShowWindow'实现危险地接近打破那个不变性。它需要一个具有自动存储持续时间的对象,其析构函数在'SetWindowPos'返回值和您对'GetLastError'的调用之间运行。调用'GetLastError'似乎是错误处理中最常见的错误。请不要发布几乎不正确的代码。 – IInspectable

+0

@IInspectable _it带一个具有自动存储持续时间的对象,其析构函数runs_ ...请为您认为具有析构函数的对象命名。我只看到POD数据类型,根据定义它没有析构函数。 – zett42

+0

*“您的执行危险**关闭**”*。和*“[...]通过发布**几乎**不正确的代码。”* – IInspectable