使用COM将结构或字符串数​​组从C ++传递给C#

时间:2011-01-05 18:02:30

标签: c# c++ arrays com struct

我有一个COM组件(在C#中),它具有以下接口:

namespace InterOp
{
    [StructLayout(LayoutKind.Sequential)]
    public struct MyStruct
    {
        [MarshalAs(UnmanagedType.BStr)]
        public string name;
        [MarshalAs(UnmanagedType.BStr)]
        public string surname;
        public int age;
    }

    public interface ITest
    {        
        void SetStringArray(string[] array);
        void SetStructArray(MyStruct[] array);
    }

    public class Test : ITest
    {
        // string arrays
        public void SetStringArray(string[] array)
        {
            for(int i = 0; i < array.Length; i++)
                MessageBox.Show(array[i]); // just do something with the array values
        }

        // struct arrays
        public void SetStructArray(MyStruct[] array)
        {
            for (int i = 0; i < array.Length; i++)
                MessageBox.Show(array[i].name + ", " + array[i].surname + " (" + array[i].age.ToString() + ")");// just do something with the array values
        }
    }
}

现在我想将数据从C ++传递给该COM对象。 我初始化了这样的界面:

HRESULT hr = CoInitialize(NULL);
ITest* pTest = NULL;
hr = CoCreateInstance(__uuidof(Test), NULL, CLSCTX_INPROC_SERVER, __uuidof(ITest), (void**)&pTest);

但我不能将对数组的引用传递给该方法,因为它需要一个SAFEARRAY *数组。我能够使用具有固定大小元素(如double,int,char数组)的数组创建SAFEARRAY,并使用以下内容正常工作:

SAFEARRAY* data = SafeArrayCreate(VT_R8, 1, &bound); //8-Byte-Real, 1 dimension

当然,对于我的用户定义的struct,没有“VT_something”,所以我不知道如何创建SAFEARRAY来解决这个问题。我尝试了VT_DISPATCH和VT_BSTR但没有成功。

传递数据的实际方法是:

bool SetStructArrayEx(MyInterOp::MyStruct* array, int arraySize, ITest* comObjectInterface)
{
    bool retVal = false;

    // Create the safearray environment
    SAFEARRAYBOUND bound;
    bound.lLbound = 0;
    bound.cElements = arraySize;

    // Init the safearray
    SAFEARRAY* data = SafeArrayCreate(VT_DISPATCH, 1, &bound); 

    // access the safearray data and copy the original data to it
    MyInterOp::MyStruct HUGEP* temp;
    HRESULT hr = SafeArrayAccessData(data, (void HUGEP* FAR*)&temp);
    if(SUCCEEDED(hr))
    {
        // finally copy the data
        for(int i=0; i<arraySize; ++i)
            *temp++ = array[i];

        comObjectInterface->SetStructArray(data);
        SafeArrayUnaccessData(data);

        retVal = true;
    }

    SafeArrayDestroy(data);

    return retVal;
}

...这不起作用(调用SetStructArray时Kernel32.dll中的异常)。

我错的任何想法?或者会有什么用?

谢谢, 马库斯

2 个答案:

答案 0 :(得分:2)

看起来您的问题与此相同:https://stackoverflow.com/questions/268117/safearray-of-structs

具体来说,请参阅http://vcfaq.mvps.org/com/4.htm

  • 通过从C#
  • 生成的类型库将结构导入C ++
  • 致电SafeArrayCreateEx(VT_RECORD)SafeArrayAccessDataSafeArrayUnaccessData填充数组

答案 1 :(得分:1)

COM对结构的支持非常差。您至少需要使用IRecordInfo来发现结构的布局,即SafeArrayCreateEx()的第4个参数。实际上并不确定CLR是否支持此功能。或者如何获取IRecordInfo接口指针。

您的C ++代码否则有正确的想法。不要使用结构,使用[ComVisible]类。结构成员可以只是属性。