閱讀文檔看起來像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