DLGOPEN.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

/*******************************************************************************
* *
* MODULE : DLGOPEN.C *
* *
* DESCRIPTION : Routines to display a standard File/Open and File/Save *
* dialog boxes. *
* *
* FUNCTIONS : DlgOpenFile() - Displays a dialog box for opening or saving a*
* file. *
* *
* DlgfnOpen() - Dialog function for the above dialog. *
* *
* AddExt() - Adds an extension to a filename if not *
* already present. *
* *
* FSearchSpec() - Checks if given string contains a wildcard *
* character. *
* *
* FillListBox() - Fills listbox with files that match specs. *
* *
* DlgCheckOkEnable() - Enables <OK> button iff there's text in *
* the edit control. *
* *
* NOTE : These routines require that the app. be running *
* SS = DS since they use near pointers into the stack. *
* *
*******************************************************************************/
#include <windows.h>
#include <string.h>
#include "showdib.h"

static PSTR szExt;
static PSTR szFileName;
static PSTR szTitle;
static DWORD flags;
static WORD fOpt;

/* Forward declarations of helper functions */

static VOID NEAR DlgCheckOkEnable(HWND hwnd, INT idEdit, UINT message);
static CHAR *NEAR FillListBox (HWND,CHAR*, UINT);
static BOOL NEAR FSearchSpec (CHAR*);
static VOID NEAR AddExt (CHAR*,CHAR*);

#define DLGOPEN_UNUSED 0

/* Mask to eliminate bogus style and bitcount combinations ...
* RLE formats, if chosen should be matched with the bitcounts:
* RLE4 scheme should be used only for 4 bitcount DIBs.
* RLE8 " " " " " " 8 " "
*
* BITCOUNTMASK is indexed by DLGOPEN_RLE4 >> 4, DLGOPEN_RLE8 >> 4
* and DLGOPEN_RLE8 >> 4
*/

static WORD BITCOUNTMASK[] = { DLGOPEN_UNUSED,
DLGOPEN_1BPP | DLGOPEN_8BPP | DLGOPEN_24BPP,
DLGOPEN_1BPP | DLGOPEN_4BPP | DLGOPEN_24BPP,
DLGOPEN_UNUSED,
0 };


/*******************************************************************************
* *
* FUNCTION :DlgOpen(LPSTR szFile) *
* *
* PURPOSE :Display dialog box for opening files. Allow user to interact *
* with dialogbox, change directories as necessary, and try to *
* open file if user selects one. Automatically append *
* extension to filename if necessary. *
* This routine correctly parses filenames containing KANJI *
* characters. *
* *
* RETURNS : - Handle to the opened file if legal filename. *
* - 0 if user presses <cancel> *
* - 1 if filename entered is illegal *
* *
*******************************************************************************/
HFILE APIENTRY DlgOpenFile (
HWND hwndParent,
CHAR *szTitleIn,
DWORD flagsIn,
CHAR *szExtIn,
CHAR *szFileNameIn,
WORD *pfOpt)
{
INT fh;
FARPROC lpProc;
CHAR achFile[128];
CHAR achExt[128];
HANDLE hInstance;
WORD w;

if (pfOpt == NULL)
pfOpt = &w;

flags = flagsIn;
fOpt = *pfOpt;

lstrcpy (szFileName = achFile, szFileNameIn);
lstrcpy (szExt = achExt, szExtIn);
szTitle = szTitleIn;

hInstance = (HANDLE)GetWindowLong (hwndParent, GWL_HINSTANCE);

/* Show the dialog box */
lpProc = MakeProcInstance ((FARPROC)DlgfnOpen, hInstance);
fh = DialogBox (hInstance, "DlgOpenBox", hwndParent, (DLGPROC)lpProc);
FreeProcInstance (lpProc);

if (fh != 0){
lstrcpy (szFileNameIn, szFileName);
*pfOpt = fOpt;
}
return fh;
}

/****************************************************************************
* *
* FUNCTION :DlgfnOpen (hwnd, msg, wParam, lParam) *
* *
* PURPOSE :Dialog function for File/Open dialog. *
* *
****************************************************************************/
LONG APIENTRY DlgfnOpen (
HWND hwnd,
UINT msg,
UINT wParam,
LONG lParam)
{
INT result = -1; /* Assume illegal filename initially */
int w;
LPSTR lpsz;
WORD f;
OFSTRUCT of;
RECT rc, rcCtl;
HWND hwndT;
BOOL fEnable;
CHAR lpBuffer[128];

switch (msg) {
case WM_INITDIALOG:
if (szTitle && *szTitle)
SetWindowText (hwnd, szTitle);

/* Set text on <OK> button according to mode (File/Open or File/Save) */
if (flags & OF_SAVE) {
LoadString(hInst, IDS_SAVESTR, lpBuffer, sizeof(lpBuffer));
SetDlgItemText(hwnd, IDOK, lpBuffer);
}
if (flags & OF_OPEN) {
LoadString(hInst, IDS_OPENSTR, lpBuffer, sizeof(lpBuffer));
SetDlgItemText(hwnd, IDOK, lpBuffer);
}
if ((flags & OF_NOOPTIONS) &&
(hwndT = GetDlgItem(hwnd,DLGOPEN_FOLDOUT)))
EnableWindow (hwndT,FALSE);

if (hwndT = GetDlgItem (hwnd, DLGOPEN_SMALL)) {
GetWindowRect (hwnd,&rc);
GetWindowRect (GetDlgItem(hwnd,DLGOPEN_SMALL),&rcCtl);

SetWindowPos (hwnd,
NULL,
0,
0,
rcCtl.left - rc.left,
rc.bottom - rc.top,
SWP_NOZORDER | SWP_NOMOVE);
}
/* fill list box with filenames that match specifications, and
* fill static field with path name.
*/
FillListBox(hwnd,szExt, WM_INITDIALOG);

/* If in Save mode, set the edit control with default (current)
* file name,and select the corresponding entry in the listbox.
*/
if ((flags & OF_SAVE) && *szFileName) {
SetDlgItemText (hwnd, DLGOPEN_EDIT, szFileName);
SendDlgItemMessage (hwnd,
DLGOPEN_FILE_LISTBOX,
LB_SELECTSTRING,
0,
(LONG)(LPSTR)szFileName);
}
else {
/* Set the edit field with the default extensions... */
if (flags & OF_NOSHOWSPEC)
SetDlgItemText (hwnd, DLGOPEN_EDIT, "");
else
SetDlgItemText (hwnd, DLGOPEN_EDIT, szExt);
}
/* ...and select all text in the edit field */
/* JAP added HWND cast*/
SendMessage((HWND)GetDlgItem(hwnd, DLGOPEN_EDIT), EM_SETSEL, GET_EM_SETSEL_MPS(0, 0x7fff));

/* check all options that are set */
for ( f = DLGOPEN_1BPP; f; f<<=1)
CheckDlgButton(hwnd, (INT)FID(f), (WORD) (fOpt & f));

break;

case WM_COMMAND:
switch (LOWORD(wParam)) {
case IDOK:
if (IsWindowEnabled (GetDlgItem(hwnd, IDOK))) {
/* Get contents of edit field and add search spec. if it
* does not contain one.
*/
GetDlgItemText (hwnd, DLGOPEN_EDIT, (LPSTR)szFileName, 128);

lpsz = CharPrev(szFileName, szFileName + lstrlen(szFileName));
switch (*lpsz) {
case '\\':
case '/':
*lpsz = 0;
break;
}
if (SetCurrentDirectory ((LPSTR)szFileName))
lstrcpy (szFileName,szExt);

/* Try to open path. If successful, fill listbox with
* contents of new directory. Otherwise, open datafile.
*/
if (FSearchSpec(szFileName)) {
lstrcpy (szExt, FillListBox (hwnd, szFileName, WM_COMMAND));
if (flags & OF_NOSHOWSPEC) {
SetDlgItemText (hwnd, DLGOPEN_EDIT, "");
} else {
SetDlgItemText (hwnd, DLGOPEN_EDIT, szExt);
}
break;
}

/* Make filename upper case and if it's a legal DOS
* name, try to open the file.
*/
CharUpper(szFileName);
AddExt(szFileName,szExt);
result = (INT)OpenFile(szFileName, &of, (WORD)flags);

if (result != -1) {
lstrcpy(szFileName,of.szPathName);
}
else if (flags & OF_MUSTEXIST) {
MessageBeep(0);
return 0L;
}

/* Get the state of all checked options */
for (f = DLGOPEN_1BPP; f; f <<= 1){
if (IsDlgButtonChecked (hwnd, FID (f)))
fOpt |= f;
else
fOpt &= ~f;
}

EndDialog (hwnd, result);
}
break;

case DLGOPEN_OPTION + DLGOPEN_RLE4:
case DLGOPEN_OPTION + DLGOPEN_RLE8:
case DLGOPEN_OPTION + DLGOPEN_RGB:
/* Mask out incompatible bitcount options and gray the
* appropriate radiobuttons.
*/
for (f = DLGOPEN_1BPP; f <= DLGOPEN_24BPP; f <<= 1){
fEnable = !(f & BITCOUNTMASK [IDF(w) >> 4 ]);
EnableWindow (GetDlgItem (hwnd, FID(f)), fEnable);

/* If the radiobutton is being grayed, uncheck it and
* and check an "allowed" option so the bitcount group
* is still accessible via the keyboard
*/
if (!fEnable && IsDlgButtonChecked (hwnd, FID (f))){
CheckDlgButton(hwnd, FID(f), FALSE);
CheckDlgButton(hwnd, FID(IDF(w) >> 3), TRUE);
}
}
break;

case IDCANCEL:
/* User pressed cancel. Just take down dialog box. */
EndDialog (hwnd, 0);
break;

/* User single clicked or doubled clicked in listbox -
* Single click means fill edit box with selection.
* Double click means go ahead and open the selection.
*/
case DLGOPEN_FILE_LISTBOX:
case DLGOPEN_DIR_LISTBOX:
switch (GET_WM_COMMAND_CMD(wParam, lParam)) {
/* Single click case */
case LBN_SELCHANGE:
/* Get selection, which may be either a prefix to a
* new search path or a filename. DlgDirSelectEx parses
* selection, and appends a backslash if selection
* is a prefix
*/
DlgDirSelectEx(hwnd, szFileName, 128, LOWORD(wParam));
lpsz = CharPrev(szFileName, szFileName + lstrlen(szFileName));
switch (*lpsz) {
case ':':
lstrcat (szFileName,".");
break;
case '\\':
case '/':
*lpsz = 0;
break;
}
SetDlgItemText(hwnd, DLGOPEN_EDIT, szFileName);
break;
/* Double click case - first click has already been
* processed as single click
*/
case LBN_DBLCLK:
PostMessage (hwnd,WM_COMMAND,IDOK,0L);
break;
}
break;

case DLGOPEN_EDIT:
DlgCheckOkEnable(hwnd, DLGOPEN_EDIT, HIWORD(lParam));
break;

case DLGOPEN_FOLDOUT:
GetWindowRect(hwnd,&rc);
GetWindowRect(GetDlgItem(hwnd,DLGOPEN_BIG),&rcCtl);

if ((rcCtl.left <= rc.right) && (rcCtl.top <= rc.bottom))
GetWindowRect (GetDlgItem (hwnd, DLGOPEN_SMALL), &rcCtl);

SetWindowPos (hwnd,
NULL,
0,
0,
rcCtl.left - rc.left,
rc.bottom - rc.top,
SWP_NOZORDER | SWP_NOMOVE);
break;
}
default:
return FALSE;
}
return TRUE;
}

/****************************************************************************
* *
* FUNCTION : static void NEAR DlgCheckOkEnable(hwnd, idEdit, message) *
* *
* PURPOSE : Enables the <OK> button in a dialog box iff the edit item *
* contains text. *
* *
****************************************************************************/
static VOID NEAR DlgCheckOkEnable(
HWND hwnd,
INT idEdit,
UINT message)
{
if (message == EN_CHANGE) {
EnableWindow ( GetDlgItem (hwnd, IDOK),
(BOOL)SendMessage (GetDlgItem (hwnd, idEdit),
WM_GETTEXTLENGTH,
0, 0L));
}
}

/****************************************************************************
* *
* FUNCTION : AddExt (pch, ext) *
* *
* PURPOSE : Add an extension to a filename if none is already specified*
* *
****************************************************************************/
static VOID NEAR AddExt (
CHAR *pch, /* File name */
CHAR *ext) /* Extension to add */
{
CHAR acExt[20];
CHAR *pext = acExt;

while (*ext && *ext != '.') {
ext = CharNext(ext);
}
while (*ext && *ext != ';') {
if (IsDBCSLeadByte(*ext)) {
*pext++ = *ext++;
}
*pext++ = *ext++;
}
*pext = 0;
pext = acExt;

while (*pch == '.') {
pch++;
if ((*pch == '.') && pch[1] == '\\')
pch += 2; /* ..\ */
if (*pch == '\\')
pch++; /* .\ */
}
while (*pch != '\0') {
if (*pch == '.')
return;
pch = CharNext(pch);
}

// *pch++ = '.';
do
*pch++ = *pext;
while (*pext++ != '\0');
}
/****************************************************************************
* *
* FUNCTION : FSearchSpec (sz) *
* *
* PURPOSE : Checks to see if NULL-terminated strings contains a "*" or *
* a "?". *
* *
* RETURNS : TRUE - if the above characters are found in the string *
* FALSE - otherwise. *
* *
****************************************************************************/
static BOOL NEAR FSearchSpec(CHAR *sz)
{
for (; *sz ;sz = CharNext(sz)) {
if (*sz == '*' || *sz == '?')
return TRUE;
}
return FALSE;
}

/****************************************************************************
* *
* FUNCTION : static char * NEAR FillListBox (hDlg,pFile, cmd) *
* *
* PURPOSE : Fill list box with filenames that match specifications, and*
* fills the static field with the path name. *
* *
* RETURNS : A pointer to the pathname. *
* *
****************************************************************************/
static CHAR * NEAR FillListBox (
HWND hDlg,
CHAR *pFile, /* [path]{list of file wild cards, separated by ';'} */
UINT cmd) /* if initdialog, or WM_COMMAND*/
{
CHAR ach[128];
CHAR *pch;
CHAR *pDir; /* Directory name or path */
CHAR pCurDir[256];

pch = pFile;
pDir = ach;
if(cmd == WM_INITDIALOG){
while (*pch && *pch != ';')
pch = CharNext(pch);
while ((pch > pFile) && (*pch != '/') && (*pch != '\\'))
pch = CharPrev(pFile, pch);
if (pch > pFile) {
*pch = 0;
lstrcpy (pDir, pFile);
pFile = pch + 1;
}
else {
lstrcpy (pDir,".");
}
}
else{
/* since SetCurrentDirectory was called already, I'll use GetCurrentDirectory*/
/* to get pDir*/
GetCurrentDirectory(256, pCurDir);
strcpy(pDir, pCurDir);
}
DlgDirList (hDlg, pDir, (INT)DLGOPEN_DIR_LISTBOX, (INT)DLGOPEN_PATH,(WORD)ATTRDIRLIST);
SendDlgItemMessage (hDlg, DLGOPEN_FILE_LISTBOX, LB_RESETCONTENT, 0, 0L);
SendDlgItemMessage (hDlg, DLGOPEN_FILE_LISTBOX, WM_SETREDRAW, FALSE, 0L);
pDir = pFile; /* save pFile to return */
while (*pFile) {
pch = ach;
while (*pFile==' ')
pFile++;
while (*pFile && *pFile != ';') {
if (IsDBCSLeadByte(*pFile)) {
*pch++ = *pFile++;
}
*pch++ = *pFile++;
}
*pch = 0;
if (*pFile)
pFile++;
SendDlgItemMessage (hDlg,
DLGOPEN_FILE_LISTBOX,
LB_DIR,ATTRFILELIST,
(LONG)(LPSTR)ach);
}
SendDlgItemMessage (hDlg, DLGOPEN_FILE_LISTBOX, WM_SETREDRAW, TRUE, 0L);
InvalidateRect (GetDlgItem (hDlg, DLGOPEN_FILE_LISTBOX), NULL, TRUE);

return pDir;
}