-2

认为这可能对某人有帮助,因为这对我来说是一种惊喜。

WriteFile 函数尝试写入其第 4 个(可选)参数,如果它为 NULL,则会导致访问冲突异常......但在 Windows 8(.1) 上不会。

这是来自msdn的函数定义:

BOOL WINAPI WriteFile(
    _In_         HANDLE hFile,
    _In_         LPCVOID lpBuffer,
    _In_         DWORD nNumberOfBytesToWrite,
    _Out_opt_    LPDWORD lpNumberOfBytesWritten, // Optional
    _Inout_opt_  LPOVERLAPPED lpOverlapped
);

lpNumberOfBytesWritten [out, optional] ... 只有当 lpOverlapped 参数不为 NULL 时,此参数才能为 NULL。

我创建了重现错误的简短示例。代码是在 Visual Studio 2008 SP1 中创建的 Win32 控制台应用程序:

int _tmain(int argc, _TCHAR* argv[])
{
    HANDLE hFile = CreateFile(L"N:\\Test\\Test.tmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL);
    if (INVALID_HANDLE_VALUE == hFile)  {
        return -1;
    }
    unsigned int testValue = 32;
    //-----------------------------------------------
    // Next line generates AV exception on Windows 7,
    // On Windows 8 it works fine:
    //-----------------------------------------------
    WriteFile(hFile, &testValue, sizeof(unsigned int), NULL, NULL);
    CloseHandle(hFile);
    return 0;
}

最后,如果我通过以下两行更改对 WriteFile() 的调用,则可以解决问题并适用于所有平台:

// Now it does not generate AV:
DWORD written = 0;
WriteFile(hFile, &testValue, sizeof(unsigned int), &written, NULL);

该代码在 Windows 7 和 Windows XP SP3 上生成访问冲突(未在 Vista 上测试)。在 Windows 8(.1) 上它可以工作,即使我在第四个参数 (lpNumberOfBytesWritten) 中传递了 NULL。

实际的问题是我开发了一个写入临时文件的模块,但我忽略了第四个参数(我读了“可选”但误读了其余的并认为它可能被忽略了)。我在 Windows 8.1 上开发并测试了它,所以代码运行良好,但是客户端机器在 Windows 7 上并且代码失败。

我学到的教训:我应该更加专注(注意细节),不要沾沾自喜(仔细测试)。

4

1 回答 1

2

The documentation for lpNumberOfBytesWritten says:

This parameter can be NULL only when the lpOverlapped parameter is not NULL.

In other words, the lpNumberOfBytesWritten parameter is only optional when you are using overlapped IO. You are passing NULL for lpOverlapped, and therefore not using overlapped IO, the lpNumberOfBytesWritten is not optional and cannot be NULL.

于 2015-03-12T15:59:32.287 回答