NativeInvoke 1.3.1

dotnet add package NativeInvoke --version 1.3.1
                    
NuGet\Install-Package NativeInvoke -Version 1.3.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NativeInvoke" Version="1.3.1">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NativeInvoke" Version="1.3.1" />
                    
Directory.Packages.props
<PackageReference Include="NativeInvoke">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NativeInvoke --version 1.3.1
                    
#r "nuget: NativeInvoke, 1.3.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NativeInvoke@1.3.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NativeInvoke&version=1.3.1
                    
Install as a Cake Addin
#tool nuget:?package=NativeInvoke&version=1.3.1
                    
Install as a Cake Tool

NativeInvoke banner

🌟 ᑎᗩTIᐯEIᑎᐯOKE ✨

Stars Issues License

High-performance, source-generated P/Invoke

NativeInvoke is a modern, zero-overhead, generics-capable P/Invoke generator for .NET.
It uses Roslyn source generation to enforce blittable, function-pointer based, lazy-loaded native bindings - without the runtime overhead of DllImport.

You write clean interfaces.
NativeInvoke generates the unsafe bits for you at compile-time.

  • Cross-platform and AOT/JIT-friendly.
  • No DllImport.
  • No delegate allocation (no pinning).
  • No runtime dependencies.
  • No marshalling.
  • No reflection.
  • No dynamic codegen (dynamic IL).
  • Just pure compile-time generation glue.

🚀 Quick Installation

Install the NuGet package:

dotnet add package NativeInvoke

Or edit your .csproj to always stay up-to-date (followed by dotnet restore --no-cache):

<ItemGroup>
    <PackageReference Include="NativeInvoke" Version="*"/>
</ItemGroup>

How floating versions work:

  • *-*: Latest version including pre-releases (e.g., 1.1.0-beta.1, 2.0.0-alpha.2)
  • *: Latest stable version only
  • 1.*: Latest stable version with major version 1
  • 1.2.*: Latest stable version with major.minor 1.2

🧠 Why NativeInvoke?

Feature Benefit
Source-generated Zero runtime overhead
Function pointers Faster than DllImport
Lazy-loading support Load symbols/functions only when needed
Interface-based Fully mockable for testing
Generics support Use generics in P/Invoke
No static pollution Clean public API surface
.NET 9 Lock support Modern, allocation-free synchronization

🛠 Requirements

  • C# 14 / .NET 9 or later
  • Unsafe code enabled (<AllowUnsafeBlocks>true</AllowUnsafeBlocks>)
  • Roslyn source generators enabled (default in SDK-style projects)

✨ Example Usage

📚 See Attribute docs.

Checkout the full Example project for more!
Here is slightly verbose example for playing a beep sound on Windows platform (a.k.a. System.Console.Beep):

1. Define your native interface

global using NativeInvoke; // Import our attributes in your project
global using NIMA = NativeInvoke.NativeImportMethodAttribute;

using BOOL = int; // Win32 BOOL is 4-bytes (0=false, 1=true)
using DWORD = uint; // double-word

#if NET6_0_OR_GREATER
[System.Runtime.Versioning.SupportedOSPlatform("windows")] // Optional (for clarity)
#endif
public interface IKernel32<TBool> // Generics are supported!
  where TBool : unmanaged
{
  [NIMA("Beep")] // Optional; Use this attribute if you want to load a different name/ordinal,
                 // or override a calling convention per function (defaults to platform-specific).
  TBool Boop(DWORD frequency, DWORD duration);

  [NIMA(null)] // Use null or empty string to skip generation; could also omit this and set ExplicitOnly=true
  void IgnoreMe();
}

2. Expose it via a static partial property

The property can be nested anywhere you want (class/struct/interface/record), and you can use any accessibility level you need - the generator will match your declaration.

public static partial class Win32
{
  private const string kernel32 = "kernel32";
  [NativeImport(
    kernel32 // Specify native library name
    , EnforceBlittable = true // Whether to enforce blittable type validation (applies to all methods, can be overriden per-method)
    , ExplicitOnly = false // Whether only methods explicitly marked with NIMA should be considered
    , Inherited = true // Whether to consider inherited interface methods
    , Lazy = false // Whether to use lazy or eager module loading
    , CallingConvention = CallingConvention.StdCall // Define the default calling convention (default is platform-specific, applies to all methods, can be overriden per-method)
    , SuppressGCTransition = false // Whether to suppress the GC transition (applies to all methods, can be overriden per-method)
    , SymbolPrefix = "" // Define common prefix (prepended to method name unless using explicit entry point)
    , SymbolSuffix = "" // Define common suffix (appended to method name unless using explicit entry point)
  )]
  public static partial IKernel32<BOOL> Kernel32 { get; }
}

3. Call it like a normal .NET API

Win32.Kernel32.Boop(600u, 300u);

Under the hood, NativeInvoke generates:

  • A nested sealed __Impl class implementing your (generic) interface
  • Static (readonly) function pointer fields (delegate* unmanaged)
  • Lazy or eager symbol resolution (NativeLibrary)
  • A clean property implementation using the field keyword
  • Thread-safe lazy initialization using .NET 9 Lock type

All without touching your container type.


💡 Future/Experiments (ToDo list)

  • Support C# 9 / .NET 5 and later via #if; current source generator is relying on C# 14 features and .NET 9 API
  • Add support for loading symbol from numeric ordinal
  • Implement default symbol name prefix and suffix
  • Add EnforceBlittable and ExplicitOnly flags
  • Switch to [UnmanagedCallConv]/typeof(CallConv*) for future-proofed calling conventions (MemberFunction, Swift, etc.)
  • Use IndentedTextWriter for source-code generation
  • Append Guid to generated fields (to prevent name collisions for overloaded functions)
  • Make unit tests
  • Auto-generate proper page for docs and examples (maybe use GitHub io page or wiki)
  • Explore micro-optimization: IL weaver via Fody, replace interface dispatch and DllImport calls with calli

🙏 Contributing

PRs, issues, and ideas are welcome.
NativeInvoke is built for developers who want maximum performance without sacrificing clean API design.


💖 Support

If you like this or you are using this in your project, consider:


📄 License

MIT - do whatever you want, just don't blame me if you calli into oblivion.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

  • .NETStandard 2.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.1 0 3/11/2026
1.3.0 0 3/11/2026
1.2.0 32 3/10/2026
1.1.0 29 3/10/2026
1.0.0 36 3/9/2026