INFO: OLE Threads Must Dispatch Messages
ID: Q136885
|
The information in this article applies to:
-
Microsoft OLE Libraries, used with:
-
Microsoft Windows NT, versions 3.51, 4.0
-
Microsoft Windows 95, with Distributed COM
-
Microsoft Windows 2000
SUMMARY
STA (Single Threaded Apartment) 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:
Q150777 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 kbole kbNTOS351 kbNTOS400 kbWinOS2000 kbWinOS95 kbGrpCom kbDSupport LeTwoArc
Version : :
Platform : NT Win95 WINDOWS
Issue type : kbinfo