Windows Programmierung: Dialogboxen
Willemers Informatik-Ecke

Eine einfache Dialogbox

Die Dialogbox wird im Ressource-Editor gestaltet. Das Ergebnis ist eine Datei mit der Endung rc, die zum Projekt hinzugebunden wird. Der Ressource-Compiler erstellt eine Datei mit der Endung res.

Im Ressource-Editor erhält sowohl die Dialogbox als auch jedes Kontrollelement des Dialogs eine Kennung (SHORT), über die sie identifizierbar ist. Wie bei einem Fenster gibt es eine Fensterfunktion, die das Verhalten des Fensters festlegt. Eine Dialogfensterfunktion unterscheidet sich in einigen Details von der normalen Fensterfunktion. So lautet die Initialisierungsnachricht WM_INITDIALOG statt WM_CREATE. Das Ende der Dialogbox erfolgt durch den Aufruf von EndDialog. Dabei wird der zweite Parameter der von EndDialog der aufrufenden Funktion zurückgegeben.

// Modul fuer die Erzeugung einer Dialogbox ABOUT
// (C) Arnold Willemer

#include <windows.h>

#include "main.h"    // hier steht die Deklaration von GlobalInstance
#include "fam_rc.h"  // Ressourcen-Header

BOOL CALLBACK InfoDlgFkt(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{

   switch (message) {
   case WM_INITDIALOG:	// Initialisierung der Elemente
      break;
   case WM_COMMAND:
   	switch(wParam) {
      	case IDOK:
            EndDialog(hWnd, IDOK);
            return TRUE;
         case IDCANCEL:
            EndDialog(hWnd, IDCANCEL);
            return TRUE;
      } // switch COMMAND
   }
   return FALSE;
}

About(HWND hWnd)
{
   if (DialogBox(GlobalInstance, MAKEINTRESOURCE(DIA_INFO),
                      (HWND)hWnd, InfoDlgFkt)==IDOK) {
      return 1;
   } else {
      return 0;
   }
}
Der Start der Dialogbox erfolgt durch den Aufruf der Funktion DialogBox oder einer ihrer Verwandten. Durch die Parameter wird festgelegt, welche Ressource-ID und welche Dialogfensterfunktion herangezogen wird. Das Programm erhält erst dann wieder die Kontrolle, wenn die Dialogfensterfunktion EndDialog aufruft und mit dieser Funktion auch den Rückgabewert von DialogBox bestimmt.

Dialogbox mit Parametern

In vielen Fällen möchte man der Dialogbox Daten übergeben. Dies funktioniert natürlich auch mit globalen Variablen. Abgesehen von der mangelnden Eleganz scheitert diese Methode spätestens bei rekursiven Aufrufen der Dialogbox.

Die Funktion DialogBoxParam verhält sich wie DialogBox. Sie erlaubt aber einen LONG als Parameter, der an die Dialogbox weitergereicht wird. Da man darüber auch einen Zeiger übergeben kann, sind beliebige Daten zu übermitteln.

   if (DialogBoxParam(GlobalInstance,
                      MAKEINTRESOURCE(DIA_FELD), (HWND)hWnd,
                      FeldDlgFkt,
                      (LPARAM)ZeilenIndex)==IDOK) {
In der Fensterfunktion wird er beim Eintreten der Message WM_INITDIALOG einfach aus dem lParam gelesen. Hierin befindet sich der übergebene Wert.
BOOL CALLBACK FeldDlgFkt(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static long ZeilenIndex;

   switch (message) {
   case WM_INITDIALOG:
      ZeilenIndex = (long) lParam;
Da bei jedem Ereignis die Funktion erneut gestartet wird, muss sich die Dialogbox die übermittelten Daten merken. Da man globale Variablen vermeiden will, muss man mit lokalen Fensterdaten arbeiten.

Dialogbox mit lokalen Fensterdaten

{
tData *myData;

   myData = (tData *) GetWindowLong(hWnd, GWL_USERDATA);
   switch (message) {
   case WM_INITDIALOG:
      myData = (tData *)lParam;
      SetWindowLong(hWnd, GWL_USERDATA, (LONG)myData);
      ...
Hier werden Daten im WM_INITDIALOG als Parameter übernommen (siehe oben) und gleich in die lokalen Fensterdaten geschoben (SetWindowLong). Bei jedem Ereignis werden diese lokalen Daten wieder neu geladen (GetWindowLong). Dadurch können mehrere Fenster gleichzeitig existieren, die mit eigenen, unabhängigen Daten arbeiten.

Nicht-modale Dialogboxen

Eine normale Dialogbox wird durch den Aufruf von DialogBox gestartet. Das Programm bleibt an dieser Stelle stehen und wartet auf das Schließen der Dialogbox. Der Anwender kann nicht weiterarbeiten, bis der Dialog beendet ist. Dieses Verhalten nennt man modal.

In bestimmten Situationen ist dieses Verhalten unerwünscht. Ein Beispiel ist ein Fortschrittsanzeiger, der nur Sinn macht, wenn im Hintergrund das Programm weiterläuft. Das gleiche gilt für alle Abbruch-Dialoge.

Eine nicht-modale Dialogbox wird nicht mit DialogBox, sondern durch den Aufruf CreateDialog und ein anschließendes ShowWindow erzeugt. Die Parameter für CreateDialog entsprechen denen von DialogBox. Auch die Fensterfunktion ist weitgehend identisch. Lediglich das Ende der Dialogbox wird durch DestroyWindow statt mit EndDialog eingeleitet. Das Programm läuft nach der Erzeugung ungehindert weiter.

Im Beispiel wird eine Dialogbox erzeugt, die Fehlermeldungen in einer Liste darstellen soll.

HWND hWndDlg = 0;

BOOL CALLBACK DlgFkt_ErrorList(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message) {
  case WM_INITDIALOG:
    return TRUE;
  case WM_COMMAND:
    switch (LOWORD(wParam)) {
    case IDOK:
      DestroyWindow(hDlg);
      hWndDlg = 0;
      return TRUE;
    }
  }
  return FALSE;
}

HWND DiaErrorList(HWND hWnd)
{
  hWndDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_ERRORLIST), hWnd, DlgFkt_ErrorList);
  ShowWindow(hWndDlg, SW_SHOW);
  return hWndDlg;
}

void Print2List(char *str)
{
  if (hWndDlg) {
    SendMessage(GetDlgItem(hWndDlg, IDC_LIST), LB_ADDSTRING, 0, (LPARAM)str);
  } else {
    Print2File(str);
  }
}