C NtWriteFile-错误\u无效\u参数(错误87)

C NtWriteFile-错误\u无效\u参数(错误87),c,winapi,C,Winapi,我为NtWriteFile做了一个简单的包装,但遇到了来自NtWriteFile的错误。这是我的密码: BOOL WINAPI WriteFile(HANDLE hFile, PVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten) { IO_STATUS_BLOCK IOBlock; NTSTATUS Status = NtWriteFile(hFile, NULL, 0, NULL

我为NtWriteFile做了一个简单的包装,但遇到了来自
NtWriteFile
的错误。这是我的密码:

BOOL WINAPI WriteFile(HANDLE hFile, PVOID lpBuffer, DWORD nNumberOfBytesToWrite, LPDWORD lpNumberOfBytesWritten) {
    IO_STATUS_BLOCK IOBlock;
    NTSTATUS Status = NtWriteFile(hFile, NULL, 0, NULL, &IOBlock, lpBuffer, nNumberOfBytesToWrite, 0, NULL);

    DWORD A = RtlNtStatusToDosError(Status); // just to get the error code

    if (Status == STATUS_PENDING) {
        Status = NtWaitForSingleObject(hFile, FALSE, NULL);
        if (NT_SUCCESS(Status)) Status = IOBlock.Status;
    }
    if (NT_SUCCESS(Status)) {
        *lpNumberOfBytesWritten = IOBlock.uInformation;
        return TRUE;
    }
    return FALSE;
}

在后面的行上设置断点后,
A
的值是
87
,它指向
错误\u无效\u参数
,问题是哪个参数无效?我做错了什么?

因为您在代码中准备了
状态\u PENDING
,并在
NtWriteFile
之后等待。在这种情况下,我假设您使用为异步I/O打开或创建的文件(hFile)。否则在
NtWriteFile
之后调用
NtWaitForSingleObject
没有意义。因此,我假设在调用
NtOpenFile
NtCreateFile
时,您既不使用
FILE\u SYNCHRONOUS\u IO\u ALERT
警报,也不使用
FILE\u SYNCHRONOUS\u NONALERT
(或者在
CreateFile
调用中使用
FILE\u FLAG\u OVERLAPPED

在异步I/O的情况下,字节偏移量(倒数第二个)参数是必需的。从windows源代码:

字节偏移量-指定要开始的文件中的起始字节偏移量 写入操作。如果未指定,则该文件将为打开 同步I/O,则使用当前文件位置如果 未为同步I/O打开文件,且参数未被激活 已指定,则它是错误的。

还有一段代码,在内核中失败:

} else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) {

    //
    // The file is not open for synchronous I/O operations, but the
    // caller did not specify a ByteOffset parameter.  This is an error
    // situation, so cleanup and return with the appropriate status.
    //

    if (eventObject) {
        ObDereferenceObject( eventObject );
    }
    ObDereferenceObject( fileObject );
    return STATUS_INVALID_PARAMETER;

} 
因此,如果我们为异步I/O打开或创建,或者如果我们使用同步文件句柄,
NtWriteFile
neverreturn
STATUS\u PENDING
并且操作总是同步完成,那么我们需要或总是直接使用ByteOffset,这是出于设计。因此,在这种情况下,对
状态\u PENDING
没有任何意义检查。您可以删除此检查并
NtWaitForSingleObject
(也可以在hFile上等待,但如果同时对文件执行多个操作,则此操作不太正确)


来自

如果调用ZwCreateFile设置其中一个CreateOptions 标志、文件同步IO警报或文件同步IO非警报, I/O管理器维护当前文件位置。如果是,来电者是谁 ZwWriteFile的可以指定当前文件位置偏移 可以使用,而不是显式字节偏移量值。本规范 可以使用以下方法之一进行:

  • 指定指向大整数值的指针,其中HighPart成员设置为-1,LowPart成员设置为系统定义的值
    文件\使用\文件\指针\位置
  • 为字节偏移量传递一个NULL指针

尽管没有明确说明否则会发生什么(没有文件同步IO警报或文件同步IO非警报标志)-可能理解,在这种情况下,I/O管理器维护当前文件位置,我们不能指定使用当前文件位置偏移量-只有显式字节偏移量值必须是

,因为您在代码中准备
状态_PENDING
,并在
NtWriteFile
之后等待在这种情况下-我假设您使用为异步i/O打开或创建的文件(hFile)。否则,在
NtWriteFile
之后调用
NtWaitForSingleObject
没有意义。因此,我假设在调用
NtOpenFile
NtCreateFile
时,您既不使用
FILE\u SYNCHRONOUS\u IO\u ALERT
警报,也不使用
FILE\u SYNCHRONOUS\u NONALERT
(或者在
CreateFile
调用中使用
FILE\u FLAG\u OVERLAPPED

在异步I/O的情况下,字节偏移量(倒数第二个)参数是必需的。从windows源代码:

字节偏移量-指定要开始的文件中的起始字节偏移量 写入操作。如果未指定,则该文件将为打开 同步I/O,则使用当前文件位置如果 未为同步I/O打开文件,且参数未被激活 已指定,则它是错误的。

还有一段代码,在内核中失败:

} else if (!ARGUMENT_PRESENT( ByteOffset ) && !(fileObject->Flags & (FO_NAMED_PIPE | FO_MAILSLOT))) {

    //
    // The file is not open for synchronous I/O operations, but the
    // caller did not specify a ByteOffset parameter.  This is an error
    // situation, so cleanup and return with the appropriate status.
    //

    if (eventObject) {
        ObDereferenceObject( eventObject );
    }
    ObDereferenceObject( fileObject );
    return STATUS_INVALID_PARAMETER;

} 
因此,如果我们为异步I/O打开或创建,或者如果我们使用同步文件句柄,
NtWriteFile
neverreturn
STATUS\u PENDING
并且操作总是同步完成,那么我们需要或总是直接使用ByteOffset,这是出于设计。因此,在这种情况下,对
状态\u PENDING
没有任何意义检查。您可以删除此检查并
NtWaitForSingleObject
(也可以在hFile上等待,但如果同时对文件执行多个操作,则此操作不太正确)


来自

如果调用ZwCreateFile设置其中一个CreateOptions 标志、文件同步IO警报或文件同步IO非警报, I/O管理器维护当前文件位置。如果是,来电者是谁 ZwWriteFile的
可以指定当前文件位置偏移 可以使用,而不是显式字节偏移量值。本规范 可以使用以下方法之一进行:

  • 指定指向大整数值的指针,其中HighPart成员设置为-1,LowPart成员设置为系统定义的值
    文件\使用\文件\指针\位置
  • 为字节偏移量传递一个NULL指针
尽管没有明确说明否则会发生什么(没有文件同步IO警报或文件同步IO非警报标志)-可能理解,在这种情况下,I/O管理器维护当前文件位置,我们不能指定使用当前文件位置偏移量-只有显式字节偏移量值必须为

,如果不选中
A
,它似乎有效吗?只有当函数实际失败时,才应该检查错误代码。@HarryJohnston:。我想您应该检查错误代码