Živě.cz o počítačích a internetu

Tipy a triky v Delphi, díl 175. – balíky BPL (dokončení)

Jan Šindelář 9.3.2005

Čeká nás dokončení povídání o balících BPL. Tentokrát si ukážeme jejich dynamické připojování k aplikaci. Ideální způsob pro tvorbu zásuvných modulů.

V minulém dílu seriálu jsme si říkali několik základních informací o balících BPL a ukazovali jsme si jejich statické linkování. Vše spočívalo vlastně jen v tom, že jsme v příslušném dialogu nastavení projektu přidali do seznamu připojených balíků náš vlastní.

Tento způsob má však jisté nevýhody. Je vhodné jej použít pro standardní balíky VCL, ale pokud naše aplikace používá mnoho oddělených balíků (přičemž každý ukrývá samostatný formulář a funkce), je lépe je volat dynamicky. Ušetří se tak paměť a zdroje, neboť budeme zavádět vždy jen ten balík, který bude potřeba. Aplikace bude startovat rychleji a jednou z výhod je rovněž to, že aplikace může ošetřit událost, kdy není balík dostupný. V případě statického připojení je aplikace ukončena, pokud není potřebný balík nalezen. U dynamického linkování lze na tento stav adekvátně reagovat.

Náplní dnešního dílu bude tedy vytvořit nový balík s jednoduchým formulářem, ten poté dynamicky připojit k aplikaci a příslušný formulář z balíku vyvolat. Právě poslední úkol bude poněkud komplikovanější, ale o tom až později.

Nejprve tedy nový balík. Vytvoříme jej stejně jako v předchozím případě. Začneme tím, že si vytvoříme nový formulář. Na něj můžeme přidat libovolné komponenty a kvůli další části příkladu dáme na formulář rovněž Memo a Checkbox. To proto, že si v další části článku ukážeme, jak tyto komponenty ovládat, tj. číst jejich stav a nebo jej měnit. Není to ovšem všechno, co musíme s formulářem udělat. S vyvoláním formuláře totiž nastává menší potíž. Máme-li balík připojen staticky jako v minulém příkladu, problém žádný není, protože příslušný unit formuláře z balíku přidáme do uses naší aplikace a můžeme jej rovnou volat. U dynamického propojení však do seznamu používaných knihoven nic nepíšeme a proto nemůžeme volat objekty formuláře přímo. O jeho zobrazení i ukončení se musíme postarat sami pomocí funkce, kterou si pro tento účel vytvoříme a přidáme do unitu formuláře. Nazveme ji Execute, bude se nacházet v implementační části a podobně jako u DLL knihoven ji vyexportujeme, aby byla dostupná z vnějšku. Abychom si ukázali ještě další možnosti, opatříme funkci dvěma parametry. První bude vstupní a umožní nám poslat funkci text, který bude poté zobrazen v komponentě Memo na formuláři. Druhý parametr nám umožní zjistit, zda-li uživatel před uzavřením formuláře zaškrtnul CheckBox. Zdrojový kód funkce včetně exportu pak bude vypadat takto:

function Execute (const MemoText: string; chbox: boolean): boolean;
begin
Result := False;
Form1 := TForm1.Create(nil);
try
  with Form1 do begin
  Memo1.Text := MemoText;
  CheckBox1.Checked := ChBox;
  ShowModal;
  Result := CheckBox1.Checked;
  end;
finally
  Form1.Release;
end;
end;

exports Execute;

Máme-li formulář připraven a uložen, můžeme přistoupit k tvorbě balíku, přičemž postup je shodný s tím, který jsme si popisovali minule. Tedy zvolíme z menu File -> New možnost Package. Tlačítkem Add přidáme do balíku náš připravený soubor PAS, nezapomeneme v Options zvolit typ balíku Runtime only a vše zkompilujeme tlačítkem Compile.

Balík je připraven, takže zbývá poslední část - vytvořit nový projekt a balík použít. Založíme si tedy novou aplikaci, vytvořený BPL balík zkopírujeme do stejné složky a na formulář vložíme tlačítko, které bude volat funkci Execute, uloženou v balíku. Samotné volání funkce sice není nijak komplikované, ale musíme využít několika pomocných funkcí. Především se jedná o funkci LoadPackage, která načte balík z externího souboru. Dále pak funkce GetProcAddress, která nám umožní přístup k příslušné funkci balíku (v našem případě funkci Execute). Funkci Execute poté spustíme s příslušnými parametry a na závěr pak nesmíme pomocí UnloadPackage balík opět uvolnit.

procedure TForm1.Button1Click(Sender: TObject);
var
phm: HModule;
ExecF: function(const p1: string; p2: boolean): boolean;
MemoText: string;
ChB: boolean;
begin
MemoText :=`Testovaci text, ktery bude zobrazen v Memu`;
phm := LoadPackage(ExtractFilePath(ParamStr(0)) + `Package1.bpl`);
if phm <> 0 then
  try
    @ExecF := GetProcAddress(phm, `Execute`);
    if Assigned(ExecF) then
      if ExecF(MemoText, ChB) then ShowMessage(`Zatrzitko zaskrtnuto`)
                              else ShowMessage(`Zatrzitko nebylo zaskrtnuto`)
                        else ShowMessage (`Funkce Execute nebyla v baliku nalezena!`);
  finally
  UnloadPackage(phm);
  end
else ShowMessage (`BPL balik nebyl nalezen!`);
end;

A jsme ve finále, nic víc už nás dneska nečeká. Umíme tedy vytvořit nový balík, umíme do něj vložit funkce, formuláře a další součásti a balík pak umíme připojit staticky a dynamicky. Právě dynamický způsob je pak ideální pro tvorbu rozličných zásuvných modulů do našich aplikací.