认为这可能对某人有帮助,因为这对我来说是一种惊喜。
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上并且代码失败。
我学到的课程:我应该更加专注(细节),不要沾沾自喜(并仔细测试)。
答案 0 :(得分:2)
lpNumberOfBytesWritten
的文档说:
仅当lpOverlapped参数不为NULL 时,此参数才可为NULL 。
换句话说,lpNumberOfBytesWritten
参数仅在使用重叠IO时才是可选的。您正在为NULL
传递lpOverlapped
,因此不使用重叠IO,lpNumberOfBytesWritten
不是可选的,不能是NULL
。