dotnet-pinvoke
Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string marshalling, memory lifetime, SafeHandle, and cross-platform patterns. USE FOR: writing new P/Invoke or LibraryImport declarations, reviewing or debugging existing native interop code, wrapping a C or C++ library for use in .NET, diagnosing crashes, memory leaks, or corruption at the managed/native boundary. DO NOT USE FOR: COM interop, C++/CLI mixed-mode assemblies, or pure managed code with no native dependencies.
npx skills add dotnet/skills --skill dotnet-pinvoke --agent claude-code
Same command for any agent — swap --agent for codex, cursor, copilot.
Weekly change comes from our own snapshots, not the repository page — it measures attention, not adoption.
What it does
Guides building and reviewing native interop between .NET and C/C++ libraries using DllImport and LibraryImport. It covers choosing between DllImport and LibraryImport, mapping native types to .NET types, writing declarations (including EntryPoint and calling conventions), correct string encoding, memory ownership models, and using SafeHandle for native handles. It also includes error handling, callbacks, and cross-platform library loading and resolving, with guidance for migrating code to LibraryImport for .NET 7+ and AOT/trimming considerations.
How it works
- Step 1: Choose DllImport or LibraryImport based on target framework and AOT needs; LibraryImport is preferred for .NET 7+ and AOT/trimming safety.
- Step 2: Map native types (e.g., long, size_t, BOOL, HANDLE, LPWSTR/LPSTR) to .NET types with cautions (e.g., use CLong, nuint/UIntPtr, SafeHandle, string encodings).
- Step 3: Write the declaration using DllImport or LibraryImport, include EntryPoint when names differ, and add appropriate CallingConvention only when targeting Windows x86.
- Step 4: Handle strings by explicitly selecting encodings (UTF-16 on Windows, UTF-8 for cross-platform C libraries); avoid CharSet.Auto and incorrect marshalling.
- Step 5: Establish memory ownership rules and choose model for who allocates/frees memory; avoid mismatched allocators.
- Step 6: Use SafeHandle for native handles to avoid leaks and double-frees; implement ReleaseHandle.
- Step 7: Handle errors via SetLastError, HRESULTs, and converting to exceptions as appropriate.
- Step 8: Handle callbacks with UnmanagedCallersOnly in .NET 8+, or rooted delegates when necessary; ensure lifetime and GC rooting to prevent crashes.
- Cross-Platform Library Loading: use NativeLibrary.SetDllImportResolver or platform-specific naming, with guidance on simple vs complex scenarios.
- Migrating DllImport to LibraryImport: steps to convert existing DllImport code to LibraryImport for .NET 7+ with partial classes and updated attributes.
When to use it
Use this skill when you are:
- Writing new [DllImport] or [LibraryImport] declarations from C/C++ headers
- Reviewing P/Invoke signatures for correctness (types, calling conventions, string encoding)
- Wrapping a C library for .NET
- Debugging boundary issues such as AccessViolationException or memory corruption
- Migrating DllImport declarations to LibraryImport for AOT/trimming compatibility
- Diagnosing memory leaks or heap corruption involving native handles or buffers
What it can touch
- Declarations using [DllImport] and [LibraryImport]
- Type mappings between C/Win32 types and .NET types (e.g., CLong, nuint, SafeHandle, string encodings)
- Error handling constructs and exceptions related to P/Invoke
- SafeHandle implementations and their ReleaseHandle logic
- Memory ownership examples and allocation/free patterns
- Callback mechanisms and function pointer handling
- NativeLibrary resolution and runtime platform checks for loading
Caveats
- Do not use for COM interop or C++/CLI mixed-mode assemblies, or code with no native dependencies
- Use LibraryImport only on .NET 7+; DllImport remains for .NET Framework
- Ensure explicit string encoding; avoid CharSet.Auto and unsafe defaults
- Be cautious with memory ownership and allocator compatibility; mismatched frees cause heap corruption
- Callbacks require careful lifetime management; delegates must be rooted if native code stores function pointers
- The guidance emphasizes avoiding risky patterns unless explicitly required by the native API or target platform
# .NET P/Invoke Calling native code from .NET is powerful but unforgiving. Incorrect signatures, garbled strings, and leaked or freed memory are the most common sources of bugs — all can manifest as intermittent crashes, silent data corruption, or access violations far from the actual defect. This skill covers both `DllImport` (available since .NET Framework 1.0) and `LibraryImport` (source-generated, .NET 7+). When targeting .NET Framework, always use `DllImport`. When targeting .NET 7+, prefer `LibraryImport` for new code. When native AOT is a requirement, `LibraryImport` is the only option. ## When to Use This Skill - Writing a new `[DllImport]` or `[LibraryImport]` declaration from a C/C++ header - Reviewing P/Invoke signatures for correctness (type sizes, calling conventions, string encoding) - Wrapping an entire C library for use from .NET - Debugging `AccessViolationException`, `DllNotFoundException`, or silent data corruption at the native boundary - Migrating `DllImport` declarations to `LibraryImport` for AOT/trimming compatibility - Diagnosing memory leaks or heap corruption involving native handles or buffers ## Stop Signals - **Single function?** Map the signature (Ste
- When to Use This Skill
- Stop Signals
- Inputs
- Workflow
- Step 1: Choose DllImport or LibraryImport
- Step 2: Map Native Types to .NET Types
- Step 3: Write the Declaration
- Step 4: Handle Strings Correctly
- Step 5: Establish Memory Ownership
- Step 6: Use SafeHandle for Native Handles
- Step 7: Handle Errors
- Step 8: Handle Callbacks (if needed)
- Cross-Platform Library Loading
- Migrating DllImport to LibraryImport
dotnet add package Microsoft.Windows.CsWin32
What does the dotnet-pinvoke skill do?
Correctly call native (C/C++) libraries from .NET using P/Invoke and LibraryImport. Covers function signatures, string marshalling, memory lifetime, SafeHandle, and cross-platform patterns. USE FOR: writing new P/Invoke or LibraryImport declarations, reviewing or debugging existing native interop code, wrapping a C or C++ library for use in .NET, diagnosing crashes, memory leaks, or corruption at the managed/native boundary. DO NOT USE FOR: COM interop, C++/CLI mixed-mode assemblies, or pure managed code with no native dependencies.
How do I install it?
Run `npx skills add dotnet/skills --skill dotnet-pinvoke --agent claude-code` — it drops the skill into your project so the agent can pick it up. Swap the --agent value for codex, cursor or copilot if you use one of those.
Where does this skill come from?
From dotnet/skills, a repository with 4,927 stars. We read it straight from the repository tree rather than a submitted listing, so what you see here is what is actually published.
Is a popular skill a good skill?
Not necessarily. Stars measure attention, not adoption — a repository can trend for a week and be abandoned. That is why we show the weekly change from our own snapshots next to the total, instead of a single flattering number.
