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

Tipy a triky v Delphi, díl 170. – DLL knihovny

Jan Šindelář 19.1.2005

Dnes si odpočineme od tématu sítí a vzdáleného ovládání počítače a skočíme na úplně jiné téma, o které si také často píšete. Podíváme se trochu na zoubek DLL knihovnám.

V tomto prvním seznámení s dynamickými knihovnami nebudeme příliš zabíhat do detailů a spíše než povídání přímo o samotných knihovnách si ukážeme jeden jednoduchý příklad se zdroji. K bližšímu popisu tohoto tématu se dostaneme určitě někdy příště, neboť si o tuto problematiku poměrně často píšete. Pro dnešek nám bude stačit krátký obecný úvod.

DLL knihovny (Dynamic link libraries) jsou vlastně základem celého systému Windows. Ponechme teď stranou diskuse o tom, zda je využívání těchto knihoven metodou dobrou či špatnou a berme jejich existenci prostě jako fakt. Ať už je realita jakákoliv, počáteční myšlenka zřejmě nebyla špatná. Do knihoven se uloží funkce či další zdroje a aplikace je pak budou z těchto knihoven volat. Výhodou je (obzvlášť u systémových programů), že může více programů pracovat se stejnou knihovnou, která je ovšem v paměti pouze jednou a navíc se z ní může dynamicky podle potřeby odstraňovat a znovu načítat. Tím dochází k šetření zdrojů a jejich sdílení mezi jednotlivými aplikacemi. Realita je poněkud horší, nicméně původní myšlenka má něco do sebe, i když jsem ji zde podal velmi zjednodušeně.

Co je zajímavé čistě z programátorského hlediska je to, že vzhledem k tomu, že DLL knihovny jsou vlastně již přeložené zdrojové kódy a existuje jednotný způsob, jak uvnitř uložené funkce volat, je vlastně lhostejné, ve kterém vývojovém nástroji (resp. programovacím jazyku) byly původně vytvořeny. Můžete tak v Delphi aplikacích používat DLL knihovny vytvořené třeba v C++ a podobně. DLL knihovny mohou navíc sami používat (stejně jako unity v Delphi) funkce z jiných DLL knihoven.

Tolik tedy velmi stručný nástin, co vlastně DLL knihovny umí a pojďme k dnešnímu příkladu. Použijeme jednu důležitou vlastnost těchto knihoven a sice tu, že stejně jako exe soubory mohou uchovávat ve svých zdrojích užitečná data jako jsou především grafika, ikony, textové řetězce či libovolná binární data. Ukážeme si, jak takovou DLL knihovnu vytvořit, jak do ní uložit obrázek a jak tento obrázek pak zpětně vyvolat v naší aplikaci. Tímto způsobem si pak později můžete navrhnout i vlastní systém pro aktualizaci vaší aplikace přes internet. Nebude pak nutná změna celého exe souboru aplikace nebo dokonce její přeinstalace, ale uživatel si pouze stáhne aktualizovanou knihovnu. Ta může obsahovat optimalizované funkce (pro větší rychlost či stabilitu vašeho programu), přičemž samotná aplikace zůstane beze změn. Samotný exe soubor se nám pak vlastně scvrkne na "pouhé" uživatelské rozhraní, které se nemusí příliš měnit, přičemž výkonná část kódu je v knihovnách.

Občas se setkáme s tím, že formou DLL knihoven jsou distribuovány i různé jazykové verze aplikací. Ano, i takto lze systém využít, i když v tomto konkrétním případě to nepovažuji za příliš šťastné, neboť pro překlady se daleko lépe hodí obyčejný (a tím pádem snadno editovatelný) textový soubor.

Teď už ale nastal čas pro náš program. Dnešní příklad má dvě části - knihovnu a aplikaci. Logicky musíme nejprve začít knihovnou, neboť tu pak bude aplikace využívat. Připravíme si libovolnou ikonku, kterou budeme posléze kompilovat do zdrojů. Obvyklým způsobem si připravíme zdrojový soubor s koncovkou rc, který bude obsahovat seznam zdrojů. V našem případě pouze název ikonky, typ a cestu k souboru. Může tedy vypadat například nějak takto:

bird ICON bird.ico

Soubor pak zkompilujeme pomocí BRCC32.EXE, který nalezneme v adresáři {Delphi}\Bin. Tento postup jsme už dělali mnohokrát, takže nemá cenu zabředávat do detailů. Výsledkem snažení by zkrátka měl být soubor se zdroji (s jednou ikonkou) s koncovkou res.

Teď přichází na řadu Delphi. Vytvoříme nový projekt, ale jako typ nezvolíme aplikaci, nýbrž DLL knihovnu. Předem připravený projektový soubor pak upravíme do této podoby:

library Project1;

{$R knihovna.RES}

begin
end.

Vidíte, že toho v kódu opravdu moc není. Pouze zmínka o tom, že se jedná o knihovnu, dále odkaz na načítání připravených externích zdrojů (hotový res soubor nezapomeňte nakopírovat do stejného adresáře, ve kterém vytváříme knihovnu) a prázdné tělo knihovny. To je vše. Projekt zkompilujte a výsledkem by měla být maličká DLL knihovna.

Teď přichází na řadu její využití. Vytvoříme si opět nový projekt, tentokrát už regulérní aplikaci, a do její složky zkopírujeme vytvořenou DLL knihovnu. Na formulář přidáme tlačítko a následujícím kódem vyvoláme uložený obrázek:

procedure TForm1.Button1Click(Sender: TObject);
const
  resICON = `bird`;
var
  h : THandle;
  Icon : HIcon;
begin
  h := LoadLibrary(`Project1.dll`);
  try
    if h <> 0 then
    begin
      Icon := LoadIcon(h, resICON);
      DrawIcon(Canvas.Handle, 10, 10, Icon);
    end
    else
    begin
      ShowMessage(`Chyba při načítání zdroje z DLL knihovny`);
    end;
  finally
    FreeLibrary(h);
  end;
end;

V konstantě je uložen název zdroje tak, jak jste jej pojmenovali v původním RC souboru. U funkce LoadLibrary pak musíte správně vyplnit jméno vaší DLL knihovny a to je vše. Uložená ikona bude načtena a zobrazena.

Dnešní příklad byl opravdu velmi jednoduchý a ukázal nám pouze elementární možnosti DLL knihoven. Však také samotný kód knihovny neobsahoval kromě názvu a odkazu na externí soubor se zdroji vůbec nic. Složitější příklady si ale ukážeme zase někdy příště.

Ukázkovou aplikaci i s knihovnou si můžete opět stáhnout.