With these preliminaries out of the way, we are now ready to create dialog box templates and dialog box procedures to assist our Windows programs in opening and saving files. The FILEDLG.C source code file, FILEDLG.H header file, and FILEDLG.DLG dialog box template file, shown in Figure 10-7 on the following pages, will be used in the POPPAD3 program in this chapter. You can use these routines (or similar ones) in your own programs.
FILEDLG.C
/*-----------------------------------------------
FILEDLG.C -- Open and Close File Dialog Boxes
-----------------------------------------------*/
#include <windows.h>
#include "filedlg.h"
BOOL FAR PASCAL FileOpenDlgProc (HWND, WORD, WORD, LONG) ;
BOOL FAR PASCAL FileSaveDlgProc (HWND, WORD, WORD, LONG) ;
LPSTR lstrchr (LPSTR str, char ch) ;
LPSTR lstrrchr (LPSTR str, char ch) ;
static char szDefExt [5] ;
static char szFileName [96] ;
static char szFileSpec [16] ;
static POFSTRUCT pof ;
static WORD wFileAttr, wStatus ;
int DoFileOpenDlg (HANDLE hInst, HWND hwnd, char *szFileSpecIn,
char *szDefExtIn, WORD wFileAttrIn,
char *szFileNameOut, POFSTRUCT pofIn)
{
FARPROC lpfnFileOpenDlgProc ;
int iReturn ;
lstrcpy (szFileSpec, szFileSpecIn) ;
lstrcpy (szDefExt, szDefExtIn) ;
wFileAttr = wFileAttrIn ;
pof = pofIn ;
lpfnFileOpenDlgProc = MakeProcInstance (FileOpenDlgProc, hInst) ;
iReturn = DialogBox (hInst, "FileOpen", hwnd, lpfnFileOpenDlgProc) ;
FreeProcInstance (lpfnFileOpenDlgProc) ;
lstrcpy (szFileNameOut, szFileName) ;
return iReturn ;
}
int DoFileSaveDlg (HANDLE hInst, HWND hwnd, char *szFileSpecIn,
char *szDefExtIn, WORD *pwStatusOut,
char *szFileNameOut, POFSTRUCT pofIn)
{
FARPROC lpfnFileSaveDlgProc ;
int iReturn ;
lstrcpy (szFileSpec, szFileSpecIn) ;
lstrcpy (szDefExt, szDefExtIn) ;
pof = pofIn ;
lpfnFileSaveDlgProc = MakeProcInstance (FileSaveDlgProc, hInst) ;
iReturn = DialogBox (hInst, "FileSave", hwnd, lpfnFileSaveDlgProc) ;
FreeProcInstance (lpfnFileSaveDlgProc) ;
lstrcpy (szFileNameOut, szFileName) ;
*pwStatusOut = wStatus ;
return iReturn ;
}
BOOL FAR PASCAL FileOpenDlgProc (HWND hDlg, WORD message,
WORD wParam, LONG lParam)
{
char cLastChar ;
short nEditLen ;
switch (message)
{
case WM_INITDIALOG :
SendDlgItemMessage (hDlg, IDD_FNAME, EM_LIMITTEXT, 80, 0L) ;
DlgDirList (hDlg, szFileSpec, IDD_FLIST, IDD_FPATH, wFileAttr) ;
SetDlgItemText (hDlg, IDD_FNAME, szFileSpec) ;
return TRUE ;
case WM_COMMAND :
switch (wParam)
{
case IDD_FLIST :
switch (HIWORD (lParam))
{
case LBN_SELCHANGE :
if (DlgDirSelect (hDlg, szFileName, IDD_FLIST))
lstrcat (szFileName, szFileSpec) ;
SetDlgItemText (hDlg, IDD_FNAME, szFileName) ;
return TRUE ;
case LBN_DBLCLK :
if (DlgDirSelect (hDlg, szFileName, IDD_FLIST))
{
lstrcat (szFileName, szFileSpec) ;
DlgDirList (hDlg, szFileName, IDD_FLIST, IDD_FPATH,
wFileAttr) ;
SetDlgItemText (hDlg, IDD_FNAME, szFileSpec) ;
}
else
{
SetDlgItemText (hDlg, IDD_FNAME, szFileName) ;
SendMessage (hDlg, WM_COMMAND, IDOK, 0L) ;
}
return TRUE ;
}
break ;
case IDD_FNAME :
if (HIWORD (lParam) == EN_CHANGE)
EnableWindow (GetDlgItem (hDlg, IDOK),
(BOOL) SendMessage (LOWORD (lParam),
WM_GETTEXTLENGTH, 0, 0L)) ;
return TRUE ;
case IDOK :
GetDlgItemText (hDlg, IDD_FNAME, szFileName, 80) ;
nEditLen = lstrlen (szFileName) ;
cLastChar = *AnsiPrev (szFileName, szFileName + nEditLen) ;
if (cLastChar == '\\' || cLastChar == ':')
lstrcat (szFileName, szFileSpec) ;
if (lstrchr (szFileName, '*') || lstrchr (szFileName, '?'))
{
if (DlgDirList (hDlg, szFileName, IDD_FLIST,
IDD_FPATH, wFileAttr))
{
lstrcpy (szFileSpec, szFileName) ;
SetDlgItemText (hDlg, IDD_FNAME, szFileSpec) ;
}
else
MessageBeep (0) ;
return TRUE ;
}
lstrcat (lstrcat (szFileName, "\\"), szFileSpec) ;
if (DlgDirList (hDlg, szFileName, IDD_FLIST,
IDD_FPATH, wFileAttr))
{
lstrcpy (szFileSpec, szFileName) ;
SetDlgItemText (hDlg, IDD_FNAME, szFileSpec) ;
return TRUE ;
}
szFileName [nEditLen] = '\0' ;
if (-1 == OpenFile (szFileName, pof, OF_READ | OF_EXIST))
{
lstrcat (szFileName, szDefExt) ;
if (-1 == OpenFile (szFileName, pof, OF_READ | OF_EXIST))
{
MessageBeep (0) ;
return TRUE ;
}
}
lstrcpy (szFileName,
AnsiNext (lstrrchr (pof->szPathName, '\\'))) ;
OemToAnsi (szFileName, szFileName) ;
EndDialog (hDlg, TRUE) ;
return TRUE ;
case IDCANCEL :
EndDialog (hDlg, FALSE) ;
return TRUE ;
}
}
return FALSE ;
}
BOOL FAR PASCAL FileSaveDlgProc (HWND hDlg, WORD message,
WORD wParam, LONG lParam)
{
switch (message)
{
case WM_INITDIALOG :
SendDlgItemMessage (hDlg, IDD_FNAME, EM_LIMITTEXT, 80, 0L) ;
DlgDirList (hDlg, szFileSpec, 0, IDD_FPATH, 0) ;
SetDlgItemText (hDlg, IDD_FNAME, szFileSpec) ;
return TRUE ;
case WM_COMMAND :
switch (wParam)
{
case IDD_FNAME :
if (HIWORD (lParam) == EN_CHANGE)
EnableWindow (GetDlgItem (hDlg, IDOK),
(BOOL) SendMessage (LOWORD (lParam),
WM_GETTEXTLENGTH, 0, 0L)) ;
return TRUE ;
case IDOK :
GetDlgItemText (hDlg, IDD_FNAME, szFileName, 80) ;
if (-1 == OpenFile (szFileName, pof, OF_PARSE))
{
MessageBeep (0) ;
return TRUE ;
}
if (!lstrchr (AnsiNext (lstrrchr (pof->szPathName, '\\')),
'.'))
lstrcat (szFileName, szDefExt) ;
if (-1 != OpenFile (szFileName, pof, OF_WRITE | OF_EXIST))
wStatus = 1 ;
else if (-1 != OpenFile (szFileName, pof,
OF_CREATE | OF_EXIST))
wStatus = 0 ;
else
{
MessageBeep (0) ;
return TRUE ;
}
lstrcpy (szFileName,
AnsiNext (lstrrchr (pof->szPathName, '\\'))) ;
OemToAnsi (szFileName, szFileName) ;
EndDialog (hDlg, TRUE) ;
return TRUE ;
case IDCANCEL :
EndDialog (hDlg, FALSE) ;
return TRUE ;
}
}
return FALSE ;
}
LPSTR lstrchr (LPSTR str, char ch)
{
while (*str)
{
if (ch == *str)
return str ;
str = AnsiNext (str) ;
}
return NULL ;
}
LPSTR lstrrchr (LPSTR str, char ch)
{
LPSTR strl = str + lstrlen (str) ;
do
{
if (ch == *strl)
return strl ;
strl = AnsiPrev (str, strl) ;
}
while (strl > str) ;
return NULL ;
}
FILEDLG.H
/*-----------------------
FILEDLG.H header file
-----------------------*/
#define IDD_FNAME 0x10
#define IDD_FPATH 0x11
#define IDD_FLIST 0x12
FILEDLG.DLG
/*--------------------------------
FILEDLG.DLG dialog definitions
--------------------------------*/
FileOpen DIALOG 10, 10, 148, 116
STYLE WS_POPUP | WS_DLGFRAME
{
LTEXT "Open File &Name:", -1, 2, 4, 76, 10
EDITTEXT IDD_FNAME, 2, 18, 100, 12, ES_AUTOHSCROLL
LTEXT "&Files in", -1, 2, 40, 38, 10
LTEXT "", IDD_FPATH, 44, 40, 98, 12
LISTBOX IDD_FLIST, 2, 54, 70, 58, WS_TABSTOP | WS_VSCROLL
DEFPUSHBUTTON "&Open", IDOK, 88, 62, 50, 14, WS_GROUP
PUSHBUTTON "Cancel", IDCANCEL, 88, 86, 50, 14, WS_GROUP
}
FileSave DIALOG 10, 10, 180, 54
STYLE WS_POPUP | WS_DLGFRAME
{
LTEXT "Save File &Name As:", -1, 6, 4, 84, 12
LTEXT "", IDD_FPATH, 90, 4, 78, 12
EDITTEXT IDD_FNAME, 6, 20, 104, 12, ES_AUTOHSCROLL
DEFPUSHBUTTON "OK", IDOK, 124, 20, 50, 14, WS_GROUP
PUSHBUTTON "Cancel", IDCANCEL, 124, 36, 50, 14, WS_GROUP
}
FILEDLG.DLG contains two dialog box templates named ”FileOpen“ and ”FileSave.“ When displayed, these look very much like the dialog boxes used in the programs that come with Windows, so the operation of the two dialog boxes will be familiar to Windows users. FileOpen contains Open and Cancel push buttons, and FileSave contains OK and Cancel push buttons. The static text field with an ID of IDD_FPATH is used to display the current disk drive and directory path. The edit field with the ID of IDD_FNAME allows a user to type in a filename. The FileOpen dialog box also contains a list box that displays all the files matching a particular file specification (we'll use ”*.TXT“ with POPPAD3), all valid disk drive letters, and all child subdirectories of the current drive and directory.
The FILEDLG.C file contains two functions named DoFileOpenDlg and DoFileSaveDlg that a program can call to invoke the dialog boxes. These functions are responsible for copying input parameters to variables within FILEDLG.C, calling DialogBox, and returning information obtained from the dialog box procedure to the program that called the FILEDLG.C functions. The parameters to the DoFileOpenDlg and DoFileSaveDlg functions include a default file specification (szFileSpecIn), a default filename extension (szDefExtIn), and a pointer to a structure of type OFSTRUCT (pofIn). The DoFileOpenDlgProc also requires a file attribute (wFileAttrIn) to be used when listing files in the list box.
The DoFileOpenDlg and DoFileSaveDlg functions return a 1 if the user ends the dialog box with Open or OK, and a 0 if the user ends with Cancel. If the user ends with Open or OK, the OFSTRUCT structure passed to the functions will contain the fully qualified filename of the selected file in the szPathName field. The filename only (without a drive or directory) is copied to the szFileNameOut character array. For DoFileSaveDlg, the pwStatusOut parameter points to a word that is set to 1 if the file does exist and to 0 if it does not.
The actual dialog box procedures are FileOpenDlgProc and FileSaveDlgProc. These are relatively complex because they must deal with the interaction between the list box and the edit control and with the checking that must be performed on filenames and subdirectories entered by the user. To help with these areas, the dialog box procedures extensively use the Windows functions DlgDirList and DlgDirSelect.