Search code examples
c#c++comunmanagedmanaged

Managed byte[] to unmanaged byte array using ATL/COM


I want to pass some image data from C# code to unmanaged C++ using ATL/COM

From C# code side i do something like this:

void SendFrame([In, MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_UI1)] ref byte[] frameData);

But I'm not sure how should I handle this function in my C++ code.

For now I have something like this:

_ATL_FUNC_INFO OnSendFrameDef = { CC_STDCALL, VT_EMPTY, 1, { VT_SAFEARRAY | VT_UI1 } };

void __stdcall OnSendFrame(SAFEARRAY* ppData)
{
   BYTE* pData;
   SafeArrayAccessData(ppData, (void **) &pData);

   // Doing some stuff with my pData

   SafeArrayUnaccessData(ppData);
}

Can anyone give me some suggestions how I can make this thing work?

Thanks.


Solution

  • I've managed to achieve my goal! For those who are interested:

    My event handler descriptor looks like this:

    _ATL_FUNC_INFO Stream::OnStreamFrameCallbackDef = { CC_STDCALL, VT_EMPTY, 1, { VT_DISPATCH } };
    

    My C++ function:

    void __stdcall Stream::OnStreamFrameCallback(IDispatch* pFrame)
    {
       // NOTE that this "IStreamFramePtr" is COM's Ptr of my "IStreamFrame"
       MyCOM::IStreamFramePtr pStreamFrame = pFrame;
    
       // Thanks casperOne♦ for this:
       CComSafeArray<byte> array;
                       array.Attach(pStreamFrame->GetBuffer());
    
       // Now I can do stuff that I need...
       byte* pBuffer = &array.GetAt(0);
    }
    

    My "IStreamFrame" in my .tlh file looks like this:

    struct __declspec(uuid("1f6efffc-0ac7-3221-8175-5272a09cea82"))
    IStreamFrame : IDispatch
    {
        __declspec(property(get=GetWidth))
        long Width;
        __declspec(property(get=GetHeight))
        long Height;
        __declspec(property(get=GetBuffer))
        SAFEARRAY * Buffer;
    
        long GetWidth ( );
        long GetHeight ( );
        SAFEARRAY * GetBuffer ( );
    };
    

    In my C# code I have something like this:

    [ComVisible(true)]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IStreamFrame
    {
        int     Width   { [return: MarshalAs(UnmanagedType.I4)]         get; }
        int     Height  { [return: MarshalAs(UnmanagedType.I4)]         get; }
        byte[]  Buffer  { [return: MarshalAs(UnmanagedType.SafeArray, SafeArraySubType=VarEnum.VT_UI1)]  get; }
    };
    
    
    [ComVisible(false)]
    public delegate void StreamFrameCallback(IStreamFrame frame);
    
    [ComVisible(true)]
    [InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)]
    public interface IMyCOMStreamEvents
    {
        [DispId(1)]
        void OnStreamFrameCallback([In, MarshalAs(UnmanagedType.IDispatch)] IStreamFrame frame);
    }
    

    Things seems to work just fine. But if anyone have any suggestions or noticed that I'm doing something wrong please let me know.

    Thanks.