Marshaling an array as a return value?

How do you marshal an array as a return value   What marshalling attributes must be specified

Specifically, using COM Interop, I want to use an interface member that returns an array.  The implementation of this interface is written using an unmanaged object and a COM style interface.

In C#, the interface declaration would look like this:

    public interface IMyInterface
    {
        int[] MyArray
        {
            get;
        }
    }


In unmanaged COM interface land, the property get function looks like this:

    struct IMyInterface : public IUnknown
    {
        virtual HRESULT STDMETHODCALLTYPE get_MyArray( int** array, int* size );
       
        // array is an "out" parameter, a pointer to an array of integers
        // size is an "out" parameter, and returns the number of elements in the array.
    };


How do I provide marshalling attributes on the MyArray property get declaration such that I can call this function

If it's not directly possible, then I am willing to make some compromises:

1)  I'm prepared to accept a method declaration in the c# interface declaration, rather than a property get.  Like this:
   int[] MyArray();

2)  I'm prepared to rewrite the implementation of the get_MyArray unmanaged function

3)  I'm prepared to modify the signature of the unmanaged function.  For example, I'm okay if it has to look like this:
    virtual HRESULT STDMETHODCALLTYPE get_MyArray( int* size, SOMETHING<SOMETHINGELSE>* array );

3)  I'm prepared to allocate the array in the implementation using CoTaskMemAlloc or whatever memory allocation necessary.

 

Some details on which I am NOT willing to compromise:
1)  The array must be a return value in C#.  I am NOT prepared to change the IMyInterface method to this:
    void MyArray( out int[] array, out int size );

2)  I do not want to take additional marshalling steps in the caller.  So I don't want to have to call:
    Marshal.FreeCoTaskMem()

3)  The size of the array must be variable, in that it must not a constant size in the marshalling attributes.  The returned array, could contain any number of elements.
   


Here's something I tried that did not work:

    public interface IMyInterface
    {
        int[] MyArray
        {
            [ return : MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1) ]
            get;
        }
    }

I get the following error:

    An unhandled exception of type 'System.Runtime.InteropServices.MarshalDirectiveException' occurred in Test.exe

    Additional information: Can not marshal return value.

 



Answer this question

Marshaling an array as a return value?

  • ducksauce

    >3)  I'm prepared to modify the signature of the unmanaged function.

    Great, then try something like this (in IDL to highlight the attributes and SAFEARRAY element type):

    HRESULT get_MyArray([out,retval] SAFEARRAY(int) *array);

    Since SAREARRAYs are selfdescribing you don't need the size parameter.

     



  • mahesh kuhikar

    SAFEARRAY is the Automation array type which carries type, rank and bounds with it. It's all documented here

    http://msdn.microsoft.com/library/en-us/automat/html/28a00e34-3b5e-4a16-9f4c-dd2a72dc8e46.asp

    I guess the C++ signature becomes

    virtual HRESULT STDMETHODCALLTYPE get_MyArray(SAFEARRAY** array);

    It's declared in Oaidl.h but you typically include Oleauto.h.



  • SS38

    I have to admit, I have no idea what SAFEARRAY is or where it's declared or anything. I'm not using MFC, or ATL, or anything like that. I'm not using the MIDL compiler. I have no .idl files. I don't have a type library.

    It's a roll-your-own implementation. All I did is derive my object from an interface class that I made that inherits from IUnknown.

    Could you explain SAFEARRAY please


  • Marshaling an array as a return value?