HOW TO Configure DCOM Timeouts
Introduction
Not long after my first attempts at ATL and DCOM, I developed two pet hates:1) 'Prefab' dialog boxes that interrupt the application and launch the taskbar
START menu when the client cannot connect to the server.
2) Lack of support for timeouts.
A worst case scenario would be: A Windows 95 LAN client belonging to the domain "engineering.mycompany" attempts to instantiate an object on the server with the NETBIOS name "Einstein". The client can try to locate "Einstein" in a number of ways, including concatenating "Einstein" and "engineering.mycompany" to a single domain name and asking the local name server to resolve this name. Let us further assume that the LAN is connected to the internet via a dial-on-demand link and that the local DNS is not a root server. If "Einstein.engineering.mycompany" cannot be resolved, the DNS server will attempt to contact the next DNS in the hierarchy on the internet.
In the meantime, the user of the DCOM client application is either looking at an hour glass or gets a dialog box encouraging him/her to task-switch to the server application - as if it were possible to task-switch across a network.
My friend Bud Millwood and I, here at Weird Solutions Inc., have been working on a client / server application based on DCOM and devised a relatively straight forward solution to both problems described above. Bud suggested that I post our solution onto the DCOM mailing list to encourage further exploration of the issue and perhaps constructive feedback. So here it is folks....
Solutions
1) Addressing the "Server Busy" dialog problem.
Declare an object, say "MyFilter" of class "COleMessageFilter" in your
application, ensure that you are including This will have registered a new implementation of the IMessageFilter
interface for your application. The IMessageFilter interface is used
for concurrency management. Your new IMessageFilter differs from the
default in that it does not display the notorious dialog boxes.
2) Contemplating a solution to the timeout problem.
The suggested method to make timeouts configurable is to implement
one's own "IMessageFilter" interface with the "MessagePending" method.
>From within this method you can return PENDINGMSG_CANCELCALL when your
patience has expired. This will unblock your application.
Canceling an ongoing DCOM call might well create temporary orphan
resources on the server, but this seems a small price to pay compared
to an non-responsive application that the user will shut down via task
manager. In any event, one is well advised to exercise good judgement
in establishing timeouts and perhaps even carry out some statistical
analysis of typical response times. I have found, for instance, that
starting a local COM service on my coding machine varies between one
and three seconds. Clearly then, a client timeout of one second would
be inappropriate, while anything in the excess of - say - 10 seconds
would provide an ample safety margin.
The question that presents itself is whether one should implement an
"IMessageFilter" interface from scratch or reuse what already ships
with MFC. The MFC class "COleMessageFilter" almost meets the
requirements; it even has a virtual function
"COleMessageFilter::OnMessagePending" that you can override in a
derived class of your own. It does, however, have one serious flaw.
You might wish to examine the source code for this class in the file
"....\vc\mfc\src\olemsgf.cpp".
Two methods are of interest here:
a) "MessagePending"
This maps to the COM interface IMessageFilter::MessagePending method
and is called by DCOM to process pending messages during an otherwise
blocking DCOM call. Its simplified structure is as follows:
b) "OnMessagePending"
This is the virtual function called by MessagePending(). You may
override this function in a derived class to customize the behaviour
of your application.
Now here is the problem: Microsoft has already decided for us what
will be returned by MessagePending(). The return value of your
implementation of OnMessagePending() is ignored completely in the
parent function MessagePending(). Hence, whatever you return from
OnMessagePending() is inconsequential.
We could of course modify the source of "COleMessageFilter" and
rebuild MFC. For our purposes, this was inappropriate.
The MS Visual C++ 5.0 help files state:
"You will probably want to implement your own message filter.The
default implementation provided by COM offers only minimal message
filtering capability."
Rather than building the message filter from scratch, I have opted to
take over the code base from "COleMessageFilter" to create my own base
class with an identical interface and named it "COleMsgFilter". It
exists parallel to and independent from the MFC class
"COleMessageFilter". The minor - but crucial - change in the
implementation of COleMsgFilter::MessagePending() is to actually
return the value from the function call to
COleMsgFilter::OnMessagePending(). This will allow returning
PENDINGMSG_CANCELCALL from within OnMessagePending() and thus allow
controlling the DCOM timeout.
3) Implementing the solution to the timeout problem.
Prepare the class header file.
------------------------------
a) Open the file "../vc/mfc/include/afxole.h". "afxole.h" is a
collection
header file for a number of OLE classes. Look for the definition of
the "COleMessageFilter" class. It is prefixed with the following
header:
b) Search for every instance of "COleMessageFilter" in the file
OleMsgFlt.h and replace it with "COleMsgFilter".
c) Change the return type of OnMessagePending() from BOOL to DWORD.
a) Open the file "../vc/mfc/src/olemsgf.cpp", copy its contents to a
new file, and save it in your project directory under
"OleMsgFlt.cpp".
b) Search for every instance of "COleMessageFilter" in the file
OleMsgFlt.cpp and replace it with "COleMsgFilter".
c) Insert the statement shown below at the top of your CPP file.
d) Insert the line shown below at the top of your CPP file
e) From the file "../vc/mfc/src/afximpl.h" copy the line shown below
to
the top of your CPP file
f) From the file ""../vc/mfc/include/afxpriv.h" copy the line shown
below to the top of your CPP file
g) Find the method "COleMsgFilter::XMessageFilter::MessagePending" and
within it, the line where OnMessagePending() is called. It should
look like this:
h) Change the return type of the implementation of OnMessagePending()
from BOOL to DWORD.
i) You will find that some of the initialization functions for the
class' data members are absent from the class implementation. This
is because they are in-lined in the file "AfxOle.inl". Their non
in-lined counterparts are shown below. You can just copy and paste
them directly into your CPP file.
MyFilter.EnableNotRespondingDialog(FALSE);
MyFilter.EnableBusyDialog(FALSE);
MyFilter.Register();
MessagePending() {
//do something useful
//call virtual function OnMessagePending
return PENDINGMSG_WAITNOPROCESS
}
What now?
///////////////////////////////////////////////////////////////////
////////// // COleMessageFilter (implements IMessageFilter)
Mark and copy the COMPLETE class definition and paste it to a new
header file, named "OleMsgFlt.h".
Prepare the class CPP file.
#include "OleMsgFlt.h"
#include
#define _countof(array) (sizeof(array)/sizeof(array[0]))
#define WM_KICKIDLE 0x036A
pThis->OnMessagePending(&msg);
Prefix this line with "return", like so:
return pThis->OnMessagePending(&msg);
void COleMsgFilter::SetRetryReply(DWORD nRetryReply) {
m_nRetryReply = nRetryReply;
}
void COleMsgFilter::SetMessagePendingDelay(DWORD nTimeout) {
m_nTimeout = nTimeout;
}
void COleMsgFilter::SetBusyReply(SERVERCALL nBusyReply) {
m_nBusyReply = nBusyReply;
}
void COleMsgFilter::EnableBusyDialog(BOOL bEnableBusy) {
m_bEnableBusy = bEnableBusy;
}
void COleMsgFilter::EnableNotRespondingDialog(BOOL
bEnableNotResponding ) {
m_bEnableNotResponding = bEnableNotResponding;
}
Compilation and linking
Insert both files into your project, make sure Usage
Derive from COleMsgFilter and implement your own OnMessagePending()
function. Here you can check for timeout and return
PENDINGMSG_CANCELCALL when your application has timed out.

Comments
Using the existing COleMessageFilter
Posted by Legacy on 03/27/2003 12:00amOriginally posted by: AchiCastor
ReplyA DCOM call after cancel does not return till the server process terminates
Posted by Legacy on 06/03/2002 12:00amOriginally posted by: Amit
Any DCOM call made after the returning PENDINGMSG_CANCELCALL from OnMessagePending Function is not completed.
Thanx
Reply
Does not work for a thread other than the application main thread
Posted by Legacy on 10/11/2000 12:00amOriginally posted by: Sebastien Abras
Hello,
thanks for this great code. Unfortunatly, it appears that it
only work when calls to the dcom are made within
theApplication Main Thread.
I tried the following :
nest the dcom calls within a CWinthread that is not the
application thread. In that thread, I register a
OleMessagefilter as described in the article. Everythings
was accepted and does not returned error. But, when I try
it, the OnMessagePending() function is never called.
So I tried declaring the message filter within the main
application thread (but still keep my DCOM in another
thread). It does not work either.
Any Idea on how to have a message filter called from within
a secondary thread ?
thanks a lot ,
sebastien
ReplyAccess Violation when I return PENDINGMSG_CANCELCALL
Posted by Legacy on 09/21/2000 12:00amOriginally posted by: Mark Jordan
Replyderive your class
Posted by Legacy on 02/25/2000 12:00amOriginally posted by: Steve M
This was a really great article. Thanks a lot for publishing it. It was very helpful for a problem I am working on. One, more or less improvement I made was to derive from COleMessageFilter instead of recopying the source code. The trickiest part is that you have to (at least I think so! also verified by coworker Eric!!) create your own nested class XMessageFilter using the BEGIN_INTERFACE_PART macros. I admit, this was almost the same amount of work as cut and pasteing the whole class,instead of just the XMessageFilter implementation. I overrode XMessageFilter::HandleIncomingCall() and MessagePending() to return an appropriate value, based on the return values of OnBusyDialog() and OnNotRespondingDialog(). Of course, this was the whole problem in the first place. I created my own MyRevoke(), MyRegister() methods. I did not override Revoke() and Register() because they were not virtual. (per coworker Eric).
ReplyThe problem that I face
Posted by Legacy on 01/20/2000 12:00amOriginally posted by: V.Madhusudhanan
If the caller is in an MTA and the callee is in either an MTA or an STA, we have problems. The calls generated from the MTA do not respond to the IMessageFilter implementation whereas the calls originating from STA can be controlled for timeout. Simply to say, there is no control over the MTA thread. Hence the difficulty in controlling the timeout.
Can Anyone help?.
Thanks in advance.
ReplyAn easier way ... ?
Posted by Legacy on 06/08/1999 12:00amOriginally posted by: DJRob
Thanks for this great article. It really helped point me in the right direction! However, a far, far easier method of implementing "timeout - auto cancel" is to simply enable the dialogs, and override COleMessageFilter's "OnBusyDialog(...)" and OnNotRespondingDialog(...)" member functions. In those, you can simply return -1 to force the message filter to cancel the COM call.
Reply