AdaskoTheBeAsT.Interop.Unmanaged
1.0.0
See the version list below for details.
dotnet add package AdaskoTheBeAsT.Interop.Unmanaged --version 1.0.0
NuGet\Install-Package AdaskoTheBeAsT.Interop.Unmanaged -Version 1.0.0
<PackageReference Include="AdaskoTheBeAsT.Interop.Unmanaged" Version="1.0.0" />
<PackageVersion Include="AdaskoTheBeAsT.Interop.Unmanaged" Version="1.0.0" />
<PackageReference Include="AdaskoTheBeAsT.Interop.Unmanaged" />
paket add AdaskoTheBeAsT.Interop.Unmanaged --version 1.0.0
#r "nuget: AdaskoTheBeAsT.Interop.Unmanaged, 1.0.0"
#:package AdaskoTheBeAsT.Interop.Unmanaged@1.0.0
#addin nuget:?package=AdaskoTheBeAsT.Interop.Unmanaged&version=1.0.0
#tool nuget:?package=AdaskoTheBeAsT.Interop.Unmanaged&version=1.0.0
AdaskoTheBeAsT.Interop.Unmanaged
🚀 A robust, type-safe, and memory-efficient .NET library for loading and managing unmanaged DLLs with zero hassle!
Why This Library?
Working with native DLLs in .NET can be tricky - memory leaks, crashes, and platform-specific quirks. This library provides a battle-tested, safe, and elegant wrapper around Windows LoadLibrary, GetProcAddress, and FreeLibrary APIs.
✨ Key Features
- 🛡️ Memory Safe - Uses
SafeHandlepattern to prevent resource leaks - 🔒 Type Safe - Strongly-typed delegate mapping for native functions
- ⚡ High Performance - Minimal overhead with optimized P/Invoke
- 🎯 Developer Friendly - Simple, intuitive API that just works
- 🔧 Flexible - Support for custom calling conventions and generic delegates
- 📦 Multi-Framework - Supports .NET Standard 2.0, .NET 8.0, and .NET 9.0
- 🧪 Production Ready - Analyzed by 20+ code quality tools
Installation
dotnet add package AdaskoTheBeAsT.Interop.Unmanaged
Or via Package Manager:
Install-Package AdaskoTheBeAsT.Interop.Unmanaged
Quick Start
Basic Usage
using AdaskoTheBeAsT.Interop.Unmanaged;
// Define your native function signature
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
delegate int Add(int a, int b);
// Load the DLL and get the function
using var library = new UnmanagedLibrary("MyNative.dll");
var addFunction = library.GetUnmanagedFunction<Add>("add");
if (addFunction != null)
{
int result = addFunction(5, 3); // result = 8
Console.WriteLine($"Result: {result}");
}
Advanced: Custom Load Flags
using AdaskoTheBeAsT.Interop.Unmanaged;
// Load with custom search paths
var flags = LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
| LoadLibraryFlags.LOAD_LIBRARY_SEARCH_SYSTEM32;
using var library = new UnmanagedLibrary(@"C:\MyLibs\custom.dll", flags);
var myFunc = library.GetUnmanagedFunction<MyDelegate>("MyFunction");
Static Helper Methods
// Load library without wrapper
var handle = UnmanagedLibrary.LoadLibrary("kernel32.dll");
// Get function from handle
var func = UnmanagedLibrary.GetUnmanagedFunction<MyDelegate>(handle, "GetVersion");
// Clean up when done
UnmanagedLibrary.FreeLibrary(handle);
Generic Delegates with Custom Calling Conventions
// Get function pointer for delegate
var ptr = UnmanagedLibrary.GetFunctionPointerForDelegate(myCallback, out var binder);
// Create delegate from function pointer with custom calling convention
var del = UnmanagedLibrary.GetDelegateForFunctionPointer<MyDelegate>(
ptr,
CallingConventions.Standard
);
API Overview
Core Classes
UnmanagedLibrary
Main class for loading and managing native DLLs.
// Constructor
UnmanagedLibrary(string fileName, LoadLibraryFlags flags = ...)
// Get function as delegate
TDelegate? GetUnmanagedFunction<TDelegate>(string functionName)
// Static helpers
static SafeLibraryHandle LoadLibrary(string fileName, LoadLibraryFlags flags)
static void FreeLibrary(SafeLibraryHandle handle)
static TDelegate? GetUnmanagedFunction<TDelegate>(SafeLibraryHandle handle, string functionName)
SafeLibraryHandle
Thread-safe handle wrapper that ensures proper cleanup.
LoadLibraryFlags
Comprehensive enum of Windows LoadLibraryEx flags for fine-grained control over DLL loading behavior.
DelegatePin
Utility struct for pinning delegates in memory to prevent garbage collection during native callbacks.
Common Use Cases
Loading a 3rd Party Native Library
using var lib = new UnmanagedLibrary("opencv_world.dll");
var cvVersion = lib.GetUnmanagedFunction<GetVersionDelegate>("cvGetVersion");
Platform-Specific DLL Loading
#if WINDOWS
var flags = LoadLibraryFlags.LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
| LoadLibraryFlags.LOAD_LIBRARY_SEARCH_SYSTEM32;
using var lib = new UnmanagedLibrary("native_win.dll", flags);
#elif LINUX
// Use DllImport or different interop mechanism
#endif
Extracting Resources from DLLs
// Load DLL as data file without executing code
var flags = LoadLibraryFlags.LOAD_LIBRARY_AS_DATAFILE;
using var lib = new UnmanagedLibrary("resource.dll", flags);
// Extract resources here
Error Handling
The library throws meaningful exceptions with context:
try
{
using var lib = new UnmanagedLibrary("missing.dll");
}
catch (Win32Exception ex)
{
// "Failed to load library 'missing.dll'."
Console.WriteLine($"Error: {ex.Message}");
Console.WriteLine($"Native Error Code: {ex.NativeErrorCode}");
}
try
{
using var lib = new UnmanagedLibrary(null!);
}
catch (ArgumentException ex)
{
// "Value cannot be null or whitespace. (Parameter 'fileName')"
Console.WriteLine($"Error: {ex.Message}");
}
Performance Tips
- Reuse library instances - Keep the
UnmanagedLibraryinstance alive if you need multiple function calls - Cache delegates - Store retrieved delegates instead of calling
GetUnmanagedFunctionrepeatedly - Use static methods - For one-off calls, static helper methods avoid object allocation
// ❌ Bad - Repeated loading
for (int i = 0; i < 1000; i++)
{
using var lib = new UnmanagedLibrary("my.dll");
var func = lib.GetUnmanagedFunction<MyDelegate>("MyFunc");
func?.Invoke();
}
// ✅ Good - Load once, use many times
using var lib = new UnmanagedLibrary("my.dll");
var func = lib.GetUnmanagedFunction<MyDelegate>("MyFunc");
for (int i = 0; i < 1000; i++)
{
func?.Invoke();
}
Security Considerations
- The library uses
SuppressUnmanagedCodeSecurityfor performance - only load trusted DLLs - Always validate file paths before loading to prevent DLL hijacking attacks
- Use
LOAD_LIBRARY_SEARCH_*flags to control DLL search paths and prevent loading from untrusted locations - Dispose library instances promptly to prevent holding locks on DLL files
Requirements
- .NET Standard 2.0 or higher
- .NET 8.0 or higher
- .NET 9.0 or higher
- Windows OS (uses Windows API under the hood)
Contributing
Contributions are welcome! This project maintains high code quality standards with:
- 20+ static analyzers (StyleCop, Roslynator, SonarAnalyzer, etc.)
- Treat warnings as errors
- Nullable reference types enabled
- Comprehensive documentation required
License
This project is licensed under the MIT License - see the LICENSE file for details.
Credits
Developed with ❤️ by Adam Pluciński
⭐ If this library saved you time, give it a star on GitHub!
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Memory (>= 4.6.3)
- System.Reflection.Emit (>= 4.7.0)
- System.Reflection.Emit.Lightweight (>= 4.7.0)
- System.Runtime.CompilerServices.Unsafe (>= 6.1.2)
-
net10.0
- No dependencies.
-
net8.0
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages (1)
Showing the top 1 NuGet packages that depend on AdaskoTheBeAsT.Interop.Unmanaged:
| Package | Downloads |
|---|---|
|
AdaskoTheBeAsT.WkHtmlToX
AdaskoTheBeAsT.WkHtmlToX c# wrapper |
GitHub repositories
This package is not used by any popular GitHub repositories.