Delphi中单独线程中运行WebService的问题
我从来没有在任何社区提出过问题,因为我总是自己解决问题或者可以在网上找到它们。但有了这个,我就走进了死胡同,需要帮助! 为了说得更清楚——我转换了一个在其他地方找到的简单应用程序,使其使用 Tthread 对象。 这个想法很简单 – 应用程序使用 Web 服务通过 THTTPRIO 组件在线检查天气,并将结果放入 Memo1 行中。
单击 Button1,我们以标准方式完成它 - 使用放置在 Form1 上的 THTTPRIO(在原始应用程序中称为 htt)并使用主线程和唯一线程。
procedure TForm1.Button1Click(Sender: TObject);
var
wf:WeatherForecasts;
res:ArrayOfWeatherData;
i:integer;
begin
wf:=(htt as WeatherForecastSoap).GetWeatherByPlaceName(edit1.Text);
if wf.PlaceName<> '' then
res:=wf.Details;
memo1.Lines.Add('The min and max temps in Fahrenheit is:');
memo1.Lines.Add(' ');
for i:= 0 to high(res) do
begin
memo1.Lines.Add(res[i].Day+' - '+ ' Max Temp. Fahr: '+res[i].MaxTemperatureF+' - '+'Min Temp Fahr: '+res[i].MinTemperatureF);
end
end;
单击 Button2 – 我们使用类 TThread
procedure TForm1.Button2Click(Sender: TObject);
var WFThread:WeatherThread;
begin
WFThread := WeatherThread.Create (True);
WFThread.FreeOnTerminate := True;
WFThread.Place := Edit1.Text;
WFThread.Resume;
end;
在 WeatherThread1 单元中的执行过程中我输入以下代码:
procedure WeatherThread.Execute;
begin
{ Place thread code here }
GetForecast;
Synchronize (ShowWeather);
end;
...以及 GetForecast 代码:
procedure WeatherThread.GetForecast;
var
HTTPRIO: THTTPRIO;
wf:WeatherForecasts;
res:ArrayOfWeatherData;
i:integer;
begin
HTTPRIO := THTTPRIO.Create(nil);
HTTPRIO.URL := 'http://www.webservicex.net/WeatherForecast.asmx';
HTTPRIO.WSDLLocation := 'http://www.webservicex.net/WeatherForecast.asmx?WSDL';
HTTPRIO.Service := 'WeatherForecast';
HTTPRIO.Port := 'WeatherForecastSoap';
wf:=(HTTPRIO as WeatherForecastSoap).GetWeatherByPlaceName(Place);
if Lines=nil then Lines:=TStringList.Create;
if wf.PlaceName<> '' then
res:=wf.Details;
Lines.Clear;
for i:= 0 to high(res) do
begin
Lines.Add(res[i].Day+' - '+ ' Max Temp. Fahr: '+res[i].MaxTemperatureF+' - '+'Min Temp Fahr: '+res[i].MinTemperatureF);
end;
end;
过程 ShowWeather 在 Form1.Memo1 中显示结果。 现在有一个问题:在主线程中,单击 Button1,一切正常。但当然,当 HTTPRIO 组件通信时,它会冻结表单。
对于 Button2,我将代码放在单独的线程中,但它不想工作!奇怪的事情发生了。当我启动应用程序并单击 Button2 时,使用 HTTPRIO 组件时出现错误。但当我单击“FIRST Button1”和“AFTER THAT Button2”时,它会工作一段时间(但它会工作一段时间,仅单击 5-7 次)。 我想我做错了什么,但不知道问题出在哪里以及如何解决。看起来线程单元中的代码不是线程安全的,但它应该是。请帮助如何使 HTTPRIO 在线程中工作!
您可以在此处找到压缩的完整代码。
I have never asked questions in any community as I always solved problems by myself or could find them online. But with this one I came to dead end and need Help!
To make it very clear – I converted a simple app, found elsewhere to make it use a Tthread object.
The idea is simple – the app checks online using webservice, through THTTPRIO component, weather and put the results in Memo1 lines.
Clicking on Button1 we get it done in standard way – using THTTPRIO put on the Form1 (it's called here htt as in original app) and using main and only thread.
procedure TForm1.Button1Click(Sender: TObject);
var
wf:WeatherForecasts;
res:ArrayOfWeatherData;
i:integer;
begin
wf:=(htt as WeatherForecastSoap).GetWeatherByPlaceName(edit1.Text);
if wf.PlaceName<> '' then
res:=wf.Details;
memo1.Lines.Add('The min and max temps in Fahrenheit is:');
memo1.Lines.Add(' ');
for i:= 0 to high(res) do
begin
memo1.Lines.Add(res[i].Day+' - '+ ' Max Temp. Fahr: '+res[i].MaxTemperatureF+' - '+'Min Temp Fahr: '+res[i].MinTemperatureF);
end
end;
Clicking on Button2 – we use class TThread
procedure TForm1.Button2Click(Sender: TObject);
var WFThread:WeatherThread;
begin
WFThread := WeatherThread.Create (True);
WFThread.FreeOnTerminate := True;
WFThread.Place := Edit1.Text;
WFThread.Resume;
end;
In Execute procedure in WeatherThread1 unit I put this code:
procedure WeatherThread.Execute;
begin
{ Place thread code here }
GetForecast;
Synchronize (ShowWeather);
end;
...and the GetForecast code:
procedure WeatherThread.GetForecast;
var
HTTPRIO: THTTPRIO;
wf:WeatherForecasts;
res:ArrayOfWeatherData;
i:integer;
begin
HTTPRIO := THTTPRIO.Create(nil);
HTTPRIO.URL := 'http://www.webservicex.net/WeatherForecast.asmx';
HTTPRIO.WSDLLocation := 'http://www.webservicex.net/WeatherForecast.asmx?WSDL';
HTTPRIO.Service := 'WeatherForecast';
HTTPRIO.Port := 'WeatherForecastSoap';
wf:=(HTTPRIO as WeatherForecastSoap).GetWeatherByPlaceName(Place);
if Lines=nil then Lines:=TStringList.Create;
if wf.PlaceName<> '' then
res:=wf.Details;
Lines.Clear;
for i:= 0 to high(res) do
begin
Lines.Add(res[i].Day+' - '+ ' Max Temp. Fahr: '+res[i].MaxTemperatureF+' - '+'Min Temp Fahr: '+res[i].MinTemperatureF);
end;
end;
Procedure ShowWeather shows results in Form1.Memo1.
And now there is a problem: In main thread, clicking Button1, everything works fine. But of course when HTTPRIO component communicates – it freezes the form.
With Button2 I put the code in separate thread but it does NOT WANT TO WORK! Something strange happens. When I start application – and click Button2, there is an error when using HTTPRIO component. But it works for a while when I click FIRST Button1 and AFTER THAT Button2 (but it works for a while, 5-7 clicks only).
I suppose I do something wrong but cannot figure out where the problem is and how to solve it. It looks like the code in threaded unit is not thread-safe, but it should be. Please help how to make HTTPRIO work in a thread!!!
You can find zipped full code here.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当我在 Delphi 2007 中运行您的代码时,madExcept 显示异常CoInitialize 尚未被调用。
在执行方法中添加对 CoInitialize 的调用后,可以毫无问题地调用 Web 服务。
可能的修复
When I run your code in Delphi 2007, madExcept shows an exception CoInitialize has not been called.
After adding the call to CoInitialize in the execute method, the webservice gets called without problems.
Possible fix
可能性很大,但我在这里错过了对 Synchronize 的调用:
您永远不应该直接从线程代码更新 GUI。
您应该将这些调用嵌入到方法中,并使用 TThread.Synchronize 调用该方法方法为此。
Delphi about 有一个关于此的很好的演示。
从 Delphi 4 开始,它在
...\demos\threads
子目录中包含一个名为sortthds.pas
的演示,显示相同的内容。——杰罗恩
A long shot, but I'm missing calls to Synchronize here:
You should never update your GUI directly from your thread code.
You should embed those calls inside a method, and call that method using the TThread.Synchronize method for this.
Delphi about has a nice demo on this.
Since Delphi 4, it includes a demo called
sortthds.pas
in the...\demos\threads
subdirectory that shows the same.--jeroen
您可能会通过动态 RIO 创建(RIO 对象有一个奇怪的生命周期)和线程在一起,并将该结果与简单的 Button1 进行比较,从而使问题变得模糊。我将制作另一个在没有线程的情况下调用 GetForecast 的按钮。看看是否有效。如果它爆炸了,那么你的问题不是线程。
You may be clouding the issue by doing the dynamic RIO creation (RIO objects have a strange lifetime) and threading together, and comparing that outcome to the straightforward Button1. I'd make another button that calls GetForecast without threads. See if that works. If it bombs, then your problem isn't threading.