RemObjects (a) client remote server interface process

Recommended for you: Get network issues from WhatsUp Gold. Not end users.

RemObjects SDK is a product of high encapsulation, and give full play to the extreme of OOP.

This paper will take RemObjects SDK's simple DEMO——FirstSampleAs an example,

The client is the whole process of how to complete the remote server interface.

Also understand why the different transmission channels (TCP/HTTP...), different message format (binary, SOAP...) to communicate with the server

The client is the three RO controls, is how to complete a call?

When the program is started, the RO has completed a series of actions,

To understand the order of execution of a Delphi main program code

Program:>

Implementation of initialization code (running in the main program to run before and is run only once) ->

{The project file}

begin
Application.Initialize;
Application.CreateForm(TForm, Form1);
Application.Run;
end.                       -->

Implementation of finalization code (running at program exit and run only once)

Also initialization code is first run, when we put the three controls on the pendulum,

Automatically added to the uROClient, uROBinMessage, uROWinInetHttpChannel,

At the same time to call the server interface, manual interface declaration file entry into the FirstSample_Intf

These three documents are the initialization, what they do?

{unit uROClient;} procedure RegisterMessageClass(aROMessageClass : TROMessageClass); begin _MessageClasses.Add(aROMessageClass); if Classes.GetClass(aROMessageClass.ClassName) = nil then Classes.RegisterClass(aROMessageClass); end; procedure RegisterTransportChannelClass(aTransportChannelClass : TROTransportChannelClass); begin if _TransportChannels.IndexOf(aTransportChannelClass.ClassName)<0 then begin _TransportChannels.AddObject(aTransportChannelClass.ClassName, TObject(aTransportChannelClass)); if Classes.GetClass(aTransportChannelClass.ClassName) = nil then Classes.RegisterClass(aTransportChannelClass); end; end; procedure RegisterProxyClass(const anInterfaceID : TGUID; aProxyClass : TROProxyClass); var s : string; begin s := GUIDToString(anInterfaceID); if _ProxyClasses.IndexOf(s)<0 then _ProxyClasses.AddObject(GUIDToString(anInterfaceID), TObject(aProxyClass)) end; initialization _MessageClasses := TClassList.Create; //TClassList just gave TList an alias _ExceptionClasses: = TClassList.Create; _ProxyClasses := TStringList.Create; _ProxyClasses.Duplicates := dupError; _ProxyClasses.Sorted := TRUE; _TransportChannels := TStringList.Create; _TransportChannels.Duplicates := dupError; _TransportChannels.Sorted := TRUE; ... ...

This initialization 3 lists, respectively for storing message format, the proxy class, transmission channel

While the three global function is added to the list of the corresponding object

{unit uROBinMessage;} initialization RegisterMessageClass(TROBinMessage); {unit uROWinInetHttpChannel;} initialization RegisterTransportChannelClass(TROWinInetHTTPChannel); {unit FirstSample_Intf;} initialization  //The first function is the interface of ID, the second is the RegisterProxyClass interface implementation class(IFirstSampleService_IID, TFirstSampleService_Proxy);

Thus, when the program is started already completed a series of operations

Next to the implementation of the main form to create the code

{unit FirstSampleClientMain;} constructor TFirstSampleClientMainForm.Create(aOwner: TComponent); begin inherited; fFirstService := (RORemoteService as IFirstSampleService); end;

Maybe for beginners a little strange, between object interface of RORemoteService and IFirstSampleService doesn't exist any relationship, can actually as ?
This is because the as operation will first call interface to query the QueryInterface, see the QueryInterface function of TRORemoteService is how to achieve

{unit uRORemoteService;} function TRORemoteService.QueryInterface(const IID: TGUID; out Obj): HResult; var proxyclass : TROProxyClass; proxy : TROProxy; begin result := inherited QueryInterface(IID, Obj); if (result <> S_OK) then begin //Refer to proxyclass through the ID query interface to achieve class interface: = FindProxyClass (IID, TRUE); if (proxyclass=NIL) then Exit else begin CheckCanConnect (false); // create interface object implementing the proxy: = proxyclass.Create(Self); proxy.GetInterface(IID, Obj); result := S_OK; end; end; end;

The FindProxyClass is defined in the ROClient

{unit uROClient;} function FindProxyClass(const anInterfaceID : TGUID; Silent : boolean = FALSE) : TROProxyClass; var idx : integer; s : string; begin result := NIL; s := GUIDToString(anInterfaceID); idx := _ProxyClasses.IndexOf(s); if (idx>=0) then result := TROProxyClass(_ProxyClasses.Objects[idx]) else begin if not Silent then RaiseError(err_UnknownProxyInterface, [s]) end; end;

So fFirstService: = (RORemoteService as IFirstSampleService); on the acquisition of the implementation of the interface of the proxy class

The proxy class to do what?

proxy := proxyclass.Create(Self); //In the QueryInterface function TRORemoteService

Proxyclass is a TROProxyClass object, while TROProxyClass= class of TROProxy; or TROProxy class reference

See the TROProxy constructor

{unit uROClient;} constructor TROProxy.Create(const aRemoteService: IRORemoteService); begin Create(aRemoteService.Message, aRemoteService.Channel); fCloneMessage := aRemoteService.CloneMessage; end; constructor TROProxy.Create(const aMessage: IROMessage; const aTransportChannel: IROTransportChannel); begin inherited Create; fMessage := pointer(aMessage); fTransportChannel := pointer(aTransportChannel); fCloneMessage := False; end;

At this point, a TRORemoteService object

The proxy class TFirstSampleService_Proxy, TROBinMessage message formats, transmission channel TROWinInetHTTPChannel together,

Executive program startup fFirstService: = (RORemoteService as IFirstSampleService); they have accomplished so much

Then look at the interface of function calls

{unit FirstSampleClientMain;} procedure TFirstSampleClientMainForm.GetButtonClick(Sender: TObject); begin NamesBox.Items.CommaText := fFirstService.Nicknames(eFullname.Text); end;

On the client, realize the interface of IFirstSampleService is in the TFirstSampleService_Proxy class implementation,

FFirstService: = (RORemoteService as IFirstSampleService); has completed the object creation,

So fFirstService.Nicknames (eFullname.Text); the actual call the Nicknames function TFirstSampleService

function TFirstSampleService_Proxy.Nicknames(const FullName: UnicodeString): UnicodeString; begin try __Message.InitializeRequestMessage(__TransportChannel, 'FirstSample', __InterfaceName, 'Nicknames'); __Message.Write('FullName', TypeInfo(UnicodeString), FullName, []); __Message.Finalize; __TransportChannel.Dispatch(__Message); __Message.Read('Result', TypeInfo(UnicodeString), result, []); finally __Message.UnsetAttributes(__TransportChannel); __Message.FreeStream; end end;

__Message is an attribute of TROProxyr,

{unit uROClient;} function TROProxy._GetMessage: IROMessage; begin result := IROMessage(fMessage); end;

As can be seen from the code, the incoming from the RORemoteService.Message class is created, it is on a ROBinMessage form,

The __TransportChannel is the form of ROWinInetHTTPChannel .


The TROBinMessage class is TROMessage, Write, Read is a virtual function in TROMessage

{unit uROClient;} {TROMessage} procedure Write(const aName : string; aTypeInfo : PTypeInfo; const Ptr; Attributes : TParamAttributes); virtual; procedure Read(const aName : string; aTypeInfo : PTypeInfo; var Ptr; Attributes : TParamAttributes); virtual;

So the actual call the TROBinMessage Write and Write

TROBinMessage Write and Write to realize the binary format to read and write, here is the realization of the code

TROSOAPMessage Write and Write realize the SOAP format to read and write

So when TRORemoteService binding of Message is TROBinMessage, the news can be in binary format for reading and writing,

When the TRORemoteService binding of Message is TROSOAPMessage, the message will be in SOAP format to read and write,

The same token, a subclass of TROTransportChannel TROIndyUDPChannel, TROWinInetHTTPChannel

The realization process in different ways of connection, this part is called the bottom communication

The Write function TROMessage client will function name and parameter packed according to a certain format

TROTransportChannelDispatchThe TROMessage is sent to the server and wait for the return,

The server will return the result into the TROMessage

The Read function TROMessage to unpack the client to read

This is the basic process of client server interface


Because the RemObject SDK closed very well, so the understanding process calls the client server interface, the key is to be aware of

The proxy class, message format, channel transmission is how to be together.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download

Posted by Margaret at December 19, 2013 - 5:00 PM