65.9K
CodeProject 正在变化。 阅读更多。
Home

调用 Invoke 的辅助类

2002 年 2 月 27 日

3分钟阅读

viewsIcon

55713

downloadIcon

663

SRComHelper 使调用 Invoke 更加容易, 尤其是在有多个 Invoke 调用时。

引言

COM 的优势之一是能够动态链接到其他 COM 对象。 在一个项目中,客户开始说“你能找到一种方法在运行程序之前或之后调用一些程序吗?”时,我学会了利用这方面。 当然,每个客户都希望调用不同的进程。 为了满足他们的需求,我们(我必须包括帮助创建此类的同事和朋友 Estelle Mangeney)开始调用诸如 OnStartOnEnd 之类的函数(实际上,从我们代码中的各种对象调用了 100 多个此类函数)。 对于每个函数,我都定义并记录了原型,并告诉客户,只要他们有一个 COM 对象(ProgID 在数据库中),我就会调用这些函数。

问题是我讨厌必须为每个函数编写调用 Invoke 的所有代码。 每次我使用 Invoke 编写对新函数的调用时,我都会犯新的错误,整个过程相当痛苦。 结果是 SRComHelper 类,该类提供了一个稍微友好的界面。 我说稍微,因为我认为它可以做得更好,但我经常太忙也太懒了。

调用 Invoke

不得不为函数调用 Invoke 的过程可能很乏味。 例如,如果有一个 COM 对象 SampleComDLL.DLL,其 progID 为“SampleComDLL.ComTest”,并且有一个函数 

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

那么调用此函数的过程将类似于

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 是一个封装上述过程并为用户提供更简单界面的类。 该类提供了一系列 SetParam 函数,用户可以使用这些函数来设置要调用的函数的参数。 使用 SRComHelper 调用上面的 Sum() 函数如下所示

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 使用起来会有些棘手。 假设我们有一个函数 
HRESULT SumAndMultiply(VARIANT num1, VARIANT num2,
                       [out] VARIANT* pProduct,
                       [out, retval] VARIANT* pSum).

SumAndMultiply 返回两个数字的和和乘积。 使用 SRComHelper 调用 Sum,然后调用 SumAndMultiply 将是

//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 不是很优雅。 必须调用 GetOutput( int index ) 函数。 但是,它仍然比每次有一个新函数时都必须编写调用 Invoke 之后的所有代码要好。

我没有详细介绍 SRComHelper 的代码,因为它是不言自明的(请参阅可供下载的代码)。 我在包含一些我构建的其他工具的 DLL 中使用此类。 该类可以直接成为项目的一部分,也可以在 DLL 中。 希望它能派上用场并节省您一些时间。 此外,并非所有数据类型都包含在 SetParams 函数中,因为我一直在根据需要添加它们。 但是其余的应该很容易添加。 另外,请注意,我将每次调用 Invoke 都视为对 Method 的调用。

© . All rights reserved.