WriteFileEx - CompletionRoutine:这是Windows 7 - 64位中的错误吗?

时间:2014-06-13 01:09:45

标签: c++ windows winapi 64-bit

似乎我最近在Windows 7 ultimate 64 Bit中发现了一个大胖子。 奇怪的是,我在谷歌或MSDN上找不到任何关于它的东西。 我是第一个发现API中的错误的人,似乎不可能像WriteFileEx那样重要,因为很长一段时间以来在市场上的操作系统中?!?!?!?

但是我的代码太简单了。

除此之外,我的代码完美地适用于: Windows XP教授32位, Windows Vista终极32位, Windows 7旗舰版32位, 如果编译为64位,它甚至适用于Windows 7 ultimate 64 Bit。

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

将文件正确写入磁盘,调用完成例程,但完成例程报告已写入零字节,最奇怪的是OVERLAPPED结构的地址错误和无效的内容!!

有人可以确认这是一个错误吗?

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;
}

结果如下:

enter image description here

2 个答案:

答案 0 :(得分:3)

您没有进行任何错误检查,或确保OVERLAPPED结构保持活动状态,直到实际调用完成例程(可能需要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;
}

答案 1 :(得分:-1)

解决:

缺少FILE_FLAG_OVERLAPPED。

我仍然认为将一个完全残缺的指针传递给回调例程肯定是一个严重的错误,并且回调告诉它写了0个字节,尽管它有6个字节!

正如我所示:并非所有操作系统都有此错误。

正确的行为是使用正确的OVERLAPPED地址调用回调例程,如Windows XP所做的那样;如果OVERLAPPED结构与未使用FILE_FLAG_OVERLAPPED打开的文件句柄一起使用,则返回ERROR_INVALID_PARAMETER。

我发现的内容非常难看,因为如果您在XP,Vista,Win7 32 Bit上开发和测试应用程序,您将永远不会发现缺少一个标记。然后,您将应用程序交付给使用Win 7 - 64位的最终用户,他们会告诉您程序不起作用。

正确编程的Windows API必须返回错误,如果给出了错误的参数但从未传递残缺的指针。

我测试的5个操作系统中有4个传递了正确的地址!