在线等待:使用线程在客户端调用Webservice,报错,谁解决还可以加200分!!! (100分)

S

sunsong

Unregistered / Unconfirmed
GUEST, unregistred user!
关键代码:
procedure TCallWebService.Execute;
begin
FreeOnTerminate := true;
frmLogin.Call2;
//Synchronize(frmLogin.Call2);如果使用这句,可以运行,但显然不符合要求,
调用过程中,窗体都不能拖动
end;
//******************
procedure TfrmLogin.Call2;
v_return :=P_Interface.CheckUser(V_ID,V_Pass);--运行到这里报错:
...eOLESsyError...'标记没有引用存储'
{ for i := 0 to 100000000do
begin
Application.ProcessMessages;
end;
}--如果把调用Webservice的语句换成循环,运行良好!为什么?
 
高手都哪里去了???
 
我自己顶!
 
http://www.thedelphimagazine.com/samples/comthread/comthreading.htm
 
这个是COM的,不一样啊,说简略一点,我遇到的现象就是:
调用Webservice提供的函数,放在线程中执行,如果用同步(Synchronize)函数,
可以执行,但执行期间窗体都不能动,如果不使用同步,就出现
'eOLESsyError...'标记没有引用存储'的异常.
我实在不知道Webservice在线程中到底出了什么问题.都一个星期了,我快崩溃了.
 
v_return 在哪里定义的?
Synchronize(frmLogin.Call2);执行结果如何?
最好列出全代码,如果不长的话
 
v_return 在哪里定义我都试过了.
源码如下,另外引用了一个RSer单元,其中定义了接口,其他引用单元可以不考虑
unit ULogin;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,StrUtils,
Dialogs, StdCtrls, Buttons, ExtCtrls, Rio, SOAPHTTPClient, Animate,
GIFCtrl, ComCtrls, WinSkinForm, ComObj;

//调用WebService时使用线程.
type
TShowAnim = class(TThread)
private
proceduredo
Animate;
{ Private declarations }
protected
procedure Execute;
override;
destructor Destroy;
override;
end;
type
TCallWebService = class(TThread)
private
{ Private declarations }
protected
procedure Execute;
override;
destructor Destroy;
override;
end;

type
TfrmLogin = class(TForm)
Panel1: TPanel;
edUser: TLabeledEdit;
edPass: TLabeledEdit;
btOK: TBitBtn;
btExit: TBitBtn;
Bevel1: TBevel;
RxGIFAnimator1: TRxGIFAnimator;
Label1: TLabel;
ProgressBar1: TProgressBar;
Animate1: TAnimate;
WinSkinForm1: TWinSkinForm;
procedure btOKClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
private
FTryLoginCount : integer;
//尝试登录次数
procedure Animate;
proceduredo
CallWeb;
{ Private declarations }
public
//输出变量:用户ID,用户口令,学籍号,所学课程
O_ID,O_Pass,O_StudentID,O_date,O_Course : string;
//是否登录成功。
O_ISLogined : Boolean;
{ Public declarations }
end;

var
frmLogin: TfrmLogin;
thrShowAmin : TShowAnim;
//调用TShowAnim线程变量
thrCallWebservice : TCallWebService;
//调用WebService线程变量
V_Return : string;
CS1,CS2:TRTLCRITICALSECTION;//定义临界变量
implementation
uses RSer, PublicUt, UDm, UMain;
{$R *.dfm}
procedure TfrmLogin.btOKClick(Sender: TObject);
begin
//临时指定登录名及所能学习的课程 Add by Gongqin
GStudentID := '1001001320030328000100';
GCourse := '100001,100002,100003,100004,100005,100006,100007';
//***********************************************
frmLogin.ModalResult := mrOk;
{Inc(FTryLoginCount);
thrShowAmin:= TShowAnim.Create(False);
//显示动画,临时注释}
end;

procedure TfrmLogin.FormCreate(Sender: TObject);
begin
InitializeCriticalSection(CS1);
//
InitializeCriticalSection(CS2);
//
//登录次数初始化
FTryLoginCount :=0;
end;

{ TCallWebService }
procedure TfrmLogin.Animate;
var
i : integer;
begin
enterCriticalSection(cs1);
//frmLogin.RxGIFAnimator1.Animate := True;
Animate1.Active := True;
thrCallWebservice:= TCallWebService.Create(False);
{ for i := 0 to 12000000do
begin
ProgressBar1.StepBy(20);
end;
}
leaveCriticalSection(cs1);
end;

procedure TfrmLogin.DoCallWeb;
var P_Interface : REducationSoap;
//WebService提供的接口变量
//向服务器端提交的用户ID号, 用户登录口令
V_ID,V_Pass: string;
begin
//EnterCriticalSection(cs2);
V_ID := frmLogin.edUser.Text;
V_Pass := frmLogin.edPass.Text;
P_Interface := Dm.SOAP as REducationSoap;
// thrShowAmin := TShowAnim.Create(False);
V_Return :=P_Interface.CheckUser(V_ID,V_Pass);
//LeaveCriticalSection(cs2);
{ for i := 0 to 100000000do
begin
Application.ProcessMessages;
end;
}
end;

procedure TShowAnim.DoAnimate;
begin
frmLogin.Animate;
end;

procedure TShowAnim.Execute;
begin
try
Priority :=tpIdle;
Synchronize(doAnimate);
except
Msg('网络服务请求失败!','提示',0,0);
end;
end;

destructor TCallWebService.Destroy;
var
//返回字串,返回学员的学籍号、用户所可学习的课程ID。
V_Field : string;
V_LoginOK : Boolean;
//是否验证成功
begin
frmLogin.Animate1.Active := false;
frmLogin.ProgressBar1.visible :=False;
begin
getInfo(V_Return, V_Field,'[Field]');
if V_Field ='True' then
begin
V_LoginOK := True;
//如果登录成功则为全局变量赋值 Add by Gongqin
getInfo(V_Return, V_Field,'[Field]');
GStudentID := V_Field;
getInfo(V_Return, V_Field,'[Field]');
GCourse := V_Field;
//**********************************************
end else
V_LoginOK := False;
if (not V_loginOk) then
begin
Msg('用户或密码不正确,请重新输入');//临时注释
frmLogin.edUser.SetFocus;
Exit;
end;
//如果用户连续输错三次登录名及密码,则应自动退出程序。
if frmLogin.FTryLoginCount > 3 then
begin
Msg('登录失败,请退出!','提示');
frmLogin.Close;
end;
Msg('登录成功','提示');
//如果登录成功,则进入程序。
frmLogin.ModalResult := mrOk;
end;
end;
procedure TfrmLogin.FormDestroy(Sender: TObject);
begin
try
begin
DeleteCriticalSection(cs1);
DeleteCriticalSection(cs2);
if thrShowAmin <> nil then
begin
thrShowAmin.Terminate;
thrShowAmin.Destroy;
end;
end;
except
end;
end;

{ TCallWebService2 }
destructor TShowAnim.Destroy;
begin
inherited;
end;

procedure TCallWebService.Execute;
begin
//Priority :=tpIdle;
FreeOnTerminate := true;
frmLogin.DoCallWeb;
// Synchronize(frmLogin.DoCallWeb);
end;

end.
 
soap 了解的不多。
不过是用string 还是Pchar? 不知道是否有关。
另外,你synchronise( ) 时,能否通过?
 
你以为Webservice不是基于Com技术吗?
任何使用Com对象的线程都要初始化Com/Ole环境.
OleInitialize(nil);
try
//add your code here
finally
OleUninitialize;
end;
 
用synchronize( )可以通过,但在调用过程中,独占线程,其他的界面都不能动.
但要是这段调用换成普通的本地操作,是可以多线程同步的.
 
同意xeen的看法,有一个小例程已经用Comobj.CoInitializeEx调通了,
这个单元还在调试过程中.
 
搞定,两种方法都可以,不过xeen的感觉更好!这一百分tanghz20,kgafly20,xeen60
另外的100分在前沿技术版(ID1718525),xeen请去顶一下,我再加给你100.
还有在控件使用版有昨天的两个帖子一个是问皮肤的50分(ID:1731136)
一个是问Listview的,100分(ID:1731398),没人回,我就不删除了,
xeen麻烦再去顶一下,分都给你了,希望以后还能跟你交流!
 
顶部