Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/129.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ WriteFilex-CompletionRoutine:这是Windows7-64位中的一个bug吗?_C++_Windows_Winapi_64 Bit - Fatal编程技术网

C++ WriteFilex-CompletionRoutine:这是Windows7-64位中的一个bug吗?

C++ WriteFilex-CompletionRoutine:这是Windows7-64位中的一个bug吗?,c++,windows,winapi,64-bit,C++,Windows,Winapi,64 Bit,似乎我最近在Windows7 ultimate 64位中发现了一个巨大的bug。 奇怪的是,我在谷歌或MSDN上找不到任何关于它的信息。 我似乎不可能是第一个发现API中的bug的人,API如此重要,就像市场上很长一段时间以来的操作系统中的writeFilex 但我的代码太简单了,不会出错 除此之外,我的代码在以下方面工作得非常完美: Windows XP prof 32位, Windows Vista ultimate 32位, Windows 7 ultimate 32位, 如果编译为64位

似乎我最近在Windows7 ultimate 64位中发现了一个巨大的bug。 奇怪的是,我在谷歌或MSDN上找不到任何关于它的信息。 我似乎不可能是第一个发现API中的bug的人,API如此重要,就像市场上很长一段时间以来的操作系统中的
writeFilex

但我的代码太简单了,不会出错

除此之外,我的代码在以下方面工作得非常完美: Windows XP prof 32位, Windows Vista ultimate 32位, Windows 7 ultimate 32位, 如果编译为64位,它甚至可以在Windows7终极64位上运行

如果编译为32位,则唯一的故障发生在Windows 7-64位上

发生的情况是,文件被正确写入磁盘,完成例程被调用,但完成例程报告已写入零字节,最奇怪的是,
重叠的
结构具有错误的地址和无效的内容

有人能确认这是一个bug吗

void WINAPI CompletionRoutine(DWORD u32_ErrorCode, DWORD u32_BytesTransfered,
                              OVERLAPPED* pk_Overlapped)
{
    printf("CompletionRoutine: Transferred: %d Bytes, AddrOverlapped: 0x%X\n", 
           u32_BytesTransfered, (DWORD_PTR)pk_Overlapped);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    printf("Compiled as: %d Bit\n", sizeof(DWORD_PTR) == 8 ? 64 : 32);

    HANDLE h_File = CreateFileW(L"E:\\Temp\\Test.txt", GENERIC_WRITE, 
                                FILE_SHARE_READ|FILE_SHARE_WRITE, 0, 
                                CREATE_ALWAYS, 0, 0);

    OVERLAPPED k_Over = {0};
    printf("Before WriteFileEx AddrOverlapped: 0x%X\n", (DWORD_PTR)&k_Over);

    WriteFileEx(h_File, "ABCDEF", 6, &k_Over, CompletionRoutine);

    printf("Before SleepEx\n");

    SleepEx(1000, TRUE);

    printf("Exit\n");
    return 0;
}
结果如下:

已解决:

缺少重叠的文件标志

我仍然认为,将一个完全损坏的指针传递给回调例程,回调告诉它已写入0字节,尽管它实际上已写入6字节,这肯定是一个严重的错误

正如我所展示的:并不是所有的操作系统都有这个bug

正确的行为是像Windows XP一样使用正确的重叠地址调用回调例程,或者如果重叠结构与文件句柄一起使用,而文件句柄未使用文件标志重叠,则返回错误\u无效\u参数

我发现的东西非常难看,因为如果你在XP、Vista、Win32位上开发和测试你的应用程序,你将永远不会发现缺少一个标志。然后你将你的应用程序交付给使用Win 7-64位的最终用户,他们会告诉你你的程序无法运行

如果给出错误的参数,正确编程的Windows API必须返回错误,但决不能传递损坏的指针


我测试的5个操作系统中有4个通过了正确的地址

在实际调用完成例程之前,您不会执行任何错误检查,也不会确保重叠的
结构保持活动状态(可能需要1秒以上)

请尝试类似以下内容:

void WINAPI CompletionRoutine(DWORD u32_ErrorCode, DWORD u32_BytesTransfered, LPOVERLAPPED pk_Overlapped)
{
    if (u32_ErrorCode != 0)
        printf("CompletionRoutine: Unable to write to file! Error: %u, AddrOverlapped: %p\n", u32_ErrorCode, pk_Overlapped);
    else
        printf("CompletionRoutine: Transferred: %u Bytes, AddrOverlapped: %p\n", u32_BytesTransfered, pk_Overlapped);

    SetEvent(pk_Overlapped->hEvent);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
    printf("Compiled as: %d Bit\n", sizeof(DWORD_PTR) == 8 ? 64 : 32);

    printf("Creating file\n");

    const LPWSTR fileName = L"E:\\Temp\\Test.txt";

    HANDLE h_File = CreateFileW(fileName, GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, 0);
    if (h_File == INVALID_HANDLE_VALUE)
    {
        printf("Unable to create file! Error: %u\n", GetLastError());
        return 0;
    }

    HANDLE h_Event = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (h_Event == NULL)
    {
        printf("Unable to create wait event! Error: %u\n", GetLastError());
        CloseHandle(h_File);
        DeleteFile(fileName);
        return 0;
    }

    OVERLAPPED k_Over = {0};
    k_Over.hEvent = h_Event;

    printf("Writing to file (AddrOverlapped: %p)\n", &k_Over);

    if (!WriteFileEx(h_File, "ABCDEF", 6, &k_Over, &CompletionRoutine))
    {
        printf("Unable to write to file! Error: %u\n", GetLastError());
        CloseHandle(h_File);
        DeleteFile(fileName);
        return 0;
    }

    printf("Waiting for write to complete\n");

    DWORD dwResult;
    do
    {
        dwResult = WaitForSingleObjectEx(k_Over.hEvent, 5000, TRUE);

        if (dwResult == WAIT_OBJECT_0)
        {
            printf("Write Completed\n");
            break;
        }

        if (dwResult != WAIT_IO_COMPLETION)
        {
            if (dwResult == WAIT_TIMEOUT)
                printf("Timeout waiting for write to complete!\n");
            else
                printf("Unable to wait for write to complete!\n");

            CancelIo(h_File);
            break;
        }
    }
    while (true);

    printf("Finished waiting\n");

    CloseHandle(h_File);
    CloseHandle(h_Event);

    printf("Exit\n");
    return 0;
}

请不要“乞求虫子”,尤其是在标题中。如果只是简单地陈述观察到的行为,而没有额外的评论,这个问题会更受欢迎。您现在满意了吗?您没有指定
文件\u标志\u重叠
。从文档中:
如果未指定此标志,则I/O操作将被序列化,即使对读写函数的调用指定了重叠结构。
谢谢!是的,当我添加文件\u标志\u重叠时,它可以工作!但是,多个操作系统中只有一个关心这个问题,这仍然很奇怪。你确定你尖叫了这个BUG!!!!够大声吗?如果你真的,真的很丢脸,说你发现了一个bug,然后发现你没有正确阅读文档,你就会知道你是这么做的。(故事的寓意是:千万不要假设你发现了数百万其他用户从未发现的bug,特别是在操作系统内部使用如此频繁的API函数中。要知道问题出在你的代码中的几率非常高。)你不明白问题出在哪里。使用CreateFile而不是CreateFileEx对我的情况来说不是一个解决方案。我没有说任何关于
CreateFileEx()
。我将
SleepEx()
替换为
WaitForSingleObjectEx()
,这样更安全。但你是对的,我最初确实错过了根本原因——丢失的
文件\u标志重叠了
标志,我在看到后将其添加到了我的答案中。我发布的代码只是为了重现问题。显然,我删除了所有错误处理,以使其更具可读性。而SleepEx正是为了达到这个目的。没有必要更换它。试试看!您假设写操作将在1000毫秒内完成。也许在这个简单的示例中,它会完成。但在现实生产项目中,这是一个危险的假设。如果将
OVERLAPPED
结构放在堆栈上,并且它在调用完成例程之前消失,则会发生不好的事情。声明:“重叠的
数据结构必须在写入操作期间保持有效。在写入操作挂起完成时,它不应是可能超出范围的变量。”这就是为什么我的示例实际上在允许重叠的
消失之前等待调用完成例程的原因。在更复杂的项目中,您通常会在堆上分配重叠的
OVERLAPPED
,并让完成例程在完成使用后释放它。您没有检查
writefilex()
,而是忽略完成例程报告的错误代码。在完成例程中,如果
u32\u-bytesttransfered
中的
u32\u-ErrorCode
不为0,则
u32\u-bytesttransfered
将为0。在WinAPI中发现的错误:0,在代码中发现的错误:1(至少)。如果不立即责怪经过良好审查的代码,编程通常效率更高,尤其是当这种责怪与个人对其“应该”如何工作的想法混杂在一起时。检查程序员可能犯下的每一个错误不是API的责任。如果您不遵守规则(在本例中,WriteFilex的文档中非常清楚地描述了这些规则),任何事情都有可能发生,甚至可能看起来是可行的。错误就在您的代码中。Windows是正确的,其行为符合设计要求。我不明白你为什么这么难接受。