.NET interface

Windows Packet Filter provides managed bindings through the official NdisApiDotNet source project in wiresock/ndisapi.net. The project targets .NET Framework 4.7.2 and .NET 6.0, 7.0, and 8.0, and wraps the native ndisapi.dll. Obtain it from the repository; a public NuGet package named NdisApiDotNet is not currently available.

Build from Source

git clone https://github.com/wiresock/ndisapi.net.git
git -C ndisapi.net checkout c224384157c317accb1750ce417d4479b5e517b7
dotnet build ndisapi.net/NdisApiDotNet/NdisApiDotNet.csproj -c Release -f net8.0 -p:LangVersion=12.0
dotnet add YourApp.csproj reference ndisapi.net/NdisApiDotNet/NdisApiDotNet.csproj

The LangVersion=12.0 property pins C# 12 for the .NET 8.0 build and avoids newer SDK compiler differences caused by the current upstream project’s LangVersion=latest setting. When building an application that references this project, pass the same property to dotnet build so it also applies to the referenced library.

Replace YourApp.csproj with your application project. Deploy a native ndisapi.dll matching the application’s architecture separately; it is not included in the driver MSI. See the driver and native SDK downloads.

Key Components

  • NdisApi: Primary class wrapping driver operations, implementing IDisposable with safe handle management.
  • NetworkAdapter: Adapter representation with system and friendly names, a PhysicalAddress MAC address, medium, handle, and MTU.
  • Packet Processing: Reusable pinned byte arrays and unsafe INTERMEDIATE_BUFFER, ETH_REQUEST, and ETH_M_REQUEST structures. Batch requests provide typed Span<NDISRD_ETH_Packet> access to packet entries.

Minimal Example (C#)

using System;
using System.ComponentModel;
using NdisApiDotNet;

try
{
    // The wrapper terminates the driver name for the native Unicode DLL.
    using var filter = NdisApi.Open();
    if (!filter.IsDriverLoaded())
    {
        Console.Error.WriteLine("WinpkFilter driver is not loaded.");
        return;
    }

    Console.WriteLine($"Driver file version: {filter.GetVersion()}");
    Console.WriteLine($"Driver IOCTL version: 0x{filter.GetNativeVersion():X8}");

    foreach (var adapter in filter.GetNetworkAdapters())
    {
        Console.WriteLine($"Adapter: {adapter.Name} ({adapter.FriendlyName})");
    }
}
catch (DllNotFoundException ex)
{
    Console.Error.WriteLine($"Could not load native ndisapi.dll: {ex.Message}");
}
catch (BadImageFormatException ex)
{
    Console.Error.WriteLine($"Check the native DLL's architecture: {ex.Message}");
}
catch (Win32Exception ex)
{
    Console.Error.WriteLine($"The native library returned an invalid object handle: {ex.Message}");
}

Open() throws DllNotFoundException when the native DLL is missing and System.ComponentModel.Win32Exception when the native library returns an invalid object handle. Handle these exceptions as appropriate for your application. A library object can exist even if the driver device was not opened; IsDriverLoaded() checks driver initialization after Open() returns.

Historical C++/CLI Reference

The separate C++/CLI binding in wiresock/ndisapi uses the NdisApi namespace. Its NetworkAdapter, RawPacket, and PacketOidData references are preserved at their existing URLs. These types are separate from the current C# project’s types.

Authoritative Repository

Official repository and full source: github.com/wiresock/ndisapi.net

Reviewed wrapper revision

The build instructions pin commit c224384157c317accb1750ce417d4479b5e517b7. In that revision, GetVersion() reads the version resource of %SystemRoot%\System32\drivers\ndisrd.sys; it is a file-version lookup. GetNativeVersion() calls the native driver-version API. The example labels the two results separately. See the two version methods.

The pinned revision includes the driver-name termination fix merged in PR #11. Open() appends the terminating NUL before encoding when needed, and Reopen() reuses the terminated bytes. Callers no longer need to append "\0" manually. The default Unicode encoding matches the modern Unicode ndisapi.dll; use useLegacyEncoding: true only with a matching legacy ANSI DLL. Match the native DLL architecture to your application as well. See Open() and Reopen().