RO代码跟踪 之 客户端代理类的工作原理

来源:互联网 发布:阿里云服务器磁盘扩容 编辑:程序博客网 时间:2024/05/24 07:17

  每个服务都会自动在XXX_Intf.pas文件中生成一个代理类TXXXService_Proxy,这个代理类从TROProxy类继承并实现了IXXXService接口.
  我们在客户端调用RO服务的时候,是这样做的:
var
  fFirstService: IFirstSampleService;  //定义接口变量
begin
  fFirstService := (RORemoteService as IFirstSampleService);  //获取接口
  NamesBox.Items.CommaText := fFirstService.Nicknames(eFullname.Text);  //调用类
end;

  对程序下断点后会发现客户端调用服务端方法的时候都是通过代理类中对应的方法转发给服务端.
function TFirstSampleService_Proxy.Nicknames(const FullName: Widestring): Widestring;
begin
  try
    //将参数和函数名称写入到消息中
    __Message.InitializeRequestMessage(__TransportChannel, 'FirstSample', __InterfaceName, 'Nicknames');
    __Message.Write('FullName', TypeInfo(Widestring), FullName, []);
    __Message.Finalize;
    //写完后使用通道传输
    __TransportChannel.Dispatch(__Message);
    //读取返回的结果
    __Message.Read('Result', TypeInfo(Widestring), result, []);
  finally
    __Message.UnsetAttributes(__TransportChannel);
    __Message.FreeStream;
  end
end;
  首先解释一下调用是如何跳转到代理类的.[这种方式很常见哦,看看THTTPRIO控件吧,delphi调用WebService的时候貌似也是用这种技巧]
  在执行fFirstService := (RORemoteService as IFirstSampleService);代码时,调用RORemoteService控件中的一个成员函数:
function TRORemoteService.QueryInterface(const IID: TGUID; out Obj): HResult; override;
var //ref : IInterface;
    proxyclass : TROProxyClass;
    proxy : TROProxy;
begin
  result := inherited QueryInterface(IID, Obj);

  if (result <> S_OK) then begin
    proxyclass := FindProxyClass(IID, TRUE);

    if (proxyclass=NIL) then Exit
    else begin
     CheckCanConnect(false);
      proxy := proxyclass.Create(fMessage, fChannel);
      proxy.GetInterface(IID, Obj);//关键之处 使Obj :=proxy
      result := S_OK;
    end;
  end;
end; 
  在跟踪一下FindProxyClass方法,就会发现原来在XXX_Inft.pas单元中的initialization节中将代理类注册到全局变量_ProxyClasses中,在做类型转换的时候由QueryInterface函数来查找注册的代理类,并创建代理类实例返回.所以fFirstService := (RORemoteService as IFirstSampleService);最终获取到的是代理类的实例.在QueryInterface方法中会将RORemoteService的Message和Channel属性类传递个代理类实例.我们在代理类中看到的__Message成员实际上就是我们指定的RO Message控件,而__TransportChannel则是我们指定的通道.
  注意:QueryInteface是IUnKnown接口定义的方法,类在实现接口的时候必须要实现的三个方法之一.[用于获取实现接口的对象]
  代理类做的事情就很直接了,首先将需要传给服务端的信息如函数名称,参数全部流化到__Message中,使用通道传输这个流,并接收服务端返回的结果.