[id(8)]
HRESULT GetBinData([in,out,size_is(dataLen)]BYTE data[], [in]LONG dataLen);
.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/*23000001*/]
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
[MethodImpl(MethodImplOptions.InternalCall,
MethodCodeType=MethodCodeType.Runtime), DispId(8)]
public virtual extern void GetBinData
([In, Out] ref byte Data, [In] int dataLen);
byte[] b = new byte[1024];
someObject.GetBinData(ref b[0], b.Length);
(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):
In case that your native method saves the reference (pointer) for some later async work, you must pin it manually:
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.