none
MSIL modification for array marshaling RRS feed

  • Question

  • Hi

    I am trying to pass an nonempty array of uint32 elements created in C# program to C++ COM object for it to fill that array with values.
    Those values will be further processed in the C# code.

    COM method signature in C++ looks like:

    HRESULT GetIdArray( [in]unsigned int buffsize, [out] unsigned int* pIDArray);

    From the following article:
    http://msdn.microsoft.com/en-us/library/z6cfh6e6.aspx

    it follows that to pass an allocated buffer to C++ and get it back with values filled in
    I need to provide a marshaler with that buffer's size. That can be done by modifying
    MSIL of the interop assembly corresponding to the COM object (I should not modify the COM object).

    The above article provides a link to how to modify MSIL with that purpose
    but following it does not lead to a helpful description.

    Does anybody know how to change MSIL of an interop assembly produced by tlbimp.exe
    from a COM type library:

      .method public hidebysig newslot abstract virtual
              instance void  GetIdArray(
                                        [in] uint32 buffsize,
                                        [out] uint32& pIDArray) runtime managed internalcall
      {
      } // end of method IRLXBaseDocument::GetIdArray

     so that to get a C# wrapper declaration like this:

    void GetIdArray(
       uint32 buffsize,
       [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=0)] uint32[] pIDArray );

    Thanks in advance

    Monday, June 22, 2009 2:02 PM

Answers

  • Writing the declaration in C#:

    public virtual void GetIdArray(
          [In]uint buffsize,
          [Out,MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] pIDArray) {
        }

    compiling it, then looking at it with Ildasm.exe produces:

    .method public hidebysig newslot virtual
            instance void  GetIdArray([in] uint32 buffsize,
                                      [out] uint32[]  marshal([ + 0]) pIDArray) cil managed

    The "marshal" attribute is what you need.

    Hans Passant.
    • Marked as answer by mpoleg Monday, June 22, 2009 3:43 PM
    Monday, June 22, 2009 2:33 PM
    Moderator

All replies

  • Writing the declaration in C#:

    public virtual void GetIdArray(
          [In]uint buffsize,
          [Out,MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 0)] uint[] pIDArray) {
        }

    compiling it, then looking at it with Ildasm.exe produces:

    .method public hidebysig newslot virtual
            instance void  GetIdArray([in] uint32 buffsize,
                                      [out] uint32[]  marshal([ + 0]) pIDArray) cil managed

    The "marshal" attribute is what you need.

    Hans Passant.
    • Marked as answer by mpoleg Monday, June 22, 2009 3:43 PM
    Monday, June 22, 2009 2:33 PM
    Moderator
  • Thank you very much

    Your technique C#2MSIL is very handy.
    And I've got what I wanted.

    As a result I've got the following C# wrapper:

    void GetIdArray(uint buffsize, uint[] pIDArray);

    It works fine but I think it would be better to have [out] before pIDArray like this:

    void GetIdArray(uint buffsize, [out] uint[] pIDArray);

    in order to know the next day that pIDArray is not an [in] parameter.

    Is there a way to do this (in accordance with [out] existing in MSIL)?


    Monday, June 22, 2009 3:52 PM
  • That should already be there when you put [out] in the IL declaration.  Note that you cannot declare it with the C# "out" keyword.  That would not be accurate since the memory actually has to be allocated by the caller.


    Hans Passant.
    Monday, June 22, 2009 4:30 PM
    Moderator
  • I checked it once more.

    This is a MSIL declaration:

    .method public hidebysig newslot abstract virtual
                     instance void GetIdArray([in] uint32 buffsize,
                                                       [out] uint32[] marshal([ + 0]) pIDArray) cil managed
    {
    } // end of method IRLXBaseDocument::GetIdArray


    And this is a C# wrapper, generated from metadata:

    void GetIdArray(uint buffsize, uint[] pIDArray);

     

     

    Monday, June 22, 2009 4:51 PM