Windows Programmierung: Dateiauswahlbox
Willemers Informatik-Ecke
Die Dialogbox zur Auswahl von Dateien ist eine Errungenschaft von Windows 3.1. Bei vorigen Versionen war sie noch nicht verfügbar. Damit aber auch Windows 3.0-Anwender die Auswahlbox benutzen können, hat Microsoft es gestattet, die für die Standarddialoge zuständige Datei COMMDLG.DLL frei zu kopieren.

Die Prototypen und Datentypen für diese Dialoge finden sich in der Datei COMMDLG.H und müssen im Programm eingebunden werden.

#include <COMMDLG.H>

Ein Beipiel

Typischerweise wird die Dateiauswahlbox aufgerufen, wenn Datei-Öffnen vom Anwender aufgerufen wurde. Damit muß der Aufruf in die Fensterfunktion an die Stelle, wo die Menüauswertung geschieht. Vorher wird der Importfilter gesetzt und eine Variable der Datenstruktur OPENFILENAME definiert. Diese Variable wird nullgesetzt und sollte nicht jedesmal neu erzeugt werden, da dann das Programm weiß, wo das letzte Mal geladen wurde und dort wieder aufsetzen wird. Wie bei vielen Windows-Strukturen muß auch hier das Feld lStructSize mit der Größe der Struktur vorbesetzt sein.
#define IMPORTFILTER "Diary (*.dry)\0*.dry\0Address (*.adr)\0*.adr\0All Files(*.*)\0*.*\0\0"
  ...
static OPENFILENAME DateiSel = {0}; // hier wird die Struktur geloescht!
  ...
    case WM_COMMAND:           // message: command from application menu
        switch( LOWORD( wParam )) {
            case M_OPEN:
            char FileName[_MAX_PATH+1] = "";
            // Die Fileselector-Struktur vorbesetzen 
            DateiSel.lStructSize       = sizeof (OPENFILENAME) ;
            DateiSel.hwndOwner         = hWnd;
            DateiSel.nMaxFile          = _MAX_PATH;
            DateiSel.lpstrFile         = FileName;
            DateiSel.lpstrFilter       = IMPORTFILTER;
            if (GetOpenFileName(&DateiSel)) {
                switch (DateiSel.nFilterIndex) {
                case 1: //
                    MessageBox(hWnd, "Diary", "hallo", MB_OK);
                    break;
                case 2: //
                    MessageBox(hWnd, "Address", "hallo", MB_OK);
                    break;
                }
            }
            break;
Im String FileName wird nach dem Aufruf der Dialogbox der ausgewählte Dateiname stehen, da diese Adresse in lpstrFile festgelegt wurde.

Die Funktionen

Die Funktion GetOpenFileName eröffnet eine Dialogbox zur Auswahl einer Datei, die gelesen werden soll. Der Parameter enthält eine Struktur, in der die Dialogbox weitgehend konfiguriert wird. Das wichtigste Element dieser Strukur ist der Zeiger lpstrFile, der den Speicherbereich angibt, in dem anschließend die ausgewählte Datei benannt wird.

Die Funktion GetSaveFileName dient der Selektion einer Datei zum Sichern.

Die Funktion GetFileTitle isoliert aus der bezeichneten Datei den reinen Dateinamen ohne Laufwerkskennung und Pfadnamen.

Die Prototypen der Funktionen GetOpenFileName, GetSaveFileName und GetFileTitle:

BOOL    WINAPI GetOpenFileName(OPENFILENAME FAR*);
BOOL    WINAPI GetSaveFileName(OPENFILENAME FAR*);
int     WINAPI GetFileTitle(LPCSTR, LPSTR, UINT);

Die Struktur OPENFILENAME

Wie man an den Parametern der Funktionen sieht, spielt die Struktur OPENFILENAME eine beson- dere Rolle. Sie dient als Struktur, um die Parameter der Funktion aufzunehmen.

typedef struct tagOFN
{
    DWORD   lStructSize;
    HWND    hwndOwner;
    HINSTANCE hInstance;
    LPCSTR  lpstrFilter;
    LPSTR   lpstrCustomFilter;
    DWORD   nMaxCustFilter;
    DWORD   nFilterIndex;
    LPSTR   lpstrFile;
    DWORD   nMaxFile;
    LPSTR   lpstrFileTitle;
    DWORD   nMaxFileTitle;
    LPCSTR  lpstrInitialDir;
    LPCSTR  lpstrTitle;
    DWORD   Flags;
    UINT    nFileOffset;
    UINT    nFileExtension;
    LPCSTR  lpstrDefExt;
    LPARAM  lCustData;
    UINT    (CALLBACK *lpfnHook)(HWND, UINT, WPARAM, LPARAM);
    LPCSTR  lpTemplateName;
}   OPENFILENAME;
typedef OPENFILENAME FAR* LPOPENFILENAME;
Zunächst wird in lStructSize die Größe der OPENFILENAME-Struktur erwartet. Diese wird mit sizeof(OPENFILENAME) festgelegt.

Der Dateiname

Die wichtigste Aufgabe der Dialogbox ist die Lieferung des Dateinamens.
static OPENFILENAME DateiSel = {0};

  DateiSel.nMaxFile    = _MAX_PATH;
  DateiSel.lpstrFile   = FileName;
  DateiSel.lpstrDefExt = "txt";
lpstrFile zeigt auf eine Stringvariable. Die Variable mit ihrem Speicherraum muß vom Programmierer definiert werden. Wichtig: Der String muß bei Start der Dialogbox vorbesetzt sein, typischerweise mit einem Leerstring. Ansonsten kann es sein, daß die Dialogbox nicht startet. Die Länge dieses Strings wird im Element nMaxFile abgelegt.

Nach Ende der Dialogbox befindet sich hier der ausgewählte Dateiname inklusive Laufwerksbuchstabe und Pfad.

Beim Sichern ohne eine Angabe der Extension wird in den meisten Fällen erwartet, dass das Programm seine eigene Extension anhängt. Dies wird durch Vorbesetzen des Elements lpstrDefExt erreicht.

Nicht ohne Filter

LPCSTR lpstrFilter
Hier wird eine Liste der Dateimasken übergeben, die bei Benutzung der Dialogbox durch eine Klapplistbox ausgewählt werden kann. Dabei werden die Strings direkt hintereinander geschrieben. Anders ausgedrückt, werden die Teilstrings durch eine binäre Null getrennt. Das Ende des gesammten Filters wird durch das Auftreten zweier Nullen hintereinander kenntlich.

Es bilden immer zwei Strings ein Paar. Das erste ist die Bezeichnung im Klartext, das zweite ist die Maske. Werden mehrere Masken für eine Auswahl benötigt, kann man sie einfach hintereinander schreiben. Wie üblich wird jeder String durch ein Nullbyte beendet. Das Ende des Filters wird durch zwei Nullen kenntlich gemacht. Hier zwei Beispielstrings:

"Stammbaum (*.dbf)\0*.dbf\0GEDCOM (*.ged)\0*.ged\0\0"
"Diary (*.dry)\0*.dry\0Address (*.adr)\0*.adr\0All Files(*.*)\0*.*\0\0"
Die Maske in Klammern dient nur der Anzeige und hat keine inhaltliche Bedeutung.

DWORD nFilterIndex
Nach Bearbeiten der Dialogbox liefert nFilterIndex welcher Filter vom Anwender ausgewählt wurde. Damit kann beispielsweise bei Importen festgestellt werden, welcher Funktion aufgerufen werden muß, um die Datei richtig zu lesen. Beim Schreiben der Datei ist es noch wichtiger, da so bestimmt werden kann, in welchem Format oder welche Inhalte geschrieben werden sollen. Der Index beginnt übrigens bei 1!

Flags

DWORD Flags
Hier werden spezielle Optionen gesetzt, die die Dialogbox konfigurieren. Die folgenden Wer- te können dabei durch Addition kombiniert werden:
OFN_READONLY
bewirkt, dass der Schreibschutzknopf bei Start der Dialogbox angewählt ist.
OFN_OVERWRITEPROMPT
bewirkt in einer "Sichern als..."-Box, dass bei Existenz der Datei nachgefragt wird, ob sie öberschrieben werden darf.
OFN_HIDEREADONLY
macht den Schreibschutzknopf unsichtbar #define OFN_NOCHANGEDIR 0x00000008 zwingt die Dialogbox dazu, das aktuelle Verzeichnis dahin zuröckzusetzen, wo es war, als die Dialogbox erzeugt wurde.
OFN_SHOWHELP
erzeugt einen Hilfsknopf. Dabei darf hwndOwner nicht NULL sein.
OFN_NOVALIDATE
erlaubt auch ungültige Zeichen im Dateinamen.
OFN_ALLOWMULTISELECT
erlaubt die Auswahl mehrerer Dateien. Im String för den Dateinamen steht dann zu- nächst Laufwerksbezeichnung und Pfadname, dann jeweils durch Leerzeichen abge- trennt die Liste der angewählten Dateinamen.
OFN_PATHMUSTEXIST
erzwingt, dass der Anwender nur existierende Pfadnamen angeben kann.
OFN_FILEMUSTEXIST
erzwingt, dass der Anwender nur existierende Dateinamen angeben kann.
OFN_CREATEPROMPT
meldet, wenn die angegebene Datei nicht existiert und ermöglicht es dem Benutzer, ihre Erzeugung in einer Dialogbox zu veranlassen.
OFN_NOREADONLYRETURN
erzwingt, dass die Datei weder schreibgeschützt noch ein schreibgeschütztes Verzeichnis ist.