Search code examples
c++atlidl

COM SafeArray of SafeArray


I have the following in my IDL which MIDL seems to like just fine. I am trying to create a method that returns an array of byte arrays (not a matrix). I am having a problem on the C++ side where neither of the ATL::CComSafeArray<LPSAFEARRAY> or ATL::CComSafeArray<ATL::CComSafeArray<byte> > is liked by the compiler. I get a error C2039: 'type' : is not a member of 'ATL::_ATL_AutomationType<T>'.

[id(1001)] HRESULT Find([out] SAFEARRAY(SAFEARRAY(byte))* features);

STDMETHOD(Find)(/*[out]*/ SAFEARRAY** features)

Is there a better way of passing array of byte arrays around (I am crossing process boundaries)?


Solution

  • Ok, try this (C++ ATL EXE server):

    [
        object,
        uuid(F7F8E65F-EBAD-4191-B916-2DB2A1EA0720),
        dual,
        nonextensible,
        helpstring("IAofA Interface"),
        pointer_default(unique)
    ]
    interface IAofA : IDispatch{
        [id(1), helpstring("method GetArray")] HRESULT GetArray([out,retval] VARIANT* pVals);
    };
    
    CComVariant CreateByteArrayAsVariant(BYTE *pData, ULONG size)
    {
        CComSafeArray<BYTE> sa(size);
        for (ULONG i=0; i!=size; ++i)
        {
            sa.SetAt(i, pData[i]);
        }
    
        CComVariant var(sa);
    
        return var;
    }
    
    
    STDMETHODIMP CAofA::GetArray(VARIANT* pVals)
    {
        CComSafeArray<VARIANT> sa(3);
    
        BYTE a[] = {1};
        BYTE b[] = {1, 2};
        BYTE c[] = {3, 2, 1};
    
        sa.SetAt(0, CreateByteArrayAsVariant(a, sizeof(a)));
        sa.SetAt(1, CreateByteArrayAsVariant(b, sizeof(b)));
        sa.SetAt(2, CreateByteArrayAsVariant(c, sizeof(c)));
    
        CComVariant var(sa);
    
        var.Detach(pVals);
    
        return S_OK;
    }
    

    Here's a VB.net client:

    Imports AofAServerLib
    
    Module Module1
    
        Sub Main()
            Dim s As IAofA = New AofA
            Dim a() = s.GetArray
    
            For i As Integer = 0 To a.Length - 1
                For j As Integer = 0 To a(i).Length - 1
                    Console.Write(a(i)(j))
                    Console.Write(" ")
                Next
                Console.WriteLine()
            Next
        End Sub
    
    End Module
    

    No error checking, but it works.