sapito
sapito

Reputation: 1522

Marshalling IntRef with P/Invoke

When I use IntPtr to reserve memory and pass a dynamic array to native code, after I initialize this memory on the C#/managed side and pass it to my native DLL, is this chunk of memory pinned or copied? I.e. if I modify the array within my native code, will I see the modifications back in my managed code?

I know it is not necessary to use IntPtr, but since the array is embedded into a complex struct, it seems more convenient.

Upvotes: 1

Views: 136

Answers (1)

Hans Passant
Hans Passant

Reputation: 942548

The only valid ways to obtain an IntPtr for a memory allocation in a .NET program are:

  • by using one of the Marshal.AllocXxx() methods. This is not pinned memory, it is unmovable memory, allocated from one of the operating system heaps. Operating systems in general do not support the notion of changing the address of an allocation, once it is made it is stuck at the same address forever. Only garbage collectors have the necessary magic, they can find pointers to the memory block back and know how to update them.
  • by using GCHandle.AddrOfPinnedObject(). Allocated from the GC heap, the address will be stable until GCHandle.Free() is called. Only use it if the allocation needs to exist for short amounts of time.
  • by using the C# fixed keyword. This is a highly optimized version of GCHandle which works without having to allocate a handle. Achieved by the jitter marking the variable as special, it will be discovered by the GC when it walks the stack, looking for roots. It otherwise has the exact same effect as GCHandle, the GC considers the target of the fixed statement pinned and won't move the object.

Be very careful with the latter two bullets, especially with the fixed keyword which requires unsafe since it is dangerous. Very important to stop using the IntPtr once code execution leaves the scope of the fixed statement. Not enforced by the runtime, the failure mode is a completely undiagnosable ExecutionEngineException when the GC discovers that the heap got corrupted. Caused by code writing through the IntPtr into the memory block after it got moved, thus overwriting something else.

Upvotes: 2

Related Questions