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 – 2021 © Manison Softworks. Všechna práva vyhrazena. Poslední aktualizace: 16. 12. 2023 |