【问题标题】:Win 32 Writefile: Access Viloation and Error 1784Win32 写入文件:访问冲突和错误 1784
【发布时间】:2012-09-28 16:01:41
【问题描述】:

以下代码有两个问题。首先,我一直在搜索这个论坛和其他各种论坛,以寻找我的 1784 错误代码的答案,但我尝试过的一切都失败了。我在stackoverflow 上检查的两个线程是WriteFile returning error 1784BlockWrite I/O Error 1784。我在这个论坛上检查了其他一些人,但我不记得现在具体是什么了。

我正在尝试将结构数组保存到一个空的二进制文件中。第一个问题是,如果我的大小变量(nNumberOfBytesToWrite 参数)小于 99000 字节,我就会遇到访问冲突。这个数字跳来跳去。有一段时间,当我测试它时,如果它是 99,999 字节而不是 100,000 字节,则会出现访问冲突。当然,我最终想要做的是将大小设置为整个数组的大小。处理的原始代码现在被注释掉了,所以我可以用各种尺寸进行测试。

发生的第二件事(如果我没有遇到访问冲突)是我收到错误代码 1784 并且 WriteFile 每次都失败。正如该主题的其他线程所述,这在 MSDN 上被定义为 ERROR_INVALID_USER_BUFFER 并且描述是“提供的用户缓冲区对于请求的操作无效”。我查看了 MSDN 自己的打开此类文件的示例 (http://msdn.microsoft.com/en-us/library/windows/desktop/bb540534%28v=vs.85%29.aspx),并根据他们的代码尝试了一些变体,但似乎没有任何效果。

这个问题可能是个大菜鸟,我敢肯定我忽略了一些简单得可笑的东西,但如果有人有建议,他们将不胜感激。

case IDM_SAVE1:
{
    HANDLE hFile = CreateFile("MineSave.mss", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
    int test_buffer[] = {1,2,3,4,5,6,7,8,9,10};

    if(hFile != INVALID_HANDLE_VALUE)
    {
        BOOL bSuccess;
        DWORD size = 100000; //DWORD size = (((sizeof(tile)) * tiles_total));
        LPDWORD bytes_written = 0;
        bSuccess = WriteFile(hFile, test_buffer, size, bytes_written, NULL);
        if(bSuccess)
        {
            MessageBox(hwnd, "File saved successfully.", "Great Job!", MB_OK);
        }
        else
        {
            DWORD error = GetLastError();
            MessageBox(hwnd, "Could not write to file.", "Error", MB_OK);
        }

        CloseHandle(hFile);
    }
    else
    {
        MessageBox(hwnd, "Could not create file.", "Error", MB_OK);
    }
}
break;

【问题讨论】:

  • 大卫的答案是正确的,如果它对你有用,应该被接受。 (你应该考虑一些更大的缓冲区,正如他所建议的那样,10000 IO 对它正在做的事情来说已经很多了,但是很好的精神牙线)。
  • 感谢 David、Whoz 和 Ben 对你们所有人的帮助。我继续并尝试了他的代码,他在编辑并保存文件后将其写在下面。但我不需要循环,因为我需要保存一次数组。一旦我查看了他的代码和我原来的代码之间的区别,我发现原来的问题出在我的语法上。这是上面的原始代码 sn-p,就像我在发帖之前所拥有的一样。 DWORD size = (((sizeof(tile)) * tiles_total)); LPDWORD bytes_written = 0; bSuccess = WriteFile(hFile, test_buffer, size, bytes_written, NULL);
  • 这是替换代码现在的样子,很抱歉我无法在这些评论窗口中正确格式化:BOOL bSuccess; DWORD size = (((sizeof(tile)) * tiles_total)); DWORD bytes_written; bSuccess = WriteFile(hFile, tile_array, size, &bytes_written, NULL); 这有效。再次感谢大卫。
  • 是的,我认为您将我们与 100,000 字节的文件写入混淆了。在您输入该疯狂值之前遇到的问题是将 NULL 传递给 lpNumberOfBytesWritten。很高兴它现在已排序。
  • 另外,当真正执行此操作时,请始终根据 dwBytesWritten 中的返回值调整您的 bytes-i've-written 计数器。即使函数返回竖起大拇指,检查您请求写入的字节数也是一种很好的做法。它可能是一些非常难以发现的细微错误的来源。

标签: c++ winapi


【解决方案1】:

您的缓冲区大小为 10 个整数,在 Windows 上为 40 个字节。您正在尝试从该缓冲区写入 100,000 个字节。那是未定义的行为,缓冲区溢出。因此访问冲突。

您不能将大于sizeof(test_buffer) 的值(即40)传递给WriteFilenNumberOfBytesToWrite 参数。

您需要循环写入此文件,一次写入 40 个字节,直到您写完所需的内容。也许是这样的:

BOOL bSuccess = TRUE;
DWORD bytesRemaining = 100000;
while (bSuccess && bytesRemaining>0)
{
    DWORD bytesToWrite = std::min(sizeof(test_buffer), bytesRemaining);
    DWORD bytesWritten;
    bSuccess = WriteFile(hFile, test_buffer, bytesToWrite, &bytesWritten, NULL);
    bytesRemaining -= bytesToWrite;
}
if (!bSuccess)
{
    //handle error;
}

一次写入 40 个字节非常慢。您会发现每次调用 WriteFile 时写入几 KB 会更有效。

请注意,如果您也将NULL 传递给lpOverlapped,则不允许将NULL 传递给lpNumberOfBytesWritten 参数,就像您在此处所做的那样。来自documentation

lpNumberOfBytesWritten [输出,可选]

......

只有当 lpOverlapped 参数不为 NULL 时,该参数才可以为 NULL。

【讨论】:

  • 要清楚,我实际上不需要将 100,000 字节写入文件。这只是我为了测试而抛出的一个数字。当大小为 100k 时,它实际上成功了。我之前将大小设置为 sizeof(test_buffer) ,那是我第一次开始遇到访问冲突的时候。这是我刚才改成的代码: DWORD size = sizeof(test_buffer); LPDWORD bytes_written = 0; bSuccess = WriteFile(hFile, test_buffer, size, NULL, NULL);仍然遇到访问冲突。还尝试为 bytes_written 传入非空 DWORD。它告诉我写入了 0 个字节。
  • 不允许最后两个参数都为NULL。 _Out_opt 注释并不能说明全部情况。 (很难发现这一点,因为 Windows 8 接受它,但以前的版本会导致访问冲突)。
  • 我以为我已经阅读了关于最后两个参数在 MSDN 上不能都为 NULL 的内容。我一直在传递那个 bytes_written LPDWORD。无论我是否将它初始化为 0 或未初始化,我仍然会遇到访问冲突,除非我尝试那个可笑的巨大的 100k 大小的变量。
  • @John 您的代码通过 NULL,因为 NULL 等于 0。请参阅我的更新版本的答案
  • 搞清楚了。感谢您的帮助,David 以及 Ben 和 Whoz。我发布了我的最终修复作为对我上面原始帖子的回复,以防其他人遇到同样的问题。我的格式都搞砸了,所以代码混在一起了。
【解决方案2】:

必须提供一个缓冲区来接收写入的字节数,lpNumberOfBytesWritten 参数必须为非 NULL,或者lpOverlapped 参数必须为非 NULL。

您为两者都传递了 NULL,这是非法的并导致访问冲突。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-27
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多