The XYDispDriver
class is a simple generic dispatch driver class that can be used to create
almost any COM object and call its methods. In my previous
article Handling COM Events
in a Console Application, I talked about enhancements to this class that makes handling
COM events easy. No need for messy template code, no event sink map,
and no sink entry macro, etc. All we need to do is create a COM object
implementing the event interface using our favourite tool and then call
the Advise
method of XYDispDriver
.
The previous version of XYDispDriver
does not deal with some complicated situations, such as multiple event
sinks or multiple event sources. Some people may worry that this
is not the right way to handle general COM events. After making some
changes to the XYDispDriver
class, I was able to write code that deals with these situations successfully.
The resulting code, as you can see, is simpler than the code you would
have written using ATL to accomplish the same thing.
The only significant change I made is adding an
assignment operator to the XYDispDriver
class. As described in my article
Getting the most out of IDispatch,
the CreateObject
method of XYDispDriver
will create a new instance of a COM object, query and store its type
information for future use. Assigning one XYDispDriver
object to another does not create a new instance of the corresponding COM
object, instead it only copies the type information and the IDispatch
pointer, and call the IDispatch::AddRef
method to bump up the reference
count. Therefore, the two XYDispDriver
objects will be referring to the same COM object after the assignment.
Let's first see the code that deals with multiple
event sinks. We will be using the same example as in the
previous
article: "TestCon"
is an ActiveX control that fires the InvalidLoginData
event when its Connect
method fails and "TestHndlr"
is another ActiveX control that implements the event interface of TestCon.
What we need to do is "connect" two instances of TestHndlr
to a single instance of TestCon
so that when the InvalidLoginData
event is fired, the event handling method will be invoked in both instances
of TestHndlr.
Here is the code of a console application that demonstrates the scenario of two event sinks.
#include <stdio.h>
#include "XYDispDriver.h"
void main()
{
XYDispDriver dispCon1, dispCon2, dispEventA, dispEventB;
���
��� if(dispCon1.CreateObject("TestCon.1"))
��� {
�������
������� dispCon2 = dispCon1;
�������
�� ���� if(dispEventA.CreateObject("TestHndlr.1"))
������� {
����������
���������� CLSID clsidEventA = {0xe77a1f7e,0xe3ff,0x11d5,{0x88,0x12,0x00,0xb0,0xd0,0x55,0xb5,0x23}};
����������
����������dispCon1.Advise(dispEventA.GetDispatch(),clsidEventA);
������� }
����� else printf("Error: %x\n",dispEventA.GetLastError());
�����
���� if(dispEventB.CreateObject("TestHndlr.1"))
������� {
����������
���������� CLSID clsidEventB = {0xe77a1f7e,0xe3ff,0x11d5,{0x88,0x12,0x00,0xb0,0xd0,0x55,0xb5,0x23}};
����������
���������dispCon2.Advise(dispEventB.GetDispatch(),clsidEventB);
������� }
������� else printf("Error: %x\n",dispEventB.GetLastError());
�������
�������
�������
�������
�������
������� dispCon1.InvokeMethod("Connect","MyName","MyPwd");
�������
��� }
��� else printf("Error: %x\n",dispCon1.GetLastError());
��� ::MessageBox(NULL,_T("Done"),_T("Test"),MB_OK);
}
The code that deals with multiple event sources
is similar. Suppose the COM object TestCon
has two different event interfaces, we can create two different types of COM objects
TestHndlrA and TestHndlrB to implement these two interfaces, respectively.
In the above code, if we let dispidEventA
and dispidEventB
be the dispids of these two event interfaces, and use the two XYDispDriver
objects dispEventA
and dispEventB
to
create these two event handler objects, then the above code will demonstrate the scenario of
two event sources.
The zip file included with this article only has
source code for the two ActiveX controls and the console app. You
can download the source code for XYDispDriver
from my article Getting the most out of IDispatch.
You can also find more articles and software from my
home
page.
Disclaimer: I am not trying to show
that ATL or any other related technology is not as good as my method.
All I am doing is demonstrate a pretty simple and flexible (maybe unconventional)
way to use COM objects.