1. File->New->Other,在打开的对话框中,选择Web Services\SOAP Server Application

2. 在这里选择ISAPI DLL

3. 问咱Create Interface for SOAP module,当然是yes啦,然后输入个名称XXX,等下会生成XXXIntf.pasXXXImple.pas这两个文件,分别对应接口和类的实现。在这里,对外公布的都是接口。

Service name: SampleService

如果这里不添加,也可以使用SOAP Server Interface向导来添加接口。

最后编译生成的叫libss.dll

这里最主要关注的是SampleServiceIntf.pasSampleServiceImpl.pas

SampleServiceIntf.pas

{ Invokable interface ISampleService }

unit SampleServiceIntf;

interface

uses InvokeRegistry, Types, XSBuiltIns;

type

   { Invokable interfaces must derive from IInvokable }
   ISampleService =
interface(IInvokable)
   ['{C003A413-B302-437C-990C-1ADFAA03A619}']

     { 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;

修改后的代码

下面是SampleServiceIntfSampleServiceImpl这两个单元修改后的代码。

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)
   [
'{C003A413-B302-437C-990C-1ADFAA03A619}']
    // 这里参数传递方法最好用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.