6

I'm trying to develop a function to communicate with an electronic card. I need to use the readFile() function :

[DllImport("kernel32.dll", SetLastError = true)]
static extern bool ReadFile(IntPtr hFile, ref byte lpBuffer,
       uint nNumberOfBytesToRead, out uint lpNumberOfBytesRead, Overlapped lpOverlapped);

My function is :

EventObject = CreateEvent(IntPtr.Zero,true,true,"");
lastError = Marshal.GetLastWin32Error();

HIDOverlapped = new System.Threading.Overlapped();
HIDOverlapped.OffsetLow = 0;
HIDOverlapped.OffsetHigh = 0;
HIDOverlapped.EventHandleIntPtr = EventObject;

readHandle = CreateFile(MyDeviceInterfaceDetailData.DevicePath, (GENERIC_READ | GENERIC_WRITE), (FILE_SHARE_READ | FILE_SHARE_WRITE), IntPtr.Zero, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, IntPtr.Zero);

 uint numberOfBytesRead;
        readBuffer= new byte[8];
        string byteValue;


 bool result = ReadFile(readHandle, ref readBuffer[0], (uint)capabilities.InputReportByteLength, out numberOfBytesRead, HIDOverlapped);
 lastError = Marshal.GetLastWin32Error(); //Problem

The function Marshal.GetLastWin32Error() in the last line returns error code 997.

In the sencond passage, an other error appears with the code 0xc0000005 (FatalExecutionEngineError) and the software crash.

Have you got an idea of what I can tried?

boboch
  • 63
  • 2
  • 7
  • 2
    Error code 997 is "Overlapped I/O operation is in progress", you might want to add this info to the question. – qqbenq Jul 03 '14 at 11:34
  • 1
    Just btw. You don't have to use the CreateEvent function. There are wrapper classes around that. Take a look at the `WaitHandle` type and its `SafeWaitHandle` property. – Florian Jul 03 '14 at 11:36
  • Did you try a different pinvoke declaration ? See: [http://www.pinvoke.net/default.aspx/kernel32.readfile](http://www.pinvoke.net/default.aspx/kernel32.readfile) – Heslacher Jul 03 '14 at 11:39
  • Your error checking is wrong in any case. `GetLastError` won't necessarily be set if the API call fails. You still need to check the return value for failures. – David Heffernan Jul 03 '14 at 12:00

2 Answers2

5

This is not a problem.

Error code 997 is ERROR_IO_PENDING, which is what ReadFile will return upon starting an overlapped read.

From the docs:

Note The GetLastError code ERROR_IO_PENDING is not a failure; it designates the read operation is pending completion asynchronously. For more information, see Remarks.

Remarks:

ReadFile may return before the read operation is complete. In this scenario, ReadFile returns FALSE and the GetLastError function returns ERROR_IO_PENDING, which allows the calling process to continue while the system completes the read operation.

Is using overlapped I/O a requirement?


How to use overlapped I/O from C# easily?

Using this function definition:

[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern SafeFileHandle CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);

You can create regular FileStreams from a file opened with the Win API:

var fileHandle = CreateFile(.....);

if (fileHandle.IsInvalid)
    Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());

// The last parameter of the FileStream constructor (isAsync) will make the class use async I/O
using (var stream = new FileStream(fileHandle, FileAccess.ReadWrite, 4096, true))
{
    var buffer = new byte[4096];

    // Asynchronously read 4kb
    var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
}
Community
  • 1
  • 1
Lucas Trzesniewski
  • 50,214
  • 11
  • 107
  • 158
  • No is not a requirement but I have a VB6 code which works and I'm trying to translate it in C#. In the VB6 code, the overlapped I/O is used but I don't know if it is neccesary to use it in C# code – boboch Jul 03 '14 at 11:47
  • Overlapped I/O is not necessary, but it lets you better use your system resources. During a synchronous read, the reading thread will be blocked while performing the I/O. With overlapped (asynchronous) I/O the thread can perform other tasks while waiting for the I/O to complete. So, it's conceptually better, but it's more difficult to get right, especially when used from the lower-level API. I'll update my answer. – Lucas Trzesniewski Jul 03 '14 at 11:59
0

Straight from MSDN:

Because the read operation starts at the offset that is specified in the OVERLAPPED structure, and ReadFile may return before the system-level read operation is complete (read pending), neither the offset nor any other part of the structure should be modified, freed, or reused by the application until the event is signaled (that is, the read completes).

If you read the linked page, you will find that if you pass anything but null as the lpOverlapped parameter it will be an asynchronous call, so most likely your problem comes from the fact, that you try to use the readBuffer before it is set by the function - or in other words: before the read completes.

And as Lucas already indicated in his answer, last error will return 997 while the operation is in progress, so this is the desired output.

qqbenq
  • 10,220
  • 4
  • 40
  • 45
  • Thank you but can you explain me why in the sencond passage, an other error appears with the code 0xc0000005 (FatalExecutionEngineError) and the software crash. – boboch Jul 03 '14 at 11:51
  • I tried to explain it my answer: most likely (but without the actual code it's hard to tell...) you try to use the readBuffer variable and this causes the crash (as it is still being used by the ReadFile method). – qqbenq Jul 03 '14 at 11:55
  • O_o I'm sorry, I haven't seen it. How I can wait the end of using bu the readFilemethod? – boboch Jul 03 '14 at 12:00