Delphi és Win32 API – Nem csak Delphi felhasználóknak: II. rész

Tallózás a mappák között – 2.

A Borland Delphi rendszer számos, a Windowsban (és a Linuxban) használt rendszereszközhöz tartalmaz komponenseket, osztályokat. Mégis érhetetlen módon több elem hiányzik belőle, melyek sokszor vagy csak ritkábban, de jól jönnének egy program fejlesztése során. Most induló cikksorozatunkban ilyen komponenseket fogunk készíteni. A sorozatot más programnyelvek használóinak is ajánlom, hiszen a bemutatott Windows API függvények bizonyára más nyelvekben is elérhetőek.

A múlt számban áttekintettük az SHBrowseForFolder Windows API függvény leírását. Mielőtt azonban hozzáfognánk a komponens megíráshoz, meg kell ismerkednünk még néhány másik API függvénnyel, fogással.

String vs. PChar

Azt kell, hogy mondjam, hogy ezen típusok a Delphiben már gyakorlatilag nem különböznek, hiszen a Delphi 2-től a string típus túllépte a Pascal-ból örökölt hosszúsághatárát. Ezt pedig csak a C-ben ismert nullavégű karakterláncokkal lehetett megoldani. Bár a tárolási módja a két típusnak nagyon hasonló, azért mégsem teljesen ugyanarról a típusról van szó. A PChar-t kifejezetten a C-vel és a Windows API-val való kompatibilitás miatt tették bele a nyelvbe. Minden egyéb helyen a string adattípus használata javasolt.

SendMessage

C++ guruk számára bizonyára ismert függvényről van szó, Delphiben ritkán alkalmazott utasítás, mivel a Delphi pontosan arra jó, hogy az API szintű programozástól megkíméljen bennünket. Mi azonban most ezzel foglalkozunk, vagyis "kénytelenek" leszünk megismerkedni vele. Mint azt az előző részben már említettem, a Windowsban minden egyes ablaknak és vezérlőnek (gomb, beviteli mező, jelölőnégyzet, stb.) van egy azonosítója, az ablak-leíró (window handle). Ez a leíró adattípusát tekintve egy LongWord, vagyis egy előjel nélküli 32 bites egész szám. A Windows, a látszat ellenére, nem objektum orientáltan, hanem esemény orientáltan működik, így ezzel a leíróval tudjuk azonosítani a rendszerben egy adott objektumot. Persze mint azt később látni fogjuk, nem csak ez az egyetlen módja van a kommunikációnak Windowsban. Ha például API szintű utasítással engedélyezni szeretnénk egy gombot, akkor küldeni kell neki egy üzenetet, melyben az ő ablak-leíróját használjuk fel. Ezt az üzenetet a SendMessage függvénnyel tudjuk elküldeni neki. Deklarációja a következő:

function SendMessage(hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;

Paraméterei:

  • hWnd: Ez az a bizonyos ablak-leíró.
  • Msg: Maga az üzenet. Ez szintén egy egész szám, melynek rengeteg értelmezhető értéke van. Természetesen ehhez is tartozik számos konstans, hogy könnyebben lehessen őket megjegyezni. A legtöbb ilyen konstans a "WM_" előtaggal kezdődik.
  • wParam, lParam: A legtöbb üzenetnek szüksége van még valamilyen paraméterre. Kettő LongInt típusú paraméter áll rendelkezésére, melyek értelmezése üzenetenként változó. Felmerülhet a kérdés, hogy akkor csak LongInt paramétereket lehet átadni? A válasz: igen is meg nem is. Például átadhatunk egy rekordot is, ha annak valójában annak mutatóját adjuk át, ami szintén egy egész szám. Ily módon pedig már mindenféle adattípust meg lehet adni.

A Delphi használata során minden vezérlőnek létezik egy publikus Handle tulajdonsága. Ezt felhasználva számos, a Delphiben egyébként már megoldott utasítást lekezelhetünk a SendMessage használatával. Egy egyszerű példa: Kezdjük egy új projektet, dobjunk egy gombot az ablakra, az OnClick eseménykezelőbe pedig írjuk be a következő sort:

SendMessage(Handle, WM_CLOSE, 0, 0);

Ha most futtatjuk a programot és rákattintunk a gombra, az ablak bezárul. Most dobjunk egy másik gombot is az ablakra és az előző sort írjuk át a következőre:

SendMessage(Button2.Handle,WM_SETTEXT,0,LongInt(PChar('Valami')));

Itt most láthatjuk azt is, hogyan lehet nem egész szám típusú értéket átadni. Erről az ún. típus kaszttolásról a cikksorozat egy későbbi részében még bővebben fogunk beszélni.

SHGetSpecialFolderLocation

Szintén az előző részben említettem, hogy a Windows a fájl-útvonalakat nem egyszerű karakterláncokkal kezeli, hanem egy amolyan láncolt listában, lehetővé téve ezzel az ún. rendszermappák (Sajátgép, Vezérlőpult, stb.) használatát. Valahogy tehát elő tudjuk állítani ezen speciális mappák útvonalát is. Ebben segít a SHGetSpecialFolderLocation függvény. Deklarációja a következő:

function SHGetSpecialFolderLocation(hwndOwner: HWND; nFolder: Integer; var ppidl: PItemIDList): HResult; stdcall;

Paraméterei:

  • hwndOwner: Talán már nem is kell magyaráznom ezen paraméter értékét. A teljesség kedvéért: a hívó rutinhoz tartozó ablak leírója.
  • nFolder: Ez egy konstans szám, mely azonosítja a rendszermappát. Néhány példa (a teljes lista megtalálható lesz a kész komponens fájljában):

CSIDL_DESKTOP

=

$0000;

//Asztal

CSIDL_CONTROLS

=

$0003;

//Vezérlőpult

CSIDL_DRIVES

=

$0011;

//Sajátgép

  • ppidl: ide fogjuk visszakapni az elem ID listáját.

A függvény nullával tér vissza (NOERROR konstans), ha sikeres volt az átalakítás.

Jogos a kérdés: hogyan tudunk egy egyszerű elérési útvonalat átalakítani. Nos, egy külön 2-3 részes sorozat témája lehetne ennek taglalása, egyelőre elégedjünk meg annyival, hogy erre is van kiskapu, melyet alkalmazni is fogunk.

SHGetPathFromIDList

Ha már átalakítottunk egy elérési útvonalat, vissza is szeretnénk alakítani. Ehhez is van persze megfelelő függvényünk. Deklarációja:

function SHGetPathFromIDList(pidl: PItemIDList; pszPath: PChar): BOOL; stdcall;

Paraméterei:

  • pidl: Az átalakításra váró ID lista.
  • pszPath: Idekapjuk vissza az átalakított elérési útvonalat. Ezt Delphiben egy MAX_PATH méretű, Char típusú tömbbel fogjuk megoldani, melynek a mutatóját fogjuk itt átadni.

A függvény TRUE értékkel tér vissza, ha a konverzió sikeres volt.

SHGetMalloc

Mint már említettem, nem csak ablak-leírókkal kommunikál a Windows. Másik használt mód az interfészek használata. Ezek már félig-meddig objektum orientált megvalósításra emlékeztetnek. Részletesebben az interfészekről később fogunk szólni, most mégis meg kell említenünk őket, mert a ID listák kapcsán szükség van egy ilyen interfészre. Mint ahogy létezik Delphi konvenció az osztályok elnevezésére (Txxxxx), úgy a Windows interfészekre is, mégpedig az "I" előtag. Az SHGetMalloc függvénnyel a rendszernek egy IMalloc interfészéhez férhetünk hozzá, mely a memória kezelésével foglalkozik. Ezen interfész Free metódusával lehet az ID listák által lefoglalt memóriát felszabadítani, amennyiben azokra már nincs szükségünk.

Most már gyakorlatilag minden szükséges tudás a rendelkezésünkre áll, hogy nekilássunk a Delphi komponenst megírására.

Geiger Tamás