1. File->New->Other,在打开的对话框中,选择Web Services\SOAP Server Application。
2. 在这里选择ISAPI DLL。
3. 问咱Create Interface for SOAP module,当然是yes啦,然后输入个名称XXX,等下会生成XXXIntf.pas和XXXImple.pas这两个文件,分别对应接口和类的实现。在这里,对外公布的都是接口。
Service name: SampleService
如果这里不添加,也可以使用SOAP Server Interface向导来添加接口。
最后编译生成的叫libss.dll。
这里最主要关注的是SampleServiceIntf.pas和SampleServiceImpl.pas。
SampleServiceIntf.pas
{ Invokable interface ISampleService }
unit SampleServiceIntf;
interface
uses InvokeRegistry, Types, XSBuiltIns;
type
{ Invokable interfaces must derive from IInvokable }
ISampleService = interface(IInvokable)
['{C
{ Methods of Invokable interface must not use the default }
{ calling convention; stdcall is recommended }
end;
implementation
initialization
{ Invokable interfaces must be registered }
InvRegistry.RegisterInterface(TypeInfo(ISampleService));
end.
SampleServiceImpl.pas
{ Invokable implementation File for TSampleService which implements ISampleService }
unit SampleServiceImpl;
interface
uses InvokeRegistry, Types, XSBuiltIns, SampleServiceIntf;
type
{ TSampleService }
TSampleService = class(TInvokableClass, ISampleService)
public
end;
implementation
initialization
{ Invokable classes must be registered }
InvRegistry.RegisterInvokableClass(TSampleService);
end.
要公布的接口必须继承IInvokable
IInvokable其实跟IInterface是一样的,不同之处在于带上了{$M}编译指令,使用这个编译指令,使得它以及它的子类都具有RTTI。
{$M+}
IInvokable = interface(IInterface)
end;
{$M-}
要用于数据传递的类必须继承TRemotable
要用于数据传递的类必须继承TRemotable,并且必须在published中以property的形式公布数据。对于复杂的类引用(包括递归引 用),也是没问题的。可是,如果在结果的地方返回一个对象,它将会在什么时候被销毁呢?会不会造成内存泄漏呢?看看TRemotable.Create的 源代码就知道了。
constructor TRemotable.Create;
begin
inherited;
if RemotableDataContext <> nil then
begin
TDataContext(RemotableDataContext).AddObjectToDestroy(Self);
Self.DataContext := TDataContext(RemotableDataContext);
end;
end;
修改后的代码
下面是SampleServiceIntf和SampleServiceImpl这两个单元修改后的代码。
SampleServiceIntf.pas
{ Invokable interface ISampleService }
unit SampleServiceIntf;
interface
uses InvokeRegistry, Types, XSBuiltIns;
type
// 要用于传送数据的类必须继承TRemotable
// 要传送的数据必须在published中用property公开
TComplex=class(TRemotable)
private
FI: real;
FR: real;
procedure SetI(const Value: real);
procedure SetR(const Value: real);
published
published
property R:real read FR write SetR;
property I:real read FI write SetI;
end;
// 复杂的数据
TExtraData=class(TRemotable)
private
FX: Integer;
procedure SetX(const Value: Integer);
published
property X:Integer read FX write SetX;
end;
TLoopable=class(TRemotable)
private
FData: TExtraData;
FNext: TLoopable;
procedure SetData(const Value: TExtraData);
procedure SetNext(const Value: TLoopable);
published
published
property Data:TExtraData read FData write SetData;
property Next:TLoopable read FNext write SetNext default nil;
end;
// 递归引用
TClassA=class;
TClassB=class(TRemotable)
private
Fref: TClassA;
procedure Setref(const Value: TClassA);
published
property ref:TClassA read Fref write Setref default nil;
end;
TClassA=class(TRemotable)
private
Fref: TClassB;
procedure Setref(const Value: TClassB);
published
property ref:TClassB read Fref write Setref default nil;
end;
{ Invokable interfaces must derive from IInvokable }
ISampleService = interface(IInvokable)
['{C
// 这里参数传递方法最好用stdcall
function ComplexAdd(a,b:TComplex):TComplex;stdcall;
function Loop(Level:Integer):TLoopable;stdcall;
function GetClassAB:TClassA;stdcall;
end;
implementation
{ TComplex }
procedure TComplex.SetI(const Value: real);
begin
FI := Value;
end;
procedure TComplex.SetR(const Value: real);
begin
FR := Value;
end;
{ TExtraData }
procedure TExtraData.SetX(const Value: Integer);
begin
FX := Value;
end;
{ TLoopable }
procedure TLoopable.SetData(const Value: TExtraData);
begin
FData := Value;
end;
procedure TLoopable.SetNext(const Value: TLoopable);
begin
FNext := Value;
end;
{ TClassA }
procedure TClassA.Setref(const Value: TClassB);
begin
Fref := Value;
end;
{ TClassB }
procedure TClassB.Setref(const Value: TClassA);
begin
Fref := Value;
end;
initialization
{ Invokable interfaces must be registered }
InvRegistry.RegisterInterface(TypeInfo(ISampleService));
end.
SampleServiceImpl.pas
{ Invokable implementation File for TSampleService which implements ISampleService }
unit SampleServiceImpl;
interface
uses InvokeRegistry, Types, XSBuiltIns, SampleServiceIntf;
type
{ TSampleService }
TSampleService = class(TInvokableClass, ISampleService)
public
function ComplexAdd(a,b:TComplex):TComplex;stdcall;
function Loop(Level:Integer):TLoopable;stdcall;
function GetClassAB:TClassA;stdcall;
end;
implementation
{ TSampleService }
function TSampleService.ComplexAdd(a, b: TComplex): TComplex;
begin
Result:=TComplex.Create;
Result.R:=a.R+b.R;
Result.I:=a.I+b.I;
// 可是这个对象,什么时候被销毁呢????
end;
function TSampleService.GetClassAB: TClassA;
begin
Result:=TClassA.Create;
Result.ref:=TClassB.Create;
Result.ref.ref:=Result;
// 这个对象能否被安全销毁呢?
end;
function TSampleService.Loop(Level: Integer): TLoopable;
var tmp:TLoopable;
I:Integer;
begin
Result:=nil;
for I := 1 to Level do
begin
tmp:=TLoopable.Create;
tmp.Data:=TExtraData.Create;
tmp.Data.X:=I;
tmp.Next:=Result;
Result:=tmp;
end;
// 返回的对象将在什么时候被销毁呢????
end;
initialization
{ Invokable classes must be registered }
InvRegistry.RegisterInvokableClass(TSampleService);
end.