Click here to Skip to main content
15,883,883 members
Articles / Desktop Programming / ATL
Article

A Helper Class for Calling Invoke

Rate me:
Please Sign up or sign in to vote.
1.89/5 (4 votes)
6 May 20023 min read 54.9K   663   26   2
SRComHelper makes it easier to call invoke specially in cases where there are several calls to Invoke

Introduction

One of the advantages of COM is the ability to dynamically link to other COM objects. I learnt to take advantage of this aspect during a project when customers would start saying "Can you find a way to call some program just before you run your program or just after." And of course each customer wanted a different process called. To cater to their needs we (I must include fellow developer and friend Estelle Mangeney who helped in creating this class) started placing calls to functions such as OnStart and OnEnd (in reality there were more than 100 such functions called from various objects in our code). For each function I defined and documented the prototype and told the customers that as long as they had a COM object (The ProgID of which was in the database) I would call the functions.

The problem was that I hated having to write all the code for calling Invoke for each of these functions. Each time I wrote the call to a new function using Invoke I made new errors and the whole process was rather painful. The result was SRComHelper a class that provides a slightly friendlier interface. I say slightly as I believe it can be made even better but I am often too busy and way too lazy.

Calling Invoke

The process of having to call Invoke for a function can be tedious. For example if there was a COM object SampleComDLL.DLL with a progID of "SampleComDLL.ComTest" with a function 

HRESULT Sum(VARIANT num1, VARIANT num2, [out, retval] VARIANT* sum) 

then the process of calling this function would be somewhat like:

void CallInvoke() {

//get the numbers to add
        int number1 = 10;
        int number2 = 20;
        int sum1And2 = 0;
//Create an instance of the object
    CLSID clsid;
        IDispatchPtr disp;
    HRESULT result = CLSIDFromProgID( progID, &clsid );
    if( SUCCEEDED( result ) ) {
        result = disp.CreateInstance(clsid);
        }
        else {
                Some error stuff;
        }
//Now Get ready to call the function

    EXCEPINFO *pExcepInfo = NULL;
    unsigned int *puArgErr = NULL;
        DISPID functionID[1];
        VARIANT dispRes;
        DISPPARAMS dispparams;
    dispparams.rgvarg[0].vt = VT_I2;
    dispparams.rgvarg[0].iVal = number2;  

        //and try to remember the reverse order

    dispparams.rgvarg[1].vt = VT_I2;
    dispparams.rgvarg[1].iVal = number1;
    dispparams.cArgs = 2;
    dispparams.cNamedArgs = 0;

    LPOLESTR GetFName[1] = {"Sum"}; //name of the function to call
    hr = disp->GetIDsOfNames(IID_NULL, GetFName, 1, LOCALE_SYSTEM_DEFAULT,
                             functionID);

    try {
        if( SUCCEEDED(hr) ) {
            hr = disp->Invoke( functionID[0], IID_NULL,
                               LOCALE_SYSTEM_DEFAULT, 
                               DISPATCH_METHOD, 
                               &dispparams, &dispRes, 
                               pExcepInfo, puArgErr );
        }
    }
    catch(_com_error* e) {
//                 Some Error Stuff        
    }
        sum1And2 = dispRes.iVal  //Get rthe resulting sum of the two numbers
}

SRComHelper

SRComHelper is class that encapsulates the above process and provides the user with a much simpler interface. The class provides a series of SetParam functions that a user can use to set the arguments of the function to call. A call to the Sum() function above using SRComHelper looks like:

int num1 = 3;
int num2 = 7;
int sum = 0;
int sumProduct = 0;

//Create the COM Helpper class with the progid of the com object
CSRComHelper comHelper( "SampleComDLL.ComTest" );
comHelper.CreateArray( 2 );  //Set up for a function with 2 arguments

//Now set the inputs
comHelper.SetParam( num1 );  //Set the values for the args
comHelper.SetParam( num2 );

CComVariant retVal ("");
CString sFunctionName( "Sum" );  //Set the name of the function to call

HRESULT hr = S_OK;
hr = comHelper.CallInvoke( sFunctionName.AllocSysString(), 
                           retVal ); //Invoke it
sum = retVal.iVal;
SRComHelper gets a little trickier to use when you have a return value and an argument passed as a pointer. Lets say we had a function 
HRESULT SumAndMultiply(VARIANT num1, VARIANT num2,
                       [out] VARIANT* pProduct,
                       [out, retval] VARIANT* pSum).

SumAndMultiply returns the sum of two numbers and the product. The call to Sum followed by a call to SumAndMultiply using SRComHelper would be:

//Create the COM Helpper class with the progid of the com object
CSRComHelper comHelper( "SampleComDLL.ComTest" );
int num1 = 3;
int num2 = 7;
int sum = 0;
int sumProduct = 0;

comHelper.CreateArray( 2 );
//Now set the inputs
comHelper.SetParam( num1 );
comHelper.SetParam( num2 );

CComVariant retVal ("");
CString sFunctionName( "Sum" );

HRESULT hr = S_OK;
hr = comHelper.CallInvoke( sFunctionName.AllocSysString(), retVal );
sum = retVal.iVal;

comHelper.Reset();      //This resets SRComHelper and sets it up for a new call
comHelper.CreateArray( 3 );
//Now set the inputs
comHelper.SetParam( num1 );
comHelper.SetParam( num2 );
comHelper.SetParam( &sumProduct );

CComVariant retVal2;
sFunctionName = CString( "SumAndMultiply" );
hr = comHelper.CallInvoke( sFunctionName.AllocSysString(), retVal2 );
VARIANT res2;
res2 = comHelper.GetOutput( 2 );  //This is the tricky part

SRComHelper
is not very elegant when getting the value of an argument passed as a pointer. One has to call the GetOutput( int index ) function. It is, however, still better than having to write all the code behind the call to Invoke each time you have a new function.

I have not gone into much detail regarding the code of SRComHelper as it is rather self explanatory (See code available for download). I use this class in a DLL with some other tools that I have built. The class can be directly part of your project or in a DLL. Hope it comes to some good use and saves you some time. Also, not all data types are included in the SetParams functions as I have been adding them as I need them. But the remaining should be easy to add. Also, please note that I treat each call to Invoke as a call to a Method.

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


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
QuestionLicensing terms Pin
AnupTR25-Apr-13 10:22
AnupTR25-Apr-13 10:22 
GeneralYou are a Best Pin
redjes1-Sep-08 21:29
redjes1-Sep-08 21:29 

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

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