Disabled runtime marshalling
When the System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute
attribute is applied to an assembly, the runtime disables most built-in support for data marshalling between managed and native representations. This article describes the features that are disabled and how .NET types map to native types when marshalling is disabled.
Scenarios where marshalling is disabled
When the DisableRuntimeMarshallingAttribute
is applied to an assembly, it affects P/Invokes and Delegate types in the assembly, as well as any calls to unmanaged function pointers in the assembly. It does not affect any P/Invoke or interop delegate types defined in other assemblies. It also does not disable marshalling for the runtime's built-in COM interop support. The built-in COM interop support can be enabled or disabled through a feature switch.
Disabled features
When the DisableRuntimeMarshallingAttribute
is applied to an assembly, the following attributes will have no effect or throw an exception:
- LCIDConversionAttribute on a P/Invoke or a delegate
SetLastError=true
on a P/InvokeThrowOnUnmappableChar=true
on a P/InvokeBestFitMapping=true
on a P/Invoke- .NET variadic argument method signatures (varargs)
in
,ref
,out
parameters
Default rules for marshalling common types
When marshalling is disabled, the rules for default marshalling change to much simpler rules. These rules are described below. As mentioned in the interop best practices documentation, blittable types are types with the same layout in managed and native code and as such do not require any marshalling. Additionally, these rules cannot be customized with the tools mentioned in the documentation on customizing parameter marshalling.
C# keyword | .NET Type | Native Type |
---|---|---|
byte |
System.Byte |
uint8_t |
sbyte |
System.SByte |
int8_t |
short |
System.Int16 |
int16_t |
ushort |
System.UInt16 |
uint16_t |
int |
System.Int32 |
int32_t |
uint |
System.UInt32 |
uint32_t |
long |
System.Int64 |
int64_t |
ulong |
System.UInt64 |
uint64_t |
char |
System.Char |
char16_t (CharSet on the P/Invoke has no effect) |
nint |
System.IntPtr |
intptr_t |
nuint |
System.UIntPtr |
uintptr_t |
System.Boolean |
bool |
|
User-defined C# unmanaged type with no fields with LayoutKind.Auto |
Treated as a blittable type. All customized struct marshalling is ignored. | |
All other types | unsupported |
Examples
The following example shows some features that are enabled or disabled when runtime marshalling is disabled. To demonstrate the manual application of this guidance, these examples use [DllImport]
as opposed to the recommended [LibraryImport]
attribute. The analyzer with ID SYSLIB1054 provides additional guidance when you use [LibraryImport]
.
using System.Runtime.InteropServices;
struct Unmanaged
{
int i;
}
[StructLayout(LayoutKind.Auto)]
struct AutoLayout
{
int i;
}
struct StructWithAutoLayoutField
{
AutoLayout f;
}
[UnmanagedFunctionPointer] // OK: UnmanagedFunctionPointer attribute is supported
public delegate void Callback();
[UnmanagedFunctionPointer(CallingConvention.Cdecl)] // OK: Specifying a calling convention is supported
public delegate void Callback2(int i); // OK: primitive value types are allowed
[DllImport("NativeLibrary", EntryPoint = "CustomEntryPointName")] // OK: Specifying a custom entry-point name is supported
public static extern void Import(int i);
[DllImport("NativeLibrary", CallingConvention = CallingConvention.Cdecl)] // OK: Specifying a custom calling convention is supported
public static extern void Import(int i);
[UnmanagedCallConv(new[] { typeof(CallConvCdecl) })] // OK: Specifying a custom calling convention is supported
[DllImport("NativeLibrary")]
public static extern void Import(int i);
[DllImport("NativeLibrary", EntryPoint = "CustomEntryPointName", CharSet = CharSet.Unicode, ExactSpelling = false)] // OK: Specifying a custom entry-point name and using CharSet-based lookup is supported
public static extern void Import(int i);
[DllImport("NativeLibrary")] // OK: Not explicitly specifying an entry-point name is supported
public static extern void Import(Unmanaged u); // OK: unmanaged type
[DllImport("NativeLibrary")] // OK: Not explicitly specifying an entry-point name is supported
public static extern void Import(StructWithAutoLayoutField u); // Error: unmanaged type with auto-layout field
[DllImport("NativeLibrary")]
public static extern void Import(Callback callback); // Error: managed types are not supported when runtime marshalling is disabled