当第 4 个(可选)参数为 NULL 时,WriteFile 抛出访问冲突
WriteFile throws Access Violation when 4th (optional) parameter is NULL
认为它可能对某人有所帮助,因为它对我来说是一种惊喜。
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]
...
This parameter can be NULL only when the lpOverlapped parameter is not 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个参数(我读了"optional"但误读了其余部分,认为它可能被忽略了)。我在 Windows 8.1 上开发并测试了它,所以代码运行良好,但客户端机器在 Windows 7 上,代码失败。
我的经验教训:我应该更用心(对细节),不要自鸣得意(并仔细测试)。
lpNumberOfBytesWritten
的文档说:
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
换句话说,lpNumberOfBytesWritten
参数仅在使用重叠IO时才可选。您正在为 lpOverlapped
传递 NULL
,因此不使用重叠 IO,lpNumberOfBytesWritten
不是可选的,不能是 NULL
。
认为它可能对某人有所帮助,因为它对我来说是一种惊喜。
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] ... This parameter can be NULL only when the lpOverlapped parameter is not 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个参数(我读了"optional"但误读了其余部分,认为它可能被忽略了)。我在 Windows 8.1 上开发并测试了它,所以代码运行良好,但客户端机器在 Windows 7 上,代码失败。
我的经验教训:我应该更用心(对细节),不要自鸣得意(并仔细测试)。
lpNumberOfBytesWritten
的文档说:
This parameter can be NULL only when the lpOverlapped parameter is not NULL.
换句话说,lpNumberOfBytesWritten
参数仅在使用重叠IO时才可选。您正在为 lpOverlapped
传递 NULL
,因此不使用重叠 IO,lpNumberOfBytesWritten
不是可选的,不能是 NULL
。