INFO: OLE Threads Must Dispatch Messages

This article was previously published under Q136885
Single-Threaded Apartment (STA) threads that do not dispatch messages cancause message broadcasters to hang. STA server threads that do not dispatchmessages are not able to receive calls from clients. STA client threadsthat do not dispatch messages are not able to receive notifications fromservers. Any STA thread that does not dispatch messages will leak smallamounts of memory.

This article only applies to threads that are single-threaded apartmentmodel. Threads in the MTA (Multi-Threading Apartment) using the free-threading model introduced in Windows NT version 4.0 and Distributed COMfor Windows 95 are not required to dispatch messages. For additionalinformation on free threading, please see the following article in theMicrosoft Knowledge Base:
150777 Descriptions and Workings of OLE Threading Models
In Windows NT 3.51 and Windows 95, OLE creates a hidden, top-level windowin each STA thread. (An STA thread is a thread that has calledCo/OleInitialize.) If someone broadcasts a message (like WM_DDE_INITIATE)to all windows, the SendMessage hangs until all top-level windows havereceived the message. To prevent the broadcaster from hanging, OLE requireseach STA thread to dispatch messages.

32-bit OLE calls between processes are made using RPC. In Apartment modelthreading and in single threading, OLE synchronizes the received RPC callwith the recipient thread by posting the thread a window message.Consequently a server OLE thread doesn't receive calls from clients if itdoesn't dispatch messages. Similarly a client OLE thread doesn't receivenotifications from servers if it doesn't dispatch messages.

For example, the following thread blocks can encounter the problemsdiscussed earlier:
   OleInitialize(NULL);   CoCreateInstance(CLSID_Hello, NULL, CLSCTX_SERVER,                        IID_IUnknown, (void **)&punk);   punk->QueryInterface(IID_IHello,  (void **)&phello);   WaitForSingleObject(hSomeObjectThatTakesALongTime);   phello->put_Visible(TRUE);   phello->SayHello();   OleUninitialize();				
You can fix this code by replacing WaitForSingleObject with a message loopfunction as in this example:
   BOOL WaitWithMessageLoop(HANDLE hEvent)   {       DWORD dwRet;       MSG msg;       while(1)       {       dwRet = MsgWaitForMultipleObjects( 1,    // One event to wait for               &hEvent,        // The array of events               FALSE,          // Wait for 1 event               INFINITE,       // Timeout value               QS_ALLINPUT);   // Any message wakes up       if(dwRet == WAIT_OBJECT_0)       {          // The event was signaled, return         return TRUE;       } else if(dwRet == WAIT_OBJECT_0 + 1)       {          // There is a window message available. Dispatch it.          while(PeekMessage(&msg,NULL,NULL,NULL,PM_REMOVE))       {                  TranslateMessage(&msg);          DispatchMessage(&msg);       }       } else       {          // Something else happened. Return.          return FALSE;       }       }   }				
Any STA thread that does not block but makes OLE calls, needs to dispatchmessages as follows.
    MSG msg;   CoInitialize(); // or OleInitialize()    // force msg-q to be created just in case, NOP otherwise    PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);    // msg to myself to do work    PostThreadMessage(GetCurrentThreadId(), WM_USER+1, 0, 0);    // msg-pump    while (GetMessage(&msg, NULL, 0, 0))          {          // this was my message -- time to do my work          if (msg.hwnd == NULL && msg.message == WM_USER+1)              {              // do my work here, CCI, work, work, release, etc              //  if this thread is doing long process, you need to break     that into smaller chunks,              //   and post another user message to process further, that     way you don't block the              //   messages which need to be processed.              // when done,              PostQuitMessage(0);              }          else              {              TranslateMessage(&msg);              DispatchMessage(&msg);              }          }      CoUninitialize();				
Windows 95 threading GetMessage

Αναγνωριστικό άρθρου: 136885 - Τελευταία αναθεώρηση: 03/16/2005 20:45:27 - Αναθεώρηση: 3.3

Microsoft COM+ 2.0 Standard Edition

  • kbcode kbinfo KB136885