На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
! user posted image
Пожалуйста, выделяйте текст программы тегом [сode=pas] ... [/сode]. Для этого используйте кнопку [code=pas] в форме ответа или комбобокс, если нужно вставить код на языке, отличном от Дельфи/Паскаля.

Соблюдайте общие правила форума

Следующие вопросы задаются очень часто, подробно разобраны в FAQ и, поэтому, будут безжалостно удаляться:
1. Преобразовать переменную типа String в тип PChar (PAnsiChar)
2. Как "свернуть" программу в трей.
3. Как "скрыться" от Ctrl + Alt + Del (заблокировать их и т.п.)
4. Как запустить программу/файл? (и дождаться ее завершения)
5. Как перехватить API-функции, поставить hook? (перехват сообщений от мыши, клавиатуры - внедрение в удаленное адресное прстранство)
... (продолжение следует) ...

Внимание:
Попытки открытия обсуждений реализации вредоносного ПО, включая различные интерпретации спам-ботов, наказывается предупреждением на 30 дней.
Повторная попытка - 60 дней. Последующие попытки - бан.
Мат в разделе - бан на три месяца...

Полезные ссылки:
user posted image MSDN Library user posted image FAQ раздела user posted image Поиск по разделу user posted image Как правильно задавать вопросы


Выразить свое отношение к модераторам раздела можно здесь: user posted image Rouse_, user posted image Krid

Модераторы: Rouse_, Krid
  
> Вызов FileRead в асинхронном режиме , чтение файла в асинхронном режиме
    решил разобраться с вызовом функций WinApi в асинхронном режиме.
    покурил msdn, накидал такой примерчик:
    ExpandedWrap disabled
      procedure TForm1.DoAsyncLoad();
      var
        lReaded: Cardinal;
        lTransferred: Cardinal;
        lBuff: Pointer;
        lRes: Boolean;
        lErr, lErr2: Cardinal;
        lFileHandle: Cardinal;
        lOverlapped: TOverlapped;
      begin
       
        lFileHandle := CreateFile( PChar( edtFileName.Text ),
                                   GENERIC_READ, 0,
                                   nil, OPEN_EXISTING,
                                   FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED, 0 );
       
        if lFileHandle = INVALID_HANDLE_VALUE then
          RaiseLastOSError;
        try
          lReaded := 0;
          ZeroMemory( @lOverlapped, SizeOf( TOverlapped ));
          GetMem( lBuff, C_BLOCK_SIZE ); //используем большой буфер
          try
            repeat
              lReaded := 0;
              //обнуляем внутренние данные для нового вызова "перекрываемой" функции
              lOverlapped.Internal := 0;
              lOverlapped.InternalHigh := 0;
              //hEvent не задаю, так как нигде ожидать ничего не будем
              lRes := ReadFile( lFileHandle,
                                lBuff^,
                                C_BLOCK_SIZE,
                                lReaded,
                                @lOverlapped );
              if not lRes then
                lErr := GetLastError
              else
                lErr := ERROR_SUCCESS;
              if not lRes then
              begin //обрабатываем случаи, когда ReadFile = False
                case lErr of //проверка ощибки ReadFile
                  ERROR_IO_PENDING: //асинхронная операция
                  begin
                    lTransferred := 0;
                    repeat
                      lRes := GetOverlappedResult( lFileHandle,
                                                   lOverlapped,
                                                   lTransferred,
                                                   False );
                      if not lRes then
                        lErr2 := GetLastError;
                      if not lRes then
                        case lErr2 of //проверка ошибки  GetOverlappedResult
                          ERROR_IO_INCOMPLETE: Application.HandleMessage; //операция не завершилась? обработаем очередное сообщение
                          ERROR_HANDLE_EOF:
                          begin //файл кончился?
                            lReaded := 0; //ничего не прочитали
                            break; //выходим из внутреннего цикла
                          end;
                          else
                            RaiseLastOSError;
                        end;
                    until lRes; //пока не завершиться операция...
                    if lRes then
                      lReaded := lTransferred; //надо ли?
                  end;
                  ERROR_HANDLE_EOF: lReaded := 0; //если файл кончилсо, то выходим из цикла
                  else
                     RaiseLastOSError;
                end;
              end;//конец ветки, когда ReadFile = false
       
              if lRes then //здесь мы оказываемся в 2х случаях:1.ReadFile=true; 2.GetOverlappedResult в конце концов тоже вернул True
              begin
                //
                //что-то делаем с lBuff
                //
                lOverlapped.Offset := lOverlapped.Offset + lReaded; //сдвигаем
              end;
            until lReaded = 0;
          finally
            FreeMem( lBuff );
          end;
        finally
          CloseHandle( lFileHandle );
        end;
      end;

    все бы ничего... да только не всегда получается асинхронный вызов.
    в случае попытки чтения большого файла с винчестера функция FileRead ждет окончания чтения и возвращает true (
    и только в случае первой попытки обращения к съемному носителю срабатывает часть кода по работе с GetOverlappedResult...
    объясните знающие люди, в чем соль?!
    Сообщение отредактировано: MetalFan -
      неплохая статья про асинхронный ввод-вывод.
        Ahilles Спасибо конечно, но ничего нового статья мне не рассказала. вся информация есть в MSDN.
        да и примеры там все с флопом.
          Цитата MetalFan @
          все бы ничего... да только не всегда получается асинхронный вызов.

          Вернее - работает не пойми как. :D
          Цитата MetalFan @
          ExpandedWrap disabled
            //hEvent не задаю, так как нигде ожидать ничего не будем
                    lRes := ReadFile( lFileHandle,
                                      lBuff^,
                                      C_BLOCK_SIZE,
                                      lReaded,
                                      @lOverlapped);
          И?? Как же так - пытаешься использовать асинхронное чтение, а главный "семафор окончания отложенной операции" не создаешь? Далее :
          Цитата MetalFan @
          ExpandedWrap disabled
            if not lRes then
                      case lErr of //проверка ощибки ReadFile
                        ERROR_IO_PENDING: //асинхронная операция
          Это не ошибка - это признак того, что отложенная операция нормально стартовала. Здесь бы лучше запустить таймер и по его срабатыванию проверять - закончилась ли операция чтения (считано ли требуемое в ReadFile количество байт (WaitForSingleObject на эвент Overlapp'a должен вернуть WAIT_OBJECT_0 - если нет - то по GetOverlappedResult смотрим, сколько считано и сравниваем с размером файла, или по флагу ERROR_HANDLE_EOF принимаем решение сбросить дальнейшее чтение). Но лучше в любом случае перед считыванием получить размер файла, чтобы знать наверняка, сколько читать.)
            Цитата medved_68 @
            И?? Как же так - пытаешься использовать асинхронное чтение, а главный "семафор окончания отложенной операции" не создаешь?

            создавать и использовать его не обязательно. но даже его создание и использование положения не меняет.

            Цитата medved_68 @
            Это не ошибка - это признак того, что отложенная операция нормально стартовала.

            отложенная операция удачно "стартовала" только если GetLastError вернул ERROR_IO_PENDING.
            да, это не ошибка по сути.

            Цитата medved_68 @
            сколько считано и сравниваем с размером файла

            как ты заметил, файл читается не целиком, а кускакми


            з.ы. ты бы проверил работу кода, ибо пока ничего неясного ты не прояснил.
            Сообщение отредактировано: MetalFan -
              M
              MetalFan, я ваш вопрос отредактировал, код не подсвечивался. Там в теге CODE было CODE=delphi, а нужно - CODE=pas, ну это так, на будущее.


              Что касается вопроса - думаю, не нужно вызывать Application.HandleMessage; так как эта процедура в конце вызывает засыпание потока на неопределенное время - пока в очередь не поступит сообщение (Idle из которого вызывается WaitMessage). Как обрабатывать сообщения и одновременно дожидаться окончания ввода/вывода гляньте здесь:
              DeviceIOControl

              Там вся соль в функции MsgWaitForMultipleObjects
                Rose Сорри, с винграда скопировал и не заметил ньюанса с pas.
                по ссылке счас почитаю, спасибо

                Добавлено
                Цитата Rose @
                так как эта процедура в конце вызывает засыпание потока

                возможно... но не в этом проблема...
                если отрабатывает часть кода при FileRead = 0(False), то все ок.
                видимо я не совсем ясно расписал ситуацию и ты меня не понял :wacko:
                  Цитата
                  возможно... но не в этом проблема...


                  Все же попробуй переделать свой код на менер того, как в приведенной ссылке - Event заведи, MsgWaitForMultipleObjects используй, ProcessMessages вместо HandleMessage, все должно работать.
                    Rose Да нет! ты не понял... ветка кода с GetOverlappedResult и так работает на "ура"! но просто при чтении с ЖД FileRead всегда возвращает true.
                    при чем тут переделка кода?
                      Цитата
                      Rose Да нет! ты не понял...


                      Видимо действительно не понял. Вторая попытка :) Рискну предположить что дело вот в чем: ReadFile не обязана вернуть код ошибки ERROR_IO_PENDING в асинхронном режиме, и в справке об этом написано. Операция чтения может быть завершена достаточно быстро и в этом случае даже в асинхрооном режиме будет прочитано сразу все. Может у Вас именно этот случай? Или на ReadFile код надолго останавливается?
                        Rose можно на "ты"? ) а то "ты мне тут не выкайте")

                        Цитата Rose @
                        ReadFile не обязана вернуть код ошибки ERROR_IO_PENDING

                        именно! в коде обрабатываются оба варианта операции...
                        блин, наверное не очень его красиво структурировал...
                        дополнил код комментариями.


                        Цитата Rose @
                        Может у Вас именно этот случай? Или на ReadFile код надолго останавливается?

                        у меня именно этот случай при работе с HDD!!!!
                        как я уже ранее предположил, система скорее всего с жесткого считывает быстро, а вот мой 50Мб-йтный буфер заполняется как раз эти 0,5-1 секунды задержки...
                        Сообщение отредактировано: MetalFan -
                          Цитата
                          Rose можно на "ты"? ) а то "ты мне тут не выкайте")

                          Привычка от других форумов, где принято на "Вы" :ph34r: Перехожу на "ты".

                          Попробую твой код в ближайшее время, пока сам не увижу - наверное не пойму в чем проблема.
                            Rose угу, пасип.
                            да проблемы даже можно сказать и нет...
                            Цитата MetalFan @
                            как я уже ранее предположил, система скорее всего с жесткого считывает быстро, а вот мой 50Мб-йтный буфер заполняется как раз эти 0,5-1 секунды задержки...
                              Цитата
                              как я уже ранее предположил, система скорее всего с жесткого считывает быстро, а вот мой 50Мб-йтный буфер заполняется как раз эти 0,5-1 секунды задержки...


                              В общем, мои исследования привели меня к выводу, что все дело в кешировании файлов. Если флаг FILE_FLAG_NO_BUFFERING не установлен, то первое обращение к файлу может занять несколько большее время, а последующие происходят значительно быстрее. Если установлен - то механиз кеширования не применяется, однако при этом нужно соблюсти некоторые требования, о которых в справке написано. Короче, то, что у тебя происходит - это нормальное поведение.
                                Цитата Rose @
                                Если флаг FILE_FLAG_NO_BUFFERING не установлен

                                проверял и с ним и без него.
                                но еще один ньюанс у меня возник (с FILE_FLAG_NO_BUFFERING) - получаю Invalid Parameter вместо ERROR_HANDLE_EOF по достижению конца файла...

                                Добавлено
                                брр... возможно я не учел замечания в msdn по поводу выделения памяти под буфер
                                  не только памяти, там еще выравнивание по размеру сектора...
                                    Цитата
                                    но еще один ньюанс у меня возник (с FILE_FLAG_NO_BUFFERING) - получаю Invalid Parameter


                                    Ну там сказано в справке, что буфер должен быть выровнен и порции считывания/записи должны быть кратны размеру сектора. У тебя это требование соблюдено?

                                    Цитата
                                    FILE_FLAG_NO_BUFFERING
                                    Instructs the operating system to open the file with no intermediate buffering or caching. This can provide performance gains in some situations. An application must meet certain requirements when working with files opened with FILE_FLAG_NO_BUFFERING:
                                    · File access must begin at byte offsets within the file that are integer multiples of the volume's sector size.
                                    · File access must be for numbers of bytes that are integer multiples of the volume's sector size. For example, if the sector size is 512 bytes, an application can request reads and writes of 512, 1024, or 2048 bytes, but not of 335, 981, or 7171 bytes.
                                    · Buffer addresses for read and write operations must be aligned on addresses in memory that are integer multiples of the volume's sector size.
                                    One way to align buffers on integer multiples of the volume sector size is to use VirtualAlloc to allocate the buffers. It allocates memory that is aligned on addresses that are integer multiples of the operating system's memory page size. Since both memory page and volume sector sizes are powers of 2, this memory is also aligned on addresses that are integer multiples of a volume's sector size.
                                    An application can determine a volume's sector size by calling the GetDiskFreeSpace function.


                                    Rouse_ меня опередил ;)
                                    Сообщение отредактировано: Rose -
                                    1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                                    0 пользователей:


                                    Рейтинг@Mail.ru
                                    [ Script execution time: 0,0471 ]   [ 15 queries used ]   [ Generated: 16.10.25, 03:26 GMT ]