Pass data between managed and unmanaged code introduction
Understand how the stack, the managed heap, and marshalling affect data you pass to native code, and when to pin data in memory.
Read time 2 minutesLast updated 2 days ago
When you pass data between managed and unmanaged code, consider how the data is stored and managed in memory.
When you pass data between functions, parameters and return values are either copied to the stack or stored on the heap. The stack is typically used for value types, and the data persists for the duration of the function call. Data with a less predictable lifespan is stored on the heap. In C#, the scripting runtime manages the heap, which involves moving data and freeing memory that's no longer in use. In unmanaged code, you directly request and manage heap memory.
When you call an unmanaged function from managed code or a managed function from unmanaged code, both sides can directly access stack data. Therefore, you can pass small value types like and without extra precautions. You don't have to worry about the data disappearing before the other side of the call accesses it.
floatintHowever, when you pass reference types and larger value types, such as strings, arrays, and some structs, the data might be on the heap. In this case, only a reference or pointer is passed between managed and unmanaged code. You must ensure that the data remains at the same memory location for as long as it might be accessed.
For the duration of a normal call into unmanaged code, the scripting runtime handles this for you. As part of marshalling, it keeps the relevant managed data alive and in place until the call returns. You only need to take extra measures if unmanaged code keeps a reference to the data and accesses it after the call returns, such as in an asynchronous callback or through a pointer that the native code stores for later use. In those cases, use the structure (Microsoft) to pin an object in memory. The scripting runtime doesn't move or free a pinned object until you free the .
GCHandleGCHandle// Create a GCHandle to pin data in memory.GCHandle handle = GCHandle.Alloc(yourObject, GCHandleType.Pinned);// Pass the data to unmanaged code that keeps it beyond the call.// Free the handle when the unmanaged code no longer needs the data.handle.Free();