The application described in the previous section also has another deadly defect. See if you can point out.
This special application is exactly written in MFC. At first, it used the MFC's AFXBEGINTHREAD function to launch a series of secondary threads. Each auxiliary thread either calls Coinitialize either call AFXoleinit (a function similar to Coinitialize in MFC) to initialize COM. Some auxiliary threads call CocreateInstance to create a COM object and send the returned interface pointer to other auxiliary threads. Calling objects from creating these objects will be very smooth, but the call from other threads is never returned. Do you know why?
If you think the problem is related to the message loop (or missing message loop), then the answer is completely correct. The fact is indeed true. When a thread calls Coinitialize or AFXoleinit, it is placed in a single-line unit (STA). When COM creates a STA, it creates an attached hidden window. Method calls for objects in STA will be converted to messages and placed in a message queue associated with the STA. When the thread running in the STA is retrieved to the message that represents the method call, the window process of the hidden window will call the message conversion method. COM uses STA to perform call serialization. Objects in STA cannot receive more than one call once, because each call is passed to one and is the only thread running in the object cell.
What if the STA-based thread cannot handle the message? What if it doesn't have a message loop? The cell method call for the object in this STA will no longer return; they will be put on the message queue. There is no message cycle in the MFC assist thread, so if you are hosting objects in these STAs to receive methods from the client of other units, the MFC auxiliary threads and STAs are not good.
What is the meaning of this story? The STA thread requires a message loop unless you are sure they don't contain objects to call from other threads. Message loops can be simpler:
MSG msg;
While (GetMessage (& MSG, 0, 0, 0))
DispatchMessage (& MSG);
Another solution is to move the COM thread into the MTA (or moving to the neutral thread unit, i.e., NTA), where there is no message queue dependencies.