开发者

Pass struct or string array from C++ to C# using COM

I have a COM component (in C#) that has the following interface:

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 v开发者_运维技巧alues
        }

        // 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
        }
    }
}

Now I want to pass data from C++ to that COM object. I initialized the interface like this:

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

But I can't pass a reference to my array to that method, as it requires a SAFEARRAY* array. I was able to create SAFEARRAYs with arrays with fixed size elements like double, int, char arrays, and it works fine using something like this:

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

Of course, for my user-defined struct there is no "VT_something", so I don't know how to create a SAFEARRAY to solve this. I tried VT_DISPATCH and VT_BSTR without success.

The actual method to pass the data is this one:

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;
}

...and this does not work (Exception in Kernel32.dll when calling SetStructArray).

Any ideas where I'm wrong? Or what would work?

Thanks, Markus


It looks like your question is the same as this: https://stackoverflow.com/questions/268117/safearray-of-structs

Specifically, see http://vcfaq.mvps.org/com/4.htm:

  • Import the struct into C++ via the type library generated from C#
  • Call SafeArrayCreateEx(VT_RECORD), SafeArrayAccessData and SafeArrayUnaccessData to populate the array


COM has very poor support for structures. At a minimum you need to use IRecordInfo to discover the layout of the structure, the 4th argument to SafeArrayCreateEx(). Not actually sure if the CLR supports this. Or how you obtain the IRecordInfo interface pointer.

Your C++ code otherwise has the right idea. Don't use a struct, use a [ComVisible] class. The struct members can just be properties.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜