2017-03-04 117 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