Compago

...free knowledge

 
  • Increase font size
  • Default font size
  • Decrease font size
Home Manuali Programmazione Esempio di In Process Automation Server in Delphi

Esempio di In Process Automation Server in Delphi

E-mail Stampa PDF

La OLE Automation permette alle applicazioni o alle librerie di "esporre" degli oggetti da usare nel loro codice.
Queste librerie o applicazioni che espongono questi oggetti programmabili sono chiamate Automation Server.
Le applicazioni che invece accedono e usano questi oggetti sono chiamate Automation Controller o client.
La tecnologia COM permette ai controller di accedere ai server usando le funzioni esposte da questi ultimi, e le convenzioni sono indipendenti dal linguaggio di programmazione, in questo modo un server o un client possono essere programmati in linguaggi differenti e interagire tramite la tecnologia COM.
Gli oggetti di tipo Automation sono essenzialmente oggetti COM che implementano l'interfaccia IDispatch oltre a quella classica IUnKnown.

Quello che andremo a fare in questo articolo è creare un In-Process server COM, registrare la sua interfaccia e successivamente creare un semplice client per un test.
I COM server In Process si differenziano da quelli Out of Process perché essi risiedono in una DLL mentre gli altri sono contenuti in una applicazione. Questo implica che essi verranno caricati, come una qualsiasi altra libreria, nello stesso spazio di memoria del "client" che li ha richiamati.

Il progetto che andremo a creare e che chiameremo Server sarà quindi una Activex  Library (New->Other->Activex Library)

Questa libreria non è altro che una normale DLL ma con alcune funzioni esportate obbligatoriamente:

library Server;

uses
ComServ;

exports
DllGetClassObject,
DllCanUnloadNow,
DllRegisterServer,
DllUnregisterServer;

{$R *.RES}

begin
end.

L'implementazione di queste quattro funzioni si trovano all'interno del modulo ComServ e sono delle procedure standard per ogni Activex Library.

Ora aggiungiamo l'automation object alla DLL.
Dal menu New->Other->Activex scegliamo Automation Object.

Verrà richiesto il nome dell'oggetto che stiamo creando (MioServerCom) e altri parametri che però lasceremo inalterati. In particolare il parametro di istanziamento è irrilevante per un in-proc server (vedi esempio out of process server) .

Verranno creati alcuni file in automatico:

  • Server.tlb             - contiene la descrizione dell'oggetto com da registrare
  • Server_TLB.pas   - contiene le dichiarazioni di interfaccia corrispondenti all'oggetto com
  • UnitServer.pas     - contiene l'implementazione della classe relativa all'interfaccia dichiarata

L'interfaccia grafica per la gestione di un COM object è solamente un aiuto per creare un file tlb secondo uno standard che è identico per tutti i linguaggi di programmazione che devono creare un oggetto COM.

A questo punto nella view TLB il nostro oggetto (server) contiene due cose: una interfaccia (IMioServerCom) e una classe (MioServerCom).
Aggiungiamo un metodo chiamato MioMetodo all'interfaccia IMioServerCom.

Questo metodo deve avere un parametro di tipo string, in modo che al momento della ricezione del testo esso possa essere utilizzato per aggiornare la FormServer.

Il contenuto del relativo file tlb è il seguente:

[
  uuid(14EE9CE6-142E-46F7-8768-5D2D0853BF4A),   version(1.0),   helpstring("Server Library")  
]
library Server
{

  importlib("STDOLE2.TLB");

  [
    uuid(402FC553-034D-46F9-8EC7-71E96314F5D4), version(1.0), helpstring("Dispatch interface for MioServerCom Object"), dual, oleautomation
  ]
   interface IMioServerCom: IDispatch
  {
    [
    id(0x000000C9)
    ]
    HRESULT _stdcall MioMetodo([in] LPSTR testo );
  };

  [
    uuid(1F37B25C-8438-4730-826B-00455C3DAA0F), version(1.0), helpstring("MioServerCom Object")
  ]
  coclass MioServerCom
  {
    [default] interface IMioServerCom;
  };
};

Il file di interfaccia TLB in pascal conterrà tutte le dichiarazioni e le definizioni necessarie ad altri moduli o altre applicazioni per poter utilizzare  il COM server creato:

unit Server_TLB;

{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
{$WARN SYMBOL_PLATFORM OFF}
{$WRITEABLECONST ON}
{$VARPROPSETTER ON}
interface

uses Windows, ActiveX, Classes, Graphics, StdVCL, Variants;

// *********************************************************************//
// GUIDS declared in the TypeLibrary. Following prefixes are used:
// Type Libraries : LIBID_xxxx
// CoClasses : CLASS_xxxx
// DISPInterfaces : DIID_xxxx
// Non-DISP interfaces: IID_xxxx
// *********************************************************************//
const
// TypeLibrary Major and minor versions
MioMetodoMajorVersion = 1;
MioMetodoMinorVersion = 0;

LIBID_MioMetodo: TGUID = '{14EE9CE6-142E-46F7-8768-5D2D0853BF4A}';

IID_IMioServerCom: TGUID = '{402FC553-034D-46F9-8EC7-71E96314F5D4}';
CLASS_MioServerCom: TGUID = '{1F37B25C-8438-4730-826B-00455C3DAA0F}';
type

// *********************************************************************//
// Forward declaration of types defined in TypeLibrary
// *********************************************************************//
IMioServerCom = interface;
IMioServerComDisp = dispinterface;

// *********************************************************************//
// Declaration of CoClasses defined in Type Library
// (NOTE: Here we map each CoClass to its Default Interface)
// *********************************************************************//
MioServerCom = IMioServerCom;

// *********************************************************************//
// Interface: IMioServerCom
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {402FC553-034D-46F9-8EC7-71E96314F5D4}
// *********************************************************************//
IMioServerCom = interface(IDispatch)
['{402FC553-034D-46F9-8EC7-71E96314F5D4}']
procedure MioMetodo(testo: PChar); safecall;
end;

// *********************************************************************//
// DispIntf: IMioServerComDisp
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {402FC553-034D-46F9-8EC7-71E96314F5D4}
// *********************************************************************//
IMioServerComDisp = dispinterface
['{402FC553-034D-46F9-8EC7-71E96314F5D4}']
procedure MioMetodo(testo: OleVariant); dispid 201;
end;

// *********************************************************************//
// The Class CoMioServerCom provides a Create and CreateRemote method to
// create instances of the default interface IMioServerCom exposed by
// the CoClass MioServerCom. The functions are intended to be used by
// clients wishing to automate the CoClass objects exposed by the
// server of this typelibrary.
// *********************************************************************//
CoMioServerCom = class
class function Create: IMioServerCom;
class function CreateRemote(const MachineName: string): IMioServerCom;
end;

implementation

uses ComObj;

class function CoMioServerCom.Create: IMioServerCom;
begin
Result := CreateComObject(CLASS_MioServerCom) as IMioServerCom;
end;

class function CoMioServerCom.CreateRemote(const MachineName: string): IMioServerCom;
begin
Result := CreateRemoteComObject(MachineName, CLASS_MioServerCom) as IMioServerCom;
end;
end.

Ora tra le altre cose è sta creata una unit (UnitServer) che contiene l'implementazione della classe TMioserverCom, la quale eredita la classe TAutoObject e sopratutto l'interfaccia che abbiamo descritto nei file precedenti IMioServerCom:

unit UnitServer;

{$WARN SYMBOL_PLATFORM OFF}

interface

uses
ComObj, ActiveX, Server_TLB, StdVcl;

type
TMioServerCom = class(TAutoObject, IMioServerCom)
protected
procedure MioMetodo(testo: PChar); safecall;
end;

implementation

uses ComServ,Dialogs;

procedure TMioServerCom.MioMetodo(testo: PChar);
begin
ShowMessage(testo);
end;

initialization
TAutoObjectFactory.Create(ComServer, TMioServerCom, Class_MioServerCom, ciMultiInstance, tmApartment);
end.

Le parti in nero sono state create automaticamente mentre le parti in rosso sono quelle inserite da me per interagire con l'utente, in pratica tramite questo server com è possibile invocare la procedura MioMetodo e far apparire il testo passato alla procedura in una dialog box.
L'unica cosa che rimane da fare è registrare l'oggetto com appena creato, in modo che un qualsiasi altro programma lo possa usare.

Con un visualizzatore per gli oggetti com di windows potremo verificare l'effettiva creazione:

Come possiamo constatare nella terza e quarta riga l'oggetto viene riconosciuto come InprocServer32 cioe come un In Process COM server.

Qui possiamo in effetti vedere come è stato registrato il nostro server, ed in particolare di come il sistema ad una eventuale richiesta di quella determinata interfaccia vada a caricare in memoria l'applicazione che la contiene (server.exe).

 

Ora per provare il funzionamento del server com creiamo un semplice client che consiste in una form con un pulsante ed un testo.

Per poter usare il server COM creato precedentemente dovremo importare il suo file TLB (Server_TLB.pas) contenente la descrizione dell'interfaccia.
Il compito del client è quello di prendere il testo che noi inseriremo nella form client e visualizzarlo sulla form server:

uses 
...
Server_TLB,
...

procedure TFormClient.Button1Click(Sender: TObject);
var
Server: IMioServerCom; //Notare che la variabile è di tipo IMioServerCom, cioè una istanza di una interfaccia
begin
Server := CoMioServerCom.Create; //Connessione al server com e se non in esecuzione viene creato
//Notare che quella che viene creata è una istanza della classe
//che implementa l'interfaccia con la funzione CoMioserverCom.Create

Server.MioMetodo(PChar(Edit1.Text)); //viene invocato un suo metodo
//Notare che noi possiamo vederlo tra i metodi perché appartiene ad una interfaccia
//ma possiamo usare il suo codice perché è implementato in una classe

end;

Quello che accadrà è semplice: avviando il client.exe e premendo il pulsante sul client verrà creata una connessione con una istanza del server e il testo del client verrà visualizzato dal server.

Ultimo aggiornamento ( Sabato 31 Luglio 2010 10:21 )  
Loading

Login