HOW TO Configure DCOM Timeouts

We will also look at how to dispense with the disturbing “Server Not
Responding – Switch To” and “Server Busy” dialog boxes.

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 and call the
following methods:


MyFilter.EnableNotRespondingDialog(FALSE);
MyFilter.EnableBusyDialog(FALSE);
MyFilter.Register();

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
“….vcmfcsrcolemsgf.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:


MessagePending() {

//do something useful

//call virtual function OnMessagePending

return PENDINGMSG_WAITNOPROCESS
}

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.

What now?

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:


///////////////////////////////////////////////////////////////////
////////// // COleMessageFilter (implements IMessageFilter)

Mark and copy the COMPLETE class definition and paste it to a new
header file, named “OleMsgFlt.h”.

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.

Prepare the class CPP file.

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.


#include “OleMsgFlt.h”

d) Insert the line shown below at the top of your CPP file


#include

e) From the file “../vc/mfc/src/afximpl.h” copy the line shown below
to
the top of your CPP file


#define _countof(array) (sizeof(array)/sizeof(array[0]))

f) From the file “”../vc/mfc/include/afxpriv.h” copy the line shown
below to the top of your CPP file


#define WM_KICKIDLE 0x036A

g) Find the method “COleMsgFilter::XMessageFilter::MessagePending” and

within it, the line where OnMessagePending() is called. It should
look like this:


pThis->OnMessagePending(&msg);

Prefix this line with “return”, like so:


return pThis->OnMessagePending(&msg);

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.


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 as well as
the standard DCOM / OLE headers are included in your project, and
compile…

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.

More by Author

Must Read