Last active
August 3, 2022 13:21
-
-
Save Tocchann/da66314cd16c860b8d907a44fd6a9d2f to your computer and use it in GitHub Desktop.
MsgWaitForMultipleObjects の例
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <map> | |
#include <functional> | |
// waitActions に登録する例は載せていない(通常は、排他制御して追加処理するのが良い) | |
std::map<HANDLE, std::function<bool(bool,bool&)>> waitActions; | |
DWORD APIENTRY SetupWaitHandles( HANDLE* waitHandles, DWORD capacityCount ) | |
{ | |
DWORD waitCount = 0; | |
if( capacityCount > 0 ) | |
{ | |
for( const auto& pair : waitActions ) | |
{ | |
if( waitCount >= capacityCount ) | |
{ | |
break; | |
} | |
waitHandles[waitCount++] = pair.first; | |
} | |
} | |
return waitCount; | |
} | |
bool APIENTRY SignalWaitAction( HANDLE wakeHandle, bool isSucceeded ) | |
{ | |
bool isContinue = true; | |
auto itr = waitActions.find( wakeHandle ); | |
if( itr != waitActions.end() ) | |
{ | |
if( !itr->second( isSucceeded, isContinue ) ) | |
{ | |
waitActions.erase( itr ); | |
} | |
} | |
return isContinue; | |
} | |
int RunMessageLoop() | |
{ | |
HANDLE waitHandles[MAXIMUM_WAIT_OBJECTS-1] ={ nullptr }; | |
// 待機ハンドルをセットアップする。待機ハンドルのセットアップは、この関数を持つクラスで行うことを想定 | |
DWORD waitCount = SetupWaitHandles( waitHandles, MAXIMUM_WAIT_OBJECTS-1 ); | |
bool isContinue = true; | |
DWORD timeoutTime = 60*1000; // デフォルトは1分ごとにタイムアウト | |
int resultCode = ERROR_SUCCESS; | |
do | |
{ | |
auto result = ::MsgWaitForMultipleObjects( waitCount, waitHandles, FALSE, timeoutTime, QS_ALLINPUT ); | |
// MsgWaitForMultipleObjects のエラー(パラメータが間違っているとかが多い) | |
if( result == WAIT_FAILED ) | |
{ | |
// エラーコードを見て処理の必要があればそれ相応に処理。ここではプログラム的なバグを想定してそのままリターン | |
resultCode = ::GetLastError(); | |
isContinue = false; | |
} | |
// タイムアウト | |
else if( result == WAIT_TIMEOUT ) | |
{ | |
// Win32 なので COMを使わないかもしれないけどサンプルとして用意 | |
CoFreeUnusedLibraries(); | |
} | |
// メッセージが何か来たのでループを回す | |
else if( result == WAIT_OBJECT_0+waitCount ) | |
{ | |
MSG msg; | |
while( ::PeekMessage( &msg, nullptr, 0, 0, PM_REMOVE ) ) | |
{ | |
if( msg.message == WM_QUIT ) | |
{ | |
resultCode = static_cast<decltype(resultCode)>(msg.wParam); | |
isContinue = false; | |
break; | |
} | |
// メッセージの事前処理 | |
// msg.hWnd == nullptr の場合やモードレスダイアログなら IsDialogMessage を呼び出すなどを行う | |
if( !PreTranslateMessage( &msg ) ) | |
{ | |
::TranslateMessage( &msg ); | |
::DispatchMessage( &msg ); | |
} | |
} | |
} | |
// 待機ハンドルがシグナル状態になった(==アクションを起こせ!) | |
else if( WAIT_OBJECT_0 <= result && result < WAIT_OBJECT_0+waitCount ) | |
{ | |
isContinue = SignalWaitAction( waitHandles[result-WAIT_OBJECT_0], true ); | |
// 継続する場合は毎回整理 | |
if( isContinue ) | |
{ | |
waitCount = SetupWaitHandles( waitHandles, MAXIMUM_WAIT_OBJECTS-1 ); | |
} | |
} | |
// 待機に失敗した(Mutexの場合のみ) | |
else if( WAIT_ABANDONED_0 <= result && result < WAIT_ABANDONED_0+waitCount ) | |
{ | |
isContinue = SignalWaitAction( waitHandles[result-WAIT_ABANDONED_0], false ); | |
// 継続する場合は毎回整理 | |
if( isContinue ) | |
{ | |
waitCount = SetupWaitHandles( waitHandles, MAXIMUM_WAIT_OBJECTS-1 ); | |
} | |
} | |
} while( isContinue ); | |
return resultCode; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment