nonVCL
Fensterprozeduren
Ein Vergleich – Fensterprozeduren und ihre Anwendung
Eine gewöhnliche Fensterprozedur:
function WndProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
Eine gewöhnliche Dialogprozedur:
function DlgProc(hWnd: HWND; uMsg: dword; wParam: WPARAM; lParam: LPARAM): BOOL; stdcall;
Beachte: Es muss immer STDCALL defniert werden!
Vergleicht man beide Statements, liegt der eigentliche Unterschied nur noch im Rückgabetyp. Tatsächlich erfüllen beide eine ähnliche Aufgabe: das Auswerten und Bearbeiten von Fensternachrichten.
Fensternachrichten sind einfache Integerwerte, die ein bestimmtes Ereignis in Bezug zum Fenster signalisieren. Es kann sich hier um einen einfachen Mausklick, aber genausogut um ein Winsock-Ereignis handeln.
Nachrichten, die nicht von der jeweiligen Fensterprozedur bearbeitet werden, sollten von einem Defaulthandler, also einer Standardprozedur, bearbeitet werden. Dazu signalisiert die Dialogprozedur FALSE, um zu zeigen, dass der Defaulthandler noch ran muss. Und die „echte“ Fensterprozedur ruft den Defaulthandler selbst auf:
Result:=DefWindowProc(hWnd, uMsg, wParam, lParam);
Aus all diesen Annahmen lässt sich dann folgendes kleine Programmgerüst entwickeln.
program test1; uses windows, messages; {$WARNINGS OFF} {$HINTS OFF} const windowleft: integer = 100; windowtop: integer = 100; windowwidth: integer = 265; windowheight: integer = 202; ClassName = 'ATestWndClassEx'; function WndProc(hWnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var IDOK: DWORD; begin Result := 0; case uMsg OF WM_CREATE: begin IDOK := createwindow('BUTTON', 'OK-Button', WS_VISIBLE OR WS_CHILD, 100, 100, 100, 30, hwnd, 0, hInstance, NIL); if IDOK = INVALID_HANDLE_VALUE then MessageBox(hwnd, 'Button nicht erzeugt', 'Meldung', 0); end; WM_DESTROY: begin PostQuitMessage(0); end; WM_COMMAND: if hiword(wparam) = BN_CLICKED then if loword(wparam) = IDOK then MessageBox(hwnd, 'OK Button gedrückt', 'Meldung', 0); else Result := DefWindowProc(hWnd, uMsg, wParam, lParam); end; end; var wc: TWndClassEx = ( cbSize: SizeOf(TWndClassEx); style: CS_OWNDC OR CS_HREDRAW OR CS_VREDRAW; cbClsExtra: 0; cbWndExtra: 0; hbrBackground: COLOR_WINDOW; lpszMenuName: NIL; lpszClassName: ClassName; hIconSm: 0; ); { mainwnd:DWORD;}//not needed msg: TMSG; rect: trect; deskh, deskw: integer; ncm: tagNONCLIENTMETRICS; begin wc.hInstance := HInstance; wc.hIcon := LoadIcon(HInstance, MAKEINTRESOURCE(1)); wc.hCursor := LoadCursor(0, IDC_ARROW); wc.lpfnWndProc := @WndProc; systemparametersinfo(SPI_GETWORKAREA, 0, @rect, 0); deskw := rect.Right - rect.Left; deskh := rect.Bottom - rect.Top; ncm.cbSize := sizeof(ncm); systemparametersinfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), @ncm, 0); windowwidth := windowleft + windowwidth; windowheight := windowtop + windowheight + ncm.iMenuHeight + ncm.iCaptionHeight; Windowleft := (deskw DIV 2) - (windowwidth DIV 2); Windowtop := (deskh DIV 2) - (windowheight DIV 2); RegisterClassEx(wc); {mainwnd:=} CreateWindowEx(WS_EX_WINDOWEDGE OR WS_EX_CONTROLPARENT OR WS_EX_APPWINDOW, ClassName, 'Caption', WS_OVERLAPPED OR WS_CAPTION OR WS_SYSMENU OR WS_MINIMIZEBOX OR WS_VISIBLE, windowleft, windowtop, windowwidth, windowheight, 0, 0, hInstance, NIL); while True do begin if not GetMessage(msg, 0, 0, 0) then break; //oops :o) translatemessage(msg); dispatchmessage(msg); end; ExitCode := GetLastError; end.
Download des Beispiels (10 KB)
Rot markiert ist alles, was uns eigentlich nicht weiter interessiert oder Grundwissen zu OPASCAL darstellt. Grüne Stellen kennen wir bereits aus obigen Erwägungen.
Neu sind die blauen Stellen. In unserem Falle eine Endlosschleife [WHILE True DO BEGIN], die unterbrochen wird, wenn keine Nachrichten mehr an das Fenster gehen [IF NOT GetMessage(msg, 0, 0, 0) THEN break;] und anderenfalls die Nachrichten übersetzt und an die Fensterprozedur weiterleitet.
Das Beispiel erzeugt ein Haupfenster, und darin einen Knopf. Außerdem wird gezeigt, wie man das Drücken auf den Knopf abfängt. Das Ganze erfolgt ohne Verwendung von Dialogressourcen.