Конференция "Сети" » XMLHTTP [D7, WinXP]
 
  • dima_q (30.06.08 13:13) [0]
    Здравствуйте Мастера!
    Есть COM библиотека служащая для общения с сервером. Общения происходит посредством xml по http. Для непосредственной связи используется объект XMLHTTP. Вопрос: Для работы с сервером, в моей либе создается отдельный поток. В потоке осуществляется вход в апартмент:
    CoInitializeEx(nil, COINIT_APARTMENTTHREADED)

    . После создания объекта c и присвоения всех свойств, вызывается метод
    XMLHTTP.send()

    . Так вот при использовании потоковой модели STA(COINIT_APARTMENTTHREADED) запрос на сервер не идет, все остается висеть навечно. А при использовании MTA все благополучно проходит. Сам сервер XMLHTTP в реестре помечен как Appartment. Подскажите в чем может быть проблема. Почему при STA не вознивает никаких ошибок, но запрос не происходит? P.S.: использовать MTA нет возможности, из-за дальнейших проблем с клиентами моей либы.
  • Сергей М. © (30.06.08 13:29) [1]
    А при CoInitialize(nil) работает ?
  • dima_q (30.06.08 13:35) [2]

    > Сергей М. ©   (30.06.08 13:29) [1]
    > А при CoInitialize(nil) работает ?

    Нет не работает. CoInitialize(nil) идентичен CoInitializeEx(nil, COINIT_APARTMENTTHREADED), это его сокращенный вызов.
  • dima_q (30.06.08 13:37) [3]
    Вся проблема в том, что при работе с CoInitializeEx(nil, COINIT_APARTMENTTHREADED) нет никаких ошибок. Просто тупо не посылает запрос.
  • Сергей М. © (30.06.08 16:37) [4]

    >  тупо не посылает запрос.


    С чего ты взял, что "не посылает" ?

    А если и не посылает, то что значит "все .. висеть" ?

    ты исключения обрабатываешь ?
  • dima_q (30.06.08 17:51) [5]
    Исключения обрабатываю, их нет. Висит, в смысле на сервере, он тоже мой, стоит бряка, но запрос не доходит до него.
  • dima_q (30.06.08 17:53) [6]
    И статус (XMLHTTP.readyStatus) не изменяется никогда, он всегда 1. Хотя сервер доступен.
  • clickmaker © (30.06.08 17:59) [7]
    onreadystatechange используешь или синхронно?
  • dima_q (30.06.08 18:09) [8]

    > clickmaker ©   (30.06.08 17:59) [7]
    > onreadystatechange используешь или синхронно?

    Не использую. Просто в цикле проверяю XMLHTTP.readyState.
  • clickmaker © (30.06.08 18:16) [9]
    погодь... насколько я знаю, там либо синхронно, тогда send не вернет, пока не выполнится, либо асинхронно, тогда надо вешать onreadystatechange
    попробуй второй вариант
  • dima_q (30.06.08 18:30) [10]
    Пробовал при асинхронном запросе вешать onreadystatechange, не происходит события. Сейчас попробую, что скажет синхронный.
  • dima_q (30.06.08 19:27) [11]
    В синхронном режиме сенд проходит нормально, не знаю что делать...
  • Сергей М. © (30.06.08 19:47) [12]

    > В синхронном режиме сенд проходит нормально


    Отсюда и вывод: threading model тут совершенно ни причем.

    Похоже что XMLHTTP в асинхр.режиме заточен на нотификацию посредством оконных сообщений. И, поскольку в теле цикла ты не предпринимаешь никаких телодвижений по выборке/диспетчеризации оных, ожидать onreadystatechange или изменение readyState придется до второго пришествия.
  • dima_q (01.07.08 09:35) [13]

    > Сергей М. ©

    Буду копать в сторону цикла обработки сообщений в потоке. Мот я просто не так добавлял его, попробую еще раз, огромное спасибо!
  • Сергей М. © (01.07.08 16:47) [14]

    > Мот я просто не так добавлял его


    Кого ?!
  • dima_q (02.07.08 09:42) [15]

    > Кого ?!

    Цикл обработки сообщений. Попробовал, не работает все равно. Незнаю, что делать:(
  • Сергей М. © (02.07.08 10:16) [16]

    > Незнаю, что делать


    Ну как что ?
    Трясти бубен, если код своего цикла показывать не желаешь)
  • dima_q (02.07.08 10:26) [17]

    > Трясти бубен, если код своего цикла показывать не желаешь)

     Думаю бубен вряд ли поможет, а код,  вот он:

       TXMLHTTPThread = class(TThread)
       private
           m_xmlHTTP30 : MSXML3.TXMLHTTP30;
           m_xmlHTTP40 : MSXML5.TXMLHTTP40;
           m_xmlHTTP50 : MSXML5.TXMLHTTP50;
         ...

           procedure ParseResponse();
           function  CheckOfTimeout(xmlHTTP : TXMLHTTP) : integer;// 0 - aborted, 1 - timed out, 4 - successful;
       public
           AlwaysSaveToFile : boolean;
           constructor Create(async : boolean; url: string; sFileName: string = ''; stmPost: TIdMultipartFormDataStream = nil);
           destructor Destroy(); override;
           procedure Execute(); override;
           ...
       end;

    ...
       function TXMLHTTPThread.CheckOfTimeout(xmlHTTP: TXMLHTTP): integer;
       var lastState, diff : integer;
           ticks : cardinal;
           rMsg : TMsg;
       const ts : array [0..3] of integer = (60*1000,60*1000,10*60*1000,10*60*1000);
       begin
           Result := 4;
           ticks := GetTickCount();
           lastState := xmlHTTP.readyState;
           while (lastState <> 4) do
           begin
               while (GetMessage (rMsg,0,0,0)) do DispatchMessage (rMsg);
               Sleep(50);
               if (GetTickCount() - ticks > ts[lastState]) then
               begin
                   xmlHTTP.abort();
                   Result := 1;
                   Exit;
               end;
               if Terminated then
               begin
                   xmlHTTP.abort();
                   Result := 0;
                   Exit;
               end;
               if (xmlHTTP.readyState > lastState) then
               begin
                  ticks := GetTickCount();
                  lastState := xmlHTTP.readyState;
               end;
           end;
       end;

       constructor TXMLHTTPThread.Create(async : boolean; url: string; sFileName: string = ''; stmPost: TIdMultipartFormDataStream = nil);
       begin
           inherited Create(true);
           m_xmlHTTP30 := nil;
           m_xmlHTTP40 := nil;
           m_xmlHTTP50 := nil;
           ...
       end;

       destructor TXMLHTTPThread.Destroy();
       begin
          ...
       end;

       procedure TXMLHTTPThread.Execute();
       var stmString : TStringStream;
           i, rs : integer;
           s : string;
       begin
           CoInitializeEx(nil, COINIT_APARTMENTTHREADED);
           //COINIT_MULTITHREADED
           //COINIT_APARTMENTTHREADED

           case (XMLVersion) of
               xml30: m_xmlHTTP30 := MSXML3.TXMLHTTP30.Create(nil);
               xml40: m_xmlHTTP40 := MSXML5.TXMLHTTP40.Create(nil);
               xml50: m_xmlHTTP50 := MSXML5.TXMLHTTP50.Create(nil);
               xmlUnknown :
               begin
                   m_error := 'Cannot access network : MSXML version 3.0 or higher is required';
                   m_completed := true;
                   CoUninitialize();
               end;
           end;

           try
               try
                   ...

                   if (XMLVersion = xml30) then
                   begin
                       if (m_stmPost <> nil) then m_xmlHTTP30.send(m_postdata)
                       else m_xmlHTTP30.send();
                       if m_async then
                           case CheckOfTimeout(TXMLHTTP(m_xmlHTTP30)) of
                               0: begin m_error := 'aborted'; Exit; end;
                               1: begin m_error := 'timed out'; Exit; end;
                           end;
                   end else if (XMLVersion = xml40) then
                   begin
                       if (m_stmPost <> nil) then m_xmlHTTP40.send(m_postdata)
                       else m_xmlHTTP40.send();
                       if m_async then
                       begin
                           case CheckOfTimeout(TXMLHTTP(m_xmlHTTP40)) of
                               0: begin m_error := 'aborted'; Exit; end;
                               1: begin m_error := 'timed out'; Exit; end;
                           end;
                       end;
                   end else
                   begin
                       if (m_stmPost <> nil) then m_xmlHTTP50.send(m_postdata)
                       else m_xmlHTTP50.send();
                       if m_async then
                       begin
                           case CheckOfTimeout(TXMLHTTP(m_xmlHTTP50)) of
                               0: begin m_error := 'aborted'; Exit; end;
                               1: begin m_error := 'timed out'; Exit; end;
                           end;
                       end;
                   end;

                   if (XMLVersion = xml30) then
                       rs := m_xmlHTTP30.readyState
                   else if (XMLVersion = xml40) then
                       rs := m_xmlHTTP40.readyState
                   else
                       rs := m_xmlHTTP50.readyState;

                   if (rs >= 2) then // LOADED, STATUS is available
                   begin
                       if (XMLVersion = xml30) then
                           m_respCode := m_xmlHTTP30.status
                       else if (XMLVersion = xml40) then
                           m_respCode := m_xmlHTTP40.status
                       else
                           m_respCode := m_xmlHTTP50.status;
                       try
                           if (m_respCode >= 400) then
                           begin
                               m_error := 'ServerXMLHTTP returned an error : ';
                               if (XMLVersion = xml30) then
                                   s := m_xmlHTTP30.statusText
                               else if (XMLVersion = xml40) then
                                   s := m_xmlHTTP40.statusText
                               else
                                   s := m_xmlHTTP50.statusText;

                               if (Length(s) > 0) then m_error := m_error + s
                               else m_error := m_error + ResponseCodeText(m_respCode);
                           end;
                       except end;
                   end;

                   if (rs = 4) then ParseResponse();

               except
                   on ex : Exception do
                   begin
                       m_error := {'ServerXMLHTTP has returned an error: ' +} ex.Message;
                   end;
               end;
           finally
               m_completed := true;
               if (XMLVersion = xml30) then
                   FreeAndNil(m_xmlHTTP30)
               else if (XMLVersion = xml40) then
                   FreeAndNil(m_xmlHTTP40)
               else
                   FreeAndNil(m_xmlHTTP50);
               CoUninitialize();
           end;
       end;
    end.
  • Сергей М. © (02.07.08 11:27) [18]
    Чудесно.

    А где в этом коде собственно установка асинхронного режима работы компонента ?

    Или это дифолтный режим ?
  • dima_q (02.07.08 11:41) [19]

    > А где в этом коде собственно установка асинхронного режима
    > работы компонента ?

    Нет не дефолтный. Он передается параметром в функцию Open:
    m_xmlHTTP50.open('POST', m_url, m_async);
    я просто удалил куски кода(где ...).
 
Конференция "Сети" » XMLHTTP [D7, WinXP]
Есть новые Нет новых   [134433   +22][b:0][p:0.001]