V druhej časti seriálu o Windows API si povieme niečo o funkciách, makrách a dátových typoch. Spomenieme tiež dôležitý pojem handleru. Pri štúdiu Windows API funkcií je treba mať na pamäti fakt, že pre Microsoft bola spätná kompatibilita jednou z dôležitých priorít.
Funkcie
Windows API je súborom tisícov funkcií určených pre vykonávanie rôznych úloh. Dokumentáciu k týmto funkciám nájdeme na Microsoft Developer Network (MSDN). Pozrime sa na deklaráciu funkcie GetLastError()
:
DWORD WINAPI GetLastError(void);
Funkcia vracia poslednú chybovú hodnotu volaného vlákna. Návratovou hodnotou funkcie je DWORD
, čo je 32-bitová celočíselná hodnota bez znamienka. DWORD
je jedným zo zabudovaných dátových typov Windows. Je garantované, že DWORD
bude mať 32 bitov na všetkých počítačoch a kompilátoroch. Východzie dátové type jazyka C, ako sú int
alebo long
, môžu mať rozličné veľkosti na rôznych kompilátoroch. Typ DWORD
bol zavedený dávno pred tým, ako bol int32_t
zavedený do špecifikácie jazyka C99.
WINAPI
je dekoráciou funkcie, ktorá určuje jej volaciu konvenciu. Volacia konvencia udáva, akým spôsobom sa argumenty funkcie uložia a manažujú na zásobníku. Dekorácia sa preloží na __stdcall
.
BOOL WINAPI SetWindowText( _In_ HWND hWnd, _In_opt_ LPCTSTR lpString );
Toto je deklarácia funkcie SetWindowText()
, ktorú môžeme nájsť na MSDN. Funkcia zmení text titulku okna. BOOL
je ďalším dátovým typom Windows. Podobne ako pri DWORD
, BOOL
bol vytvorený dávno pred tým, ako bol Boolean typ zavedený do C99.
V skutočnosti je pod pokrievkou SetWindowText()
makrom, ktoré sa transformuje na SetWindowTextA()
alebo SetWindowTextW()
v závislosti od toho, či máme zostavu Unicode alebo ANSI. Typ LPCTSTR
sa takisto transformuje na LPCSTR
alebo na LPCWSTR
.
BOOL WINAPI SetWindowTextA(HWND, LPCSTR); BOOL WINAPI SetWindowTextW(HWND, LPCWSTR);
Toto sú deklarácie funkcií na ktoré sa transformuje makro SetWindowText()
. V minulosti bolo bežné, že sa programy zostavovali aj v ANSI aj v UNICODE. Bolo to preto, že vývojári chceli podporovať staršie verzie Windows (Windows 95/98/ME), ktoré nemali podporu UNICODE. V súčasnosti ide už o prežitok. Dnes sa programy zostavujú pre UNICODE a volajú sa priamo UNICODE funkcie.
_In_
a _In_opt_
sú takzvané SAL anotácie. Microsoft source-code annotation language (SAL) je množinou anotácií, ktoré opisujú ako funkcia používa svoje parametre, aké predpoklady vytvára o parametroch a aké garancie dáva, keď sa ukončí. Anotácia _In_
hovorí, že parametrom je hodnota určená len na čítanie. Anotácia _In_opt_
prezrádza, že parameter je voliteľný a že je určený len na čítanie. SAL anotácie sú využívané rôznymi statickými analyzátormi a poskytujú tiež dodatočné informácie vývojárom pre ich hlbšie porozumenie.
CopyFile() CopyFileEx() CopyFile2()
Často natrafíme na názvy funkcií, ktoré sa líšia sufixmi. Dôvodom je znova snaha o zachovanie spätnej kompatibility. Časom došli vývojári k poznaniu, že funkcia nespĺňa všetky požiadavky, resp. bolo potrebné pridať ďalšiu funkcionalitu. Keďže však jazyk C nepodporuje polymorfické funkcie, vznikli nové funkcie líšiace sa príponami.
Windows dátové typy
Windows API definuje svoje vlastné dátové typy. Tieto dátové typy definujú návratové hodnoty funkcií, parametre funkcií a správ a členy štruktúr. Windows dátové typy sú písané veľkými písmenami. Niektoré z definovaných typov neexistovali v jadre jazyka C v čase písania Windows API. (Fundamenty Windows API vznikli v osemdesiatych rokoch.)
- VOID
- SHORT
- INT
- LONG
- FLOAT
- CHAR
Toto sú duplikáty existujúcich dátových typov v C. Boli zavedené kvôli úplnosti.
- WORD
- DWORD
- DWORDLONG
- USHORT
- ULONG
- UCHAR
- UINT
Tieto dátové typy boli odvodené z existujúcich dátových typov. Napríklad DWORD
je definovaný nasledovne:
typedef unsigned long DWORD;
Ide o 32-bitovú celočíselnú hodnotu v rozmedzí od 0 do 4294967295.
- HDC
- HFILE
- HCURSOR
- HFONT
- HICON
Toto sú handlery k zdrojom Windows. Napríklad HFILE
je handler k otvorenému súboru.
Existujú viaceré reťazcové dátové typy. LPSTR
je long ukazovateľ na reťazec (long ukazovateľ je relikt 16-bitových Windows), LPCSTR
je long ukazovateľ na konštantný reťazec, LPWSTR
je long ukazovateľ na široký reťazec a LPCWSTR
je long ukazovateľ na konštantný široký reťazec.
int WINAPI lstrlenW(LPCWSTR lpString);
Funkcia lstrlenW()
vypočíta dĺžku reťazca so širokými znakmi. Funkcia prijíma typ LPCWSTR
.
WPARAM
, LPARAM
a LRESULT
sú typy pre doručenie a návrat polymorfických hodnôt. V minulých verziách Windows boli parametre posúvané oknu v dvoch formátoch: 1) 16-bitový parameter WORD
a 32-bitový parameter LONG
. Tieto parametre boli definované ako WPARAM
(16-bitov) a LONG
(32-bitov). V súčasnosti, v moderných 64-bitových Windows sú oba parametre WPARAM
a LPARAM
64-bitové. Z dôvodu zachovania spätnej kompatibility sa ich názvy nemenili.
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
Toto je deklarácia Windows procedúry, čo je užívateľsky definovaná callback funkcia, ktorá spracúva správy posielané oknu. LRESULT
je dátový typ určený pre výsledok spracovanie správ. CALLBACK
je volacia konvencia určená pre callback funkcie; interne sa prekladá na __stdcall
. WPARAM
je dátový typ prvého parametra funkcie a LPARAM
je dátový typ druhého.
Handlery
Vo Windows API je objektom dátová štruktúra, ktorá reprezentuje systémový zdroj, napríklad súbor, vlákno alebo obrázok. Handler je unikátnym identifikátorom objektu. Handlery sú posúvané funkciám Windows API prostredníctvom ktorých sa vykonávajú rôzne úkony.
Aplikácia nemôže priamo pristupovať k dátam objektu alebo systémovým zdrojom, ktoré objekt reprezentuje. Aplikácia musí získať handler objektu, pomocou ktorého skúma alebo modifikuje systémový zdroj. Windows API má typ HANDLE
na identifikáciu handlerov.
Pomocou HANDLE
sa definujú handlery k rôznym druhom zdrojov. Nasleduje zoznam niekoľkých definovaných handlerov:
- HWND — handler k oknu
- HPEN — handler ku kreslacemu peru
- HICON — handler k ikonke
- HBITMAP — handler k bitmape
- HFONT — handler k fontu
- HBRUSH — handler k výplni
- HMENU — handler k menu
- HFILE — handler k súboru
Majme napríklad funkciu CreateWindowEx()
, ktorá slúži na vytvorenie okna.
HWND WINAPI CreateWindowEx(DWORD dwExStyle, LPCTSTR lpClassName, LPCTSTR lpWindowName, DWORD dwStyle, int x, int y, int nWidth, int nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam );
Typ návratovej hodnoty je HWND
, čo je handler okna.
BOOL WINAPI SetWindowTextW(HWND hWnd , LPCWSTR lpString);
Tento handler sa neskôr použije napríklad vo funkcii SetWindowTextW()
, ktorá nastavuje titulok okna. Používaním handleru sa interná štruktúra okna skrýva pred programátorom, ktorý nemusí vedieť nič bližšie o štruktúre okna a jej členoch.
Makrá
Windows API obsahuje množstvo makier. Makrá nám uľahčujú prácu v rôznych oblastiach. Nasledovný zoznam obsahuje zopár užitočných makier:
- COLORREF
- RGB
- HIWORD
- LOWORD
- MAKELPARAM
- MAKEWPARAM
Napríklad makro COLORREF
sa používa na špecifikovanie farby vo formáte RGB
, HIWORD
získa horné slovo z 32-bitovej hodnoty a MAKELPARAM
vytvára hodnotu, ktorá sa použije ako lParam
parameter v správe.
Príklad
Na záver si uvedieme krátky príklad, v ktorom si demonštrujeme spomenuté koncepty.
#include <windows.h> #include <strsafe.h> #include <wchar.h> #define BUF_LEN 8191 int wmain(void) { WCHAR buf[BUF_LEN] = {0}; HRESULT r = StringCchGetsW(buf, ARRAYSIZE(buf)); if (SUCCEEDED(r)) { wprintf(L"You have entered: %ls\n", buf); } else { wprintf(L"StringCchGetsW() failed\n"); return 1; } return 0; }
V príklade načítame riadok zo štandardného inputu a vypíšeme ho späť na konzolu.
#include <strsafe.h>
V súbore strsafe.h
sa nachádza definícia funkcie StringCchGetsW()
.
#define BUF_LEN 8191
Podľa dokumentácie MSDN môže mať maximálny input dĺžku 8191 znakov. Túto hodnotu použijeme pri tvorbe poľa, do ktorého uložíme užívateľský input.
WCHAR buf[BUF_LEN] = {0};
Definujeme a inicializujeme pole o dĺžke BUF_LEN
. Pole bude typu WCHAR
, čo je dátový typ pre široké znaky. WCHAR
typ je identický k typu wchar_t
, ktorý bol neskoršie zavedený do jazyka C.
HRESULT r = StringCchGetsW(buf, ARRAYSIZE(buf));
Funkcia StringCchGetsW()
prečíta riadok zo štandardného inputu, vrátane znaku nového riadku. Prvým parametrom funkcie je buffer, do ktorého sa skopírujú prečítané znaky. Druhý parameter určuje veľkosť bufferu v znakoch. Na výpočet veľkosti poľa použijeme makro ARRAYSIZE
. HRESULT
je dátový typ, ktorý reprezentuje chybové kódy funkcií.
if (SUCCEEDED(r)) {
Pomocou makra SUCCEEDED
zistíme, či funkcie StringCchGetsW()
skončila bez chyby.
C:\Users\Jano\Documents\Pelles C Projects\ReadLine>ReadLine.exe Today is a beautiful day. You have entered: Today is a beautiful day.
Program skompilujeme a spustíme z príkazovej riadky.
Záver
V tomto článku sme vo všeobecnosti spomenuli Windows API funkcie, makrá, dátové typy, a handlery. Mnohé skutočnosti, ktoré sa nám môžu zdať zvláštne sú spôsobené tým, že Windows API sa vyvíjalo vyše 30 rokov a snahou Microsoftu o čo najväčšiu spätnú kompatibilitu. V tomto článku boli použité materiály z autorovho e-booku a tutoriálu.