Erstellen einer benutzerspezifischen MessageBox


Abstract

Dieser Artikel beschreibt, wie man die MessageBox aus der user32.dll von Windows über die gewöhnlichen Möglichkeiten hinaus an seine Bedürfnisse anpassen kann.

Die Idee

Jeder kennt die standard MessageBoxen die die Windows API zur Verfügung stellt:

int MessageBox(      
    HWND hWnd,
    LPCTSTR lpText,
    LPCTSTR lpCaption,
    UINT uType
);

Mit den möglichen Werten für den letzten Parameter lässt sich der Dialog noch etwa anpassen. Will man allerdings zum Beispiel die Beschriftungen der Schaltflächen mit eigenen Texten versehen,

muss man etwas in die Trickkiste greifen.

Die Umsetzung

Die MessageBox ist ein einfaches Fenster aus einer Windows Ressource, welches, wenn es aufgerufen wird, entsprechend der Parameter angepasst wird. Da wir auf die Ressource keinen Einfluss haben, müssen wir an einer anderen Stelle zu einem anderen Zeitpunkt eingreifen, um sie unseren Wünschen entsprechend anpassen zu können. Der geeignete Zeitpunkt wäre kurz bevor das Fenster der MessageBox angezeigt wird. Die einzige Möglichkeit diesen Zeitpunkt mitzubekommen, ist die Installation eines entsprechenden Hooks. Anbieten tut sich hier ein CBT (Computer-Bases Training) Hook:

These Hooks provide notification when any Window in your process is created, activated, focused, moved or destroyed.

Also genau das, was wir brauchen. Die weitere Vorgehensweise ergibt sich dann von selbst:

  1. Hook lokal mit SetWindowsHookEx [1] installieren.
  2. Abfangen der Benachrichtigung von HCBT_ACTIVATE [2]. (Bei HCBT_CREATEWND existiert das Fenster noch nicht.)
  3. Innerhalb der Hook-Prozedur das Fenster der MessageBox modifizieren.
  4. Hook wieder deinstallieren.

Installieren des Hooks und aufrufen der MessageBox:

  // lokalen CBT-Hook installieren
  hMsgBoxHook := SetWindowsHookEx(WH_CBT, @CBTProc, 0, GetCurrentThreadId);
  if hMsgBoxHook <> 0 then
  begin
    // MessageBox aufrufen
    case MessageBox(0, PChar(rsText), PChar(rsCustomCaption), MB_YESNO) of
      IDYES: Writeln('IDYES');
      IDNO: Writeln('IDNO');
    end;
    // Hook deinstallieren
    UnhookWindowsHookEx(hMsgBoxHook);
  end
  else
    Writeln(rsError + ': %d', GetLastError);
  readln;

Modifizieren des Fensters in der Hook-Prozedur:

function CBTProc(nCode: Integer; wP: WPARAM; lP: LPARAM): LRESULT; stdcall;
var
  Handle            : THandle;
  hBtn              : THandle;
begin
  if nCode < 0 then
  begin
    result := CallNextHookEx(hMsgBoxHook, nCode, wP, lP);
    exit;
  end;
  case nCode of
    HCBT_ACTIVATE:
      begin
        Handle := wP;
        hBtn := GetDlgItem(Handle, IDYES);
        SetWindowText(hBtn, PChar(rsYES));
        hBtn := GetDlgItem(Handle, IDNO);
        SetWindowText(hBtn, PChar(rsNO));
        result := 0;
        exit;
      end;
  end;
  result := CallNextHookEx(hMsgBoxHook, nCode, wP, lP);
end;

Beitrag Customized About MessageBox [3] in der Delphi-Praxis.

Downloads


CustomizedMsgBox.zip Wednesday, 29-Dec-2010 23:45:15 CET 11K

Links

[1] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/setwindowshookex.asp
[2] http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/hooks/hookreference/hookfunctions/cbtproc.asp
[3] http://www.delphipraxis.net/topic98946_customized+about+messagebox.html


2010-12-29T23:44:40 +0100, mail+homepage[at]michael-puff.de