ReadFile и WriteFile с перекрывающимся вводом-выводом, если не ERROR_IO_PENDING?

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

ТИА!!

вы также можете вызвать GetOverlappedResult, когда запрос ввода-вывода (чтение/запись) возвращает значение true. msdn неправильный, как обычно. в любом случае, если запрос не завершится ошибкой - количество байт будет в OVERLAPPED.InternalHigh. Параметр lpNumberOfBytesWritten должен иметь значение NULL. - это тоже абсолютно неправильно. вы можете передать здесь не 0 и использовать его значение, если ввод-вывод возвращает true

RbMm 11.07.2019 09:32
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
4 146
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

If hFile was opened with FILE_FLAG_OVERLAPPED The lpNumberOfBytesWritten parameter should be set to NULL.

это неправда (ошибка или ложь). lpNumberOfBytesWrittenмогу должен быть установлен в НУЛЕВОЙ, но не должен. если запрос ввода-вывода завершен синхронно с успехом, в *lpNumberOfBytesWritten будет допустимое количество байтов.

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

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

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

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

поэтому лучше всего всегда передавать не 0 лпнумберофбайтес в 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);
}

@eryksun - да, конечно Offset и OffsetHigh должны быть явно установлены, если файл поддерживает позицию файла (файловая система). скажем, смещение труб не имеет значения. но я не акцентировал на этом внимание. вопрос был о другом

RbMm 11.07.2019 15:02

Является ли NumberOfBytesRead действительным, если GetOverlappedResult возвращает FALSE. Скажем, частичное чтение до возникновения ошибки или неопределенного значения?

user3161924 16.07.2019 08:26

@user3161924 user3161924 — если GetOverlappedResult возвращает FALSE — NumberOfBytesRead недействителен. Количество байтов (чтение/запись) допустимо только после успешного завершения операции. если ошибка ввода-вывода - Количество байтов недействителен, а фактическое значение равно 0

RbMm 16.07.2019 12:41

«не должен указывает на местоположение ...», я думаю, легко ввести в заблуждение. Лучше, ИМО, было бы "не обязательно указывать на местоположение...". Не должно создаваться впечатление, что он не может/не должен "указывать на местоположение..."

nyholku 21.03.2020 10:32

@nyholku - да, согласен. я просто плохо знаю английский

RbMm 21.03.2020 12:11

Другие вопросы по теме