ReadFile и WriteFile с перекрывающимся результатом ввода-вывода, если не ERROR_IO_PENDING? - PullRequest
0 голосов
/ 11 июля 2019

Документы для FILE_FLAG_OVERLAPPED на WriteFile() говорят, что вы должны предоставить OVERLAP и рекомендовать NULL для lpNumberOfBytesWritten, поскольку значение вводит в заблуждение.Однако документы для GetOverlappedResult() говорят только о вызове, если WriteFile() вернул FALSE с ERROR_IO_PENDING.Таким образом, остается тот случай, когда ReadFile() / WriteFile() завершается в самом вызове API.Как вы должны получить количество прочитанных / записанных байтов?Вы предполагаете, что это запрошенный номер?Но WriteFile() говорит: «При записи в неблокирующий дескриптор канала в байтовом режиме с недостаточным буферным пространством WriteFile возвращает TRUE с * lpNumberOfBytesWritten

TIA !!

1 Ответ

2 голосов
/ 11 июля 2019

Если hFile был открыт с помощью FILE_FLAG_OVERLAPPED lpNumberOfBytesWritten Параметр должен быть установлен на NULL .

это не так (ошибка или ложь). lpNumberOfBytesWritten может быть установлен на NULL , но не должен . если запрос ввода-вывода завершится синхронно с успехом в *lpNumberOfBytesWritten, будет действительное число байтов.

обратите внимание также, что lpNumberOfBytes не должен указывать на местоположение, которое будет действовать до завершения операции (например, lpOverlapped) - оно может указывать на локальную переменную в функции для пример, и вы можете выйти из функции до завершения ввода-вывода - и это тоже будет хорошо. система просто скопирует InternalHigh из OVERLAPPED в *lpNumberOfBytes. так в псевдокоде:

if (lpNumberOfBytes) *lpNumberOfBytes = (ULONG)lpOverlapped->InternalHigh;

двузначное правильное значение в *lpNumberOfBytes будет только в том случае, если ввод / вывод уже завершен успешно. так и может использовать его только в этом случае. система не запоминает значение lpNumberOfBytes - потому что оно должно быть действительным только при [Write|Read]File вызове, но не при активном вводе / выводе (что может быть больше в случае асинхронного ввода / вывода)

GetOverlappedResult мы можем позвонить, если запрос ввода-вывода завершится синхронно с успехом (в случае ReadFile или WriteFile, если вы вернете TRUE), если ожидание вернулось. этот API нельзя вызвать только в случае сбоя запроса ввода / вывода (ReadFile или WriteFile return FALSE и GetLastError() != ERROR_IO_PENDING)

так что лучшие всегда передают не 0 lpNumberOfBytes в api и используют его, если api завершается успешно. в противном случае используйте GetOverlappedResult или, если скажете, что вы используете BindIoCompletionCallback - вы сразу получите dwNumberOfBytesTransfered в обратном вызове.

, поэтому концептуально можно использовать следующий код:

inline ULONG BOOL_TO_ERROR(BOOL f)
{
    return f ? NOERROR : GetLastError();
}

HANDLE hFile = CreateFile(*, FILE_GENERIC_READ, FILE_SHARE_READ, 0, 
    OPEN_EXISTING, FILE_FLAG_OVERLAPPED, 0);

if (hFile != INVALID_HANDLE_VALUE)
{
    UCHAR buf[0x200];
    OVERLAPPED ov = {};
    ULONG NumberOfBytesRead;

    ULONG dwError = BOOL_TO_ERROR(ReadFile(hFile, buf, sizeof(buf), &NumberOfBytesRead, &ov));

    switch (dwError)
    {
    case ERROR_IO_PENDING:
        dwError = BOOL_TO_ERROR(GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE));
        if (dwError != NOERROR) goto __default;
        [[fallthrough]];

    case NOERROR:
        DbgPrint("NumberOfBytesRead=%x\n", NumberOfBytesRead);
        // use GetOverlappedResult(hFile, &ov, &NumberOfBytesRead, TRUE) here also possible
        break;
__default:
    default:
    DbgPrint("dwError = %u\n", dwError);
    }

    CloseHandle(hFile);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...