I have been trying to find a good architecture for one application in the last few days, and after some research, I finally got stuck, and the reason is in COM.
There will be several GUI threads in this application, and they will plan work items for the workflow. The worker thread initializes COM through CoInitialize (NULL); creates several COM components and goes into a loop that will wait WaitForMultipleObjects (2, ...) (ExitEvent to indicate that the application is closing, and ManualResetEvent to indicate that there are actually work items to process), and when waiting successfully process the elements and send them back to the GUI threads. ManualResetEvent will reset inside the worker if the queue is empty and occurs inside the critical section of the queue.
The problem is that COM, as usual, makes ALL 1000x more complicated ...
If I understand correctly, CoInitialize (NULL); creates a hidden window, and any message sent during WaitForSingle / MultipleObject / s can cause a deadlock.
So, I need to call the MsgWaitForMultiple objects. This, in turn, may be unsuccessful if the messages are not pumped correctly. Unfortunately, I can’t figure out how to properly pump them. Should I create my own custom message loop? Application crash if COM decides to create a message box?
So far it seems to me that I should act as follows:
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)) { 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; }
But what about a hidden window, message boxes, am I even on the right track?