从非托管代码调用托管COM:SAFEARRAY

时间:2014-12-27 08:01:19

标签: c# c++ vb.net com

我有一个用VB.net编写的COM组件。此COM组件的接口是

Public Interface IEdge
    Function FooFunc() As Integer
    Function Exec(ByVal modelName As String, ByVal Params As Object()) As Object
    Sub Foo()
    Sub Fooint(ByVal a As Integer)
End Interface

我正在使用

在Native C ++代码中使用此COM组件的Type Library
#import "..\Edge.tlb" named_guids raw_interfaces_only

Main的C ++代码是

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = CoInitialize(NULL);  //Initialize all COM Components

    ICOMEdgePtr myEdge;
    HRESULT hRes =   myEdge.CreateInstance(CLSID_COMEdge);
    if (hRes == S_OK)
    {
        VARIANT lResult ;
        BSTR str;

        myEdge->Foo();
        myEdge->Fooint(1234);
        long abc = 0;
        myEdge->FooFunc(&abc);

        SAFEARRAYBOUND aBound[2];
        aBound[1].cElements = 2;
        aBound[1].lLbound = 0;
        SAFEARRAY* sf = SafeArrayCreate(VT_INT, 1, &aBound[1]);

        long index1=0;
        int val1=20;
        SafeArrayPutElement(sf, &index1, &val1);

        long index2=1;
        int val2=30;
        SafeArrayPutElement(sf, &index2, &val2);

        myEdge->Exec(L"Add", sf, &lResult);
        //Using lResult after this  
    }

    CoUninitialize (); 
    return 0;
}

我可以致电FooFunc()Foo()Fooint()

但是我无法调用Exec函数,它没有显示任何错误,也没有报告崩溃。

对于测试,我在VB.net中使用了这个COM组件(使用CreateObject(CLSID)),可以从那里调用Exec。我需要从Native C ++中调用它。

我怀疑SafeArrayObject()转换存在问题。接口定义是错误的吗?

我尝试使用System.Array<MarshalAs(UnmanagedType.SafeArray)>,但没有解决问题。我已经MsgBox()作为Exec定义的第一个语句,以便我知道是否Exec被调用。

1 个答案:

答案 0 :(得分:1)

根据Hans Passant给出的建议,我可以使用SAFEARRAY。

我在C ++中使用基于Dotnet的COM组件。最后,我更改了C ++代码以保持COM安全。

我已将VARIANT替换为CComVariant,将BSTR替换为CComBSTR,将SAFEARRAY替换为CComSafeArray

现在Main的代码如下:

int _tmain(int argc, _TCHAR* argv[])
{
    HRESULT hr = CoInitialize(NULL);  //Initialize all COM Components

    ICOMEdgePtr myEdge;
    HRESULT hRes =   myEdge.CreateInstance(CLSID_COMEdge);
    if (hRes == S_OK)
    {
        CComVariant lResult ;
        CComSafeArray<VARIANT> arr(2,0);
        arr[0] = 20;
        arr[1] = 30;

        CComBSTR methodName;
        methodName = L"Add";

        myEdge->Exec(methodName, arr, &lResult);
        wprintf(L"The result is %d\n", lResult.intVal);
        //Using lResult after this
    }

    CoUninitialize (); 
    return 0;
}