2014-06-13 2 views
-5

Кажется, что я недавно обнаружил большую жирную ошибку в 64-битной версии Windows 7. Странно то, что я ничего не могу найти в Google или MSDN. Кажется невозможным, что я первым обнаружил ошибку в API, столь важную как WriteFileEx в операционной системе, которая существует на рынке с давних времен?!?!?!?WriteFileEx - CompletionRoutine: Это ошибка в Windows 7 - 64 бит?

Но мой код слишком прост, чтобы быть неправдой.

Кроме того мой код работает отлично на: Windows XP Prof 32 Bit, Windows Vista Ultimate 32 Bit, Windows 7 Ultimate 32 Bit, и он даже работает на Windows 7 Ultimate 64 бит, если скомпилирован как 64-Bit ,

Единственный сбой произошел в Windows 7 - 64 бит, если скомпилирован как 32 бит.

Что происходит, так это то, что файл правильно записан на диск, вызывается процедура завершения, но процедура завершения сообщает, что были записаны нулевые байты, и самое странное, что структура 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

+0

Пожалуйста, не делать «клянчить ошибки», особенно в названиях. Этот вопрос будет получен более благоприятно, если просто укажет на наблюдаемое поведение - без дополнительных комментариев. – user2864740

+0

ОК Я изменил название. Ты сейчас счастлив ? – Elmue

+4

Вы не указали 'FILE_FLAG_OVERLAPPED'. Из документов: 'Если этот флаг не указан, операции ввода/вывода сериализуются, даже если вызовы функций чтения и записи указывают структуру OVERLAPPED.' –

ответ

-1

Решено:

FILE_FLAG_OVERLAPPED отсутствует.

Я все еще думаю, что это определенно серьезная ошибка, что полностью искалеченный указатель передается подпрограмму обратного вызова, и обратный вызов сообщает, что он написал 0 байтов, хотя он имеет дело на 6 байт!

И как я показал: не все операционные системы имеют эту ошибку.

Правильное поведение должно заключаться в вызове процедуры обратного вызова с правильным адресом OVERLAPPED, так как Windows XP делает или возвращает ERROR_INVALID_PARAMETER, если структура OVERLAPPED используется с дескриптором файла, который не был открыт с помощью FILE_FLAG_OVERLAPPED.

То, что я обнаружил, очень уродливо, потому что, если вы разрабатываете и тестируете свое приложение на XP, Vista, Win7 32 Bit, вы никогда не обнаружите, что отсутствует флаг. А затем вы доставляете свое приложение конечным пользователям, использующим Win 7 - 64 бит, и они сообщают вам, что ваша программа не работает.

Правильно запрограммированный API Windows должен возвращать ошибку, если указан неправильный параметр, но никогда не передается искалеченным указателем.

И 4 из 5 операционных систем, которые я тестировал, передают правильный адрес!

+1

Вы не проверяете 'WriteFileEx()' для кода ошибки, и вы игнорируете код ошибки, указанный в процедуре завершения. –

+0

В процедуре завершения 'u32_BytesTransfered' будет 0, если' u32_ErrorCode' не равен 0. –

+0

Я удалил всю проверку ошибок, чтобы сделать код более читаемым. Здесь совершенно неважно. И u32_ErrorCode также равен нулю. Все, что вы пишете, не имеет никакого отношения к вопросу. – Elmue

2

Вы не проверяете ошибки или не сохраняете структуру 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; 
} 
+0

Вы не поняли, в чем проблема. Использование CreateFile вместо CreateFileEx не является решением для моего дела. – Elmue

+2

Я ничего не говорил о 'CreateFileEx()'. Я заменил 'SleepEx()' на 'WaitForSingleObjectEx()', что безопаснее. Но вы правы, что я действительно пропустил основную причину - отсутствующий флаг FILE_FLAG_OVERLAPPED', который я добавил к своему ответу после того, как увидел его. –

+0

Код, который я написал, только для того, чтобы воспроизвести проблему. Очевидно, я удалил всю обработку ошибок, чтобы сделать ее более читаемой. И SleepEx отлично работает для этой цели. Нет необходимости его заменять. Попробуй! – Elmue

Смежные вопросы