|
|
| Import funkcí do Delphi Delphi |
|||||||||||||||||||||||||||||||
|
Zpět
Domů |
Přestože jsou spolu s Delphi dodávány desítky unit importující množství
funkcí ze systémových knihoven, není tato kolekce vždy zcela úplná a ne vždy nám
deklarace od Borlandu musí vyhovovat. V tomto článku si ukážeme, jak importovat
funkce nejen ze systémových knihoven do tohoto populárního vývojového prostředí.
Dynamické knihovny, hlavičkové soubory a SDKJak víme, tak veškeré funkce, které Windows poskytují programátorům (Windows API), se skrývají v dynamicky linkovaných knihovnách (DLL). K tomu, abychom mohli použít některou z funkcí z DLL v našem programu, musíme znát její jméno, počet a typ jednotlivých parametrů, typ návratové hodnoty a volací konvenci. Microsoft poskytuje ke svým knihovnám dokumentaci jako součást Platform SDK (Software Development Kit) nebo on-line na MSDN (Microsoft Developer Network). Deklarace funkcí v SDK je v jazyce v C, stejně jako v hlavičkových souborech, kterými je SDK doprovázena. Pokud máme dostatek informací o funkci a knihovně, ve které je uložena, můžeme přistoupit k samotné deklaraci.Shlwapi.pasAni v posledních verzích Delphi nejsou k dispozici funkce z knihovny shlwapi (shlwapi.dll, Shell light-weight utility API), a to přesto, že některé z nich jsou velmi užitečné. Pojďme si nyní vytvořit vlastní unit tak, abychom mohli tyto funkce využívat ve svých programech. Podívejme se do SDK nebo MSDN na funkciColorHLSToRGB, která
převádí barvu z barevného modelu HLS (hue-luminance-saturation,
odstín-světlost-nasycení) na barevný model RGB (red-green-blue,
červená-zelená-modrá).
Funkce má tři parametry typu WORD reprezentující složky odstínu, světlosti a
nasycení a návratovou hodnotu typu COLORREF. Typ
WORD z Delphi známe, je to celé
neznaménkové číslo o šířce šestnácti bitů, proměnné tohoto typu mohou tedy
nabývat hodnot 0 až 65535. Co je to ale typ COLORREF? Zapátráme-li v SDK,
zjistíme, že datový typ COLORREF je dvaatřicetibitové číslo, které reprezentuje
červenou, zelenou a modrou složku barvy. Zapíšeme-li toto číslo v šestnáctkové
soustavě, jeho tvar bude následující:
bb, gg a
rr jsou hodnoty
modré, zelené a červené složky v rozsahu 0 až 255. Nyní tedy již můžeme napsat
deklaraci funkce ColorHLSToRGB tak, jak bude vypadat v Delphi.
Podíváme-li se
nyní do unit Windows.pas, nalezneme tam následující definici typu
COLORREF:
Můžeme tedy rovnou přehledněji napsat
Většina typů nalezených v SDK je definovaná právě
v unit Windows.pas nebo v unit, jejíž jméno odpovídá hlavičkovému souboru, jehož
jméno nalezneme v SDK pod popisem datového typu. Jméno typu můžeme použít buď
přesně tak, jak jej nalezneme v dokumentaci (viz např.
COLORREF) anebo jako
upravené jméno s písmenem T na začátku (TColorRef). Pokud definici typu v žádné
unit nenalezneme, nezbývá než si tento typ definovat sami. V tabulce jsou
shrnuty nejpoužívanější jednoduché datové typy a typy jim odpovídající v Delphi:
TColor z unit Graphics.pas, což je také vlastně číslo o šířce 32 bitů.
Nejlepší deklarace naší funkce bude tedy
Na konci popisu
každé funkce je uvedeno, v jaké dynamické knihovně je přeložena. O funkci
ColorHLSToRGB se dozvíme, že se nachází v knihovně shlwapi.dll. Pro import
funkce do Delphi použijeme klíčové slovo external:
Pokud jste nyní
zkusili spustit program používající tuto funkci, pravděpodobně havaroval. Na
začátku už jsme se stručně zmínili o volacích konvencích. Delphi běžně používají
volací konvenci register (zvanou také fastcall). Při použití tohoto způsobu se
většina parametrů uloží do registrů procesoru a volání tak může proběhnout velmi
rychle. Funkce Windows API ale používají volací konvenci standard call (existují
vyjímky potvrzující pravidlo), při které jsou parametry volající funkcí uloženy
na zásobník a odtud jsou volanou funkcí vyzvednuty. Protože funkce se snažila
přistoupit do zásobníku pro parametry, které byly ve skutečnosti uloženy
v registrech, došlo při volání k porušení ochrany paměti a následné vyjímce.
Abychom mohli bez obav funkci použít, musíme k deklaraci připsat direktivu
stdcall:
Ukazatele, hodnoty a referencePodívejme se nyní na funkci inverzní kColorHLSToRGB:
Funkce převádí barvu
v modelu RGB na barevné složky H, L a S. První parametr je známého typu
COLORREF
a další tři parametry jsou ukazatele na typ Word (WORD následovaný hvězdičkou).
Funkce "má návratovou hodnotu typu void", v Delphi budeme tedy deklarovat
proceduru (viz tabulka výše):
PWord je
ukazatel na typ Word z Windows.pas:
Volání takové funkce pak
bude vypadat následovně:
Jazyk C neumožňuje na
rozdíl od jiných vyšších programovacích jazyků (včetně C++) předávat parametry
odkazem, ale jen hodnotou. Tento problém se tedy v jazyce C řeší častým
používáním ukazatelů. V Delphi nemáme důvod nevyužít možnosti předávat hodnoty
odkazem proto napíšeme deklaraci lépe:
Nyní můžeme jednodušeji použít
[Tip: Při převádění
systémových barev funkcí ColorRGBToHLS musíte barevnou konstantu (clBtnFace,
clScrollBar) nejdříve převést funkcí ColorToRGB. Je to proto, že typ Delphi
TColor je ve skutečnosti nadmnožinou Windows API typu
COLORREF. Proto je třeba
před předáním typu TColor Windows API funkci provést určitou konverzi.]Protože parametry pwHue,
pwLuminance, pwSaturation slouží jako výstup jednotlivých
složek, je vhodné použít místo klíčového slova var slovo
out abychom předešli
případnému varování kompilátoru o pokusu předat funkci neinicializované proměnné:
Stejně tak v případě, kdy parametr slouží pouze pro předání dat do funkce,
použijeme klíčové slovo const, např. (viz Windows.pas):
[Funkce IsRectEmpty zjistí, zda obsah obdálníku, jehož rozměry
jsou funkci předávny v záznamu typu TRect (všimněme si opět změny názvu z
RECT
na TRect), je nenulový.]U parametrů, které slouží k přenosu dat oběma směry je na místě zachovat klíčové slovo var.Ne vždy je ale takovéto nahrazení ukazatelů ideální. Podívejme se na funkci ExtractIconEx z knihovny shell32.dll: a na
odpovídající deklaraci od Borlandu do souboru ShellAPI.pas:
Funkce v souboru daném parametrem lpszFile najde počet
nIcons velkých a/nebo malých
ikon a jejich handly uloží do pole, na jehož první prvek ukazuje parametr
phiconLarge a/nebo phiconSmall. Funkce tak, jak je deklarovaná v ShellAPI.pas
ale neumožňuje extrahovat jen malé nebo jen velké ikony, v každém případě musíme
extrahovat obě velikosti ikon, neboť do parametru předávanému odkazem nelze
uložit hodnotu nil. Pokud budeme chtít využít popsané možnosti musíme si napsat
vlastní deklaraci této funkce:
type PHICON = ^HICON; function ExtractIconEx(lpszFile: PChar; nIconIndex: Integer; phiconLarge, phiconSmall: PHICON; nIcons: UINT): UINT; stdcall; external 'shell32.dll';Nebo můžeme částečně zachovat výhody předávání parametrů odkazem a vytvořit několik přetížených verzí funkce s různým typem parametrů:
Nyní můžeme použít všechny čtyři kombinace volání:
Řětězce a Ansi vs. UnicodeKnihovna shlwapi obsahuje mnoho užitečných funkcí pro práci s řetězci. Viděli jsme, že většinu datových typů popsaných v dokumentaci můžeme přímo bez nejmenších potíží použít také v Delphi. S řetězci to ale tak jednoduché není. Řetězec v Delphi je vlastně ukazatel na dynamicky alokované pole znaků ukončené znakem s kódem 0. Ovšem před samotným polem znaků se nacházejí ještě dvě položky - jedna obsahuje délku řetězce a druhá počet odkazů na něj. Pokud mezi sebou přiřadíme dva řetězce, nedojde k vytvoření kopie pole znaků, ale pouze se o jedničku zvětší počítadlo odkazů. K vytvoření kopie dojde až v okamžiku změny jednoho z řetězců. Prázdné řetězce (řetězce nulové délky) mají hodnotu ukazatelenil. Všechny popsané operace se v Delphi dějí naprosto automaticky, bez zásahu
programátora.
PChar. Naštěstí, jak tedy vidíme,
stačí při volání API funkcí, které mají řetězcové parametry, přetypovat řetězec
string na ukazatel PChar, konstanty dokonce není nutno ani přetypovat.
V případě různých výstupních bufferů je výhodnější než složitá manipulace s řetězci použít pole znaků indexované od nuly, se kterým lze zacházet
podobně jako s řetězci.
Aby vše nebylo tak jednoduché, není PChar jediný typ řetězců používaných ve
Windows API. Každý prvek řetězce je reprezentován jedním bajtem, tzn. že
obsahuje jeden z množiny 256 znaků. Pro abecedy, jako je např. japonská hiragana
a katakana nebo arabská písma je 256 znaků nedostatečných. Proto bylo zavedeno
kódování Unicode, kde je každý znak reprezentován dvěma bajty, tzn. je k
dispozici přes 60 tisíc znaků. V Delphi byly pro podporu širokých znaků a
řetězců zavedeny typy WideChar,
WideString, pro komunikaci s Windows API slouží
typ PWideChar. Kódování jednobajtových řetězců používaných ve Windows se nazývá
ANSI (podle americké standardizační organizace). V Delphi jsou v současnosti
typy AnsiChar a AnsiString shodné s typy
Char a string. Oba typy řetězců můžeme
v Delphi mezi sebou přiřazovat a přetypovávat, o potřebné konverze se stará
kompilátor bez našeho vědomí. Stejně jako můžeme přetypovat
string na
PChar,
můžeme také WideString přetypovat na
PWideChar. Funkce s
řetězcovými parametry jsou v knihovnách Windows přeloženy většinou ve dvou
variantách: jméno ANSI varianty funkce končí písmenem
A, Unicode
verze má poslední písmeno W:
[Funkce vrací True pokud je cesta k souboru specifikovaná parametrem
lpszPath relativní.]
Ve Windows 95/98/Me jsou domácím typem ANSI řetězce a naopak Windows NT/2000/XP používají Unicode řetězce. To ale neznamená, že ve Windows 9x/Me nemůžeme používat Unicode znaky a funkce a obráceně. Windows 9x/Me používají interně ANSI kódování a při volání Unicode funkce dojde ke konverzi parametru na ANSI řetězec a následně je vyvolána ANSI verze funkce. Ve Windows NT/2000/XP je tomu naopak. Ne všechny funkce mají dvě varianty, např. už jednou zmíněná funkce pro extrakci ikon existuje ve třech formách: ExtractIconExA (ANSI),
ExtractIconExW
(Unicode) a ExtractIconEx (bez postfixu,
také ANSI). To je spíše vyjímečný případ, funkce nově představené ve Windows XP
najdeme v knihovnách už jen ve verzi s kódováním Unicode.V tabulce jsou shrnuty řetězcové typy používané ve Windows API a jim odpovídající typy v Delphi:
LPTSTR, což znamená,
že v knihovně existují obě verze funkce. V C je podle potřeby tento typ
překládán jako ANSI nebo Unicode, stejně tak všechny funkce mají definovány
svoje bezpostfixové jméno, které se podle nastaveného přepínače vyhodnotí jako
ANSI nebo Unicode.Bohužel v Delphi je tento typ vždy překládán jako ANSI, takže vytvořit plně Unicode aplikaci v Delphi je zatím takřka nemožné. Ve Windows.pas nalezneme tisíce podobných řádků:
Direktiva name říká: Budu používat funkci LoadLibrary, ale v knihovně kernel32.dll ji hledej pod jménem
LoadLibraryA.
Funkce s proměnným počtem parametrůNakonec si všimněmě funkcewsprintf:
Na místě výpustky lze při volání funkce dosadit žádnou, jednu nebo více hodnot
různých datových typů. Funkce podle řetězce lpFmt a dodatečných parametrů
naformátuje řetězec a uloží ho do bufferu lpOut. Nyní se podívejme na
překvapení, jaké skrývá unit Windows.pas:
Takto deklarované funkci nemůžeme předat ani jeden dodatečný parametr. Dokonce
ji ani nemůžeme degradovat na pouhé kopírování znaků mezi dvěma řetězci.
Aplikace, která se pokusí použít tuto funkci s největší pravděpodobností dříve
či později havaruje, protože u funkcí s různým počtem parametrů musíme použít
volací konvenci jazyka C. V nových verzích Delphi existuje direktiva
varargs
právě pro import funkcí s různým počtem parametrů. Správná deklarace má tedy
vypadat následovně:
V dřívějších verzích Delphi, které neznají direktivu varargs, je možné vytvořit pro každý případ přetíženou deklaraci s potřebným počtem a typem parametrů.
Naštěstí v knihovnách Delphi existuje v tomto případě funkce
Format, která je v
tomto prostředí mnohem lépe použitelná.
h2pas a jiné nástrojePřevádění hlavičkových souborů do paskalských unit je zdlouhavá a nudná operace, proto existuje několik více či méně zdařilých nástrojů pro automatizaci tohoto úkolu. Jeden z těch zdařilejších se nachází v archivech FreePascalu a jmenuje se symbolicky h2pas. Vstupem je hlavičkový soubor v jazyce C s deklaracemi funkcí a výstupem je unit se stejnými deklaracemi v Pascalu. Nakonec je stejně třeba výslednou unit zkontrolovat a případně poupravit.Slovníček
DownloadStáhnout projekt pro Delphi 5 (19 KB)Stáhnout ukázkovou aplikaci (191 KB) OdkazyDownload Microsoft Platform SDKMicrosoft Developer Network FreePascal |
||||||||||||||||||||||||||||||
| 2003 – 2025 © Manison Softworks. Všechna práva vyhrazena. Poslední aktualizace: 30. 12. 2024 |