I've been trying to find a good architecture for one application for the last few days, and after some research I'm finally stuck, and the reason is COM.
The app in question will have multiple GUI threads, and they will schedule work items for worker thread. The worker thread will initialize COM via CoInitialize(NULL);, create few COM components and will go into a loop which will wait for WaitForMultipleObjects(2, ...) (ExitEvent - to indicate that app is shutting down and ManualResetEvent - to indicate that there are actually work items to process), and on successful wait, will process the items and PostMessage them back to GUI threads. The ManualResetEvent will be reset inside worker if the queue will be empty and will happen inside queue critical section.
The problem is that COM, as usual, makes EVERYTHING 1000x harder...
If I understand correctly, CoInitialize(NULL); creates a hidden window, and any message posted during WaitForSingle/MultipleObject/s can cause a deadlock.
So, I need to call the MsgWaitForMultiple objects. Which in turn can fail if messages are not pumped correctly. Unfortunately, I can't quite understand how to pump them in a correct way. Do I have to create my own message loop? Will the app crash if COM decides to create a messagebox?
So far it seems I have to proceed like this?
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;
}
But what about hidden window, messageboxes, am I even on the right path?