Verwenden von Dialogressourcen

Einleitung

In Visual Basic lassen sich mit geringem Aufwand Formulare, d. h., Fenster, die Steuerelemente enthalten, entwerfen. Dennoch sollte man wissen, daß unter Windows Formulare auch in Ressourcendateien abgelegt werden können. Das Windows-API stellt die Möglichkeit bereit, in Ressourcendateien definierte Formulare während der Laufzeit zu laden und in der Anwendung zu benutzen. Dieser Artikel zeigt, wie Formulare in Ressourcendateien definiert werden und sie in Visual-Basic-Anwendungen geladen, manipuliert und angezeigt werden können.

Grundlagen

Was sind Dialoge?

Unter einem Dialog versteht man im Allgemeinen ein Fenster, über das der Benutzer mit der Anwendung „kommuniziert“. Heutzutage enthält fast jede Anwendung mehrere Dialoge. Einfachstes Beispiel ist ein Anmeldungsdialog oder der legendäre Versionsinformationsdialog, der bei fast keiner Anwendung fehlt. Allerdings sind nicht alle Fenster unter Windows Dialoge im Sinne von Dialogressourcen. Ein Großteil der Anwendungen besteht aus einem Hauptfenster, bei dem es sich nicht um eine Dialogressource handelt. Dieses Hauptfenster enthält meist eine Werkzeugleiste, eine Menüleiste und eine Statusleiste. Dabei ist zu bemerken, daß auch Menüs und Werkzeugleisten aus Ressourcendateien geladen werden können.

Motivation für die Verwendung von Dialogressourcen

Wie bereits angesprochen, werden Hauptfenster nicht aus Ressourcendateien geladen. Natürlich kann man bei allen Dialogen einer Anwendung so verfahren, jedoch muß man dann dem Code die entsprechenden Anweisungen zum Erstellen des Fensters, der darauf enthaltenen Steuerelemente und der notwendigen Ereignisverarbeitungsroutinen hinzufügen, was den Codeumfang vergrößern würde. Dies war einer der Gründe, warum der Ressourcentyp DIALOG eingeführt wurde; weitere Ursachen sind die Folgenden:

Dialogressourcen versus Visual-Basic-Dialogfenster

Das Formularsystem von Visual Basic

Natürlich werden Sie sich die Frage stellen, warum man eigentlich Dialoge aus Ressourcen verwenden soll, bietet doch Visual Basic bereits eine so einfache Möglichkeit, Dialoge zu erstellen und zu verwalten. Sieht man sich aber Formulare und Steuerelemente unter Visual Basic genauer an, so erkennt man schnell die etwas starre Struktur und die mangelnde Flexibilität. Bestes Beispiel hierfür sind die schreibgeschützten und fehlenden Eigenschaften. Wer unter Visual Basic eine wirklich professionelle Anwendungsoberfläche erstellen will, findet sowieso keinen Umweg um die Verwendung von Plattformfunktionen; warum sollte man nicht gleich auch die Dialoge per API-Aufrufen erstellen und organisieren?

Bei näherer Betrachtung des Visual-Basic-eigenen Steuerelementsystems wird man feststellen, daß die Steuerelemente keine „echten“ Windows-Steuerelemente sind. Unter Windows gibt es mehrere Standardsteuerelemente, die jeweils Instanzen einer bestimmten Fensterklasse sind. Der Klassennname einer Schaltfläche beispielsweise ist BUTTON, der eines TextBox-Steuerelements wäre EDIT. Wenn man nun die Klassennamen der Steuerelemente in einer mit Visual Basic erstellten Anwendung ansieht (beispielsweise mit dem Werkzeug Spy++), wird man feststellen, daß es sich hier um andere Klassennamen handelt, die nur die Windows-Steuerelementtypen kapseln.

Probleme und Einschränkungen des Visual-Basic-Formularsystems

Normalerweise hat man damit auch kein Problem, spätestens seit Windows 2000 gibt einem diese Architektur aber zu denken: Windows 2000 bietet nämlich einen eigenen Darstellungsmodus an, in dem die Zugriffstasten nicht unterstrichen werden und auch keine Fokusrechtecke angezeigt werden. Dies verleiht Anwendungen ein moderneres und aufgelockerteres Design, wenngleich auch die Benutzerfreundlichkeit etwas darunter leidet. Während bei normalen Anwendungen Fenster in diesem Modus gestartet werden, werden bei Visual-Basic-Anwendungen immer die Zugriffstasten unterstrichen und Fokusrechtecke angezeigt; dies kann allerdings über Windows-API-Funktionen ausgeschaltet werden.

Ein weiterer Vorteil ist, daß Steuerelemente wie ListView oder StatusBar ohne Verwendung der Komponente Microsoft Windows Common Controls eingebunden werden können. Leider können diese Steuerelemente anschließend nur über Plattformfunktionen modifiziert werden, was aber auch als Vorteil betrachtet werden kann. Wenn man schon auf API-Funktionen zurückgreifen muß, um verschiedene Merkmale und Verhaltensweisen zu erzielen, dann kann man die Steuerelemente auch gleich per API-Aufrufen erstellen und in weiterer Folge auch verwalten. Das selbe gilt auch für Formulare.

Weiters sind Dialogressourcen vorteilhaft, da bestimmte Aussehenseigenschaften wie z. B. seitenverkehrte Fenster komfortabel eingestellt werden können. Das Formularsystem von Visual Basic stellt zwar die wichtigsten Eigenschaften bei der Formularklasse zur Verfügung, jedoch ist nur eine Teilmenge der Möglichkeiten direkt verfügbar.

Nachteil der Verwendung von Dialogressourcen unter Visual Basic ist, daß die Tabulatorreihenfolge der Steuerelemente in den daraus geladenen Dialogen nicht korrekt funktioniert. Außerdem ist zu beachten, daß die Verwendung von Dialogressourcen unter Visual Basic nicht vorgesehen ist und daher auch von der Entwicklungsumgebung nicht vollständig unterstützt wird. Damit eine Dialogressource geladen werden kann, muß die Anwendung als kompilierte Anwendung vorliegen, beim Ausführen aus der Entwicklungsumgebung heraus funktioniert das Laden der Ressourcen nicht, da App.hInstance auf die Instanz der Entwicklungsumgebung, nicht aber auf die Anwendung selbst verweist.

Der Ressourcentyp DIALOG

Hier wird auf eine genauere Beschreibung des Aufbaus von DIALOG-Ressourcen verzichtet, da diese nur selten als Code bearbeitet werden müssen. Für nähere Informationen sei auf die Dokumentation verweisen. Zum Erstellen von Ressourcendateien kann beispielsweise Microsoft Visual C++ verwendet werden. Diese Entwicklungsumgebung bietet die Möglichkeit, in einem WYSIWYG-Editor mittels Drag and Drop Dialogfelder zu erstellen. Dabei können Steuerelemente, wie dies aus Visual Basic bekannt ist, mit der Maus in einer grafischen Entwurfsansicht positioniert und formatiert werden. Anschließend wird das Ressourcenskript zu einer Ressourcendatei kompiliert. Die fertige Ressourcendatei kann dann dem Visual-Basic-Projekt hinzufügt werden.

Relevante Win32-API-Funktionen

Aus Gründen der leichteren Nachvollziehbarkeit wird hier ein einfach gehaltenes Beispiel zur Nutzung von Dialogressourcen vorgestellt, das nicht die gesamte Palette an Möglichkeiten, die Dialogressourcen bieten, darstellt.

Die Funktion CreateDialogParam

Die Funktion CreateDialogParam wird benutzt, um einen Dialog zu erstellen. Sie wird wie folgt deklariert:

Private Declare Function CreateDialogParam _
    Lib "user32.dll" _
    Alias "CreateDialogParamA" _
( _
    ByVal hInstance As Long, _
    ByVal lpName As String, _
    ByVal hWndParent As Long, _
    ByVal lpDialogFunc As Long, _
    ByVal lParamInit As Long _
) As Long
Deklaration der Funktion CreateDialogParam.

Im Parameter hInstace wird die Zugriffsnummer der Instanz der Anwendung angegeben, also App.hInstance, lpName ist der Name der Dialogressource in der Ressourcendatei in Form einer Zeichenfolge, hWndParent gibt das Fenster an, das als Elternfenster verwendet werden soll, lpDialogFunc ist ein Zeiger auf die Rückrufprozedur für die Dialognachrichten und der Parameter lParamInit ist nicht relevant, wir übergeben im Beispiel den Wert 0&. Als Rückgabewert wird die Zugriffsnummer des Dialogs geliefert. Tritt ein Fehler auf, dann ist der Rückgabewert 0.

Die Funktion EndDialog

EndDialog wird verwendet, um den Dialog wieder zu entladen. Die Deklaration sieht folgendermaßen aus:

Private Declare Function EndDialog Lib "user32.dll" ( _
    ByVal hDlg As Long, _
    ByVal nResult As Long _
) As Long
Deklaration der Funktion EndDialog.

Der Parameter nResult ist hier nicht relevant, hDlg ist die Zugriffsnummer des Dialogs (der Rückgabewert von CreateDialogParam).

Die Rückrufprozedur DialogProc

Wie bereits in der Beschreibung zur Funktion CreateDialogParam angeführt, muß im Parameter lpDialogFunc ein Zeiger auf eine benutzerdefinierte Rückruffunktion übergeben werden. Dies ist seit Visual Basic 5.0 über den Operator AddressOf möglich. Gemäß der Dokumentation hat diese Rückruffunktion folgendes Aussehen:

BOOL CALLBACK DialogProc(
  HWND hwndDlg,  // handle to dialog box
  UINT uMsg,     // message
  WPARAM wParam, // first message parameter
  LPARAM lParam  // second message parameter
);
Prototyp der Rückruffunktion DialogProc.

Übersetzt man dies in Visual-Basic-Syntax, sieht der Kopf der Funktion wie folgt aus:

Public Function DialogProc( _
    ByVal hwndDlg As Long, _
    ByVal uMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long _
) As Long
Der Kopf der Funktion DialogProc in Visual Basic.

Die Funktionsdeklaration gleicht jener von Fensterprozeduren.

Behandeln von Ereignissen

Folgendes Beispiel zeigt, wie im Programmcode auf Ereignisse der Steuerelemente des Dialogs reagiert werden kann. Im Beispiel wird beim Klick auf die Schaltfläche IDC_SHOWMSG des Dialogs der Inhalt des ebenfalls am Fenster enthaltenen TextBox-Steuerelements IDC_MSGTEXT in einem Meldungsfenster angezeigt. Die Ereignisbehandlung aller Steuerelemente im Fenster erfolgt in der Funktionsprozedur DialogProc. Folgendes Listing zeigt eine stark vereinfachte Version des Codes aus dem Beispielprojekt:

Public Function DialogProc( _
    ByVal hwndDlg As Long, _
    ByVal uMsg As Long, _
    ByVal wParam As Long, _
    ByVal lParam As Long _
) As Long
    
    ' Klick auf 'IDC_SHOWMSG'.
    If wParam = IDC_SHOWMSG And uMsg = WM_COMMAND Then
        Dim s As String, n As Long
        
        ' Ermitteln des TextBox-Inhalts.
        s = Space$(256)
        n = GetDlgItemText(hwndDlg, IDC_MSGTEXT, s, Len(s))
        s = Left$(s, n)
        
        ' Anzeigen des Textes.
        Call MsgBox(s)
    End If
End Function
Implementierung des laufenden Beispiels.

Schlußwort

Auch wenn die vorgestellte Methode ihre Einschränkungen hat und in der Praxis wohl kaum einsetzbar ist, sollte man als Programmierer darüber bescheid wissen. Es ist nämlich auch möglich, Dialogressourcen aus anderen Anwendungsdateien und Bibliotheken zu laden und mit eigenen Ereignisbehandlungsroutinen auszustatten. Ein Beispiel dazu ist im nachfolgenden Abschnitt zu finden.

Downloads

Beispielprojekt (DialogResource.zip)

Projekt im Visual-Basic-6.0-Format.

Beispielprojekt (DialogExplorer.zip)

Visual-Basic-6.0-Code eines Werkzeugs zum Ansehen der Dialogressourcen anderer Anwendungen.