NullifyNetwork

The blog and home page of Simon Soanes
Skip to content
[ Log On ]

Want to access a physical device (COM port, tape drive, LPT port, anything...) using C# .net?

You can't.  Not natively anyway:

FileStream fs = File.Open("\\\\.\\COM1", FileMode.Open, FileAccess.ReadWrite, FileShare.None);

Happily errors out saying you can't use the \\.\ format with a FileStream (\\.\ becomes \\\\.\\ when you escape the backspaces with more backspaces).

FileStream does however allow opening a handle, so all is not lost, you can simply use the format:

FileStream fs = new FileStream(handle, FileAccess.ReadWrite);

After opening the handle using a CreateFile API call.  To use this API call you need to platform invoke it, which is easily done once you look at the docs for it:

[DllImport("Kernel32.dll")]
static
extern IntPtr CreateFile(string filename, [MarshalAs(UnmanagedType.U4)]FileAccess fileaccess, [MarshalAs(UnmanagedType.U4)]FileShare fileshare, int securityattributes, [MarshalAs(UnmanagedType.U4)]FileMode creationdisposition, int flags, IntPtr template);

(http://www.pinvoke.net/ is a great place to cheat)

You can then get handle (note that rather than defining the actual handle variable I'm going to put the CreateFile call inside the FileStream constructor - you could instead do InPtr handle = CreateFile() etc) by using CreateFile:

FileStream fs = new FileStream(CreateFile("\\\\.\\COM1", FileAccess.ReadWrite, FileShare.ReadWrite, 0, FileMode.Create, 0, IntPtr.Zero), FileAccess.ReadWrite);

First timers should remember to update their using statements, one for the FileStream, and one for the [DllImport]:

using System.IO;
using
System.Runtime.InteropServices;

Permalink  1 Comments 

File handle as IntPtr deprecated in VS 2008 by ms_koster at 02/20/2009 16:03:33
The above code worked perfectly well for me (thank you Simon), however according to Microsoft it doesn't: VS 2008 give you this warning: "warning CS0618: 'System.IO.FileStream.FileStream(System.IntPtr, System.IO.FileAccess)' is obsolete: 'This constructor has been deprecated. Please use new FileStream(SafeFileHandle handle, FileAccess access) instead."

Using SafeFileHandle is rather simple: change the platform invoke bit into

[DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern SafeFileHandle CreateFile(string filename, [MarshalAs(UnmanagedType.U4)]FileAccess fileaccess,
[MarshalAs(UnmanagedType.U4)]FileShare fileshare, int securityattributes,
[MarshalAs(UnmanagedType.U4)]FileMode creationdisposition, int flags, IntPtr template);

and update your using statements with

using Microsoft.Win32.SafeHandles;

To be really safe it would be advisable to put the FileStream creation part and any subsequent IO commands in a try / catch block (but you probably guessed that already).