DLL, Delphi a FastMM4

vložil Radek Červinka 7. května 2010 23:01

Pravidelní čtenáři již vědí co je FastMM4, pro ty dva zbývající: nejlepší správce paměti, defaultní správce paměti pro Delphi 2005+, detektor chyb v uvolňování a v neposlední řadě náhrada ShareMem alias BorlndMM.dll, což je ve starších verzích Delphi originální možnost pro předávání dat do DLL - což ale předbíháme.

Trocha nutné teorie o DLL

DLL (aka Dynamic Linked Library - dynamická připojovaná knihovna) je jedním ze základních kamenů (nejen) Windows, přičemž hlavním smyslem bylo umožnit programům sdílet programový kód, případně rozšiřovat jejich možnosti. Nebudu to moc rozpitvávat, je o tom dost textů, spíše se zaměřím na některé specifika.

String alias řetězec je v Delphi provozován velmi efektivně. Kromě jiného má implementováno počítání referencí, copy on write (tj. rozkopírování řetězce až při zápisu) a další techniky pro urychlení. Pokud bych na něco zajímavého zapomněl, tak můžete použít komentáře, přece jen řetězce v Delphi jsou trošku magie kompilátoru.

Takové vlastnosti ale potřebují trošku speciální podporu, kterou právě dodává správce paměti. Problémem je, že pokud napíšeme DLL, nelze přímo spojit správce paměti hlavního programu se správcem paměti, který je vkompilován do DLL. Když nic neuděláme, tak jak hlavní program tak DLL bude používat vlastního správce paměti, což by v nejhorším nevadilo, tedy pokud nechceme předávat řetězce, třídy obsahující řetezce nebo záznamy mezi aplikací a DLL.

Na druhou stranu, pokud chceme aby naše DLL používal i někdo bez Delphi, musíme se předávání klasických řetězců vyvarovat a použít buďto PChar nebo ShortString, což je pole znaků, nebo pole znaků. Ale toto teď řešit nebudeme.

To bohužel ještě není úplně vše. Je třeba i definovat volací konvenci.

Volací konvence

Co je to volací konvence? Jedná se o způsob, jak jsou předávány parametry mezi vykonávaným programem a procedurou. V podstatě existuje pět způsobů, ale pro funkce exportované z DLL se primárně používá jen jeden. Liší se pořadím parametrů (tj. zprava doleva PL nebo zleva doprava LP) a tím, kdo uklidí zásobník

  • Fast-Call (register) - LP, primárně používaná konvence v Delphi (první tři parametry se předávají přes registry, zbytek jako Pascal), nejrychlejší, pokud nic neuvedete, tak bude použita tato
  • StdCall - PL, doporučené pro funkce exportované z DLL, standard ve Win32
  • Pascal - LP, standard ve Win16
  • Cdecl - PL, jediná volací konvence, kde se o úklid zásobníku stará volající kód, nikdy jsem nepochopil smysl
  • Safecall - PL, nahradí Delphi výjimky na COM chyby

Nejčastější chybou je použití špatné volací konvence. Správně by to měla být StdCall, některé knihovny v C exportují jako Cdecl.

Poslední věcí než si úkážeme nějaký kód je zmínka o speciálních DLL knihovnách pro Delphi - balíčky (BPK). Ale o tom až někdy příště.

Vlastní DLL

První se rozhodněte, zda DLL bude používána jen z Delphi a C++Builderu, nebo dáte šanci o jiným. Já momentálně předpokládám, že ne - tj. Delphi Only. V takovém případě je vhodné zvážit použití balíčků, ale to teď neřeším.

Uděláme DLL knihovnu, která bude demonstrovat použití řetězců za pomoci FastMM4. Pokud nepoužijeme FastMM (tj. do Delphi 7 bez externího FastMM4) musíme distribuovat i BorlndMM.dll (která zaručí uvedené propojení), což se mi ekluje, nebo můžeme použít FastShareMem, což je jeden unit, který pokud je uveden jako první dokáže propojit správce paměti aplikace a DLL bez uvedené BorlndMM.dll.

To samé jako FastShareMem umí i FastMM, jen budete mít navíc i lepšího správce paměti. Takže konec řečí.

    1library testdll;
    2
    3uses
    4  SimpleShareMem; // pouzije FastMM4 integrovane v Delphi - neni treba borlandmm.dll
    5
    6procedure TestString(var sTestString:ansistring);  stdcall;
    7begin
    8  sTestString := 'string z dll';
    9end;
   10
   11exports
   12  TestString; // pozor na velká a malá písmena!
   13end.

SimpleShareMem musí být první uvedený unit. Kód uložte pod jménem testdll.dpr a po kompilaci se vytvoří testdll.dll, což je naše rozmilá DLL knihovna, která exportuje jednu a jen právě jednu funkci TestString (pozor na velikost písmen). Pokud by bylo třeba exportovat více, oddělujte jména čárkami.

Statické linkování

Nyní máme DLL, tak ji použijeme. Nejdříve staticky, tj. necháme Delphi ať zařídí co je třeba, my jen řekneme v které knihovně má funkci hledat.

Vytvoříme konzolovou aplikaci (ať se nám to neplete) app.dpr.

    1program app;
    2
    3// staticke linkovani
    4uses
    5  SimpleShareMem, // <- pouzije FastMM4 integrovane v Delphi
    6  sysutils;
    7{$APPTYPE CONSOLE}
    8
    9const
   10 lib  = 'testdll.dll';    // jmeno knihovny
   11
   12
   13procedure TestString(var sTestString:ansistring); // deklarace externi funkce z dll
   14  stdcall; // volaci konvence
   15  external lib // v knihovne
   16  name 'TestString'; // exportovane jmeno
   17
   18var
   19 s: ansistring;
   20begin
   21try
   22  TestString(s);
   23  writeln(s);
   24  readln;
   25except
   26  on e: Exception do
   27    writeln(e.Message);
   28end;
   29end.

SimpleShareMem musí být první uvedený unit. AnsiString je neunicode string, ať nedojde ke zmatení.

Řádky 13 - 16 říkáme linkeru Delphi, že se jedná o externí funkci, kde ji má najít ('testdll.dll'), jak se jmenuje (name 'TestString'), jak ji má volat (StdCall) a jaké má parametry (musí odpovídat).

Zavedení knihovny je automaticky po startu programu a my se o nic nestaráme.

Dynamické linkování

Statické linkování je pohodlné, ale taková knihovna je v paměti po celou dobu, což v případě, že ji potřebujeme jen někdy v určité části programu není ideální. Tehdy je výhodné použít dynamické linkování. Pro představu: určitě znáte EasterEgg v Delphi - v about boxu držte ALT a napište TEAM, což zobrazí seznam autorů (mimochodem těch slov je možno zkusit více). Ve starších verzích Delphi seznam vypadal jako úvodní titulky hvězdných válek a byl dělán v OpenGL, které se dotáhlo právě v okamžiku zobrazení tohoto vajíčka, takže do té doby nezabíralo v paměti nic.

Implementačně je to krapet složitější, ale ne zas tak moc. Zato máte plnou kontrolu nad zaváděním a uvolňováním. Použijeme stejnou DLL, ale program bude jiný - soubor dynapp.dpr .

    1program dynapp;
    2
    3// dynamicke linkovani
    4uses
    5  SimpleShareMem, // <- pouzije FastMM4 integrovane v Delphi
    6  sysutils, Windows;
    7{$APPTYPE CONSOLE}
    8
    9const
   10 lib  = 'testdll.dll';    // jmeno knihovny
   11
   12type
   13  // prototyp funkce z DLL - typ procedura
   14  TTestStringProc = procedure (var sTestString:ansistring); stdcall;
   15
   16
   17var
   18 s: ansistring;
   19 TestString: TTestStringProc; // vlastni funkce
   20 hDLLHandle: HModule; // handle pro DLL
   21
   22begin
   23try
   24  hDLLHandle := LoadLibrary(lib); //zaved DLL
   25  if hDLLHandle <> 0 then
   26  begin
   27    try
   28      // najdi exportovanou funkci
   29      TestString := GetProcAddress(hDLLHandle, 'TestString');
   30      if Assigned(TestString) then // povedlo se?
   31      begin
   32        TestString(s); //získej řetezec
   33        writeln(s);
   34      end
   35      else
   36        writeln('Knihovna neexportuje pozadovanou proceduru.');
   37    finally
   38      FreeLibrary(hDLLHandle);
   39    end;
   40  end
   41  else
   42    writeln('Nemohu nalezt dll knihovnu '+lib);
   43  readln;
   44except
   45  on e: Exception do
   46    writeln(e.Message);
   47end;
   48end.

Pokud si to vhodně objektově zapouzdříte, tak to není ani moc složité.

Nyní si za pomocí FastMM klidně můžete vytvořit DLL a předávat jí parametry libovolného typu.


Nabízíme Delphi školení a konzultace na různá témata, primárně ve Vaší firmě.

Tagy: , , ,

Praxe

Komentování ukončeno

Naše nabídka

Partial English version.

MVP
Ing. Radek Červinka - Embarcadero MVP
profil na linkedin, Twitter:@delphicz

Nabízím placené poradenství a konzultace v oblasti programování a vývoje SW.
Dále nabízíme i vývoj speciálního software na zakázku.

Neváhejte nás kontaktovat (i ohledně reklamy nebo burzy práce).

Pokud chcete podpořit tento server libovolnou částkou, můžete použít PayPal. Moc děkuji.

Delphi Certified Developer

O Delphi.cz

Delphi je jediný moderní RAD nástroj podporující tvorbu nativních aplikací pro platformu Win32, Win64 , Mac OSX a na iPhone a Android (s výhledem na další platformy díky FireMonkey) na současném trhu (včetně Windows 8.1).

V současnosti je světová komunita přes dva miliónů vývojářů.

Delphi.cz je nezávislý portál pro uživatele Delphi. Portál není koncipován pro úplné začátečníky, i když i ti se zde nebudou nudit, ale spíše na programátory, kteří již něco znají a chtějí své znalosti dále rozvíjet a sledovat novinky.

Anketa

Poslední komentáře

Comment RSS