在过去的几天里,我一直在尝试为一个应用程序寻找一个好的架构,经过一些研究,我最终被困住了,原因是COM。
有问题的应用程序将有多个GUI线程,它们将为工作线程安排工作项。工作线程将通过CoInitialize(NULL);初始化COM,创建少量COM组件并进入等待WaitForMultipleObjects(2,...)的循环中。(ExitEvent -表示应用程序正在关闭,ManualResetEvent -表示实际上有工作项要处理),在成功等待时,将处理这些项并将它们PostMessage回GUI线程。如果队列将为空并发生在队列临界区内,则ManualResetEvent将在worker内部重置。
问题是,像往常一样,COM让一切都变得1000倍困难……
如果我没理解错,CoInitialize(NULL);会创建一个隐藏窗口,并且在WaitForSingle/MultipleObject/s期间发布的任何消息都可能导致死锁。
因此,我需要调用MsgWaitForMultiple对象。如果消息没有被正确地泵送,则其继而可能失败。不幸的是,我不能很好地理解如何以正确的方式使用它们。我必须创建我自己的消息循环吗?如果COM决定创建messagebox,应用程序会崩溃吗?
到目前为止,我似乎不得不这样做?
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;
}但是隐藏窗口,信箱,我是不是走对了路?
发布于 2010-09-28 23:48:25
看起来有点过头了,但这对我很有效:
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单元中创建对象的问题。这些都需要编组...
发布于 2010-10-01 00:09:00
只需使用CoWaitForMultipleHandles,它就会在隐藏的COM窗口上执行必要的消息泵操作,以实现线程间同步。
隐藏窗口的类是OleMainThreadWndClass,标题是OleMainThreadWndName,但在win9x上,它的类是WIN95 RPC Wmsg。它是隐藏的,这意味着你不能直接使用EnumThreadWindows来找到它。
https://stackoverflow.com/questions/3814425
复制相似问题