Click here to Skip to main content
Licence 
First Posted 1 Oct 2001
Views 138,897
Bookmarked 48 times

Buried treasure in MFC: COleDispatchDriver

By | 8 Nov 2001 | Article
Introducing a simple and dynamic com dispatch driver class

Introduction

If you have used the VC++ ClassWizard to import a class from a type library, you will be familiar with the COleDispatchDriver class. This class is typically used as the base class of machine generated wrapper classes for COM objects. Actually, I have never seen it being used for anything else except as the base of wrapper classes (until now, of course). Why do I bother to write an article about COleDispatchDriver? The reason is that I think this class has some unreleased power that will make a C++ developer's life a lot easier.

Have you noticed that VB developers can create almost any COM object and call its methods at run-time, and VC++ developers have to use compile-time generated wrapper classes? Anyone understands COM will say that we can do the same thing in C++, but we don't want to bother with writing so much low-level com code to accomplish this. My goal is to derive a utility class from COleDispatchDriver so that we can write code like the following in VC++ without generating any wrapper class at compile-time:

// declare a utility object
MyUtilityClass utility;
// create a com object with prog id "MyComObj1"
utility.CreateObject("MyComObj1");
// call the method "GetData" (no argument) in the com object
CString strData = utility.CallMethod("GetData");
// create another com object with prog id "MyComObj2"
utility.CreateObject("MyComOb2");
// call the method "GetMsgCount" with one argument
long nUserID = 3;
long nCount = utitilty.CallMethod("GetMsgCount", nUserID);

As you can see later, I came pretty close to achieving this goal. If someone flames me for damaging a developer's brain with VB-style code, then my job is done :-). Please note that this is not meant to replace other existing methods of creating and using a com object.

I would like to thank Chris Losinger and Aaron Schaefer for answering my "anonymous" programming questions.

XYDispDriver

XYDispDriver is the name of my utility class. The source code project will build a library XYDispDriver.dll which exports the XYDispDriver class. As usual, you may use and modify the source code anyway you wish, I would appreciate some acknowledgment for my contribution (if possible). Here is the header file of my class.
#include <afxdisp.h>

class XYDispDriver: public COleDispatchDriver
{
    // an internal array to store type information
    CPtrArray m_arrayDispInfo;
    // an internal function to get index to stored type information
    int FindDispInfo(const CString strName, const WORD wFlag = DISPATCH_METHOD);
    // clear internal storage
    void Clear();
    // these 3 functions are here to hide functions with the same names in the base class
    BOOL CreateDispatch(REFCLSID clsid, COleException* pError = NULL) { return FALSE; }
    void AttachDispatch(LPDISPATCH lpDispatch, BOOL bAutoRelease = TRUE ) {}
    LPDISPATCH DetachDispatch( ) { return NULL; }
public:
    XYDispDriver();
    ~XYDispDriver();
    // create a com object with given prog id, this function
    // hide the function with the same name in the base class
    BOOL CreateDispatch(LPCTSTR lpszProgID);
    // get the type of a property
    VARTYPE GetPropertyType(const CString strPropertyName);
    // get the property value
    void* GetProperty(const CString strPropertyName);
    // set the property value
    void SetProperty(const CString strPropertyName, ...);
    // get return type of a method
    VARTYPE GetReturnType(const CString strMethodName);
    // get number of parameters in a method
    int GetParamCount(const CString strMethodName);
    // get the type of a parameter in a method
    VARTYPE GetParamType(const CString strMethodName, const int nParamIndex);
    // invoke a method
    void* InvokeMethod(const CString strMethodName, ...);
};

To use the XYDispDriver class, you first need to declare an instance of this class and call the CreateDispatch member function passing the prog id of a com object. This method not only creates an IDispatch pointer, it also retrieves and stores all the necessary type information using the ITypeInfo interface. Then you can call other member functions to either invoke a method in the com object or get/set a property value.

Please note that GetProperty and InvokeMethod both return a void pointer. To access the return data, you need to cast the pointer to the appropriate data type and then dereference it. Also, the return data will be over-ridden by the next call to the same method. I know this is cumbersome and un-OO like, but who said the world is perfect? :-)

Please also note that methods of XYDispDriver may throw exceptions of type COleException, an MFC class.

Sample code

Here is a sample program that creates an XYMailClient object described in my other article and sends/receives e-mail messages. The code can be written and executed without using any type library at compile-time.
/*************** Test.cpp ***********************/

#include "XYDispDriver.h&quot

void main()
{
    XYDispDriver disp;
    try
    {
       if(disp.CreateDispatch("XYMailClient.1"))
        {
           if(*(BOOL*)disp.InvokeMethod("InitSession","MyProfile","")==FALSE)
            {
                printf("Failed to call InitSession\n");
                return;
            }
           if(!*(BOOL*)disp.InvokeMethod("SendMsg","<a href="mailto:XiangYangL@aol.com">XiangYangL@aol.com</a>",
                                         "","","Hello","This is a test",""))
            {
                printf("Failed to call SendMsg\n");
            }
           long nCount = *(long*)disp.InvokeMethod("FetchMsg");
            printf("Total messages = %d\n",nCount);
           for(int i=0;i<nCount;i++)
            {
                printf("Message %d: %s\n",i,*(CString*)disp.InvokeMethod("GetMsg",i));
            }
            disp.InvokeMethod("DeleteMsg",0);
            disp.InvokeMethod("EndSession");
        }
       else
        {
            printf("Failed to create com obj\n");
        }
    }
    catch(COleException* e)
    {
        printf("Ole exception\n");
       TCHAR buf[251];
        e->GetErrorMessage(buf,250);
        printf("%s\n",buf);
        e->Delete();
    }
    printf("Done\n");
}
/**************** End of Test.cpp ****************/
 

Using XYDispDriver in your own program

XYDispDriver is implemented with VC++ 5.0 and MFC.

To use XYDispDriver, you need only to add the source files to your project or use it as a dll. You should always use the CString class for string data, although you can pass literal strings as input parameters. I have not done extensive testing with various data types except for strings and numbers. Please let me know if you found or fixed a bug.

Thank you for reading this article. Please visit my home page for my other articles and programs.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Xiangyang Liu 刘向阳



United States United States

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionHow to Manage COM Events PinmemberRoberto Guerzoni21:21 4 Aug '10  
Generalsmart pointer for class derived from COleDispatchDriver Pinmemberravi malik2:22 7 May '10  
GeneralProblem with COleDispatchDriver::CreateDispatch(...). It is failing on x64 platform. Pinmembersumd21:34 21 Feb '09  
QuestionHow to make it can create an instance of a class on remote machine Pinmemberchaocai22:23 8 Dec '03  
GeneralQuestion PinmemberAnthony_Yio19:37 11 Mar '03  
GeneralRe: Question PinmemberXiangyang Liu15:59 12 Mar '03  
GeneralNote from the Author PinmemberXiangYangLiu5:13 5 Oct '01  
GeneralRe: Note from the Author PinmemberXiangYangLiu9:19 16 Nov '01  
GeneralEverybody relax PinmemberGogglesPisano3:45 5 Oct '01  
GeneralRe: Microsoft's #import directive PinmemberXiangYangLiu1:46 3 Oct '01  
GeneralRe: Microsoft's #import directive PinmemberJohn Smith II2:11 3 Oct '01  
GeneralRe: Microsoft's #import directive PinmemberXiangYangLiu2:52 3 Oct '01  
GeneralRe: Microsoft's #import directive PinmemberAnonymous1:07 9 Oct '01  
GeneralRe: Microsoft's #import directive PinmemberXiangYangLiu2:45 3 Oct '01  
GeneralRe: Microsoft's #import directive PinmemberXiangYangLiu3:04 3 Oct '01  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120517.1 | Last Updated 9 Nov 2001
Article Copyright 2001 by Xiangyang Liu 刘向阳
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid