当第4个(可选)参数为NULL时,WriteFile会引发访问冲突

时间:2015-03-12 15:56:40

标签: c++ winapi visual-studio-2008 access-violation writefile

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

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)上,它工作,即使我在第4个参数(lpNumberOfBytesWritten)中传递NULL。

实际的问题是我开发了一个写入临时文件的模块,但是我忽略了第4个参数(我读了"可选"但是误读了其余部分并认为它可能会被忽略)。我在Windows 8.1上开发并测试了它,因此代码工作正常,但客户端机器在Windows 7上并且代码失败。

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

1 个答案:

答案 0 :(得分:2)

lpNumberOfBytesWritten的文档说:

  

仅当lpOverlapped参数不为NULL 时,此参数才可为NULL

换句话说,lpNumberOfBytesWritten参数仅在使用重叠IO时才是可选的。您正在为NULL传递lpOverlapped,因此不使用重叠IO,lpNumberOfBytesWritten不是可选的,不能是NULL