[英]COM + WaitForSingleObject
在過去的幾天里,我一直試圖為一個應用程序找到一個好的架構,經過一些研究后我終於卡住了,原因就是COM。
有問題的應用程序將有多個GUI線程,他們將為工作線程安排工作項。 工作線程將通過CoInitialize(NULL)初始化COM;創建幾個COM組件並進入循環,等待WaitForMultipleObjects(2,...)(ExitEvent - 表示應用程序正在關閉,ManualResetEvent - 表示實際上有工作項處理),並且在成功等待時,將處理項目並將它們PostMessage回GUI線程。 如果隊列為空並且將在隊列關鍵部分內發生,則ManualResetEvent將在worker內重置。
問題是,像往常一樣,COM使得一切都變得更難了......
如果我理解正確,CoInitialize(NULL); 創建一個隱藏窗口,在WaitForSingle / MultipleObject / s期間發布的任何消息都可能導致死鎖。
所以,我需要調用MsgWaitForMultiple對象。 如果消息未正確泵送,則反過來可能會失敗。 不幸的是,我不太明白如何以正確的方式泵送它們。 我是否必須創建自己的消息循環? 如果COM決定創建一個消息框,應用程序會崩潰嗎?
到目前為止,似乎我必須這樣做?
HANDLE hEvents[2] = {};
int ThreadProc(LPVOID lpParam) {
int nRetVal = 0;
CoInitialize(NULL);
CComPtr<ISomething> smthn;
smthn.CoCreateInstance(...);
MSG msg = {};
bool bRun = true;
while(bRun) {
while(PeekMessage(&msg, ??NULL/-1??, 0, 0, PM_REMOVE)) { /*Which one here?*/
if(msg.Message == WM_QUIT) {
bRun = false;
nRetVal = msg.wParam;
break;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(MsgWaitForMultipleObjects(2, &hEvents, ...)) {
if(exitevent) { bRun = false; nRetVal = 0; }
else if(processevent) { [processdata] }
}
}
smthn.release();
CoUninitialize();
return nRetVal;
}
但是隱藏的窗口,消息框呢,我甚至在正確的道路上?
只需使用CoWaitForMultipleHandles
,它就會在隱藏的COM窗口上進行必要的消息抽取,以進行線程間同步。
隱藏窗口是OleMainThreadWndClass
類, OleMainThreadWndName
作為標題但在win9x上它的類是WIN95 RPC Wmsg
。 它是隱藏的意味着你不能使用直接的EnumThreadWindows
來找到它。
看起來像矯枉過正,但這對我有用:
int waitAndDispatch( HANDLE* event_handle, unsigned int ev_count, DWORD timeout )
{
int rval = -1;
bool bLoop = true; // if the loop should terminate
HANDLE* pHList = new HANDLE[ev_count];
for( unsigned int i = 0; i < ev_count; ++i )
{
pHList[i] = event_handle[i];
}
while( bLoop )
{
DWORD res = ::MsgWaitForMultipleObjects( ev_count, pHList, false, timeout, QS_ALLPOSTMESSAGE | QS_SENDMESSAGE );
if( res == WAIT_OBJECT_0 + ev_count ) // messages arrived
{
MSG tmpMsg;
bool hasMsg = true;
while( bLoop && hasMsg )
{
::PeekMessage( &tmpMsg, 0, 0, 0, PM_NOREMOVE );
if( ::PeekMessage( &tmpMsg, 0, WM_USER, WM_USER, PM_REMOVE ) || // WM_USER for COM
::PeekMessage( &tmpMsg, 0, 0, WM_KEYFIRST - 1, PM_REMOVE ) // all destroy update, ...
)
{
DWORD val = ::WaitForMultipleObjects( ev_count, pHList, false, 0 );
if( val >= WAIT_OBJECT_0 && val <= (WAIT_OBJECT_0 + ev_count) )
{
rval = val - WAIT_OBJECT_0;
bLoop = false;
}
::DispatchMessage( &tmpMsg );
}
else
{
hasMsg = false;
}
}
}
else if( res >= WAIT_OBJECT_0 && res < (WAIT_OBJECT_0 + ev_count) )
{
rval = res - WAIT_OBJECT_0;
bLoop = false;
}
else if( res == WAIT_TIMEOUT )
{
rval = ev_count;
bLoop = false;
}
else
{
rval = -1;
bLoop = false;
}
}
delete[] pHList;
return rval;
}
我不得不為VB6編寫這篇文章,並在com隔層上編寫線程交互....
如果使用CoInitializeEx( 0, COINIT_MULTITHREADED )
初始化線程CoInitializeEx( 0, COINIT_MULTITHREADED )
,則COM調用將不會排隊到消息隊列中。 但是你有在不同COM公寓中創建的對象的問題。 這些需要整理......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.