Compago

...free knowledge

 
  • Increase font size
  • Default font size
  • Decrease font size
Home Manuali Programmazione Come creare e usare un client COM

Come creare e usare un client COM

E-mail Stampa PDF

Ci sono diversi metodi per usare un oggetto COM, e quindi di implementare un COM client.
Se l'oggetto COM ha una interfaccia IDispatch allora viene chiamato Automation Server e il suo client sarà un Automation controller.

Ora supponiamo di avere a che fare con un normale oggetto COM di nome sia "MioServerCom". Quello che vogliamo fare è connetterci ad esso ed chiamare un suo metodo, che ad esempio potrebbe chiamarsi "CallServer".
Per fare questo dovremo prima di tutto importare la unit della type library con la descrizione della interfaccia (Server_TLB) , senza la quale non potremo conoscere come è stato definito l'oggetto COM  e i suoi metodi.

uses
Server_TLB,ComObj;
...
var
FServer: IMioServerCom;
...
FServer:=CreateComObject(CLASS_MioServerCom) as IMioServerCom;
Fserver.CallServer;

L'argomento della funzione CreateComObject è il GUID della co-classe, ma come alternativa, dato che stiamo usando la unit della type library potremo usare il "costruttore" della co-classe (non è più necessario importare la unit ComObj):

uses
Server_TLB;
...
var
FServer: IMioServerCom;
...
FServer:=CoMioComServer.create;
Fserver.CallServer;

Questi due modi di procedere sono assolutamente equivalenti, e quello che fanno è creare una istanza dell'oggetto COM e ottenere un riferimento alla sua interfaccia che comprende il metodo che vogliamo utilizzare.
Col secondo metodo viene sempre restituito un riferimento all'interfaccia di default, mentre col primo metodo potremo direttamente accedere a una qualsiasi interfaccia implementata dalla coclasse in questione.

var
FServer: IAltraIntf;
...
FServer:=CreateComObject(CLASS_MioServerCom) as IAltraIntf;

Ad ogni modo è sempre possibile passare da una interfaccia ad un altra forzando la tipologia (type casting):

(FserverIntf1 as IAltraIntf).MetodoAltraIntf;

L'unico problema di questo tipo di oggetti e che dobbiamo avere le informazioni relative all'interfaccia e ai suoi metodi per poterli usare e per fare questo di occorrono le informazioni della type library. Ad ogni modo se possiamo seguire questa strada il metodo con cui verranno invocati i vari metodi (early binding) sarà molto più veloce dei procedimenti descritti in seguito, dato che gia in fase di compilazione si conosceranno gli indirizzi delle varie funzioni tramite un offset.

Se non avessimo tutte queste informazioni sull'oggetto COM potremo sempre sperare di avere a che fare con un Automation Server, il quale ci viene incontro con l'uso di una interfaccia aggiuntiva (IDispatch) che ci permette di accedere ai vari metodi usando il loro nome o un codice identificativo (late binding).
Per capire meglio facciamo un esempio di Automation Server. Anche in questo scenario vale tutto quello che abbiamo visto nel caso dei normali oggetti COM, e potremo quindi chiamare la sua interfaccia direttamente.

uses
Server_TLB;
...
var
FServer: IMioAutomationServer;
...
FServer:=CoMioAutomationServer.create;
Fserver.CallServer;

Oppure

uses
Server_TLB,ComObj;
...
var
FServer: IMioAutomationServer;
...
FServer:=CreateComObject(CLASS_MioAutomationServer) as IMioAutomationServer;
Fserver.CallServer;

Ora passiamo alla novità dell' interfaccia IDispatch. L'oggetto eredita sia l'interfaccia IUnknow che IDispatch per questo motivo si dice che l'automation server implementa una dual interface, che ci permetterà diversi approcci ai suoi metodi. Nel file Server_TLB sono state dichiarate come:

 IMioAutomationServer = interface(IDispatch)
     ['{402FC553-034D-46F9-8EC7-71E96314F5D4}']
     procedure CallServer; safecall;
 end;

 IMioAutomationServerDisp = dispinterface
     ['{402FC553-034D-46F9-8EC7-71E96314F5D4}']
     procedure CallServer; dispid 201;
 end;

Il GUID è lo stesso dato che si tratta della stessa interfaccia e la dispinterface elenca gli stessi metodi assegnandogli un codice identificativo (dispid).
Se nella  funzione sono presenti dei parametri questi devono essere compatibili con le tipologie previste dagli standard OLE data type. Questo è stato reso necessario perchè un oggetto COM e il suo client non è detto che siano prodotti con lo stesso linguaggio di programmazione.

Automation specs Type library editor Delphi VBA
boolean VARIANT_BOOL WordBool Boolean
unsigned char unsigned char Byte Byte
double double Double Double
float float Single Single
int int SYSINT Long
long long Integer Long
short short SmallInt Integer
BSTR BSTR WideString String
CURRENCY CURRENCY Currency Currency
DATE DATE TDateTime Date
Idispatch IDispatch * Idispatch Object
Iunknown IUnknown * IUnknown Unknown
CoClass TypeName (struct tag )TypeName * TypeName TypeName
SafeArray(TypeName) SafeArray(TypeName) PSafeArray TypeName()

VARIANT OleVariant Variant

Come è possibile notare tra i tipi di dati compatibili non è presente il tipo String ma troviamo solo il tipo WideString, di questo dovremo tenerne conto in caso di metodi che richiedano questo tipo di parametri.

Ritornando all'implementazione del controller, per usare la dispinterface dobbiamo dichiarare una variabile di tipo IMioAutomationServerDisp e connetterci al server usando questo riferimento:

uses
Server_TLB,ComObj;
...
var
DispServer:IMioAutomationServerDisp;
...
DispServer:=CreateComObject(CLASS_MioAutomationServer) as IMioAutomationServerDisp;
DispServer.CallServer;

Ancora i vantaggi non si vedono, vediamo di andare oltre e di usare una nuova funzione: CreateOleObject. Essa è Definita in questo modo:

 function CreateOleObject(const ClassName: string): IDispatch;

Usando questa funzione potremo creare un Automation Object usando il nome della classe ("NomeProgetto.NomeOggetto") e non il suo GUID:

uses
Server_TLB,ComObj;
...
var
DispServer:IMioAutomationServerDisp;
...
DispServer:=CreateOleObject('server.MioAutomationServer') as IMioAutomationServerDisp;
DispServer.CallServer;

oppure ritornando all'interfaccia

uses
Server_TLB
,ComObj;
...
var
Server:IMioAutomationServer;
...
Server:=CreateOleObject('server.MioAutomationServer') as IMioAutomationServer;
Server.CallServer;

In questo modo ci siamo liberati dei GUID, ora non ci rimane che liberarci anche della struttura dell'interfaccia, in modo da non avere più bisogno della type library.
Per face questo ci serviremo di una variabile di tipo Variant o OleVariant, che tra i vari tipi di dati che possono gestire hanno anche il tipo IDispatch. In particolare il tipo OleVariant  può usare solo tipi di dati compatibili con la tecnologia OLE, ad esempio il tipo String viene convertito in WideString.

uses
  ComObj;
...
var

Server: Variant;
...
Server:=CreateOleObject('server.MioAutomationServer');
Server.CallServer;

Quindi non sarà più necessario importare la type library (server_TLB) ma perderemo la facilitazione del "Code Insight" nell IDE Delphi, quindi per sapere quali metodi e come usarli dovremo far riferimento a qualche documentazione sul oggetto COM.
Uno svantaggio di cui a volte occorre tenere conto è che usando i variant o le disp interface ogni chiamata ad un metodo risulta molto più laboriosa e quindi più lenta rispetto alle chiamate fatte tramite l'interfaccia.



Ultimo aggiornamento ( Lunedì 15 Novembre 2010 22:53 )  
Loading

Login