Anp.Serial.Win32 1.0.0

dotnet add package Anp.Serial.Win32 --version 1.0.0
                    
NuGet\Install-Package Anp.Serial.Win32 -Version 1.0.0
                    
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="Anp.Serial.Win32" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Anp.Serial.Win32" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Anp.Serial.Win32" />
                    
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 Anp.Serial.Win32 --version 1.0.0
                    
#r "nuget: Anp.Serial.Win32, 1.0.0"
                    
#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 Anp.Serial.Win32@1.0.0
                    
#: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=Anp.Serial.Win32&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Anp.Serial.Win32&version=1.0.0
                    
Install as a Cake Tool

Anp.Serial.Win32

Managed Windows serial (COM port) library for .NET Framework 4.8, .NET Standard 2.0, and .NET 8+. Focused on USB CDC devices and USB-to-serial adapters, with full support for Bluetooth virtual COM ports and physical RS232 ports. All via Win32 P/Invoke.

Devices are identified by their device interface path — the stable, unique symbolic link assigned by the OS — rather than a COM port number. PortName (e.g. COM3) is populated on a best-effort basis from the PnP registry for display and interop with legacy APIs, but the path is the primary identifier used for discovery, open, and hot-plug matching.

NuGet

Features

  • Discovery — enumerate all COM port devices, optionally filtered by USB VID/PID
  • Hot-plug monitoring — get notified when devices arrive or are removed (Windows 8+)
  • Async I/OReadAsync, WriteAsync, ReadExactAsync, ReadToAsync, ReadLineAsync, WriteLineAsync with meaningful per-call timeouts (default 2 s, configurable per operation)
  • Graceful disconnect handling — mid-I/O device removal raises SerialDisconnectedException instead of corrupting state; the device transitions cleanly to closed
  • Sync wrappersWrite, ReadText, ReadLine, ReadTo for simple use cases
  • Serial control — baud rate, data bits, parity, stop bits, DTR/RTS, modem status, purge
  • Device metadataVendorId / ProductId parsed from the device path; FriendlyName and PortName (best-effort, e.g. COM3) read from the PnP registry
  • SubclassableOnOpened() / OnClosing() hooks for protocol initialization and teardown
  • Diagnostics — subscribe to SerialDiag.Error for library-level error reporting

Quick Start

A SerialDevice can be created via the built-in discovery or directly from a device interface path obtained from any external source — your own enumeration, a config file, a saved user preference, or a tool like PnpDeviceToolkit.

Discover devices

using Anp.Serial.Win32;

// All COM port devices
var devices = SerialDiscovery.GetDevices();

// Filter by USB VID/PID
var filtered = SerialDiscovery.GetDevices(vendorId: 0x1234, productId: 0x5678);

foreach (var device in devices)
{
    Console.WriteLine($"{device.PortName} — {device.FriendlyName} (VID={device.VendorId}, PID={device.ProductId})");
    device.Dispose();
}

Open, write, read (USB CDC)

USB CDC devices typically don't require PortSettings — the actual line rate is negotiated over the USB control interface, and the default 8N1 configuration works out of the box:

using Anp.Serial.Win32;

// From discovery, config file, or any other source
var device = new SerialDevice(@"\\?\USB#VID_1234&PID_5678#serial#{...}");
device.Open();

// No PortSettings needed for USB CDC — just start talking
await device.WriteLineAsync("HELLO");
string response = await device.ReadLineAsync(timeout: TimeSpan.FromSeconds(5));

device.Close();
device.Dispose();

Open, write, read (USB-to-serial adapter)

For USB-to-serial adapters and physical RS232 ports, configure PortSettings to match the target device:

var device = new SerialDevice(@"\\?\FTDIBUS#VID_0403+PID_6001+...#{...}");
device.Open();

device.PortSettings = new PortSettings
{
    BaudRate = 115200,
    DataBits = 8,
    Parity = Parity.None,
    StopBits = StopBits.One
};

await device.WriteLineAsync("HELLO");
string response = await device.ReadLineAsync(timeout: TimeSpan.FromSeconds(5));

device.Close();
device.Dispose();

Monitor hot-plug events

using Anp.Serial.Win32;

using (var watcher = new SerialWatcher(vendorId: 0x1234))
{
    watcher.DeviceArrived += (s, e) => Console.WriteLine($"Connected: {e.DevicePath}");
    watcher.DeviceRemoved += (s, e) => Console.WriteLine($"Disconnected: {e.DevicePath}");
    watcher.StartWatching();

    Console.ReadLine(); // keep alive
}

Subclass for protocol initialization

public class MyDevice : SerialDevice
{
    public MyDevice(string path) : base(path) { }

    protected override void OnOpened()
    {
        // Device is open — send handshake, configure settings, etc.
        PortSettings = new PortSettings { BaudRate = 9600, DataBits = 8 };
        WriteLineAsync("INIT").GetAwaiter().GetResult();
    }

    protected override void OnClosing()
    {
        // Device is about to close — send goodbye, flush, etc.
        WriteLineAsync("BYE").GetAwaiter().GetResult();
    }
}

// Use with discovery
var devices = SerialDiscovery.GetDevices<MyDevice>(path => new MyDevice(path));

API Overview

SerialDevice

Member Description
Open() / Close() Open and close the device for I/O
IsOpen Whether the device is currently open
IsOpenChanged Event raised after open/close transitions
DevicePath Device interface path (symbolic link)
PortName COM port name (e.g. COM3), or null
FriendlyName Windows device name (e.g. USB Serial Device (COM3)), or null
VendorId / ProductId USB IDs parsed from the device path, or null
PortSettings Get/set baud rate, data bits, parity, stop bits
PortTimeouts (Advanced) Get/set driver-level COM port timeouts — reserve for edge cases where the default return-immediately behavior doesn't suit the driver
DtrEnable / RtsEnable DTR and RTS signal control
Encoding Byte encoding for text I/O (default: ASCII)
NewLine Delimiter for ReadLineAsync / WriteLineAsync (default: \n)
ReadAsync(byte[], int, int) Read bytes into a buffer
ReadAsync(int) Read up to N bytes, return as byte[]
ReadExactAsync(int) Read exactly N bytes (loops until full)
WriteAsync(byte[], int, int) Write bytes from a buffer
WriteAsync(byte[]) Write an entire byte array
ReadTextAsync(int) Read bytes and decode as string
ReadToAsync(string) Read until delimiter is found
ReadLineAsync() Read until NewLine delimiter
WriteTextAsync(string) Encode and write a string
WriteLineAsync(string) Write a string followed by NewLine
GetModemStatus() Read CTS, DSR, Ring, RLSD signals
Purge(bool, bool) (Advanced) Clear receive and/or transmit buffers
OnOpened() / OnClosing() Virtual hooks for subclass initialization

All async methods accept an optional TimeSpan? timeout parameter (default: 2 seconds).

SerialDiscovery

Member Description
GetDevices(vendorId?, productId?) Discover and return SerialDevice instances
GetDevices<T>(factory, vendorId?, productId?) Discover with custom factory for derived types
GetDevicePaths(vendorId?, productId?) Return device interface paths only

SerialWatcher

Member Description
DeviceArrived Event: a matching COM port device was connected
DeviceRemoved Event: a matching COM port device was disconnected
StartWatching() / StopWatching() Begin/end PnP monitoring (Windows 8+)

Diagnostics

SerialDiag.Error += (sender, error) =>
{
    Console.WriteLine($"[{error.Member}] {error.Message} {error.Exception}");
};

Requirements

  • .NET Framework 4.8, .NET Standard 2.0, or .NET 8+ (Windows)
  • Windows Vista or later (discovery and I/O)
  • Windows 8 or later (SerialWatcher hot-plug monitoring)

License

See LICENSE in the repository root.

Product 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 was computed.  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.  net8.0-windows7.0 is compatible.  net9.0 was computed.  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 was computed.  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 is compatible.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.8

    • No dependencies.
  • .NETStandard 2.0

  • net8.0-windows7.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.0.0 97 3/29/2026