ReadFile 和 WriteFile with Overlapped IO result if not ERROR_IO_PENDING?

ReadFile and WriteFile with Overlapped IO result if not ERROR_IO_PENDING?

WriteFile() 上 FILE_FLAG_OVERLAPPED 的文档说您必须提供 OVERLAP 并建议 lpNumberOfBytesWritten 为 NULL,因为值具有误导性。但是 GetOverlappedResult() 的文档说只有在 WriteFile() 返回 FALSE 且 ERROR_IO_PENDING 时才调用。因此,ReadFile() / WriteFile() 在 API 调用本身中完成的情况。你应该如何获得字节数read/written?你认为这是要求的号码吗?但是 WriteFile() 说 "When writing to a non-blocking, byte-mode pipe handle with insufficient buffer space, WriteFile returns TRUE with * lpNumberOfBytesWritten < nNumberOfBytesToWrite".

TIA!!

If hFile was opened with FILE_FLAG_OVERLAPPED The lpNumberOfBytesWritten parameter should be set to NULL.

这不是真的(错误或谎言)。 lpNumberOfBytesWritten可以设置为NULL,但是不应该.如果 I/O 请求在 *lpNumberOfBytesWritten 中成功同步完成,将是有效的字节数。

另请注意,lpNumberOfBytes 不得 指向在操作完成之前有效的位置(如 lpOverlapped) - 例如,它可以指向函数中的局部变量,您可以在 I/O 完成之前退出函数 - 这也可以。系统只需将 InternalHighOVERLAPPED 复制到 *lpNumberOfBytes。所以在伪代码中:

if (lpNumberOfBytes) *lpNumberOfBytes = (ULONG)lpOverlapped->InternalHigh;

*lpNumberOfBytes 中明显的正确值只有在 I/O 已经成功完成时才会出现。所以只能在这种情况下使用它。系统不记得 lpNumberOfBytes 的值 - 因为它必须仅在 [Write|Read]File 调用期间有效,而不是在 I/O 活动期间(可以是如果异步 I/O)

则更长

GetOverlappedResult 我们可以调用 if I/O 请求完成与成功同步(如果 ReadFileWriteFile,如果 return TRUE) 如果待处理 returned。只有在 I/O 请求失败(ReadFileWriteFile return FALSEGetLastError() != ERROR_IO_PENDING 时才能调用此 api

所以最好总是将 not 0 lpNumberOfBytes 传递给 api 并使用它,如果 api 成功完成。否则使用 GetOverlappedResult 或者如果说你使用 BindIoCompletionCallback - 你直接在回调中得到 dwNumberOfBytesTransfered

所以在概念上可以使用下一个代码:

inline ULONG BOOL_TO_ERROR(BOOL f)
{
    return f ? NOERROR : GetLastError();
}

HANDLE hFile = CreateFile(*, FILE_GENERIC_READ, FILE_SHARE_READ, 0, 
    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

if (hFile != INVALID_HANDLE_VALUE)
{
    UCHAR buf[0x200];
    OVERLAPPED ov = {};
    ULONG NumberOfBytesRead;

    ULONG dwError = BOOL_TO_ERROR(ReadFile(hFile, buf, sizeof(buf), &NumberOfBytesRead, &ov));

    switch (dwError)
    {
    case ERROR_IO_PENDING:
        dwError = BOOL_TO_ERROR(GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE));
        if (dwError != NOERROR) goto __default;
        [[fallthrough]];

    case NOERROR:
        DbgPrint("NumberOfBytesRead=%x\n", NumberOfBytesRead);
        // use GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE) here also possible
        break;
__default:
    default:
    DbgPrint("dwError = %u\n", dwError);
    }

    CloseHandle(hFile);
}