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
15 changes: 15 additions & 0 deletions .openpublishing.redirection.json
Original file line number Diff line number Diff line change
Expand Up @@ -2234,6 +2234,21 @@
"redirect_url": "/dotnet/standard/native-interop/index",
"redirect_document_id": true
},
{
"source_path": "docs/standard/native-interop/customize-parameter-marshalling.md",
"redirect_url": "/dotnet/standard/native-interop/customize-parameter-marshaling",
"redirect_document_id": true
},
{
"source_path": "docs/standard/native-interop/customize-struct-marshalling.md",
"redirect_url": "/dotnet/standard/native-interop/customize-struct-marshaling",
"redirect_document_id": true
},
{
"source_path": "docs/standard/native-interop/type-marshalling.md",
"redirect_url": "/dotnet/standard/native-interop/type-marshaling",
"redirect_document_id": true
},
{
"source_path": "docs/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-thread-local-variables.md",
"redirect_url": "/dotnet/standard/parallel-programming/how-to-write-a-parallel-foreach-loop-with-partition-local-variables",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ OData Actions provide a way to implement a behavior that acts upon a resource re

3. Storing any results from Invoke() so they can be retrieved using GetResult()

The parameters may be passed as tokens. This is because it is possible to write a Data Service Provider that works with tokens that represent resources, if this is the case you may need to convert (marshal) these tokens into actual resources before dispatching to the actual action. After the parameter has been marshalled, it must be in an editable state so that any changes to the resource that occur when the action is invoked will be saved and written to disk.
The parameters may be passed as tokens. This is because it is possible to write a Data Service Provider that works with tokens that represent resources, if this is the case you may need to convert (marshal) these tokens into actual resources before dispatching to the actual action. After the parameter has been marshaled, it must be in an editable state so that any changes to the resource that occur when the action is invoked will be saved and written to disk.

This interface requires two methods: Invoke and GetResult. Invoke invokes the delegate that implements the action’s behavior and GetResult returns the result of the action.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ Other unsupported interop features include:
- <xref:System.Runtime.InteropServices.UnmanagedType.AsAny?displayProperty=fullName>
- <xref:System.Runtime.InteropServices.UnmanagedType.CustomMarshaler?displayProperty=fullName>

Rarely used marshalling APIs:
Rarely used marshaling APIs:

- <xref:System.Runtime.InteropServices.Marshal.ReadByte%28System.Object%2CSystem.Int32%29?displayProperty=fullName>
- <xref:System.Runtime.InteropServices.Marshal.ReadInt16%28System.Object%2CSystem.Int32%29?displayProperty=fullName>
Expand Down
18 changes: 9 additions & 9 deletions docs/standard/native-interop/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ The guidance in this section applies to all interop scenarios.
|---------|---------|----------------|---------|
| <xref:System.Runtime.InteropServices.DllImportAttribute.PreserveSig> | `true` | keep default | When this is explicitly set to false, failed HRESULT return values will be turned into exceptions (and the return value in the definition becomes null as a result).|
| <xref:System.Runtime.InteropServices.DllImportAttribute.SetLastError> | `false` | depends on the API | Set this to true if the API uses GetLastError and use Marshal.GetLastWin32Error to get the value. If the API sets a condition that says it has an error, get the error before making other calls to avoid inadvertently having it overwritten.|
| <xref:System.Runtime.InteropServices.DllImportAttribute.CharSet> | `CharSet.None`, which falls back to `CharSet.Ansi` behavior | Explicitly use `CharSet.Unicode` or `CharSet.Ansi` when strings or characters are present in the definition | This specifies marshalling behavior of strings and what `ExactSpelling` does when `false`. Note that `CharSet.Ansi` is actually UTF8 on Unix. _Most_ of the time Windows uses Unicode while Unix uses UTF8. See more information on the [documentation on charsets](./charset.md). |
| <xref:System.Runtime.InteropServices.DllImportAttribute.CharSet> | `CharSet.None`, which falls back to `CharSet.Ansi` behavior | Explicitly use `CharSet.Unicode` or `CharSet.Ansi` when strings or characters are present in the definition | This specifies marshaling behavior of strings and what `ExactSpelling` does when `false`. Note that `CharSet.Ansi` is actually UTF8 on Unix. _Most_ of the time Windows uses Unicode while Unix uses UTF8. See more information on the [documentation on charsets](./charset.md). |
| <xref:System.Runtime.InteropServices.DllImportAttribute.ExactSpelling> | `false` | `true` | Set this to true and gain a slight perf benefit as the runtime will not look for alternate function names with either an "A" or "W" suffix depending on the value of the `CharSet` setting ("A" for `CharSet.Ansi` and "W" for `CharSet.Unicode`). |

## String parameters
Expand All @@ -38,7 +38,7 @@ Remember to mark the `[DllImport]` as `Charset.Unicode` unless you explicitly wa

**❌ DO NOT** use `[Out] string` parameters. String parameters passed by value with the `[Out]` attribute can destabilize the runtime if the string is an interned string. See more information about string interning in the documentation for <xref:System.String.Intern%2A?displayProperty=nameWithType>.

**❌ AVOID** `StringBuilder` parameters. `StringBuilder` marshalling *always* creates a native buffer copy. As such, it can be extremely inefficient. Take the typical scenario of calling a Windows API that takes a string:
**❌ AVOID** `StringBuilder` parameters. `StringBuilder` marshaling *always* creates a native buffer copy. As such, it can be extremely inefficient. Take the typical scenario of calling a Windows API that takes a string:

1. Create a SB of the desired capacity (allocates managed capacity) **{1}**
2. Invoke
Expand All @@ -52,11 +52,11 @@ in another call but this still only saves *1* allocation. It's much better to us

The other issue with `StringBuilder` is that it always copies the return buffer back up to the first null. If the passed back string isn't terminated or is a double-null-terminated string, your P/Invoke is incorrect at best.

If you *do* use `StringBuilder`, one last gotcha is that the capacity does **not** include a hidden null, which is always accounted for in interop. It's common for people to get this wrong as most APIs want the size of the buffer *including* the null. This can result in wasted/unnecessary allocations. Additionally, this gotcha prevents the runtime from optimizing `StringBuilder` marshalling to minimize copies.
If you *do* use `StringBuilder`, one last gotcha is that the capacity does **not** include a hidden null, which is always accounted for in interop. It's common for people to get this wrong as most APIs want the size of the buffer *including* the null. This can result in wasted/unnecessary allocations. Additionally, this gotcha prevents the runtime from optimizing `StringBuilder` marshaling to minimize copies.

**✔️ CONSIDER** using `char[]`s from an `ArrayPool`.

For more information on string marshalling, see [Default Marshalling for Strings](../../framework/interop/default-marshaling-for-strings.md) and [Customizing string marshalling](customize-parameter-marshalling.md#customizing-string-parameters).
For more information on string marshaling, see [Default Marshaling for Strings](../../framework/interop/default-marshaling-for-strings.md) and [Customizing string marshaling](customize-parameter-marshaling.md#customizing-string-parameters).

> __Windows Specific__
> For `[Out]` strings the CLR will use `CoTaskMemFree` by default to free strings or `SysStringFree` for strings that are marked
Expand All @@ -69,7 +69,7 @@ as `UnmanagedType.BSTR`.

## Boolean parameters and fields

Booleans are easy to mess up. By default, a .NET `bool` is marshalled to a Windows `BOOL`, where it's a 4-byte value. However, the `_Bool`, and `bool` types in C and C++ are a *single* byte. This can lead to hard to track down bugs as half the return value will be discarded, which will only *potentially* change the result. For more for information on marshalling .NET `bool` values to C or C++ `bool` types, see the documentation on [customizing boolean field marshalling](customize-struct-marshalling.md#customizing-boolean-field-marshalling).
Booleans are easy to mess up. By default, a .NET `bool` is marshaled to a Windows `BOOL`, where it's a 4-byte value. However, the `_Bool`, and `bool` types in C and C++ are a *single* byte. This can lead to hard to track down bugs as half the return value will be discarded, which will only *potentially* change the result. For more for information on marshaling .NET `bool` values to C or C++ `bool` types, see the documentation on [customizing boolean field marshaling](customize-struct-marshaling.md#customizing-boolean-field-marshaling).

## GUIDs

Expand All @@ -83,7 +83,7 @@ GUIDs are usable directly in signatures. Many Windows APIs take `GUID&` type ali

## Blittable types

Blittable types are types that have the same bit-level representation in managed and native code. As such they do not need to be converted to another format to be marshalled to and from native code, and as this improves performance they should be preferred.
Blittable types are types that have the same bit-level representation in managed and native code. As such they do not need to be converted to another format to be marshaled to and from native code, and as this improves performance they should be preferred.

**Blittable types:**

Expand Down Expand Up @@ -122,7 +122,7 @@ You can see if a type is blittable by attempting to create a pinned `GCHandle`.
For more information, see:

- [Blittable and Non-Blittable Types](../../framework/interop/blittable-and-non-blittable-types.md)
- [Type Marshalling](type-marshalling.md)
- [Type Marshaling](type-marshaling.md)

## Keeping managed objects alive

Expand Down Expand Up @@ -206,7 +206,7 @@ A Windows `PVOID` which is a C `void*` can be marshaled as either `IntPtr` or `U

Managed structs are created on the stack and aren't removed until the method returns. By definition then, they are "pinned" (it won't get moved by the GC). You can also simply take the address in unsafe code blocks if native code won't use the pointer past the end of the current method.

Blittable structs are much more performant as they can simply be used directly by the marshalling layer. Try to make structs blittable (for example, avoid `bool`). For more information, see the [Blittable Types](#blittable-types) section.
Blittable structs are much more performant as they can simply be used directly by the marshaling layer. Try to make structs blittable (for example, avoid `bool`). For more information, see the [Blittable Types](#blittable-types) section.

*If* the struct is blittable, use `sizeof()` instead of `Marshal.SizeOf<MyStruct>()` for better performance. As mentioned above, you can validate that the type is blittable by attempting to create a pinned `GCHandle`. If the type is not a string or considered blittable, `GCHandle.Alloc` will throw an `ArgumentException`.

Expand Down Expand Up @@ -241,4 +241,4 @@ internal unsafe struct SYSTEM_PROCESS_INFORMATION
}
```

However, there are some gotchas with fixed buffers. Fixed buffers of non-blittable types won't be correctly marshalled, so the in-place array needs to be expanded out to multiple individual fields. Additionally, in .NET Framework and .NET Core before 3.0, if a struct containing a fixed buffer field is nested within a non-blittable struct, the fixed buffer field won't be correctly marshalled to native code.
However, there are some gotchas with fixed buffers. Fixed buffers of non-blittable types won't be correctly marshaled, so the in-place array needs to be expanded out to multiple individual fields. Additionally, in .NET Framework and .NET Core before 3.0, if a struct containing a fixed buffer field is nested within a non-blittable struct, the fixed buffer field won't be correctly marshaled to native code.
8 changes: 4 additions & 4 deletions docs/standard/native-interop/charset.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
---
title: Charsets and marshalling - .NET
title: Charsets and marshaling - .NET
description: Learn how different values of CharSet can change how .NET marshals your data to native code.
author: jkoritzinsky
ms.author: jekoritz
ms.date: 01/18/2019
---

# Charsets and marshalling
# Charsets and marshaling

The way `char` values, `string` objects, and `System.Text.StringBuilder` objects are marshalled depends on the value of the `CharSet` field on either the P/Invoke or structure. You can set the `CharSet` of a P/Invoke by setting the <xref:System.Runtime.InteropServices.DllImportAttribute.CharSet?displayProperty=nameWithType> field when declaring your P/Invoke. To set the `CharSet` for a structure, set the <xref:System.Runtime.InteropServices.StructLayoutAttribute.CharSet?displayProperty=nameWithType> field on your struct declaration. When these attribute fields are not set, it is up to the language compiler to determine which `CharSet` to use. C# and VB use the <xref:System.Runtime.InteropServices.CharSet.Ansi> charset by default.
The way `char` values, `string` objects, and `System.Text.StringBuilder` objects are marshaled depends on the value of the `CharSet` field on either the P/Invoke or structure. You can set the `CharSet` of a P/Invoke by setting the <xref:System.Runtime.InteropServices.DllImportAttribute.CharSet?displayProperty=nameWithType> field when declaring your P/Invoke. To set the `CharSet` for a structure, set the <xref:System.Runtime.InteropServices.StructLayoutAttribute.CharSet?displayProperty=nameWithType> field on your struct declaration. When these attribute fields are not set, it is up to the language compiler to determine which `CharSet` to use. C# and VB use the <xref:System.Runtime.InteropServices.CharSet.Ansi> charset by default.

The following table shows a mapping between each charset and how a character or string is represented when marshalled with that charset:
The following table shows a mapping between each charset and how a character or string is represented when marshaled with that charset:

| CharSet | Windows | Unix on .NET Core 2.2 and earlier | Mono and Unix on .NET Core 3.0 and later |
|---------|--------------------|-----------------------------|------------------------------------------|
Expand Down
Loading