开发者

Can someone explain this .NET COM interoperability code

开发者 https://www.devze.com 2023-01-07 19:18 出处:网络
I have a COM interface method definition in IDL as follows: [id(8)] HRESULT GetBinData([in,out,size_is(dataLen)]BYTE data[], [in]LONG dataLen);

  • I have a COM interface method definition in IDL as follows:

    [id(8)]
    HRESULT GetBinData([in,out,size_is(dataLen)]BYTE data[], [in]LONG dataLen);
    

  • It is mapped automatically to this .NET IL code (note that no MarshallAs LPArray is used on data):

    .method /*06000021*/ public hidebysig newslot virtual 
       instance void GetBinData([in][out] uint8& Data,
                                [in] int32 dataLen) runtime managed internalcall
    // SIG: 20 02 01 10 05 08
    {
      .custom /*0C000052:0A000009*/ instance void
         [mscorlib/*230000开发者_运维百科01*/]
         System.Runtime.InteropServices.DispIdAttribute/*0100000F*/::.ctor(int32)
           /* 0A000009 */ = ( 01 00 08 00 00 00 00 00 ) 
      .override test.ISomething/*02000002*/::GetBinData/*02000002::06000008*/ 
    } // end of method SomethingClass::GetBinData
    

  • That code looks in C#:

    [MethodImpl(MethodImplOptions.InternalCall,
        MethodCodeType=MethodCodeType.Runtime), DispId(8)]
    public virtual extern void GetBinData
        ([In, Out] ref byte Data, [In] int dataLen);
    

  • My code (that seems to work ok) uses it as shown next:

    byte[] b = new byte[1024];
    someObject.GetBinData(ref b[0], b.Length);
    

  • Now my question is NOT how to do this better (I know that) but: (a) why my code above works at all? (b) are there cases when such code may not work (eg., memory moved inside CLR while calling GetBinData, etc).

  • Garbage collection should not concern you, since you object is pinned automatically as soon as you pass it to the method (source: MSDN):

    When the runtime marshaler sees that your code is passing to native code a reference to a managed reference object, it automatically pins the object.

    In case that your native method saves the reference (pointer) for some later async work, you must pin it manually:

    byte[] b = new byte[1024];
    GCHandle pinHandle = GCHandle.Alloc(b, GCHandleType.Pinned);
    try
    {
       someObject.GetBinData(ref b[0], b.length);
    }
    finally
    {
       pinHandle.Free();
    }
    

    Otherwise, there is no reason why it shouldn't work. You are allocating the memory before calling the method, CLR pins your object until the method is executed, and your native code should take care that array length is taken into account.

    0

    精彩评论

    暂无评论...
    验证码 换一张
    取 消