-
Здравствуйте Мастера!
Есть 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);
я просто удалил куски кода(где ...).
-
Ну тогда твой цикл ожидания/выборки/диспетчеризации сообщений никуда не годится - "вис" происходит на GetMessage, когда из очереди выбраны и диспетчеризованы все имеющиеся там сообщения (т.е. очередь пуста).
-
> Ну тогда твой цикл ожидания/выборки/диспетчеризации сообщений
> никуда не годится - "вис" происходит на GetMessage, когда
> из очереди выбраны и диспетчеризованы все имеющиеся там
> сообщения (т.е. очередь пуста).
Подскажите выход... пожалуйсто:) Каим должен быть цикл выборки сообщений, можно пример?
-
Без учета таймаута примерно таким:
while not Terminated and (lastState <> 4) do
begin
if PeekMessage(rMsg,0,0,0, PM_REMOVE) then
DispatchMessage (rMsg)
else
Sleep(0);
end;
-
Уважаемый
> Сергей М. ©
огромнейшее, просто громадное Вам человеческое спасибо!!! Все работает... Вопрос закрыт.
-
Всем доброго времени суток.
У меня задача схожая с dima_q, и отличается лишь тем, что данные передаются через SSL. Приложение пишу на ВСВ. Установил OpenSSL, подвязал сертификат. Если функция send пустая, идет обращение на сервер, запрашивается сертификат, получаю ответ с сервера. А если заполняю send данными получаю пустое окно ответа и сертификат не запрашивается. Скорее всего с передаваемыми данными что-то не так. Может что-то посоветуете.
Игорь
-
> Если функция send пустая
Как это "пустая" ?
> заполняю send данными
Как можно "заполнить функцию данными" ?
Ерунда какая-то ..
-
Функция send может быть как с параметром так и без него: send() или
send(data)
Игорь.
-
И что ?
Вызов функции, с параметром или без, - это просто вызов функции, не более того.
Причем здесь какое-то там ее "наполнение" ?
-
Сергей! Не придирайся к словам. Давай по существу проблемы...
-
Проблема в тебе.
Я понятия не имею, что у тебя творится в этой самой send
-
Спасибо за теплые слова.
Передаю на сервер через SSL следующее:
Variant bstr;
bstr.VType=VT_BSTR;
SysFreeString(bstr.bstrVal);
bstr.bstrVal=SysAllocString(L"<?xml\ version='1.0'\ encoding='WINDOWS-1251'?><request><tpnum>-1</tpnum></request>");
hRes=pXMLHTTP->send(bstr);
На локальном HTTP сервере передача информации проходит успешно.
-
> На локальном HTTP сервере передача информации проходит успешно
Чудесно.
А какое отношение это имеет к STA и MTA ?
-
Вопрос связан с передачей информации через SSL методом XMLHTTP.send(data).
-
> igor_r © (11.08.08 14:12) [32]
А у автора вопрос был совершенно о другом.
-
Но решаемые задачи схожие. Форум практически единственный который затронул эту тему. Да и автор вопроса ковырнул эту тему глубоко...
-
> автор вопроса ковырнул эту тему глубоко
А ты внимательно читал ветку, перед тем как сделать вывод о якобы "схожести" ?
-
Тема открытая автором XMLHTTP.
Сергей, тебе что поговорить не с кем? Лучше бы толковое что написал.
Считаю вопрос закрытым.
-
> Тема открытая автором XMLHTTP
А дальше идет речь о конкретностях - об особенностях функционирования компонента в тех или иных условиях и режимах.
Ты же не сподобился даже изложить свои условия и режим эксплуатации компонента !
Какого же лешего ты ожидаешь услышать в ответ что-то "толковое" ?
Вот изволь сначала привести эти немаловажные подробности, потом и разговор будет предметным.