Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 8 additions & 8 deletions docs/framework/interop/copying-and-pinning.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
title: "Copying and Pinning"
description: Review how the interop marshaller can copy or pin data that's being marshalled. Copying data places a copy of data from one memory location into another location.
ms.date: "03/30/2017"
ms.date: 05/12/2022
helpviewer_keywords:
- "pinning, interop marshalling"
- "copying, interop marshalling"
Expand All @@ -11,15 +11,15 @@ ms.assetid: 0059f576-e460-4e70-b257-668870e420b8
---
# Copying and Pinning

When marshalling data, the interop marshallercan copy or pin the data being marshalled. Copying the data places a copy of data from one memory location in another memory location. The following illustration shows the differences between copying a value type and copying a type passed by reference from managed to unmanaged memory.
When marshalling data, the interop marshaller can copy or pin the data being marshalled. Copying the data places a copy of data from one memory location in another memory location. The following illustration shows the differences between copying a value type and copying a type passed by reference from managed to unmanaged memory.

![Diagram that shows how value and reference types are copied.](./media/copying-and-pinning/interop-marshal-copy.gif)

Method arguments passed by value are marshalled to unmanaged code as values on the stack. The copying process is direct. Arguments passed by reference are passed as pointers on the stack. Reference types are also passed by value and by reference. As the following illustration shows, reference types passed by value are either copied or pinned:

![Diagram showing reference types passed by value and by reference.](./media/copying-and-pinning/interop-marshal-reference-pin.gif)

Pinning temporarily locks the data in its current memory location, thus keeping it from being relocated by the common language runtime's garbage collector. The marshaller pins data to reduce the overhead of copying and enhance performance. The type of the data determines whether it is copied or pinned during the marshalling process. Pinning is automatically performed during marshalling for objects such as <xref:System.String>, however you can also manually pin memory using the <xref:System.Runtime.InteropServices.GCHandle> class.
Pinning temporarily locks the data in its current memory location, thus keeping it from being relocated by the common language runtime's garbage collector. The marshaller pins data to reduce the overhead of copying and enhance performance. The type of the data determines whether it is copied or pinned during the marshalling process. Pinning is automatically performed during marshalling for objects such as <xref:System.String>, however you can also manually pin memory using the <xref:System.Runtime.InteropServices.GCHandle> class.

## Formatted Blittable Classes

Expand Down Expand Up @@ -56,22 +56,22 @@ Reference types have the following conditional behavior:

To avoid unnecessarily copying and conversion, these types are marshalled as In parameters. You must explicitly apply the **InAttribute** and **OutAttribute** attributes to an argument for the caller to see changes made by the callee.

- If a reference type is passed by value and it has only members of blittable types, it can be pinned during marshalling and any changes made to the members of the type by the callee are seen by the caller. Apply **InAttribute** and **OutAttribute** explicitly if you want this behavior. Without these directional attributes, the interop marshallerdoes not export directional information to the type library (it exports as In, which is the default) and this can cause problems with COM cross-apartment marshalling.
- If a reference type is passed by value and it has only members of blittable types, it can be pinned during marshalling and any changes made to the members of the type by the callee are seen by the caller. Apply **InAttribute** and **OutAttribute** explicitly if you want this behavior. Without these directional attributes, the interop marshaller does not export directional information to the type library (it exports as In, which is the default) and this can cause problems with COM cross-apartment marshalling.

- If a reference type is passed by reference, it will be marshalled as In/Out by default.

## System.String and System.Text.StringBuilder

When data is marshalled to unmanaged code by value or by reference, the marshallertypically copies the data to a secondary buffer (possibly converting character sets during the copy) and passes a reference to the buffer to the callee. Unless the reference is a **BSTR** allocated with **SysAllocString**, the reference is always allocated with **CoTaskMemAlloc**.
When data is marshalled to unmanaged code by value or by reference, the marshaller typically copies the data to a secondary buffer (possibly converting character sets during the copy) and passes a reference to the buffer to the callee. Unless the reference is a **BSTR** allocated with **SysAllocString**, the reference is always allocated with **CoTaskMemAlloc**.

As an optimization when either string type is marshalled by value (such as a Unicode character string), the marshallerpasses the callee a direct pointer to managed strings in the internal Unicode buffer instead of copying it to a new buffer.
As an optimization when either <xref:System.String> or <xref:System.Text.StringBuilder> is marshalled by value (such as a Unicode character string), the marshaller passes the callee a direct pointer to managed strings in the internal Unicode buffer instead of copying it to a new buffer.

> [!CAUTION]
> When a string is passed by value, the callee must never alter the reference passed by the marshaller. Doing so can corrupt the managed heap.

When a <xref:System.String?displayProperty=nameWithType> is passed by reference, the marshaller copies the contents the string to a secondary buffer before making the call. It then copies the contents of the buffer into a new string on return from the call. This technique ensures that the immutable managed string remains unaltered.
When a <xref:System.String?displayProperty=nameWithType> is passed by reference, the marshaller copies the contents of the string to a secondary buffer before making the call. It then copies the contents of the buffer into a new string on return from the call. This technique ensures that the immutable managed string remains unaltered.

When a <xref:System.Text.StringBuilder?displayProperty=nameWithType> is passed by value, the marshaller passes a reference to a temporary copy of the internal buffer of the **StringBuilder** to the caller. The caller and callee must agree on the size of the buffer. The caller is responsible for creating a **StringBuilder** of adequate length. The callee must take the necessary precautions to ensure that the buffer is not overrun. **StringBuilder** is an exception to the rule that reference types passed by value are passed as In parameters by default. It is always passed as In/Out.
When a <xref:System.Text.StringBuilder?displayProperty=nameWithType> is passed by value, the marshaller passes a reference to a temporary copy of the internal buffer of the **StringBuilder** to the caller. The caller and callee must agree on the size of the buffer. The caller is responsible for creating a **StringBuilder** of adequate length. The callee must take the necessary precautions to ensure that the buffer is not overrun. **StringBuilder** is an exception to the rule that reference types passed by value are passed as `In` parameters by default. `StringBuilder` is always passed as `In`/`Out`.

## See also

Expand Down
2 changes: 1 addition & 1 deletion docs/framework/interop/default-marshalling-behavior.md
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ interface _Graphics {
}
```

The same rules used to marshal values and references to platform invoke calls are used when marshalling through COM interfaces. For example, when an instance of the `Point` value type is passed from the .NET Framework to COM, the `Point` is passed by value. If the `Point` value type is passed by reference, a pointer to a `Point` is passed on the stack. The interop marshallerdoes not support higher levels of indirection (**Point** \*\*) in either direction.
The same rules used to marshal values and references to platform invoke calls are used when marshalling through COM interfaces. For example, when an instance of the `Point` value type is passed from the .NET Framework to COM, the `Point` is passed by value. If the `Point` value type is passed by reference, a pointer to a `Point` is passed on the stack. The interop marshaller does not support higher levels of indirection (**Point** \*\*) in either direction.

> [!NOTE]
> Structures having the <xref:System.Runtime.InteropServices.LayoutKind> enumeration value set to **Explicit** cannot be used in COM interop because the exported type library cannot express an explicit layout.
Expand Down
2 changes: 1 addition & 1 deletion docs/framework/interop/default-marshalling-for-arrays.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ void New3(ref String ar);
[MarshalAs(UnmanagedType.LPArray, SizeConst=128)] int[] ar );
```

When marshalling arrays from unmanaged code to managed code, the marshallerchecks the **MarshalAsAttribute** associated with the parameter to determine the array size. If the array size is not specified, only one element is marshalled.
When marshalling arrays from unmanaged code to managed code, the marshaller checks the **MarshalAsAttribute** associated with the parameter to determine the array size. If the array size is not specified, only one element is marshalled.

> [!NOTE]
> The **MarshalAsAttribute** has no effect on marshalling managed arrays to unmanaged code. In that direction, the array size is determined by examination. There is no way to marshal a subset of a managed array.
Expand Down
4 changes: 2 additions & 2 deletions docs/framework/interop/default-marshalling-for-objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,12 @@ To propagate changes back to the caller, the parameters must be passed by refere

**Default behavior for marshalling a variant with the VT_BYREF flag set**

- A variant being passed to managed code by value can have the **VT_BYREF** flag set to indicate that the variant contains a reference instead of a value. In this case, the variant is still marshalled to an object because the variant is being passed by value. The marshallerautomatically dereferences the contents of the variant and copies it into a newly created object before making the call. The object is then passed into the managed function; however, on return from the call, the object is not propagated back into the original variant. Changes made to the managed object are lost.
- A variant being passed to managed code by value can have the **VT_BYREF** flag set to indicate that the variant contains a reference instead of a value. In this case, the variant is still marshalled to an object because the variant is being passed by value. The marshaller automatically dereferences the contents of the variant and copies it into a newly created object before making the call. The object is then passed into the managed function; however, on return from the call, the object is not propagated back into the original variant. Changes made to the managed object are lost.

> [!CAUTION]
> There is no way to change the value of a variant passed by value, even if the variant has the **VT_BYREF** flag set.

- A variant being passed to managed code by reference can also have the **VT_BYREF** flag set to indicate that the variant contains another reference. If it does, the variant is marshalled to a **ref** object because the variant is being passed by reference. The marshallerautomatically dereferences the contents of the variant and copies it into a newly created object before making the call. On return from the call, the value of the object is propagated back to the reference within the original variant only if the object is the same type as the object passed in. That is, propagation does not change the type of a variant with the **VT_BYREF** flag set. If the type of the object is changed during the call, an <xref:System.InvalidCastException> occurs on return from the call.
- A variant being passed to managed code by reference can also have the **VT_BYREF** flag set to indicate that the variant contains another reference. If it does, the variant is marshalled to a **ref** object because the variant is being passed by reference. The marshaller automatically dereferences the contents of the variant and copies it into a newly created object before making the call. On return from the call, the value of the object is propagated back to the reference within the original variant only if the object is the same type as the object passed in. That is, propagation does not change the type of a variant with the **VT_BYREF** flag set. If the type of the object is changed during the call, an <xref:System.InvalidCastException> occurs on return from the call.

The following table summarizes the propagation rules for variants and objects.

Expand Down
Loading