Home » Tutorials » Systemnahe Programmierung » nonVCL

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.