4

I am working on a c# project where i communicate with an USB device. I open the connection with:

[DllImport("Kernel32.dll", SetLastError = true)]
static extern Microsoft.Win32.SafeHandles.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);
private Microsoft.Win32.SafeHandles.SafeFileHandle safeFileHandle;

...

safeFileHandle = CreateFile("\\\\.\\HsiUsb1", FileAccess.ReadWrite,FileShare.ReadWrite, 0, FileMode.Create, 0, IntPtr.Zero);

if (safeFileHandle.IsInvalid)
{
      return Marshal.GetLastWin32Error();
}
var HsiPort = new FileStream(safeFileHandle, FileAccess.ReadWrite);
if (!HsiPort.CanRead)
{
     return -1;
}

The connection is closed with:

if (HsiPort != null)
{
    HsiPort.Close();                
    HsiPort = null;
}

if (safeFileHandle != null)
{
    safeFileHandle.Close();               
    safeFileHandle = null;
}

As long as I read and write data to/from the FileStream synchroneously everything is fine and I can close and open the usb connectione several times. However, since the USB device sends data upon certain events and it is not known how many bytes are sent the programm will be stuck with the FileStream.Read(). So I started to read the data asynchroneously with FileStream.BeginRead () and EndRead(). Everything works fine, however, when I close the connection and start it again the handle is not valid and the obtained error code is 5. Can anyone help me with this? How can I close the SafeFileHandle properly? Thanks in advance

Ahmed Salman Tahir
  • 1,783
  • 1
  • 17
  • 26
user3144196
  • 51
  • 1
  • 4
  • 1
    I'm fairly sure you should _not_ close the SaveFileHandle manually once it has been attached to a FileStream. – Joachim Isaksson Dec 29 '13 at 16:23
  • @JoachimIsaksson - the safe option is to always call close. Disposable objects live under the contract that it is always sensible to call Dispose (or its aliases such as Close()) even multiple times. It may do nothing, but it should still be safe to do so. – antiduh Dec 29 '13 at 23:34
  • @user3144196, As for your actual problem, are you canceling the asynchronous read/writes that you started? Under the hood they're probably implemented as win32 overlapped calls, which are notoriously picky. As a debugging aid, you could set everything to null, call GC.Collect() and GC.WaitForPendingFinalizers(), and then use a tool like Process Explorer to see what handles you still have open. That might help you figure out what's still holding on to the file handle. – antiduh Dec 29 '13 at 23:37

1 Answers1

2

Try make use of using statements as the base of SafeFileHandle implements IDisposable.

The following should work just fine:

    [DllImport("Kernel32.dll", SetLastError = true)]
    static extern Microsoft.Win32.SafeHandles.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);
    //private Microsoft.Win32.SafeHandles.SafeFileHandle safeFileHandle;

    public static int doSomething()
    {
        using (var safeFileHandle = CreateFile("\\\\.\\HsiUsb1", FileAccess.ReadWrite, FileShare.ReadWrite, 0, FileMode.Create, 0, IntPtr.Zero))
        {
            if (safeFileHandle.IsInvalid)
            {
                return Marshal.GetLastWin32Error();
            }
            using (var HsiPort = new FileStream(safeFileHandle, FileAccess.ReadWrite))
            {
                if (!HsiPort.CanRead)
                {
                    return -1;
                }
            }
        }

        return 0;
    }

If you want to use the file handle later within another method. Do remove the first using block. Then you would have to make sure you dispose the handle correctly whenever you are done with the work on that file.

Implementing IDisposable youself within your class and dispose the resources would be one (good) way to do this.

MichaC
  • 13,104
  • 2
  • 44
  • 56
  • MichaC I have to think if I can change my code in order to use the using statements. I implemented IDisposable, and disposed HsiPort, however, it did not solve the problem: When I reopen the usb connection the obtained error code is 5 – user3144196 Dec 29 '13 at 19:07
  • Ok you want to interact with an usb device, didn't really noticed that one. Maybe this blog helps http://channel9.msdn.com/coding4fun/articles/Is-that-you-Writing-Better-Software-for-Cool-USB-Hardware. You can download the code from here: http://sourceforge.net/projects/usbwisec/. This should give you some more examples of how to create files for example ;) – MichaC Dec 29 '13 at 19:29