OPEN.C

/************************************************************************ 

File: open.c

Purpose:

This file contains the routines to control the CDTEST.EXE "Open" dialog
box. The "Open" dialog box allows the user to enter values into an
OPENFILENAME structure and then create GetOpenFileName() dialog boxes
on the fly.

Functions:

DoOpenDialog() -- starts off the main dialog for "open"

OpenFunc() -- Callback function for main dialog

InitOpenStruct() -- Fills initial OPENFILENAME structure.

FillOpenDlg() -- Fills the dialog with the values from
the OPENFILENAME structure.

GetOpenDlg() -- Retrieves the users entries from the
main dialog and puts them in the
OPENFILENAME structure.

InitFilterString() -- Creates filter string

InitCustFiltString() -- Creates custom filter string

InterpretCustomFilterString() -- Parses custom filter string returned
from GetOpenFileName()

GetCorrectResourceHandle() -- Loads custom templates from file
as resource handles

OpenSaveHookProc() -- The hook function that will be
called if GetOpen/Save is called
with the OFN_ENABLEHOOK flag set.

MultiThreadOpenSave() -- Creates two Open/Save dialogs that
the user can simultaneously access

OpenSaveThread1Proc() -- The starting address of thread 1

OpenSaveThread2Proc() -- The starting address of thread 2

DoOpenSaveStuff() -- Does the actuall calling of
GetOpen/SaveFileName()

OpenMultiThreadEnableButtons() -- Enables and disables buttons in
main dialog. Needed when multi-
threading.

************************************************************************/

#include <windows.h>
#include <commdlg.h>
#include <stdlib.h>
#include <winnls.h>
#include "cdtest.h"
#include "open.h"
#include "save.h"
#include "dlgs.h" //include file that contains all #defines for the
//commdlg dialog templates.


/* All functions defined in this file + 1 external function
and one external variable */

extern UINT uMode ; //see cdtest.c
extern LONG MyAtol(LPTSTR, BOOL, LPBOOL) ;
void InterpretCustomFilterString(void) ;
HANDLE GetCorrectResourceHandle(void) ;
void DoOpenSaveStuff(LPOPENFILENAME) ;
UINT APIENTRY OpenSaveHookProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam) ;
DWORD OpenSaveThread1Proc(LPDWORD) ;
DWORD OpenSaveThread2Proc(LPDWORD) ;
void MultiThreadOpenSave(void) ;
void OpenMultiThreadEnableButtons(BOOL, HWND) ;


/* All global variables defined in this file */

HWND hwndMainDialog ; //global handle for open dialog.

HANDLE hRes ; //handles to the resource and dialog for
HANDLE hDialog ; //ofn_enabletemplatehandle

HBRUSH hBrushDlg ;
HBRUSH hBrushEdit ; //brush handles for new colors done with hook proc
HBRUSH hBrushButton ;

HANDLE hOpenSaveThread1, hOpenSaveThread2 ; //variables for the
DWORD dwThreadID1, dwThreadID2 ; //multithreading part
DWORD dwThreadParm1, dwThreadParm2 ;
OPENFILENAME ofnThread1, ofnThread2 ;
int nOpenDialogCount ;





/************************************************************************

Function: DoOpenDialog(HWND)

Purpose: To create the GetOpenFileName() and GetSaveFileName()
creation dialog.

Returns: Nothing.

Comments:

GetOpenFileName() and GetSaveFileName() are similiar enough so that
the same dialog can be used to edit their creation structure elements,
so a global variable "bDoOpenDlg" keeps track of which one to create
when the user clicks the OK or Multithread buttons...

************************************************************************/


void DoOpenDialog(HWND hwnd)
{

bDoOpenDlg = TRUE ;


DialogBox(hInst, MAKEINTRESOURCE(ID_OPENDIALOG), hwnd, OpenFunc) ;

}






/************************************************************************


Function: OpenFunc(HWND, UINT, UINT, LONG)

Purpose:

This is the callback function for the dialog box containing the
GetOpenFileName() and the GetSaveFileName() creation options.

This function will handle the messages for this dialog and create
either a GetOpenFileName() dialog or a GetSaveFileName() dialog
depending on the state of the bDoOpenDlg variable.

Returns: TRUE or FALSE depending on the situation.

Comments:


************************************************************************/


BOOL APIENTRY OpenFunc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
switch (msg)
{

case WM_INITDIALOG:

if (bDoOpenDlg)
SetWindowText(hwnd, TEXT("GetOpenFileName()")) ;
else
SetWindowText(hwnd, TEXT("GetSaveFileName()")) ;


/* initialize the OPENFILENAME structure members */

InitOpenStruct(hwnd, &ofn) ;


/* Fill these values into the creation dialog */

FillOpenDlg(hwnd, &ofn) ;


/* There are three separate OPENFILENAME structures. One for
the main Open/Save dialog and one for each multithreaded dialog.
Set them equal to begin with */

*(&ofnThread1) = *(&ofnThread2) = *(&ofn) ;

hwndMainDialog = hwnd ;

SetFocus(GetDlgItem(hwnd, ID_STRUCTSIZEO)) ;

break ;



case UMSG_DECREMENTDLGCOUNT: //user defined message indicating
//the closure of a multithreaded dialog

/* When we are multithreading, there is nothing to prevent the
user from interacting with the creation dialog once the first
GetOpen(Save) file name dialog has returned. So, in order
to prevent the Multithread" button from being pressed again
before the previous two multithreaded dialogs have been canceled,
disable the controls until we get a message from each thread
that the dialog has ended */


nOpenDialogCount-- ;

if (nOpenDialogCount == 0)
OpenMultiThreadEnableButtons(TRUE, hwnd) ;

break ;


case WM_COMMAND:
{
switch (LOWORD(wParam))
{

case IDOK:
GetOpenDlg(hwnd, &ofn) ; //get the user's input
DoOpenSaveStuff(&ofn) ; //do the dialog
break ;


case IDCANCEL:
EndDialog(hwnd, FALSE) ;
break ;


case ID_RESETOPEN:

SendDlgItemMessage(hwnd, ID_FILTERO, CB_RESETCONTENT,
(WPARAM) 0, (LPARAM) 0) ;

InitOpenStruct(hwnd, &ofn) ;

FillOpenDlg(hwnd, &ofn) ;

SendDlgItemMessage(hwnd, ID_NULLSTRUCTO, BM_SETCHECK, (WPARAM)0, (LPARAM)0) ;
SendDlgItemMessage(hwnd, ID_USEHINSTO, BM_SETCHECK, (WPARAM)0, (LPARAM)0) ;

*(&ofnThread1) = *(&ofnThread2) = *(&ofn) ;

SetFocus(GetDlgItem(hwnd, ID_STRUCTSIZEO)) ;

break ;


case ID_ADD1O:

GetDlgItemText(hwnd, ID_FILTERO, szTemp, 100) ;

if (*szTemp)
{
SendDlgItemMessage(hwnd, ID_FILTERO, CB_ADDSTRING, (WPARAM) 0,
(LPARAM) (LPTSTR) szTemp) ;
SetWindowText(GetDlgItem(hwnd, ID_FILTERO), TEXT("")) ;
}
break ;


case ID_ADD2O:

GetDlgItemText(hwnd, ID_CUSTFILTO, szTemp, 100) ;

if (*szTemp)
{
SendDlgItemMessage(hwnd, ID_CUSTFILTO, CB_ADDSTRING, (WPARAM) 0,
(LPARAM) (LPTSTR) szTemp) ;
SetWindowText(GetDlgItem(hwnd, ID_CUSTFILTO), TEXT("")) ;
}
break ;


case ID_CLEAR1O:
SendDlgItemMessage(hwnd, ID_FILTERO, CB_RESETCONTENT,
(WPARAM) 0, (LPARAM) 0) ;
break ;

case ID_CLEAR2O:
SendDlgItemMessage(hwnd, ID_CUSTFILTO, CB_RESETCONTENT,
(WPARAM) 0, (LPARAM) 0) ;
break ;

case ID_MULTIOPEN:

/* First, disable the OK, Cancel, and MultiThread buttons */

OpenMultiThreadEnableButtons(FALSE, hwnd) ;


/* Then multithread the dialogs */

nOpenDialogCount = 2 ;

MultiThreadOpenSave() ;

break ;


default: //end WM_COMMAND case
break ;
}
}

default:

/* If the help button is pressed in the GetOpen/SaveFileName()
dialogs, it will send a message Registered with RegisterWindowMessage()
to the parent window. The message nHelpMessage was registered
at application startup */

if (msg == nHelpMessage)
MessageBox(GetForegroundWindow(),
TEXT("Hello from the help button"),
TEXT("Open Help Button"), MB_OK | MB_APPLMODAL) ;

break ;

}

return FALSE ;
}







/************************************************************************


Function: InitOpenStruct(HWND, LPOPENFILENAME)

Purpose:

Initializes the OPENFILENAME structure. The structure is referenced
via a pointer passed in as the second parameter so that we can pass
any of the three OPENFILENAME structures into this function and
Initialize them.

Returns: Nothing.

Comments:

The szFilterInits and szCustFiltInits arrays are initialized to
contain some default strings. Eventually the strings in
these arrays must be arranged one after the other with a null
character between them and two null characters at the end:

"Text files\0*.txt\0All files\0*.*\0\0"

************************************************************************/


void InitOpenStruct(HWND hwnd, LPOPENFILENAME po)
{
int i = 0 ;
szFileName[0] = 0 ;
szFileTitle[0] = 0 ;

dwFlags = OFN_READONLY | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_SHOWHELP ;

if (bDoOpenDlg)
lstrcpy(szDlgTitle, TEXT("Open Dialog Title")) ;
else
lstrcpy(szDlgTitle, TEXT("Save Dialog Title")) ;

lstrcpy(szDefExt, TEXT("rat")) ;
lstrcpy(szInitialDir, TEXT("c:\\")) ;
lstrcpy(szTempName, TEXT("opentemp1")) ;

lstrcpy(&szFilterInits[0][0], TEXT("All Files (*.*)")) ;
lstrcpy(&szFilterInits[1][0], TEXT("*.*")) ;
lstrcpy(&szFilterInits[2][0], TEXT("Fat Files (*.fat)")) ;
lstrcpy(&szFilterInits[3][0], TEXT("*.fat")) ;
szFilterInits[4][0] = (TCHAR) 0 ;

lstrcpy(&szCustFiltInits[0][0], TEXT("Last Filter Used")) ;
lstrcpy(&szCustFiltInits[1][0], TEXT("*.lst")) ;
szCustFiltInits[2][0] = (TCHAR) 0 ;


/*

These two functions will create "strings" in the applications
data area that are in the form

"Filter Description"\0
"Filter"\0
"Filter Description"\0
"Filter"\0
..
..
\0\0

The filters must be in this form in order that the common dialogs
interpret it correctly...
*/

InitFilterString() ;

InitCustFilterString() ;

po->lStructSize = sizeof(OPENFILENAME) ;
po->hwndOwner = hwnd ;
po->hInstance = hInst ;
(LPTSTR) po->lpstrFilter = lpszFilterString ;
po->lpstrCustomFilter = lpszCustFilterString ;
po->nMaxCustFilter = MAXCUSTFILTER ;
po->nFilterIndex = 1L ;
po->lpstrFile = szFileName ;
po->nMaxFile = FILENAMESIZE ;
po->lpstrFileTitle = szFileTitle ;
po->nMaxFileTitle = FILETITLESIZE ;
po->lpstrInitialDir = szInitialDir ;
(LPTSTR) po->lpstrTitle = szDlgTitle ;
po->Flags = dwFlags ;
po->nFileOffset = 0 ;
po->nFileExtension = 0 ;
(LPTSTR) po->lpstrDefExt = szDefExt;
po->lCustData = 0L ;
po->lpfnHook = OpenSaveHookProc ;
(LPTSTR) po->lpTemplateName = szTempName ;

return ;
}







/************************************************************************


Function: FillOpenDlg(HWND, LPOPENFILENAME)

Purpose:

- This function will fill in the edit boxes that correspond to each
of the fields in the OPENFILENAME structure. The user can accept
these values to create the common dialog or edit them.

Returns: Nothing.

Comments:

The contents of the strings "szShortFilter" and "szLongFilter"
determine how a WORD or a DWORD value is represented in the edit boxes

************************************************************************/

void FillOpenDlg(HWND hwnd, LPOPENFILENAME po)
{
int i = 0 ;

wsprintf(szTemp, szShortFilter, (int) po->lStructSize) ;
SetDlgItemText(hwnd, ID_STRUCTSIZEO, szTemp) ;

wsprintf(szTemp, szLongFilter, (LONG) po->hwndOwner) ;
SetDlgItemText(hwnd, ID_HWNDOWNERO, szTemp) ;

wsprintf(szTemp, szLongFilter, (LONG) po->hInstance) ;
SetDlgItemText(hwnd, ID_HINSTANCEO, szTemp) ;


SendDlgItemMessage(hwnd, ID_FILTERO, CB_RESETCONTENT,
(WPARAM) 0, (LPARAM) 0) ;

while (szFilterInits[i][0] != (TCHAR) 0)
{
SendDlgItemMessage(hwnd, ID_FILTERO, CB_ADDSTRING, (WPARAM) 0,
(LPARAM) (LPTSTR) &szFilterInits[i][0]) ;
i++ ;
}

SendDlgItemMessage(hwnd, ID_FILTERO, CB_SETCURSEL,
(WPARAM) 0, (LPARAM) 0 ) ;



SendDlgItemMessage(hwnd, ID_CUSTFILTO, CB_RESETCONTENT,
(WPARAM) 0, (LPARAM) 0) ;

for (i=0; i<2; i++)
SendDlgItemMessage(hwnd, ID_CUSTFILTO, CB_ADDSTRING, (WPARAM) 0,
(LPARAM) (LPTSTR) &szCustFiltInits[i][0]) ;

SendDlgItemMessage(hwnd, ID_CUSTFILTO, CB_SETCURSEL,
(WPARAM) 0, (LPARAM) 0) ;


wsprintf(szTemp, szShortFilter, (int) po->nMaxCustFilter) ;
SetDlgItemText(hwnd, ID_MAXCUSTFILTO, szTemp) ;

wsprintf(szTemp, szShortFilter, (int) po->nFilterIndex) ;
SetDlgItemText(hwnd, ID_FILTINDEXO, szTemp) ;

SetDlgItemText(hwnd, ID_SZFILEO, po->lpstrFile) ;

wsprintf(szTemp, szShortFilter, (int) po->nMaxFile) ;
SetDlgItemText(hwnd, ID_MAXSZFILEO, szTemp) ;

SetDlgItemText(hwnd, ID_SZFILETITLEO, po->lpstrFileTitle) ;

wsprintf(szTemp, szShortFilter, (int) po->nMaxFileTitle) ;
SetDlgItemText(hwnd, ID_MAXSZFILETITLEO, szTemp) ;

SetDlgItemText(hwnd, ID_SZINITDIRO, po->lpstrInitialDir) ;

SetDlgItemText(hwnd, ID_SZTITLEO, po->lpstrTitle) ;

wsprintf(szTemp, szLongFilter, po->Flags) ;
SetDlgItemText(hwnd, ID_FLAGSO, szTemp) ;

wsprintf(szTemp, szShortFilter, po->nFileOffset) ;
SetDlgItemText(hwnd, ID_FILEOFFO, szTemp) ;

wsprintf(szTemp, szShortFilter, po->nFileExtension) ;
SetDlgItemText(hwnd, ID_FILEEXTO, szTemp) ;

SetDlgItemText(hwnd, ID_SZDEFEXTO, po->lpstrDefExt) ;

wsprintf(szTemp, szLongFilter, po->lCustData) ;
SetDlgItemText(hwnd, ID_CUSTDATAO, szTemp) ;

wsprintf(szTemp, szLongFilter, po->lpfnHook) ;
SetDlgItemText(hwnd, ID_HOOKO, szTemp) ;

SetDlgItemText(hwnd, ID_TEMPLATEO, po->lpTemplateName) ;

return ;
}








/************************************************************************


Function: GetOpenDlg(HWND, LPOPENFILENAME)


Purpose:

This function will retrieve the contents of each edit box corresponding
with each field in the OPENFILENAME structure, and fill in the
OPENFILENAME structure with these values.

Returns: Nothing.

Comments:

if (uMode == IDM_HEXMODE), then the numbers should be interpreted as
hexidecimal and the MyAtol() function is called with its "bHex"
parameter set to true.

************************************************************************/

void GetOpenDlg(HWND hwnd, LPOPENFILENAME po)
{
int i ;
BOOL b ;
TCHAR szNum[20] ;

GetDlgItemText(hwnd, ID_STRUCTSIZEO, szNum, 20) ;
po->lStructSize = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_HWNDOWNERO, szNum, 20) ;
po->hwndOwner = (HWND) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_HINSTANCEO, szNum, 20) ;
po->hInstance = (HANDLE) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;


/* these are just strings, no conversion necessary */

i = 0 ;
while (SendDlgItemMessage(hwnd, ID_FILTERO, CB_GETLBTEXT, (WPARAM) i,
(LPARAM) (LPTSTR) szFilterInits[i]) != CB_ERR)
{ i++ ; }


/* create the filter string */

InitFilterString() ;


i = 0 ;

while (SendDlgItemMessage(hwnd, ID_CUSTFILTO, CB_GETLBTEXT, (WPARAM) i,
(LPARAM) (LPTSTR) szCustFiltInits[i]) != CB_ERR)
{ i++ ; }


InitCustFilterString() ;


GetDlgItemText(hwnd, ID_MAXCUSTFILTO, szNum, 20) ;
po->nMaxCustFilter = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_FILTINDEXO, szNum, 20) ;
po->nFilterIndex = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_SZFILEO, po->lpstrFile, MAXBUF) ;

GetDlgItemText(hwnd, ID_MAXSZFILEO, szNum, 20) ;
po->nMaxFile = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_SZFILETITLEO, po->lpstrFileTitle, MAXBUF) ;

GetDlgItemText(hwnd, ID_MAXSZFILETITLEO, szNum, MAXBUF) ;
po->nMaxFileTitle = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_SZINITDIRO, (LPTSTR) po->lpstrInitialDir, MAXBUF) ;

GetDlgItemText(hwnd, ID_SZTITLEO, (LPTSTR) po->lpstrTitle, MAXBUF) ;

GetDlgItemText(hwnd, ID_FLAGSO, szNum, 20) ;
po->Flags = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_FILEOFFO, szNum, 20) ;
po->nFileOffset = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_FILEEXTO, szNum, 20) ;
po->nFileExtension = (WORD) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_SZDEFEXTO, (LPTSTR) po->lpstrDefExt, DEFEXTSIZE) ;

GetDlgItemText(hwnd, ID_CUSTDATAO, szNum, 20) ;
po->lCustData = MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_HOOKO, szNum, 20) ;
po->lpfnHook = (LPOFNHOOKPROC) MyAtol(szNum, uMode==IDM_HEXMODE, &b) ;

GetDlgItemText(hwnd, ID_TEMPLATEO, (LPTSTR) po->lpTemplateName, TEMPNAMESIZE) ;


/* if we are supposed to use a preloaded resource handle, load it and put it in
OPENFILENAME.hInstance... */

if (IsDlgButtonChecked(hwnd, ID_USEHINSTO) == 1)
po->hInstance = GetCorrectResourceHandle() ;

return ;
}







/************************************************************************


Function: InitFilterString(void)


Purpose:

This function will create a "string" in memory in the form that the
GetOpenFileName() function will expect for the filters it fills into
the "List Files of Type" combo box.

Returns: Nothing.

Comments:

The szFilterInits and szCustFiltInits arrays are initialized to
contain some default strings. Eventually the strings in
these arrays must be arranged one after the other with a null
character between them and two null characters at the end:

"Text files\0*.txt\0All files\0*.*\0\0"

************************************************************************/


void InitFilterString(void)
{
int i ;
int nInc = 0 ;
LPTSTR lpStr = szFilterString ;


/* First, zero out this memory just for the sake of sanity */

for (i=0; i<MAXBUF; i++)
szFilterString[i] = 0 ;


/* Now, for each string in the szFilterInits array, concatenate it to
the last one right after the last one's null terminator */

i = 0 ;

while (szFilterInits[i][0] != (TCHAR) 0)
{
lstrcpy(lpStr, &szFilterInits[i][0]) ;
nInc+=lstrlen(&szFilterInits[i][0]) + 1 ; //1 past null term...
lpStr = &szFilterString[nInc] ;
i++ ;
}

szFilterString[nInc] = (TCHAR) 0 ; //double terminator


/* Set the lpszFilterString to point to the memory we just filled in
with the filters because lpszFilterString is what is in
OPENFILENAME->lpstrFilter */

lpszFilterString = szFilterString ;

return ;
}









/************************************************************************


Function: InitCustFiltString(void)


Purpose:

This function will create a "string" in memory in the form that the
GetOpenFileName() function will expect for a custom filter.

Returns: Nothing.

Comments:

The szFilterInits and szCustFiltInits arrays are initialized to
contain some default strings. Eventually the strings in
these arrays must be arranged one after the other with a null
character between them and two null characters at the end:

"Text files\0*.txt\0All files\0*.*\0\0"

This program initializes these strings, but they do not need to be
initialized. The GetOpenFileName() functiion will write a filter
into this memory area if the user types a new filter into the
"FileName" box and returns by clicking the OK button (indicating that
a file matching that filter was found).

************************************************************************/


void InitCustFilterString(void)
{
int i ;
LPTSTR lpStr = szCustFilterString ;
int nInc = 0 ;

for (i=0; i<MAXBUF; i++)
szCustFilterString[i] = 0 ;

i = 0 ;

for(i=0; i<2; i++) //only two for the custom filter
{
lstrcpy(lpStr, &szCustFiltInits[i][0]) ;
nInc+=lstrlen(&szCustFiltInits[i][0]) + 1 ;
lpStr = &szCustFilterString[nInc] ;
}

szCustFilterString[nInc] = (TCHAR) 0 ;

lpszCustFilterString = szCustFilterString ;

return ;
}









/************************************************************************

Function: InterpretCustomFilterString(void)


Purpose:

This function will parse the memory that is being used for the
custom filter string. If the user returned TRUE after entering
their own filter, the new filter will be here and so we need to
add it to our custom filter init array...

Returns: Nothing.

Comments:

************************************************************************/

void InterpretCustomFilterString(void)
{
LPTSTR pNext ;

int nCount = lstrlen(ofn.lpstrCustomFilter) ;

pNext = ofn.lpstrCustomFilter + nCount + 1 ; //one past the NULL


/* add it to the filter inits array */

lstrcpy(&szCustFiltInits[0][0], ofn.lpstrCustomFilter) ;
lstrcpy(&szCustFiltInits[1][0], pNext) ;

}









/************************************************************************

Function: GetCorrectResourceHandle(void)

Purpose:

This function will use FindResource() to find the correct custom
template resource, use LoadResource() to get a handle to it.

Returns: A handle to a custom template resource.

Comments:

The names for the custom template for GetOpenFileName() are

"opentemp1" -- normal
"opentemp2" -- contains a multi-select list box for the file names

If the user has marked the "Preloaded Template" box and specified
OFN_ENABLETEMPLATEHANDLE in the "Flags" edit box, this handle
will be used to create the GetOpenFileName() dialog box.

************************************************************************/


HANDLE GetCorrectResourceHandle(void)
{
if (ofn.Flags & OFN_ALLOWMULTISELECT)
{
hRes = FindResource(hInst, TEXT("opentemp2"), RT_DIALOG) ;
hDialog = LoadResource(hInst, hRes) ;
}

else
{
hRes = FindResource(hInst, TEXT("opentemp1"), RT_DIALOG) ;
hDialog = LoadResource(hInst, hRes) ;
}

return hDialog ;
}







/************************************************************************

Function: OpenSaveHookProc(HWND, UINT, UINT, LONG) ;

Purpose:

This function is the hook function for the GetOpenFileName() function.
If GetOpenFileName() is called with the OFN_ENABLEHOOK flag, this
function will be called before the normal GetOpenFileName() dialog
function is called.

Returns: FALSE to pass the message on to the normal GetOpenFileName()
logic, TRUE to discard the message.

Comments:

To enable this function in this program, enter the value for
OFN_ENABLEHOOK in the "Flags" edit box.

************************************************************************/


UINT APIENTRY OpenSaveHookProc(HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
LPOPENFILENAME pOfn ;
TCHAR szMsg[50] ;

switch(msg)
{
case WM_INITDIALOG:

pOfn = (LPOPENFILENAME) lParam ;


/* During initialization, if there is a hook proc, the getopen()
code will send pointer to the OPENFILENAME strucure in the
lParam. To demonstrate this, pop up a message box if this
structure has a non zero value in the lCustData structure member */


if (pOfn->lCustData != 0L)
{
wsprintf(szMsg, TEXT("OPENFILENAME->lCustData is: %ld"), pOfn->lCustData) ;

MessageBox(hwnd, szMsg, TEXT("lCustData Sent!"), MB_OK) ;
}

SetWindowText(hwnd, TEXT("Open Hook Proc Dialog")) ;

break ;


/* use the WM_CTLCOLOR* messages to change the color of the Open
dialog */

case WM_CTLCOLORDLG:

if (!hBrushDlg)
hBrushDlg = GetStockObject(LTGRAY_BRUSH) ;

return (UINT) hBrushDlg ;

break ;


case WM_CTLCOLORBTN:

SetBkMode((HDC) wParam, TRANSPARENT) ; //sets background color
//for push and check box
//buttons...

if (!hBrushButton)
hBrushButton = GetStockObject(LTGRAY_BRUSH) ;

return (UINT) hBrushButton ;

break ;


case WM_CTLCOLORSTATIC:

SetTextColor((HDC) wParam, RGB(0x00, 0xff, 0x00)) ; //green
SetBkMode((HDC) wParam, TRANSPARENT) ; //transparent text

if (!hBrushDlg)
hBrushDlg = GetStockObject(LTGRAY_BRUSH) ;

return (UINT) hBrushDlg ;

break ;


case WM_COMMAND:
switch (LOWORD(wParam))
{
case chx1:
MessageBox(hwnd, TEXT("Read-Only button clicked..."),
TEXT("Open"), MB_OK | MB_APPLMODAL) ;
break ;

case ID_FILEPREVIEW:
MessageBox(hwnd, TEXT("File Preview Button Clicked"),
TEXT("Open"), MB_OK | MB_APPLMODAL) ;
break ;

default: break ;
}
break ;

default:

if (msg == nOpenShareVMsg)
{
MessageBox(hwnd, TEXT("The SHAREVSTRING message is here!"),
TEXT("Open"),
MB_ICONEXCLAMATION | MB_OK | MB_APPLMODAL) ;

return OFN_SHAREWARN ;
}
break ;
}

return FALSE ; //send msg to the common dialog code
}









/************************************************************************

Function: MultiThreadOpenSave(void)

Purpose:

This function will start two threads and then return. The two
threads will create GetOpenFileName() dialogs, and the user
can interact with two Open dialogs at once.

Returns: Nothing.

Comments:

This will create two Open dialogs, but they will be created in the
same location on the screen. The only way to change that would be
to call the function with a hookproc and move one of the windows.

But that would mean that if the user did not enter OFN_ENABLEHOOK
in the "Flags" edit box, we would be no better off than before. So,
in order to see both dialogs, you just have to move the top one out
of the way a little.

Multithreading note:

This function will return before the common dialog functions return.

Therefore, do not pass any parameters to this function that will be 
referenced by the common dialogs because as soon as this function
ends those parameters will be gone.

************************************************************************/

void MultiThreadOpenSave(void)
{

if (!(hOpenSaveThread1 = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0,
(LPTHREAD_START_ROUTINE) OpenSaveThread1Proc,
&dwThreadParm1, CREATE_SUSPENDED, &dwThreadID1)))

{
MessageBox(GetForegroundWindow(), TEXT("Cannot create thread 1"), NULL, MB_OK | MB_ICONEXCLAMATION) ;
OpenMultiThreadEnableButtons(TRUE, hwndMainDialog) ;
nOpenDialogCount = 0 ;
return ;
}



if (!(hOpenSaveThread2 = CreateThread((LPSECURITY_ATTRIBUTES) NULL, 0,
(LPTHREAD_START_ROUTINE) OpenSaveThread2Proc,
&dwThreadParm2, CREATE_SUSPENDED, &dwThreadID2)))
{
MessageBox(GetForegroundWindow(), TEXT("Cannot create thread 2"), NULL, MB_OK | MB_ICONEXCLAMATION) ;
OpenMultiThreadEnableButtons(TRUE, hwndMainDialog) ;
nOpenDialogCount = 0 ;
return ;
}


ResumeThread(hOpenSaveThread1) ;
ResumeThread(hOpenSaveThread2) ;

}







/************************************************************************

Function: OpenSaveThreadProc1(LPDWORD)

Purpose:

This is the address where the first thread starts executing.

Returns: Any DWORD value.

Comments:

************************************************************************/


DWORD OpenSaveThread1Proc(LPDWORD pDw)
{

/* Get the user's input */

GetOpenDlg(hwndMainDialog, &ofnThread1) ;


/* Do the dialog */

DoOpenSaveStuff(&ofnThread1) ;


/* send a message to the parent telling it to decrement the dialog count.
When the dialog count reaches zero, all the buttons are enabled again. */

SendMessage(hwndMainDialog, UMSG_DECREMENTDLGCOUNT, 0, 0L) ;

return 0L ;
}







/************************************************************************

Function: OpenSaveThreadProc2(LPDWORD)

Purpose:

This is the address where the second thread starts executing.

Returns: Any DWORD value.

Comments:

************************************************************************/

DWORD OpenSaveThread2Proc(LPDWORD pDw)
{
GetOpenDlg(hwndMainDialog, &ofnThread2) ;

DoOpenSaveStuff(&ofnThread2) ;

SendMessage(hwndMainDialog, UMSG_DECREMENTDLGCOUNT, 0, 0L) ;

return 0L ;
}







/************************************************************************

Function: DoOpenSaveStuff(LPOPENFILENAME)

Purpose:

This is the function that actually calls GetOpenFileName() or
GetSaveFileName(). It receives a pointer to the structure to
use as its only parameter.

Returns: Nothing.

Comments:

************************************************************************/

void DoOpenSaveStuff(LPOPENFILENAME po)
{
BOOL bRet = TRUE ;


/* If bOpenDlg is TRUE, do GetOpenFileName(), else do GetSave().
If the "NULL Structure" button is checked, send in a NULL pointer
to the function */

if (bDoOpenDlg)
{
if (IsDlgButtonChecked(hwndMainDialog, ID_NULLSTRUCTO) == 1)
bRet = GetOpenFileName((LPOPENFILENAME) NULL) ;
else
bRet = GetOpenFileName(po) ;
}

else
{
if (IsDlgButtonChecked(hwndMainDialog, ID_NULLSTRUCTO))
bRet = GetSaveFileName((LPOPENFILENAME) NULL) ;
else
bRet = GetSaveFileName(po) ;
}


/* Record the results */

wsprintf(szTemp, szLongFilter, CommDlgExtendedError()) ;
SetDlgItemText(hwndMainDialog, ID_ERRORO, szTemp) ;

wsprintf(szTemp, szShortFilter, (int) bRet) ;
SetDlgItemText(hwndMainDialog, ID_RETURNO, szTemp) ;

InterpretCustomFilterString() ;

FillOpenDlg(hwndMainDialog, po) ;

if (hDialog)
{
FreeResource(hDialog) ; //free ofn.hInstance
hDialog = (HANDLE) 0 ;
hRes = (HANDLE) 0 ;
}
}







/************************************************************************

Function: OpenMultiThreadEnableButtons(BOOL, HWND)

Purpose:

Enable or disable the buttons that might affect the state of the
OPENFILENAME structures. This is necessary because during a
multithreading session, these buttons may be accessible even though
there are Open dialogs still working and we don't want to change
the OPENFILENAME structure out from under them.


Returns: Nothing.

Comments:

************************************************************************/

void OpenMultiThreadEnableButtons(BOOL bEnable, HWND hwnd)
{
EnableWindow(GetDlgItem(hwnd, IDOK), bEnable) ;
EnableWindow(GetDlgItem(hwnd, IDCANCEL), bEnable) ;
EnableWindow(GetDlgItem(hwnd, ID_RESETOPEN), bEnable) ;
EnableWindow(GetDlgItem(hwnd, ID_MULTIOPEN), bEnable) ;
}