Valószínüleg a legtöbb programozót a hányinger kerülgeti ha a windows API-ról van szó, különösen mert a .NET kényelmének árnyékában miért nyúlna az ember ehhez az
elavult, ronda, logikátlan, idióta, szerencsétlen, <egyéb featureök> felülethez? Mondjuk mert a cég ahol dolgozol ebben írta meg a programot, és bármennyire is
toporzékolsz, nem fogják átírni az egészet csak azért mert neked herótod van a windowstól.
WinAPI, na!
Mindenki elolvassa a wikipédián, hogy mikböl is áll a winapi. A két legfontosabb dolog a GDI (rajzolgatás a grafkártyával)
és az UI (ablakok, controlok, stb.). Amit még használni szokás, az a shell modul, például processz indításhoz illetve a base/advanced services ha mondjuk fel akarod sorolni, hogy
milyen fájlok vannak egy directoryban.
CODE
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, INT nShowCmd)
{
return 0;
}
Atyaúristen...a windowsban instance-nak nevezik valamilyen modulnak egy példányát, ami lehet például EXE, vagy egy DLL, a lényeg, hogy van egy belépési pontja. Ahhoz, hogy csinálj mondjuk egy ablakot, meg kell adnod az instance-ot, ami használni akarja és a winapi osztály nevét, ami azonositja az...ablakot (a winapiban ugyanis a controlok is ablakok, söt úgy is hozod öket létre, mint az ablakot). A legtöbb esetben úgy indul a program, hogy csinálsz magadnak egy saját window class-t, ami a föablakodat jelenti:
CODE
WNDCLASSEX wc =
{
sizeof(WNDCLASSEX),
CS_CLASSDC,
(WNDPROC)WndProc,
0L, 0L,
hInst,
NULL, NULL, NULL, NULL,
"TestClass", NULL
};
RegisterClassEx(&wc);
// ...
UnregisterClass("TestClass", wc.hInstance);
return 0;
Valamit azért elárul a felület minöségéröl, hogy mindenki vécének deklarálja ezt az objektumot. A WndProc nevü változó egy függvény lesz, nevezetesen az ablak-osztály üzenetkezelöje. Azaz minden ilyen osztályú ablak a programon belül ugyanazt a függvényt használja üzenetkezelésre. Ez most még nem baj, de amikor majd gombokat akarsz csinálni, akkor bizony elég nagy baj lesz. Szerencsére az ablakleírót mindig megkapod, így ügyes programozással mindig el lehet dönteni, hogy ki küldte az üzenetet.
CODE
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hWnd, msg, wParam, lParam);
}
Na akkor most csináljunk egy ilyen ablakot. A CreateWindow függvény paraméterei annyira nem bonyolultak, az ablak feature-jeit például összevagyolt flagekkel lehet megadni.
CODE
int w = GetSystemMetrics(0);
int h = GetSystemMetrics(1);
DWORD style = WS_CLIPCHILDREN|WS_CLIPSIBLINGS|WS_SYSMENU|WS_BORDER|WS_CAPTION;
hwnd = CreateWindowA("TestClass", "Winapi1", style,
(w - 800) / 2, (h - 600) / 2, 800, 600,
NULL, NULL, wc.hInstance, NULL);
Nem kell tudnod mi mit jelent, ha érdekel megnézed guglin. Ami még hátravan az fö üzenethurok leimplementálása. Ez egy elég idióta név, angol nyelvén message hook/loop; ugyanolyan hülyén hangzik. Közös megegyezés alapján (amiben csak én vehetek részt) nevezzük el addigfussamigquitnemjön ciklusnak. Máris mennyivel jobb nem?
CODE
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while( msg.message != WM_QUIT )
{
while( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Az üzenetek mindig egy FIFO sorba kerülnek be (first in, first out), a PeekMessage kiveszi az elsöt és ideadja neked. A TranslateMessage winapiról lefordítja winapira. Ismeritek azt a viccet, hogy: Két windows beszélget: - Te, mi kompatibilisek vagyunk egymással? - Mit mondtál? Ez mindent megmagyaráz szerintem. A DispatchMessage pedig elküldi az üzenetkezelönek (wndproc). Végezetül még csináljuk meg azt, hogy az Esc billentyüre kilépjen a program:
CODE
LRESULT WINAPI WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch( msg )
{
case WM_CLOSE:
ShowWindow(hWnd, SW_HIDE);
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_KEYUP:
switch(wParam)
{
case VK_ESCAPE:
SendMessage(hWnd, WM_CLOSE, 0, 0);
break;
}
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
Elsöre legyen elég ennyi. Vagy inkább örökre? Kód itt. Höfö:
|