Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.
Quelldateien prüfen
Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.
Mit Codex oder Claude installieren Kopieren Sie diesen Prompt, fügen Sie ihn in Codex, Claude oder einen anderen Assistant ein und lassen Sie die Skill-Seite prüfen und installieren.
Ein direkter Befehl überspringt den Prüf-Prompt. Prüfen Sie die Quelle, bevor Sie ihn ausführen.
Calls native libraries via P/Invoke. LibraryImport, marshalling, cross-platform resolution.
dotnet-native-interop
Platform Invoke (P/Invoke) patterns for calling native C/C++ libraries from .NET: [LibraryImport] (preferred, .NET 7+)
vs [DllImport] (legacy), struct marshalling, string marshalling, function pointer callbacks,
NativeLibrary.SetDllImportResolver for cross-platform library resolution, and platform-specific considerations for
Windows, macOS, Linux, iOS, and Android.
Version assumptions: .NET 7.0+ baseline for [LibraryImport]. [DllImport] available in all .NET versions.
NativeLibrary API available since .NET Core 3.0.
Scope
LibraryImport (.NET 7+) and DllImport declarations
Struct and string marshalling patterns
Function pointer callbacks and delegates
NativeLibrary.SetDllImportResolver for cross-platform resolution
Out of scope
AOT-specific P/Invoke concerns (direct pinvoke) -- see [skill:dotnet-native-aot]
COM interop and CsWin32 source generator -- see [skill:dotnet-winui]
WASM JavaScript interop (JSImport/JSExport) -- see [skill:dotnet-aot-wasm]
Cross-references: [skill:dotnet-native-aot] for AOT-specific P/Invoke and [LibraryImport] in publish scenarios,
[skill:dotnet-aot-architecture] for AOT-first design patterns including source-generated interop, [skill:dotnet-winui]
for CsWin32 source generator and COM interop, [skill:dotnet-aot-wasm] for WASM JavaScript interop (not native P/Invoke).
LibraryImport vs DllImport
[LibraryImport] (.NET 7+) is the preferred attribute for new P/Invoke declarations. It uses source generation to
produce marshalling code at compile time, making it fully AOT-compatible and eliminating runtime codegen overhead.
[DllImport] is the legacy attribute. It relies on runtime marshalling, which may require codegen not available in AOT
scenarios. Use [DllImport] only when targeting .NET 6 or earlier, or when the SYSLIB1054 analyzer indicates
[LibraryImport] cannot handle a specific signature.
Decision Guide
Scenario
Use
New code targeting .NET 7+
[LibraryImport]
Targeting .NET 6 or earlier
[DllImport]
SYSLIB1054 analyzer flags incompatibility
[DllImport] (with comment explaining why)
Publishing with Native AOT
[LibraryImport] (required for full AOT compat)
LibraryImport Declaration
using System.Runtime.InteropServices;
publicstaticpartialclassNativeApi
{
[LibraryImport("mylib")]
internalstaticpartialintProcessData(
ReadOnlySpan<byte> input,
int length);
[LibraryImport("mylib", StringMarshalling = StringMarshalling.Utf8)]
internalstaticpartialintOpenByName(string name);
[LibraryImport("mylib", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internalstaticpartialboolCloseResource(nint handle);
}
```text
Key requirements for `[LibraryImport]`:
- Method must be `staticpartial` in a `partial` class
- Stringmarshallingmustbeexplicitlyspecifiedvia `StringMarshalling` or `[MarshalAs]` ( )
- `[: ()]`
- `<>` `<>` -- `[]` ( )
### ()
```
;
{
[]
;
[]
[]
;
}
```text
The `SYSLIB1054` analyzer suggests converting `[DllImport]` to `[LibraryImport]` provides code fixes. Key changes:
Replace `[DllImport]` `[LibraryImport]`
Change ` ` to ` `
Make the containing ``
4. `` ``
5. `` ``
6. `[]` ``
```
[("", = CharSet.Unicode, SetLastError = )]
;
[]
;
```text
---
Native library names differ across platforms. Use `NativeLibrary.SetDllImportResolver` conditional compilation to handle .
Windows uses `.dll` files. The loader searches the application directory, system directories, `PATH`.
```csharp
[]
;
```text
Windows also supports omitting the extension -- the loader appends `.dll` automatically:
```csharp
[]
;
```text
macOS uses `.dylib` files; Linux uses `.so` files. The .;
```text
.NET probing order library name ``:
`foo` (exact name)
`foo.dll`, `foo.so`, `foo.dylib` (platform extension)
`libfoo`, `libfoo.so`, `libfoo.dylib` (lib prefix + extension)
iOS does allow loading libraries at runtime. Native code must be statically linked the application binary. Use `__Internal` the library name to call functions linked the main executable:
```csharp
[]
;
```csharp
For iOS, =>
<NativeReference Include=>
<Kind>Static</Kind>
<ForceLoad></ForceLoad>
</NativeReference>
</ItemGroup>
```text
Android uses `.so` files loaded the apps lib/<abi>/ directory
[]
;
```csharp
Include platform-specific `.so` files each target ABI the project:
```xml
<ItemGroup Condition=>
<AndroidNativeLibrary Include= Abi= />
<AndroidNativeLibrary Include= Abi= />
</ItemGroup>
```text
WebAssembly does support traditional P/Invoke. Native C/C++ code cannot be called via `[LibraryImport]` `[DllImport]` browser WASM. For JavaScript interop, see [skill:dotnet-aot-wasm].
---
`NativeLibrary.SetDllImportResolver` (.NET Core +) provides runtime control over library resolution. This the recommended approach cross-platform library loading name probing insufficient.
```csharp
System.Reflection;
System.Runtime.InteropServices;
NativeLibrary.SetDllImportResolver(
Assembly.GetExecutingAssembly(),
DllImportResolver);
{
(libraryName == )
{
(OperatingSystem.IsWindows())
NativeLibrary.Load(, assembly, searchPath);
(OperatingSystem.IsMacOS())
NativeLibrary.Load(, assembly, searchPath);
(OperatingSystem.IsLinux())
NativeLibrary.Load(, assembly, searchPath);
}
.Zero;
}
```text
| Scenario | Why resolver needed |
|----------|----------------------|
| Versioned `.so` = NativeLibrary.Load();
(NativeLibrary.TryLoad(, h))
{
funcPtr = NativeLibrary.GetExport(h, );
(NativeLibrary.TryGetExport(h, , fp))
{
}
NativeLibrary.Free(h);
}
```text
---
Structs passed to native code must have a well-defined memory layout. Use `[StructLayout]` to control layout alignment.
```csharp
System.Runtime.InteropServices;
[]
Point
{
X;
Y;
}
[]
ValueUnion
{
[] IntValue;
[] FloatValue;
[] DoubleValue;
}
[]
PackedHeader
{
Magic;
Length;
Version;
}
```text
**Blittable structs** (containing only primitive types sequential/ layout) are passed directly to native code without copying. Non-blittable structs require marshalling, which incurs overhead.
Blittable primitive types: ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``, ``.
**Not blittable:** `` (marshals - `BOOL` ), `` (depends charset), ``, arrays of non-blittable types.
Specify encoding explicitly. Never rely marshalling behavior.
```csharp
[]
;
[]
;
[]
;
```text
For output buffers, use `[]` `[]` `ArrayPool` instead of `StringBuilder`:
```csharp
[]
;
[] buffer = ArrayPool<>.Shared.Rent();
{
result = GetName(buffer, buffer.Length);
name = (buffer, , result);
}
{
ArrayPool<>.Shared.Return(buffer);
}
```text
Modern .NET (.NET +) prefers function pointers over -based callbacks better performance AOT compatibility.
**Preferred: Unmanaged function pointers `[UnmanagedCallersOnly]`**
```csharp
System.Runtime.InteropServices;
[]
;
[])]
{
;
}
{
RegisterCallback(&MyCallback, .Zero);
}
```text
**Alternative: Delegate-;
[]
;
NativeCallback? s_callback;
{
s_callback = NativeCallback(MyManagedCallback);
RegisterCallbackDelegate(s_callback, .Zero);
}
{
* ;
}
```text
Use `SafeHandle` subclasses to manage native resource lifetimes instead of raw `IntPtr`/``. This prevents resource leaks use-after-free bugs.
```csharp
System.Runtime.InteropServices;
Microsoft.Win32.SafeHandles;
:
{
{ }
{
NativeApi.CloseResource(handle);
;
}
}
{
[]
;
[]
;
[]
;
}
```text
---
Map C/C++ types to .NET types carefully. Some C types have platform-dependent sizes.
| C/C++ Type | .NET Type | Size |
|------------|-----------|------|
| `int8_t` / `` | `` | |
| `uint8_t` / `unsigned ` | `` | |
| `int16_t` / `` | `` | bytes |
| `uint16_t` / `unsigned ` | `` | bytes |
| `int32_t` / `` | `` | bytes |
| `uint32_t` / `unsigned ` | `` | bytes |
| `int64_t` / ` ` | `` | bytes |
| `uint64_t` / `unsigned ` | `` | bytes |
| `` | `` | bytes |
| `` | `` | bytes |
| C/C++ Type | .NET Type | Notes |
|------------|-----------|-------|
| `size_t` / `ptrdiff_t` | `` / `` | Pointer-sized |
| `*` / pointer types | `` `*` | Pointer-sized |
| `` (C/C++) | `CLong` (.NET +) | bytes Windows, bytes Unix -bit |
| `unsigned ` | `CULong` (.NET +) | Same platform variance `` |
| Windows `BOOL` | `` | bytes ( ``) |
| Windows `BOOLEAN` | `` | |
Do use C
---
**Do use `[DllImport]` .NET + code without justification.** Use `[LibraryImport]` which generates marshalling at compile time. Only fall back to `[DllImport]` SYSLIB1054 analyzer indicates incompatibility.
**Do assume `` marshals .** .NET marshals `` a - Windows `BOOL` . Use `[MarshalAs(UnmanagedType.U1)]` C `_Bool`/``, `[MarshalAs(UnmanagedType.Bool)]` Windows `BOOL` explicitly.
**Do use C
**Do use `StringBuilder` output buffers.** `[LibraryImport]` does support `StringBuilder` at all, `[DllImport]` it allocates multiple intermediate copies. Use `[]` `[]` `ArrayPool` instead.
**Do use `[LibraryImport]` `[DllImport]` WASM.** WebAssembly does support traditional P/Invoke. For JavaScript interop WASM, see [skill:dotnet-aot-wasm].
**Do use library loading iOS.** iOS prohibits loading libraries at runtime. Use `` the library name statically linked native code.
**Do use `System.Delegate` fields interop structs.**
Code Navigation (Serena MCP)
Primary approach: Use Serena symbol operations for efficient code navigation:
Find definitions: serena_find_symbol instead of text search
Understand structure: serena_get_symbols_overview for file organization
Track references: serena_find_referencing_symbols for impact analysis
Precise edits: serena_replace_symbol_body for clean modifications
When to use Serena vs traditional tools:
Use Serena: Navigation, refactoring, dependency analysis, precise edits
Use Read/Grep: Reading full files, pattern matching, simple text operations
Fallback: If Serena unavailable, traditional tools work fine
NET runtime automatically probes common name variations (withand without `lib` prefix, with platform-specific extensions).
```csharp
// Use the logical name without extension -- .NET probes:// libsqlite3.dylib (macOS), libsqlite3.so (Linux), sqlite3.dll (Windows)
[LibraryImport("libsqlite3")]
internalstaticpartialintsqlite3_open(
[MarshalAs(UnmanagedType.LPUTF8Str)] string filename,
outnint db)
for
"foo"
1.
2.
3.
### iOS
not
dynamic
into
as
into
// Calls a function statically linked into the iOS app binary
LibraryImport("__Internal")
internalstaticpartialintNativeFunction(int input)
the native library must be compiled as a staticlibrary (`.a`) and linked during the Xcode build phase. MAUI and Xamarin handle this through native references in the project file:
```xml
<ItemGroup Condition
's native library directory. The library name typically omits the `lib` prefix and `.so` extension in the P/Invoke declaration:
```csharp
// Android loads libmynative.so from the APK'
onLinux (e.g., `libfoo.so.2`) | Default probing does not check versioned names |
| Library in a non-standard path | Load from a custom directory at runtime |
| Bundled native library per RID | Resolve to `runtimes/<rid>/native/` path |
| Feature detection at load time | Try multiple library names and fall back gracefully |
### NativeLibrary API
The `NativeLibrary` class provides low-level library management:
```csharp
// Load a library explicitlynint handle
"mylib"
// Try to load without throwing
if
"mylib"
out
nint
// Get a function pointer by name
nint
"my_function"
// Or try without throwing
if
"my_function"
out
nint
// Use function pointer
## Marshalling Patterns
### Struct Marshalling
and
using
// Sequential layout -- fields laid out in declaration order
StructLayout(LayoutKind.Sequential)
public
struct
public
int
public
int
// Explicit layout -- fields at specific byte offsets (for unions)
StructLayout(LayoutKind.Explicit)
public
struct
FieldOffset(0)
public
int
FieldOffset(0)
public
float
FieldOffset(0)
public
double
// Sequential with packing -- override default alignment
StructLayout(LayoutKind.Sequential, Pack = 1)
public
struct
public
byte
public
int
// No padding before this field
public
short
value
with
explicit
byte
sbyte
short
ushort
int
uint
long
ulong
float
double
nint
nuint
bool
as
4
byte
by
default
char
on
string
### String Marshalling
string
on
default
// UTF-8 strings (most common for cross-platform C APIs)
internalstaticpartialintReadResource(NativeResourceHandle handle,
Span<byte> buffer, int count)
## Cross-Platform Data Type Mapping
### Fixed-Size Types
char
sbyte
1
byte
char
byte
1
byte
short
short
2
short
ushort
2
int
int
4
int
uint
4
long
long
long
8
long
long
ulong
8
float
float
4
double
double
8
### Platform-Dependent Types
nint
nuint
void
nint
or
void
long
6
4
on
8
on
64
long
6
as
long
int
4
not
bool
byte
1
byte
not
# `long` for C/C++ `long` -- they have different sizes on Unix 64-bit. Use `CLong`/`CULong` for portable interop.
## Agent Gotchas
1.
not
in
new
7
when
2.
not
bool
as
1
byte
bool
as
4
byte
by
default
for
bool
or
for
3.
not
# `long` to interop with C/C++ `long`.** C `long` is 4 bytes on Windows but 8 bytes on 64-bit Unix. Use `CLong`/`CULong` (.NET 6+) for cross-platform correctness.
4.
not
for
string
not
and
with
char
or
byte
from
5.
not
or
for
not
in
6.
not
dynamic
on
dynamic
"__Internal"
as
for
7.
not
in
Use typed delegates orunmanaged function pointers (`delegate* unmanaged`). Untyped delegates can destabilize the runtime during marshalling.
8. **Do not forget to keep delegate instances alive during native use.** The GC may collect a delegate that native code still references. Store delegates in a static field or use `GCHandle` for the duration of native callbacks.
---
## Prerequisites
- .NET 7+ SDK for `[LibraryImport]` source generation
- .NET Core 3.0+ for `NativeLibrary` API
- Native libraries compiled for each target platform/architecture
- For iOS: Xcode with native static libraries linked via `NativeReference`
- For Android: native `.so` files for each target ABI (arm64-v8a, x86_64)
---
## References
- [Platform Invoke (P/Invoke)](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke)
- [Native interoperability best practices](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/best-practices)
- [LibraryImport source generation](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/pinvoke-source-generation)
- [Type marshalling](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/type-marshalling)
- [Customizing struct marshalling](https://learn.microsoft.com/en-us/dotnet/standard/native-interop/customize-struct-marshalling)
- [NativeLibrary class](https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary)