簡體   English   中英

COM + WaitForSingleObject

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM