Microsoft KB Archive/136885

From BetaArchive Wiki
Knowledge Base


INFO: OLE Threads Must Dispatch Messages

Article ID: 136885

Article Last Modified on 3/16/2005



APPLIES TO

  • Microsoft COM+ 2.0 Standard Edition, when used with:
    • Microsoft Windows 95
    • Microsoft Windows NT 3.51 Service Pack 5
    • Microsoft Windows NT 4.0
    • Microsoft Windows 2000 Standard Edition



This article was previously published under Q136885

SUMMARY

Single-Threaded Apartment (STA) threads that do not dispatch messages can cause message broadcasters to hang. STA server threads that do not dispatch messages are not able to receive calls from clients. STA client threads that do not dispatch messages are not able to receive notifications from servers. Any STA thread that does not dispatch messages will leak small amounts of memory.

This article only applies to threads that are single-threaded apartment model. Threads in the MTA (Multi-Threading Apartment) using the free- threading model introduced in Windows NT version 4.0 and Distributed COM for Windows 95 are not required to dispatch messages. For additional information on free threading, please see the following article in the Microsoft Knowledge Base:

150777 Descriptions and Workings of OLE Threading Models


MORE INFORMATION

In Windows NT 3.51 and Windows 95, OLE creates a hidden, top-level window in each STA thread. (An STA thread is a thread that has called Co/OleInitialize.) If someone broadcasts a message (like WM_DDE_INITIATE) to all windows, the SendMessage hangs until all top-level windows have received the message. To prevent the broadcaster from hanging, OLE requires each STA thread to dispatch messages.

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

For example, the following thread blocks can encounter the problems discussed 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 loop function 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 dispatch messages 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();
                


Additional query words: Windows 95 threading GetMessage

Keywords: kbcode kbinfo KB136885