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) ; 
}