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

Не приветствуется поднятие старых тем. Если ваш вопрос перекликается со старой темой, то для вопроса лучше создать новую тему, а старую указать в первом сообщении с описанием взаимосвязи.

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

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


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

Модераторы: Krid, Rouse_
  
> Передача данных через модем (TAPI) , Не работает передача, счетчик переданных байт всегда 0.
    Пытаюсь работать с модемом через TAPI.
    Все более или менее работает. Номер набирается, соединение устанавливается...
    Хэндл, для передачи данных получается. Покрайней мере ошибок не возникает. Хэндл получаю так:
    ExpandedWrap disabled
      procedure TiaFlowmeterModemTAPIProvider.afterConnected;
      var
        vVarString: LPVARSTRING;
      begin
        try
          try
            vVarString := AllocMem(1024);
            vVarString.dwTotalSize := 1024;
            {$WARNINGS OFF}
            TapiCheck(LineGetID(0, 0, fCall, LINECALLSELECT_CALL, vVarString, 'comm/datamodem'));
            fCommHandle := PInteger(PChar(vVarString) + vVarString.dwStringOffset)^;
            {$WARNINGS ON}
          finally
            FreeMem(vVarString);
          end;
        except
          self.Close();
          raise;
        end;
      end;

    Здесь в fCommHandle выставляется некий хэндл, через который я потом пытаюсь писать данные вот так:
    ExpandedWrap disabled
      Var
        vOutBufLen: Cardinal;
        vWritedCount: Cardinal;
      begin
        If Not GetActive then
          raise EiaModemTAPIProviderError.Create(ERR_TP_PROVIDERINACTIVE, ERR_TP_PROVIDERINACTIVE_UIN, ERR_TP_PROVIDERINACTIVE_UIN);
       
        vOutBufLen := Length(aData);
       
        WriteFile(fCommHandle, aData[0], vOutBufLen, vWritedCount, nil);
       
        If vOutBufLen <> vWritedCount then
          raise EiaModemTAPIProviderError.Create(ERR_TP_WRITEDATAERROR, ERR_TP_WRITEDATAERROR_UIN, ERR_TP_WRITEDATAERROR_UIN);


    vOutBufLen всегда не равна vWritedBufLen, которая всегда равна 0.
    На той стороне тоже ничего не приходит! Пробовал посылать просто текстовую строку...

    Как правильно сделать???
      почяему не проверяешь, что возвращает WriteFile?
        Хм... не знаю. Не подумал об этом. Взял кусок из старого проекта где с ком-портом прога работала...
        Посмотрю в ближайшее время, как получится с напарником состыковаться для дозвона, что она там возвращает...
        А пока, мне пришла в голову одна мысль... Вроде как этот хэндл должен быть открыть асинхронно... А в асинхронном режиме, вроде как этот счетчик и должне равняться нулю...

        Как можно открыть этот хендл в синхронном режиме? Т.к. асинхронный режим мне вообще не нужен! Только лишнее усложнение :(

        ЗЫЖ Почему в сетевое то? Уж тогда в работу с железом или АПИ :)
          Цитата Felan @
          Хм... не знаю. Не подумал об этом.

          Знаешь, а тут думать не надо. Есть четкое правило - ВСЕГДА проверять коды возврата.

          Добавлено
          Цитата Felan @
          Как можно открыть этот хендл в синхронном режиме? Т.к. асинхронный режим мне вообще не нужен! Только лишнее усложнение

          никак. TAPI сама открывает порт, ты на это никак повлиять не можешь..
            Цитата Felan @
            А пока, мне пришла в голову одна мысль... Вроде как этот хэндл должен быть открыть асинхронно...

            Цитата jack128 @
            никак. TAPI сама открывает порт, ты на это никак повлиять не можешь..

            Цитата Felan @
            А в асинхронном режиме, вроде как этот счетчик и должне равняться нулю...

            GetOverlappedResult ??????
              Так... Попробовал я посмотреть, что возвращается...
              Делал так:

              ExpandedWrap disabled
                procedure TiaFlowmeterModemTAPIProvider.Send(aData: TiaBuf;
                  const aDoSuccessEvent, aManageErrorEvent, aDoErrorEvent: Boolean);
                Var
                  vOutBufLen: Cardinal;
                  vWritedCount: Cardinal;
                  vWFResult: Boolean;
                  vError: Cardinal;
                  vOvr: TOverlapped;
                 
                  vS: String;
                  Len: Integer;
                  Buffer: array[0..255] of Char;
                begin
                  If Not GetActive then
                    raise EiaModemTAPIProviderError.Create(ERR_TP_PROVIDERINACTIVE, ERR_TP_PROVIDERINACTIVE_UIN, ERR_TP_PROVIDERINACTIVE_UIN);
                 
                  vOutBufLen := Length(aData);
                 
                  SetLastError(0);
                  vWFResult := false;
                 
                  vWFResult := WriteFile(fCommHandle, aData[0], vOutBufLen, vWritedCount, {@vOvr} nil);
                 
                  vError := GetLastError;
                 
                  Len := FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM or
                    FORMAT_MESSAGE_ARGUMENT_ARRAY, nil, vError, 0, Buffer,
                    SizeOf(Buffer), nil);
                  while (Len > 0) and (Buffer[Len - 1] in [#0..#32, '.']) do
                    Dec(Len);
                  SetString(vS, Buffer, Len);
                 
                  vS := IntToStr(vError) + ': ' + vS;
                 
                  if not vWFResult then
                    showmessage(vS);
                 
                  If vOutBufLen <> vWritedCount then
                    raise EiaModemTAPIProviderError.Create(ERR_TP_WRITEDATAERROR, ERR_TP_WRITEDATAERROR_UIN, ERR_TP_WRITEDATAERROR_UIN);
                end;


              WriteFile возвращает всевремя false.
              Если в ней вместо vOvr, стоит nil то возвращается 87. Судя по MSDN это ERROR_INVALID_PARAMETER.
              Исли указать оверлаппед структуру, то возвращается 6 - ERROR_INVALID_HANDLE.

              1. Если я правильно понял, то писать данные синхронно нелзя совсем? :(
              2. Как тогда правильно получить хэндл, в который писать данные?
                Вроде разобрался с этим всем. Все работает и передается.
                Есть еще такой вопрос. Когда делаем дисконнект почему не закрывается хэндл ком-порта(хэндл через который идет передача fCommHandle из поста #1)? Если он открывается неявно, то почему его надо закрывать самому?

                Получается, что если при дисконнекте(закрытии) соединения не сделать ему closehandle то в следующий раз соединение не устанавливаетя по "неизвестной причине", код тапи ...000048.
                Если же его закрыть, то вроде все работает...
                  Цитата Felan @
                  почему его надо закрывать самому?

                  потому что так написано в sdk ;-)
                    Блин... :) Где же я это пропустил-то... :)
                    Аж интересно прям теперь самому прочитать... Счас посмотрел по быстрому, опять не нашел.. :(
                      Следующая проблема.
                      На данном этапе все работает соединяется и передается. Но, когда циклически происходит опрос, и когда много раз... В моем случае это чтение записей архива устройства чтение очень часто зависает. Т.е. read попадает на (ERROR_IO_PENDING, она кстати всегда на нее попадает, но это вроде как нормально обрабатывается...) и этот пендинг никогда не заканчивается.

                      Чтение сделал так:
                      ExpandedWrap disabled
                        procedure TiaFlowmeterModemTAPIProvider.Receive(var aData: TiaBuf;
                          aCount: Cardinal; var aReadedCount: Cardinal; const aDoSuccessEvent,
                          aManageErrorEvent, aDoErrorEvent: Boolean);
                        Var
                          vOvr: TOverlapped;
                          vError: Cardinal;
                        begin
                          If Not GetActive then
                            raise EiaModemTAPIProviderError.Create(ERR_TP_PROVIDERINACTIVE, ERR_TP_PROVIDERINACTIVE_UIN, ERR_TP_PROVIDERINACTIVE_UIN);
                         
                          SetLength(aData, aCount);
                         
                          SetLastError(0);
                          vOvr.hEvent := CreateEvent(nil, false, false, nil);
                          //Читаем
                          try
                            {$WARNINGS OFF}
                            if ReadFile(fCommHandle, aData[0], aCount, aReadedCount, @vOvr) then
                              begin
                                //Проверка на правильность отправки
                                if not GetOverlappedResult(fCommHandle, vOvr, aReadedCount, true) then
                                  showErrorMessage(GetLastError);
                              end
                            else
                              begin
                                vError := GetLastError;
                                if (vError <> ERROR_IO_PENDING) then
                                  showErrorMessage(vError)
                                else
                                  begin
                                    if WaitForSingleObject(vOvr.hEvent, INFINITE) = WAIT_OBJECT_0 then
                                      begin
                                          begin
                                            //Проверка на правильность отправки
                                            if not GetOverlappedResult(fCommHandle, vOvr, aReadedCount, true) then
                                              begin
                                                vError := GetLastError;
                                                if (vError <> ERROR_IO_PENDING) then
                                                  showErrorMessage(vError);
                                              end;
                                          end
                                      end
                                    else
                                      begin
                                        if (vError <> ERROR_IO_PENDING) then
                                          showErrorMessage(vError)
                                      end;
                                  end;
                                end;
                            {$WARNINGS ON}
                          finally
                            CloseHandle(vOvr.hEvent);
                          end;
                         
                          //Проверка на правильность принятия
                          If aCount <> aReadedCount then
                            raise EiaModemTAPIProviderError.Create(ERR_TP_READANSWERERROR, ERR_TP_READANSWERERROR_UIN, ERR_TP_READANSWERERROR_UIN);
                        end;


                      Так вот совершенно в случайном месте ожидание WaitForSingleObject(vOvr.hEvent, INFINITE) зависает до бесконечности...
                      Если вместо INFINITE поставить таймаут, то ессно по его истечению программа продолжает работать, и ессно получаем ошибку, т.к. не все байты приняты.

                      Так вот вопросы следующие:
                      1 При работе через модем нет никакого подтверждения доставки как в сокетах? Т.е. получается, что то что мне послали, впринципе может и не прийти, даже если соединение модемы не разорвали и надо еще раз повторить запрос?

                      2 Почему все время readFile попадает на ERROR_IO_PENDING? Даже в том случае, если чтение происходит первый раз, т.е. я псылаю первую команду, и пытаюсь читать ответ? Понятно, что при посылке я жду не опустожения буфера передачи, а момента, когда в этот буфер будет записано все, что я хочу передать, но ведь вроде полный дуплекс? Получается, что сначала надо дождаться, что бы передалось, а потом уже принимать?

                      3 Как вообще правильно поступать при приеме данных с модема? Как определить, что это какой-то случайная ошибка, что бы потом перезапросить данные?
                        Цитата Felan @
                        1 При работе через модем нет никакого подтверждения доставки как в сокетах? Т.е. получается, что то что мне послали, впринципе может и не прийти, даже если соединение модемы не разорвали и надо еще раз повторить запрос?

                        Felan зачем ты заморачиваешься такой проблемой??? Ты отправил запрос и будь уверен, если канал связи налажен - то твой запрос дойдет. Как - это проблема модема. Если не получается отправить (рухнул канал) модем вернет ошибку связи, которую ты должен словить и обработать.
                        Цитата Felan @
                        2 Почему все время readFile попадает на ERROR_IO_PENDING?

                        Ну вообще то сей флаг указывает что процедура Overlapped нормально стартовала и не закончена, т.е. число переданных/принятых байт не равно числу запрашиваемых тобой при вызове функции Read/Write. Определять, что процедура Overlapped завершена (считано/записано нужное тебе количество байт) необходимо по установке евента, дескриптор которого ты передаешь в данную процедуру. И про GetOverlappedResult не забывать, она позволяет контролировать ход отправки получения. Если, например, в течении определенного времени число принятых байт остается равным, то проверяй состояние модема (статус) - может он уже орет тебе об ошибке канала и необходимо повторить либо установку связи, либо повторно отправить запрос на прием и т.д.
                          Суть то понятно. Я другое че-то никак не осмыслю. Связь то не рвется. А прием не заканчивается. Т.е. удаленный модем отправил данные, а они не все пришли... потерялись где-то по дороге или из-за ошибок или ище почему-то... Как это определить? Если сам модем это определяет, то что именно он говорит в таких случаях?
                          Я что-то смотрел в МСДН, но не понял, как это должно обрабатываться...
                          Если не трудно по подробнее объясни?
                          1 пользователей читают эту тему (1 гостей и 0 скрытых пользователей)
                          0 пользователей:


                          Рейтинг@Mail.ru
                          [ Script execution time: 0,0828 ]   [ 15 queries used ]   [ Generated: 5.11.25, 01:10 GMT ]