Sviluppo di applicazioni multi lingue create con Delphi
Andrea Raimondi    I° parte
 andrea_raimondi@hotmail.com

Download Esempio

QuestÆarticolo illustra lÆutilizzo del link dinamico delle DDL.

Salve a tutti. Ci sono molte applicazioni, in giro, in grado di estendere le proprie potenzialità attraverso appositi moduli scritti anche da terze parti. Bene, quello che stiamo per affrontare è un viaggio breve ma intenso. Ciò che vÆillustrerò è una tecnica molto interessante. Leggendo questÆarticolo, infatti, sarete in grado di scrivere applicazioni capaci di parlare una lingua qualsiasi.

EÆ possibile, infatti, tramite lÆuso di DDL scritte ad hoc, cambiare la lingua "parlata" dallÆapplicazione. Programmi scritti per lÆitaliano potranno facilmente "parlare" inglese, francese, spagnolo, ecc. Tutto senza cambiare quasi nulla di applicazioni già scritte e con poche righe aggiuntive in quelle ancora da scrivere. LÆopera di traduzione sarà semplice e potrà essere fatta da un qualsiasi programmatore, anche poco esperto, che rispetti le specifiche dellÆautore dellÆapplicazione. Iniziamo il nostro viaggio. Dovete sapere che Delphi permette il caricamento dinamico delle DDL. Questo significa che anziché assegnare unÆinterfaccia predefinita alla libreria, se ne può creare una " al volo ". Mi spiego. Ecco come appare unÆinterfaccia statica ad una Dll:

Unit DLLIntf; { Dichiara la unit di interfaccia alla DLL. }

Interface

function DoFirst( N : Integer ) : PChar;

procedure DoSecond;

implementation

function DoFirst( N : Integer ) : PChar; external æMyDllÆ name æDoFirstÆ;

procedure DoSecond;external æMyDllÆ name æDoSecondÆ;

à..

end.

Beh, questo è il metodo " classico " di interfacciare una DLL. Ma si potrebbe anche pensare ad un modo meno convenzionale di affrontare la cosa. Servono poche righe in più, ma il risultato può essere molto soddisfacente. Osservate :

Unit DynamicDLLIntf; { Dichiara la unit di interfaccia alla DLL. Utilizza un link dinamico alle

Funzioni. }

Interface

Uses Windows;

Type DoFirstFunc = function( N : Integer ) : Pchar;

DoSecondProc = procedure;

var LoadResult : ShortInt;

const LoadOk = 0;

LoadFailed = -1;

procedure InitLibrary;

function DoFirst( N : Integer ) : Pchar;

procedure DoSecond;

procedure DoneLibrary;

implementation

Var LibHandle : Thandle;

FuncFirst : DoFirstFunc;

ProcSecond : DoSecondProc;

procedure InitLibrary;

begin

LibHandle := LoadLibrary( æMyDllÆ );

if Handle = 0 then LoadResult := LoadFailed

else LoadResult := LoadOk;

end;

function DoFirst( N : Integer ) : Pchar;

begin

FuncFirst := GetProcAddress( Handle,æDoFirstFuncÆ );

if @FuncFirst = nil then LoadResult := LoadFailed

else LoadResult := LoadOk;

if ( LoadResult = LoadOk ) then

begin

Result := FuncFirst( N );

end

else Result := Pchar( æFunzione non caricata correttamenteÆ ); { Utilizza un valore di default da

controllare successivamente}

end;

procedure DoSecond;

begin

ProcSecond:= GetProcAddress( Handle,æDoSecondProcÆ );

if @ProcSecond = nil then LoadResult := LoadFailed

else LoadResult := LoadOk;

if ( LoadResult = LoadOk ) then

begin

ProcSecond;

end

else message( æRoutine non caricataÆ );

end;

procedure DoneLibrary;

begin

FreeLibrary( Handle );

end;

intialization

begin

InitLibrary;

end;

finalization

begin

DoneLibrary;

end;

end.

Ecco. Questa è una possibile implementazione di interfaccia ad una DLL in modo dinamico. Il compilatore, in sostanza, non si preoccupa di trovare gli indirizzi delle funzioni, di agganciare i riferimenti ecc. Questo dà al programmatore uno spazio di gestione notevole ed un controllo sulle

librerie dellÆapplicazione difficilmente raggiungibile in altro modo. Ovviamente ogni tecnica ha i suoi vantaggi e svantaggi. Questa in particolare ha varie controindicazioni. La prima è, ovviamente, il fattore tempo. EÆ chiaro che se le librerie utilizzate sono grandi e le funzioni sono tante, ci potrebbe essere un notevole dispendio di tempo per caricarle. Inoltre, bisogna sempre ricordarsi di liberare la memoria quando la DLL non serve più. Ed infine un altro aspetto negativo è la grandezza del codice. Ma ci sono tanti vantaggi. Supponiamo, a mero titolo esemplificativo, di voler creare un programma non solo in italiano ma anche in Inglese. Teleologicamente, quella che vi sto presentando, è unÆottima tecnica. Allegato allÆarticolo vi è il programma completo da me sviluppato, molto semplice, che attua questo tipo di tecnica. Non è prevista alcuna gestione degli errori in quel programma û anche perché non ve ne dovrebbero essere. A proposito, Ricordate SEMPRE di richiamare la routine FREELIBRARY dopo aver finito di usare le funzioni della DLL. Il rischio, infatti, è che lÆapplicazione ad ogni avvio successivo fino al restart o allo spegnimento del PC, inizi a fare le bizze dandovi dei criptici errori di runtime che sono dovuti, semplicemente, alla presenza in memoria della DLL in questione. Non dimenticatelo mai.

Ora vi propongo un poÆ di codice tratto dal programma da me realizzato, tanto per darvi una idea di ciò che ho spiegato fin qui :

unit Lang_Intf;

interface

uses Windows;

Type Caption_Text_Func = function : PChar;

procedure InitLanguage( LanguageDLL : String );

function GetFormCaption : String;

function GetButton1Caption : String;

function GetButton2Caption : String;

procedure DoneLanguage;

implementation

var LibHandle : THandle;

Capt_Func1,

Capt_Func2,

Capt_Func3 : Caption_Text_Func;

procedure InitLanguage( LanguageDLL : String );

begin

LibHandle := LoadLibrary( PChar( LanguageDLL ) );

@Capt_Func1 := GetProcAddress( LibHandle,PChar( 'GetFormCaption' ) );

@Capt_Func2 := GetProcAddress( LibHandle,PChar( 'GetButton1Caption' ) );

@Capt_Func3 := GetProcAddress( LibHandle,PChar( 'GetButton2Caption' ) );

end;

function GetFormCaption : String;

begin

Result := String( Capt_Func1 );

end;

function GetButton1Caption : String;

begin

Result := String( Capt_Func2 );

end;

function GetButton2Caption : String;

begin

Result := String( Capt_Func3 );

end;

procedure DoneLanguage;

begin

FreeLibrary( LibHandle );

end;

end.

Riferimenti bibliografici :

On Line Help di Delphi 3.

Requisiti necessari alla corretta comprensione dellÆarticolo:

Conoscenza e sviluppo di DLL per Windows.