0

I have a COM class (developed in C++, just in case it matters), which has a method "GetStructList" which should return a list of some custom type, and I'm developing a .NET application which should get that list.

I control the COM class code as well as the application, and I am unable to obtain the data.

The COM class code:

1- IDL:

HRESULT GetList([in,out] SAFEARRAY(struct MyStruct)* myStructs);
// I have also tried with [out] instead of [in, out]

[uuid(628913FC-CC26-1654-472F-0B70CC39DEE0)]
struct MyStruct
{
    int myInt;
    DOUBLE myDouble;

};

2- CPP:

STDMETHODIMP MyClass::GetList(SAFEARRAY** myStructs)
{
    SAFEARRAY* psa = *myStructs;
    SAFEARRAYBOUND sab = {someSize, 0};
    MyStruct *pData;
    IRecordInfo *pRI;
    HRESULT hr;

    hr = GetRecordInfoFromGuids(LIBID_MyCOMLib, 1, 0, 0x409, __uuidof(MyStruct), &pRI);
    psa = SafeArrayCreateEx(VT_RECORD, 1, &sab, pRI);
    pRI->Release();
    pRI = NULL;
    hr = SafeArrayAccessData(psa, (void**)&pData);
    for (size_t i = 0; i < someSize; i++) 
    {
        pData[i].myInt = someInt;
        pData[i].myDouble = somedouble;
    }
    hr = SafeArrayUnaccessData(psa);

    return S_OK;
}

.Net Code (VB):

Option Strict
...
<MarshalAs(UnmanagedType.SafeArray, safearraysubtype:=VarEnum.VT_RECORD)>
Private m_List As MyStruct()

Private Sub btnGetList_Click(sender As System.Object, e As System.EventArgs) 
    Dim m_List() As MyStruct
    m_ComObject.GetList(m_List) 

    ' I have tried several other things, getting different errors with each of them'
    'm_ComObject.GetList(CType(m_List, Array))'

    'Dim structs() As MyStruct'
    'Dim arr as System.Array = structs '
    'm_ComObject.GetList(arr)'

    For Each o In cortes
        Dim s As MyStruct = CType(o, MyStruct)
        MsgBox(s.myInt)
        Exit For
    Next
End Sub

How can I achieve this?

raven
  • 2,574
  • 2
  • 27
  • 49

1 Answers1

1

What is the generated interop signature?

What exact errors do you get?

The myStruct argument in COM interface should be [out], not [in, out]

Is the part:

Dim m_List() As SceneCutInfo
m_ComObject.GetList(m_List) 

meant to be:

Dim m_List() As MyStruct
m_ComObject.GetList(m_List) 

However, unless you have a really good reason to use SAFEARRAYs (e.g. an Automation compliant interface), I would suggest using normal arrays, as there is no need to fight with VT_RECORD stuff.

Zdeslav Vojkovic
  • 14,391
  • 32
  • 45
  • Thank you, I tried hard to omit the SAFEARRAY word in the question because I don't have any reason to use SAFEARRAYs, any way to return an array is valid for me. I think SAFEARRAYs have become my standard due to too much code called from VB6. Now, how do I define a normal array for COM interop? – raven Oct 02 '12 at 14:32
  • do you get same problems if you use floats instead of doubles? – Zdeslav Vojkovic Oct 02 '12 at 15:20
  • Yes, "SceneCutInfo" was the original struct name, and I forgot to change it again; I've fixed it now. The error are mostly Null References. – raven Oct 02 '12 at 15:20
  • The error persists using floats instead of doubles. The exact code I posted doesn't seem to compile with Option Strict On, so I'm passing CType(m_List, Array) isntead of just m_List. – raven Oct 02 '12 at 15:23
  • Hmm, I have finally fixed this. I'm not sure what I was doing wrong but it works now. Now, what should I use instead of SAFEARRAYs? If I use MyStruct*, then I don't know the array length... – raven Oct 02 '12 at 15:31
  • hmm, the problem is when interface is defined in .idl, the tlbimp converts the array to `IntPtr`. When it is defined in .NET code, tlbexp creates proper signature. I am trying to solve it. For the other way round, there is some info at http://stackoverflow.com/questions/12503041/passing-an-array-of-structs-from-c-sharp-to-c-using-com-callable-wrapper/12508525#12508525 – Zdeslav Vojkovic Oct 02 '12 at 15:41