Click here to Skip to main content
Click here to Skip to main content
Go to top

Dynamic Creation of IDispatch interfaces using simple classes

, 3 Sep 2001
Rate this:
Please Sign up or sign in to vote.
Create dynamic objects that you can pass using IDispatch interfaces
<!-- Download Links --> <!-- Main HTML starts here -->

Introduction

This concept may be hard to grasp so I will tell you what my original intent for these classes were, and that should help you understand how you can use them.

I was writing a piece of software exposing certain objects to a VBscript host. This is easy when you write your objects in ATL or create an ActiveX object - you just pass in the IDispatch to the scripting host and it takes care of resolving method and property ID's/names so your object can be naturally scripted.

So after getting the scripting host working I decided that it would be really nice if I could write plugins that could somehow be exposed to the script host as well. I did not want to limit the plugins to a specific number of methods or properties. Essentially what I wanted to do was create an ActiveX control in real-time.

I did not know if this was possible, so the search began, the coding began, the headaches began. The end result of all this work is a set of classes that can be used to create IDispatch interfaces 'on the fly'.  A friend of mine made the comment "why bother" well if you see any use for this then paste it on the thread please.

I learned a lot more about COM than I really wanted to throughout this exercise, but in the end my idea actually worked. And the information I picked up did help down the road.

The interesting thing about this is that you don't have to concern yourself with GUIDs or other things to create and use these objects. They don't have to be registered, they only have to exist.

In my original code I would query a DLL for what props and methods it wanted, give it a name, and then added it as an object to the script host. It made writing scriptable plugins easy, and allowed the plugins to have all the flexibility of exposing their own unique interfaces to the VBscript without having to worry about COM.

The classes involved are:

CDynamicMethodData

CDynamicInterface

CDynamicObject

The CDynamicMethodData object is used to set up our desired properties/methods. It has a method called

CreateNewMethod(CString sMethodName,unsigned short usMethodType).

sMethodName - the name of the method or property
usMethodType - what kind of call is this (method)

the valid method types are :
DISPATCH_METHOD (call a function),
DISPATCH_PROPERTYGET (self explanatory)
DISPATCH_PROPERTYPUT (self explanatory)

The CDynamicInterface encapsulates the CDynamicMethodData, and provides the mechanisms for actually generating the realtime COM interfaces.

void CDynamicInterface::AddMethod(CString sMethod,CString sParms)

Since I wanted to make adding methods and properties easier I decided that sending a string of parameters for a method made more sense than repetively calling the AddMethod function. So to set up a method Called "SetPoint" with two parameters we would do this:

myDynamicInterface.AddMethod("SetPoint","VT_INT,VT_INT");

To add a property we simply call:

myDynamicInterface.AddProperty("intprop",VT_INT);

Make note that we use VARIANTS for everything. Also know that when you add a property you are actually adding 2 methods (1 for put and 1 for get). If you call the CDynamicMethodData directly to add props then you can specify if you want just a DISPATCH_PROPERTYPUT or just a DISPATCH_PROPERTYGET. In the case of my dynamic interface I made it simple and add both when you create a property.

Whenever a method or property is added to an interface you need realize that it is assigned an ID (0 based). This makes it important for your eventual implementation class to know the order that you added properties and methods so that you can deal with them appropriately. (will become more clear in a minute)

So now we get to the CDynamicObject which is the class you will inherit from to make your dynamic objects a reality. It is based directly on IDispatch and will handle any incoming property query or interface call. In my implementation I decided to make the CDynamicMethodData a pointer instead of a an actual object. The decision made sense at the time, if you create multiple objects of the same type, why would you want to create copies of an already existing interface? This could also be achieved using a static member variable, which you can choose to implement if you really want to.

So by now we may have added some props and methods, so how do we deal with incoming request calls?
In our implementation class (based on CDynamicObject) we need to implement the function:

HRESULT vDispInvoke(
	void FAR* _this,
	ITypeInfo FAR* ptinfo,
	DISPID dispidMember,
	unsigned short wFlags,
	DISPPARAMS FAR* pparams,
	VARIANT FAR* pvarResult,
	EXCEPINFO* pexcepinfo,
	unsigned int FAR* puArgErr );

Don't worry its a lot less scary than it looks. The key is the dispidMember variable. Remember when I told you to keep track of the order in which you added the properties and methods? Well if you did not then you are out of luck figuring out what the heck you should do. In my implementation I used #define to set up props and methods for my dynamic objects. First we figure out what kind of method the caller wants:

if( (wFlags & DISPATCH_PROPERTYGET) || (wFlags & DISPATCH_PROPERTYPUT) )
{
// Its a property Alright...
// But Which one?
} else if(wFlags & DISPATCH_METHOD)
> {
// Its a method Call..
// which one?
}

The answer of "which one?" is contained within the dispidMember variable. If (when you were initializing the interface) you added "SetPoint" first and the dispidMember = 0, then "SetPoint" is the method. Remember that properties have two IDs (one for get and one for set).

So here's an example of what a fully implemented vDispInvoke might look like:

HRESULT CMyDynamicObject::vDispInvoke( 
		void FAR*  _this,        
		ITypeInfo FAR*  ptinfo,  
		DISPID  dispidMember,
    		unsigned short  wFlags,  
		DISPPARAMS FAR*  pparams,  
		VARIANT FAR*  pvarResult,
  		EXCEPINFO*  pexcepinfo,   
		unsigned int FAR*  puArgErr )
{
	/*
		This is where all the work really takes place...
		Since we know most of the methods, functions etc....
	*/

         // call a function
	if(dispidMember == MY_INSTANCE_FUNCTION)
		return i_MyFunction(wFlags,pparams,pvarResult);

	if(dispidMember == INSTANCE_GET_X || 
	   dispidMember ==     INSTANCE_SET_X)// X
		return i_HandleGetSetX(wFlags,pparams,pvarResult);

	if(dispidMember == INSTANCE_GET_Y || 
	   dispidMember ==   INSTANCE_SET_Y)// Y
		return i_HandleGetSetY(wFlags,pparams,pvarResult);

	return S_OK;
}
I chose to implement one function for getting/setting a property. It looks like this:
HRESULT CMyDynamicObject::i_HandleGetSetX(unsigned short wFlags,DISPPARAMS FAR* pparams,VARIANT FAR* pvarResult)
{
	if(wFlags & DISPATCH_PROPERTYGET)
	{
		pvarResult->vt = VT_INT;
		pvarResult->intVal = m_iX;
	}
	else
		m_iX=pparams->rgvarg->intVal;

	return S_OK;
}



Receiving the method call is almost the same.

HRESULT CMyDynamicObject::i_MyFunction(unsigned short wFlags, DISPPARAMS FAR* pparams, 
                                       VARIANT FAR* pvarResult)
{
	VARIANT* pVars = pparams->rgvarg;// our array of parameters (which we should know)

	// do something interesting
	return S_OK;
}

The end result of all of this is that you now have an object that can be used by a scripting host or anything that accepts an IDispatch interface. The caveat is that your interfaces are only known at runtime, which was the point right? I do not have time at the moment, but will be updating this article at a later date with a working automation project that shows an example of these classes being used.

You are free to use the code as you wish, just drop me an email if you use it in something interesting, extend it, or just want to say "hey!".

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

Share

About the Author

dswigger

United States United States
No Biography provided

Comments and Discussions

 
QuestionHow to get INTERFACEDATA from ITypeInfo? Pinmembermasterhe11-Nov-12 3:43 
GeneralBjarke Viksoe had made same implement at "http://www.viksoe.dk/code/atldyndispatch.htm" Pinmemberlxu4net2-Mar-09 3:30 
QuestionHow to use in MFC or ATL ???Help me!!! Pinmemberytweiwei29-Dec-05 21:01 
AnswerRe: How to use in MFC or ATL ???Help me!!! Pinmemberzcjky200621-Feb-06 22:03 
GeneralITypeInfo does'nt work Pinmemberkemaikin21-Jun-05 22:34 
GeneralDynamic creation of properties PinmemberFraBue30-May-05 0:03 
GeneralBeautiful. I hope I can get this to work Pinmemberdugbug3-Jun-04 5:01 
GeneralRe: Beautiful. I hope I can get this to work Pinmemberdswigger3-Jun-04 18:14 
GeneralIDispatch PinmemberAnthony_Yio21-Apr-04 21:47 
GeneralRe: IDispatch Pinmemberdswigger22-Apr-04 4:34 
GeneralThe idea is great PinmemberYao Zhifeng2-Jan-03 18:29 
QuestionHow to using an object that we know it just a little bit!? PinsussAnonymous24-Oct-02 23:11 
AnswerRe: How to using an object that we know it just a little bit!? Pinmemberdswigger25-Oct-02 3:37 
GeneralObject Object communication Pinmembermadhu14-Jan-02 17:55 
GeneralRe: Object Object communication Pinmemberdswigger25-Oct-02 3:34 
Generalexample PinmemberAnonymous3-Oct-01 23:49 
QuestionWhy do you need to implement such? Pinmembermao3-Oct-01 4:08 
AnswerRe: Why do you need to implement such? Pinmemberdswigger3-Oct-01 4:37 
GeneralIDispatchEx PinmemberBart van Haaff3-Sep-01 22:58 
GeneralRe: IDispatchEx Pinmemberdswigger4-Sep-01 6:17 
GeneralRe: IDispatchEx Pinmemberpeterchen30-Jun-04 18:17 
GeneralRe: IDispatchEx Pinmemberdhaag28-Sep-04 15:41 

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.

| Advertise | Privacy | Mobile
Web01 | 2.8.140926.1 | Last Updated 4 Sep 2001
Article Copyright 2001 by dswigger
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid