【问题标题】:pInvoke readFile() : Overlapped I/O operation is in progresspInvoke readFile() : 重叠的 I/O 操作正在进行中
【发布时间】:2014-07-03 11:29:55
【问题描述】:

我正在尝试开发一种与电子卡通信的功能。我需要使用 readFile() 函数:

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

我的功能是:

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

最后一行函数Marshal.GetLastWin32Error()返回错误码997。

在第二段中,出现另一个错误,代码为 0xc0000005 (FatalExecutionEngineError) 并且软件崩溃。

你知道我可以尝试什么吗?

【问题讨论】:

  • 错误代码 997 是“Overlapped I/O operation is in progress”,您可能需要将此信息添加到问题中。
  • 顺便说一句。您不必使用 CreateEvent 函数。有围绕它的包装类。查看WaitHandle 类型及其SafeWaitHandle 属性。
  • 您是否尝试过不同的 pinvoke 声明?见:http://www.pinvoke.net/default.aspx/kernel32.readfile
  • 你的错误检查在任何情况下都是错误的。如果 API 调用失败,则不一定会设置 GetLastError。您仍然需要检查返回值是否失败。

标签: c# pinvoke


【解决方案1】:

不是问题。

错误代码 997 是 ERROR_IO_PENDING,这是 ReadFile 在开始重叠读取时返回的内容。

来自docs

注意 GetLastError 代码 ERROR_IO_PENDING 不是失败;它指定读取操作异步等待完成。有关详细信息,请参阅备注。

备注:

ReadFile 可能在读取操作完成之前返回。在这种情况下,ReadFile 返回 FALSE,GetLastError 函数返回 ERROR_IO_PENDING,允许调用进程在系统完成读取操作时继续。

是否需要使用重叠 I/O?


如何轻松使用 C# 中的重叠 I/O?

使用这个函数定义:

[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);

您可以从使用 Win API 打开的文件创建常规 FileStreams:

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);
}

【讨论】:

  • No 不是必需的,但我有一个有效的 VB6 代码,我正在尝试用 C# 翻译它。在VB6代码中使用了重叠I/O,但我不知道在C#代码中是否需要使用它
  • 重叠 I/O 不是必需的,但它可以让您更好地使用系统资源。在同步读取期间,读取线程将在执行 I/O 时被阻塞。使用重叠(异步)I/O,线程可以在等待 I/O 完成时执行其他任务。因此,它在概念上更好,但更难做到正确,尤其是在较低级别的 API 中使用时。我会更新我的答案。
【解决方案2】:

直接来自MSDN

因为读取操作从指定的偏移量开始 OVERLAPPED 结构,并且 ReadFile 可能会在 系统级读操作完成(读挂起),既不 偏移量或结构的任何其他部分都不应被修改、释放、 或由应用程序重用,直到事件发出信号(即, 读取完成)。

如果您阅读链接页面,您会发现如果您传递除 null 以外的任何内容作为 lpOverlapped 参数,这将是一个异步调用,因此您的问题很可能来自您尝试使用 @ 987654323@ 在函数设置之前 - 或者换句话说:在读取完成之前。

正如卢卡斯在他的回答中已经指出的那样,最后一个错误将在操作进行时返回 997,所以这是所需的输出。

【讨论】:

  • 谢谢,但是你能解释一下为什么在第二段中,会出现另一个错误,代码为 0xc0000005 (FatalExecutionEngineError) 并且软件崩溃。
  • 我试图解释我的答案:很可能(但没有实际代码很难说...)您尝试使用 readBuffer 变量,这会导致崩溃(因为它仍在由 ReadFile 方法使用)。
  • O_o 对不起,我没看到。我如何才能等待使用 bu 的 readFile 方法结束?
猜你喜欢
  • 1970-01-01
  • 2015-05-09
  • 2014-12-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-29
相关资源
最近更新 更多