首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >COM + WaitForSingleObject

COM + WaitForSingleObject
EN

Stack Overflow用户
提问于 2010-09-28 23:32:40
回答 2查看 2.1K关注 0票数 4

在过去的几天里,我一直在尝试为一个应用程序寻找一个好的架构,经过一些研究,我最终被困住了,原因是COM。

有问题的应用程序将有多个GUI线程,它们将为工作线程安排工作项。工作线程将通过CoInitialize(NULL);初始化COM,创建少量COM组件并进入等待WaitForMultipleObjects(2,...)的循环中。(ExitEvent -表示应用程序正在关闭,ManualResetEvent -表示实际上有工作项要处理),在成功等待时,将处理这些项并将它们PostMessage回GUI线程。如果队列将为空并发生在队列临界区内,则ManualResetEvent将在worker内部重置。

问题是,像往常一样,COM让一切都变得1000倍困难……

如果我没理解错,CoInitialize(NULL);会创建一个隐藏窗口,并且在WaitForSingle/MultipleObject/s期间发布的任何消息都可能导致死锁。

因此,我需要调用MsgWaitForMultiple对象。如果消息没有被正确地泵送,则其继而可能失败。不幸的是,我不能很好地理解如何以正确的方式使用它们。我必须创建我自己的消息循环吗?如果COM决定创建messagebox,应用程序会崩溃吗?

到目前为止,我似乎不得不这样做?

代码语言:javascript
复制
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;
}

但是隐藏窗口,信箱,我是不是走对了路?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2010-09-28 23:48:25

看起来有点过头了,但这对我很有效:

代码语言:javascript
复制
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 )初始化线程单元,则COM调用将不会排队到消息队列中。但是,您会遇到在不同的COM单元中创建对象的问题。这些都需要编组...

票数 1
EN

Stack Overflow用户

发布于 2010-10-01 00:09:00

只需使用CoWaitForMultipleHandles,它就会在隐藏的COM窗口上执行必要的消息泵操作,以实现线程间同步。

隐藏窗口的类是OleMainThreadWndClass,标题是OleMainThreadWndName,但在win9x上,它的类是WIN95 RPC Wmsg。它是隐藏的,这意味着你不能直接使用EnumThreadWindows来找到它。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3814425

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档