2010-09-28 4 views
4

Я пытался найти хорошую архитектуру для одного приложения в течение последних нескольких дней, и после некоторых исследований я, наконец, застрял, и причина в COM.COM + WaitForSingleObject

В этом приложении будет несколько потоков графического интерфейса, и они будут планировать рабочие элементы для рабочего потока. Рабочий поток инициализирует COM через CoInitialize (NULL); создает несколько COM-компонентов и перейдет в цикл, который будет ждать WaitForMultipleObjects (2, ...) (ExitEvent - для указания того, что приложение закрывается, а ManualResetEvent - для указания что на самом деле есть рабочие элементы для обработки), и при успешном ожидании обрабатывают элементы и отправляют их обратно в потоки графического интерфейса. ManualResetEvent будет сброшен внутри рабочего, если очередь будет пустой и произойдет внутри критической секции очереди.

Проблема заключается в том, что COM, как обычно, делает все труднее 1000x ...

Если я правильно понимаю, 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; 
} 

А как насчет скрытого окна, сообщений, я даже на правильном пути?

+0

Переместить объекты COM из потока в поток? Или они живут в одной нити? Что делают объекты COM, в двух словах? Я думаю, что ваша архитектура далека от поля, потому что вы плохо знаете совет. –

+0

У меня вопрос не возникает. В чем проблема? –

+0

Также поясните «несколько потоков графического интерфейса». Вы просто ссылаетесь на скрытое окно COM, или вы действительно пытаетесь использовать несколько основных графических потоков? –

ответ

1

кажется излишним, но это работает для меня:

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 и его взаимодействие потоков над ком отсеками ....

Если вы инициализируете свою нить квартиры CoInitializeEx(0, COINIT_MULTITHREADED), ваши вызовы COM не будут поставлены в очередь в очереди сообщений. Но тогда у вас есть проблема с объектами, созданными в разных COM-квартирах. Они должны быть маршализованы ....

+0

Можете ли вы порекомендовать мне статью, которую я мог бы попробовать прочитать? Я хотел бы лучше понять различные аргументы и внутренности этой маршрутизации, например, когда удалять сообщения, а когда нет. Например, почему> // WM_USER для COM – Coder

+0

Несколько лет назад, когда я написал этот код, я ничего не мог найти по этому поводу. Мне потребовались дни отладки в COM/VB6, чтобы придумать решение. В настоящее время я, скорее всего, займусь проблемами с этим, создав (/ несколько) выделенные потоки, разделяющие объекты GUI/COM, чтобы обойти всю модель квартиры COM. – Christopher

+0

-1 для фильтрации сообщений bizzare, которые будут прерываться - без уважительной причины - любые другие окна сообщений, которые используют сообщения> WM_USER (например, диапазон WM_APP). –

2

Просто используйте CoWaitForMultipleHandles, и он будет выполнять необходимую передачу сообщений в скрытом окне COM для межпоточной синхронизации.

Скрытое окно имеет класс OleMainThreadWndClass с OleMainThreadWndName как подпись, но на win9x его класс WIN95 RPC Wmsg. Он скрыт, что означает, что вы не можете использовать прямой EnumThreadWindows, чтобы его найти.

Смежные вопросы