Introduction
Don't be fooled by the title. Even if you are not (will not be) dealing with the
IDispatch
interface directly, this article and the included source code could be very useful to you. In my previous article
"Buried treasure in MFC: COleDispatchDriver", I introduced
XYDispDriver
, a class derived from
COleDispatchDriver
, that can be used to dynamically create and use com objects. The advantage of
XYDispDriver
is its simple interface. You create and use all (well, almost all) com objects the same way. There is no need for wrapper classes. You don't even need type libraries at compile time.
Then I realized that not all people love MFC as I do. By diving into the source code of COleDispatchDriver
, I found out that there is really no need to get MFC involved. I have re-coded the class XYDispDriver
from scratch so that it does not depend on any library (sorry, ATL and STL fans :-).
Most of my code is borrowed from MFC, of course. Fortunately, XYDispDriver
without MFC is still simple and easy to use.
XYDispDriver
Here are some of the public methods of
XYDispDriver
. Please note the changes from its previous version.
class XYDispDriver
{
...
public:
XYDispDriver();
~XYDispDriver();
bool CreateObject(LPCTSTR strProgID,
DWORD dwClsContext = CLSCTX_ALL, LPCTSTR
strServerName = NULL); bool CreateObject(CLSID clsid, DWORD
dwClsContext = CLSCTX_ALL, LPCTSTR strServerName = NULL);
VARTYPE GetPropertyType(LPCTSTR strPropertyName);
VARIANT* GetProperty(LPCTSTR strPropertyName);
bool SetProperty(LPCTSTR strPropertyName, ...);
VARTYPE GetReturnType(LPCTSTR strMethodName);
int GetParamCount(LPCTSTR strMethodName);
VARTYPE GetParamType(LPCTSTR strMethodName, const int nParamIndex);
VARIANT* InvokeMethod(LPCTSTR strMethodName, ...);
HRESULT GetLastError() { return m_hRet; }
EXCEPINFO* GetExceptionInfo() { return m_pExceptInfo; }
};
The CreateObject
functions create a com object: getting a pointer to its IDispatch
interface and also querying its ITypeInfo
interface to load all the necessary type information. This makes it possible to use the InvokeMethod
function to call various com methods in an incredibly flexible way.
The output values of GetProperty
and InvokeMethod
are stored in internal variables of type VARIANT
. These methods will return a pointer to VARIANT
or NULL
if unsuccessful (for example, the method or property with given name does not exist, or there is a com error). If you don't store the return value, it will be overridden when the same method (or property) is invoked the next time. There is no need to clean up memory for the internal variables. To use XYDispDriver
in a multi-threaded process, you can either use a separate object in each different thread or serialize the access to shared objects using critical sections. Please note that the InvokeMethod
function can take a variable number of arguments.
For power users, the GetLastError
returns the last SCODE
and the GetExceptionInfo
returns a pointer to an EXCEPINFO
structure (maybe NULL
if there is no exception).
Sample code
The following code demonstrates how to use
XYDispDriver
to create a com object and call its methods in a console application.
#include "XYDispDriver.h"
void main()
{
XYDispDriver disp;
if(disp.CreateObject("XYDBREADER.XYDBReaderCtrl.1"))
{
VARIANT* pOutput = disp.InvokeMethod("OpenDB","XY_TAG","","");
if(pOutput&&pOutput->boolVal)
{
printf("Database opened\n");
pOutput = disp.InvokeMethod("OpenQuery",0,
"select * from XYTagName");
if(pOutput&&pOutput->lVal)
{
printf("Query opened: %d\n",pOutput->lVal);
long nQueryID = pOutput->lVal;
pOutput = disp.InvokeMethod("GetAllRec",nQueryID);
if(pOutput)
{
printf("Got data");
wprintf(L"Returned data:\n%s\n",pOutput->bstrVal);
disp.InvokeMethod("CloseQuery",nQueryID);
}
}
disp.InvokeMethod("CloseDB");
}
}
printf("done\n");
}
It is also possible to use XYDispDriver
with existing com objects. All you need to do is declare an instance of XYDispDriver
and call the Attach
method (not listed above) passing the IDispatch
pointer of the existing com object.
Other Features
You can use XYDispDriver
with COM+ to create com object on a remote machine. Here is what you have to do.
- Register the com dll or exe on the remote machine. Create a COM+ "Server" application and add this component.
- Export the COM+ application from the remote machine (generate a .MSI file).
- Import the COM+ application to your local machine (run the .MSI file).
- Call the
CreateObject
method of XYDispDriver
passing the name of the remote machine as the third parameter.
The XYDispDriver
retrieves type info of a com object it created and uses the type info to call com methods dynamically. Sometimes it is not possible to retrieve type info or not efficient to do so. There is an InvokeVariantMethod
method (not listed above) in the XYDispClass
class which can be used to invoke almost any com method as long as we have the IDispatch
pointer of the com object. To use this method, you need to provide the following.
IDispatch
pointer of a com object.
- The name of the com method.
- Invocation flag (
DISPATCH_METHOD
, DISPATCH_PROPERTYGET
, or DISPATCH_PROPERTYPUT
).
- Number of parameters for the com method.
- List of parameters (the parameter values have to be in
VARIANT
variables).
Thank you for reading this article, please refer to my home page for other articles and programs.
Recent Updates
- 12/11/2003 - Modified article text and code to create com object on a remote machine.