-
Здравствуйте Мастера! Есть COM библиотека служащая для общения с сервером. Общения происходит посредством xml по http. Для непосредственной связи используется объект XMLHTTP. Вопрос: Для работы с сервером, в моей либе создается отдельный поток. В потоке осуществляется вход в апартмент: CoInitializeEx(nil, COINIT_APARTMENTTHREADED) . После создания объекта c и присвоения всех свойств, вызывается метод XMLHTTP.send() . Так вот при использовании потоковой модели STA(COINIT_APARTMENTTHREADED) запрос на сервер не идет, все остается висеть навечно. А при использовании MTA все благополучно проходит. Сам сервер XMLHTTP в реестре помечен как Appartment. Подскажите в чем может быть проблема. Почему при STA не вознивает никаких ошибок, но запрос не происходит? P.S.: использовать MTA нет возможности, из-за дальнейших проблем с клиентами моей либы.
-
А при CoInitialize(nil) работает ?
-
> Сергей М. © (30.06.08 13:29) [1] > А при CoInitialize(nil) работает ?
Нет не работает. CoInitialize(nil) идентичен CoInitializeEx(nil, COINIT_APARTMENTTHREADED), это его сокращенный вызов.
-
Вся проблема в том, что при работе с CoInitializeEx(nil, COINIT_APARTMENTTHREADED) нет никаких ошибок. Просто тупо не посылает запрос.
-
> тупо не посылает запрос.
С чего ты взял, что "не посылает" ?
А если и не посылает, то что значит "все .. висеть" ?
ты исключения обрабатываешь ?
-
Исключения обрабатываю, их нет. Висит, в смысле на сервере, он тоже мой, стоит бряка, но запрос не доходит до него.
-
И статус (XMLHTTP.readyStatus) не изменяется никогда, он всегда 1. Хотя сервер доступен.
-
onreadystatechange используешь или синхронно?
-
> clickmaker © (30.06.08 17:59) [7] > onreadystatechange используешь или синхронно?
Не использую. Просто в цикле проверяю XMLHTTP.readyState.
-
погодь... насколько я знаю, там либо синхронно, тогда send не вернет, пока не выполнится, либо асинхронно, тогда надо вешать onreadystatechange попробуй второй вариант
-
Пробовал при асинхронном запросе вешать onreadystatechange, не происходит события. Сейчас попробую, что скажет синхронный.
-
В синхронном режиме сенд проходит нормально, не знаю что делать...
-
> В синхронном режиме сенд проходит нормально
Отсюда и вывод: threading model тут совершенно ни причем.
Похоже что XMLHTTP в асинхр.режиме заточен на нотификацию посредством оконных сообщений. И, поскольку в теле цикла ты не предпринимаешь никаких телодвижений по выборке/диспетчеризации оных, ожидать onreadystatechange или изменение readyState придется до второго пришествия.
-
> Сергей М. ©
Буду копать в сторону цикла обработки сообщений в потоке. Мот я просто не так добавлял его, попробую еще раз, огромное спасибо!
-
> Мот я просто не так добавлял его
Кого ?!
-
> Кого ?!
Цикл обработки сообщений. Попробовал, не работает все равно. Незнаю, что делать:(
-
> Незнаю, что делать
Ну как что ? Трясти бубен, если код своего цикла показывать не желаешь)
-
> Трясти бубен, если код своего цикла показывать не желаешь)
Думаю бубен вряд ли поможет, а код, вот он:
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.
-
Чудесно.
А где в этом коде собственно установка асинхронного режима работы компонента ?
Или это дифолтный режим ?
-
> А где в этом коде собственно установка асинхронного режима > работы компонента ?
Нет не дефолтный. Он передается параметром в функцию Open: m_xmlHTTP50.open('POST', m_url, m_async); я просто удалил куски кода(где ...).
|