fileopen.c
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 277k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. /*++
  2. Copyright (c) 1990-1995,  Microsoft Corporation  All rights reserved.
  3. Module Name:
  4.     fileopen.c
  5. Abstract:
  6.     This module implements the Win32 fileopen dialogs.
  7. Revision History:
  8. --*/
  9. //
  10. //  Include Files.
  11. //
  12. #include <nt.h>
  13. #include <ntrtl.h>
  14. #include <nturtl.h>
  15. #include <windows.h>
  16. #include <port1632.h>
  17. #include <lm.h>
  18. #include <winnetwk.h>
  19. #include <npapi.h>
  20. #include <shellapi.h>
  21. #include <shlapip.h>
  22. #include <commctrl.h>
  23. #include <comctrlp.h>
  24. #include <tchar.h>
  25. #include "privcomd.h"
  26. #include "fileopen.h"
  27. //
  28. //  Constant Declarations.
  29. //
  30. #define WNTYPE_DRIVE    1
  31. #define MIN_DEFEXT_LEN  4
  32. #define BMPHIOFFSET     9
  33. //
  34. //  hbmpDirs array index values.
  35. //  Note:  Two copies: for standard background, and hilite.
  36. //         Relative order is important.
  37. //
  38. #define OPENDIRBMP    0
  39. #define CURDIRBMP     1
  40. #define STDDIRBMP     2
  41. #define FLOPPYBMP     3
  42. #define HARDDRVBMP    4
  43. #define CDDRVBMP      5
  44. #define NETDRVBMP     6
  45. #define RAMDRVBMP     7
  46. #define REMDRVBMP     8
  47.   //
  48.   //  If the following disktype is passed to AddDisk, then bTmp will be
  49.   //  set to true in the DISKINFO structure (if the disk is new).
  50.   //
  51. #define TMPNETDRV     9
  52. #define MAXDOSFILENAMELEN (12 + 1)     // 8.3 filename + 1 for NULL
  53. //
  54. //  Global Variables.
  55. //
  56. //
  57. //  Caching drive list.
  58. //
  59. extern DWORD dwNumDisks;
  60. extern OFN_DISKINFO gaDiskInfo[MAX_DISKS];
  61. DWORD dwNumDlgs = 0;
  62. //
  63. //  Used to update the dialogs after coming back from the net dlg button.
  64. //
  65. BOOL bGetNetDrivesSync = FALSE;
  66. LPTSTR lpNetDriveSync = NULL;
  67. BOOL bNetworkInstalled = TRUE;
  68. //
  69. //  Following array is used to send messages to all dialog box threads
  70. //  that have requested enumeration updating from the worker
  71. //  thread.  The worker thread sends off a message to each slot
  72. //  in the array that is non-NULL.
  73. //
  74. HWND gahDlg[MAX_THREADS];
  75. //
  76. //  For WNet apis.
  77. //
  78. HANDLE hLNDThread = NULL;
  79. extern HANDLE hMPR;
  80. extern HANDLE hMPRUI;
  81. TCHAR szCOMDLG32[] = TEXT("comdlg32.dll");
  82. TCHAR szMPR[]      = TEXT("mpr.dll");
  83. TCHAR szMPRUI[]    = TEXT("mprui.dll");
  84. //
  85. //  WNet stuff from mpr.dll.
  86. //
  87. typedef DWORD (WINAPI *LPFNWNETCONNDLG)(HWND, DWORD);
  88. typedef DWORD (WINAPI *LPFNWNETOPENENUM)(DWORD, DWORD, DWORD, LPNETRESOURCE, LPHANDLE);
  89. typedef DWORD (WINAPI *LPFNWNETENUMRESOURCE)(HANDLE, LPDWORD, LPVOID, LPDWORD);
  90. typedef DWORD (WINAPI *LPFNWNETCLOSEENUM)(HANDLE);
  91. typedef DWORD (WINAPI *LPFNWNETFORMATNETNAME)(LPTSTR, LPTSTR, LPTSTR, LPDWORD, DWORD, DWORD);
  92. typedef DWORD (WINAPI *LPFNWNETRESTORECONN)(HWND, LPTSTR);
  93. LPFNWNETCONNDLG lpfnWNetConnDlg;
  94. LPFNWNETOPENENUM lpfnWNetOpenEnum;
  95. LPFNWNETENUMRESOURCE lpfnWNetEnumResource;
  96. LPFNWNETCLOSEENUM lpfnWNetCloseEnum;
  97. LPFNWNETFORMATNETNAME lpfnWNetFormatNetName;
  98. LPFNWNETRESTORECONN lpfnWNetRestoreConn;
  99. //
  100. //  !!!!!
  101. //  Keep CHAR until unicode GetProcAddrW.
  102. //
  103. CHAR szWNetGetConn[] = "WNetGetConnectionW";
  104. CHAR szWNetConnDlg[] = "WNetConnectionDialog";
  105. CHAR szWNetOpenEnum[] = "WNetOpenEnumW";
  106. CHAR szWNetEnumResource[] = "WNetEnumResourceW";
  107. CHAR szWNetCloseEnum[] = "WNetCloseEnum";
  108. CHAR szWNetFormatNetName[] = "WNetFormatNetworkNameW";
  109. CHAR szWNetRestoreConn[] = "WNetRestoreConnectionW";
  110. WNDPROC lpLBProc = NULL;
  111. WNDPROC lpOKProc = NULL;
  112. //
  113. //  Drive/Dir bitmap dimensions.
  114. //
  115. LONG dxDirDrive = 0;
  116. LONG dyDirDrive = 0;
  117. //
  118. //  BUG! This needs to be on a per dialog basis for multi-threaded apps.
  119. //
  120. WORD wNoRedraw = 0;
  121. UINT msgWOWDIRCHANGE;
  122. UINT msgLBCHANGEA;
  123. UINT msgSHAREVIOLATIONA;
  124. UINT msgFILEOKA;
  125. UINT msgLBCHANGEW;
  126. UINT msgSHAREVIOLATIONW;
  127. UINT msgFILEOKW;
  128. BOOL bInChildDlg;
  129. BOOL bFirstTime;
  130. BOOL bInitializing;
  131. //
  132. //  Used by the worker thread to enumerate network disk resources.
  133. //
  134. extern DWORD cbNetEnumBuf;
  135. extern LPTSTR gpcNetEnumBuf;
  136. //
  137. //  List Net Drives global variables.
  138. //
  139. extern HANDLE hLNDEvent;
  140. BOOL bLNDExit = FALSE;
  141. extern CRITICAL_SECTION g_csLocal;
  142. extern CRITICAL_SECTION g_csNetThread;
  143. extern DWORD g_tlsiCurDir;
  144. extern DWORD g_tlsiCurThread;
  145. extern HDC hdcMemory;
  146. extern HBITMAP hbmpOrigMemBmp;
  147. HBITMAP hbmpDirDrive = HNULL;
  148. //
  149. //  Static Declarations.
  150. //
  151. static WORD cLock = 0;
  152. //
  153. //  Not valid RGB color.
  154. //
  155. static DWORD rgbWindowColor = 0xFF000000;
  156. static DWORD rgbHiliteColor = 0xFF000000;
  157. static DWORD rgbWindowText  = 0xFF000000;
  158. static DWORD rgbHiliteText  = 0xFF000000;
  159. static DWORD rgbGrayText    = 0xFF000000;
  160. static DWORD rgbDDWindow    = 0xFF000000;
  161. static DWORD rgbDDHilite    = 0xFF000000;
  162. TCHAR szCaption[TOOLONGLIMIT + WARNINGMSGLENGTH];
  163. TCHAR szWarning[TOOLONGLIMIT + WARNINGMSGLENGTH];
  164. LPOFNHOOKPROC glpfnFileHook = 0;
  165. //
  166. //  BUG!!
  167. //  Of course, in the case where there is a multi-threaded process
  168. //  that has > 1 threads simultaneously calling GetFileOpen, the
  169. //  following globals may cause problems.  Ntvdm???
  170. //
  171. static LONG dyItem = 0;
  172. static LONG dyText;
  173. static BOOL bChangeDir = FALSE;
  174. static BOOL bCasePreserved;
  175. //
  176. //  Used for formatting long unc names (ex. banyan).
  177. //
  178. static DWORD dwAveCharPerLine = 10;
  179. //
  180. //  Function Prototypes.
  181. //
  182. SHORT
  183. GetFileTitleX(
  184.     LPTSTR lpszFile,
  185.     LPTSTR lpszTitle,
  186.     WORD wBufSize);
  187. BOOL
  188. GetFileName(
  189.     POPENFILEINFO pOFI,
  190.     WNDPROC qfnDlgProc);
  191. BOOL
  192. FileOpenDlgProc(
  193.     HWND hDlg,
  194.     UINT wMsg,
  195.     WPARAM wParam,
  196.     LPARAM lParam);
  197. BOOL
  198. FileSaveDlgProc(
  199.     HWND hDlg,
  200.     UINT wMsg,
  201.     WPARAM wParam,
  202.     LPARAM lParam);
  203. BOOL
  204. InitFileDlg(
  205.     HWND hDlg,
  206.     WPARAM wParam,
  207.     POPENFILEINFO pOFI);
  208. INT
  209. InitTlsValues();
  210. DWORD
  211. InitFilterBox(
  212.     HANDLE hDlg,
  213.     LPCTSTR lpszFilter);
  214. VOID
  215. InitCurrentDisk(
  216.     HWND hDlg,
  217.     POPENFILEINFO pOFI,
  218.     WORD cmb);
  219. VOID
  220. vDeleteDirDriveBitmap();
  221. BOOL
  222. LoadDirDriveBitmap();
  223. void
  224. SetRGBValues();
  225. BOOL
  226. FSetUpFile();
  227. BOOL
  228. FileOpenCmd(
  229.     HANDLE hDlg,
  230.     WPARAM wP,
  231.     DWORD lParam,
  232.     POPENFILEINFO pOFI,
  233.     BOOL bSave);
  234. BOOL
  235. UpdateListBoxes(
  236.     HWND hDlg,
  237.     POPENFILEINFO pOFI,
  238.     LPTSTR lpszFilter,
  239.     WORD wMask);
  240. BOOL
  241. OKButtonPressed(
  242.     HWND hDlg,
  243.     POPENFILEINFO pOFI,
  244.     BOOL bSave);
  245. BOOL
  246. MultiSelectOKButton(
  247.     HWND hDlg,
  248.     POPENFILEINFO pOFI,
  249.     BOOL bSave);
  250. BOOL WINAPI
  251. dwOKSubclass(
  252.     HWND hOK,
  253.     UINT msg,
  254.     WPARAM wP,
  255.     LPARAM lP);
  256. BOOL WINAPI
  257. dwLBSubclass(
  258.     HWND hLB,
  259.     UINT msg,
  260.     WPARAM wP,
  261.     LPARAM lP);
  262. INT
  263. InvalidFileWarning(
  264.     HWND hDlg,
  265.     LPTSTR szFile,
  266.     DWORD wErrCode,
  267.     UINT mbType);
  268. VOID
  269. MeasureItem(
  270.     HWND hDlg,
  271.     LPMEASUREITEMSTRUCT mis);
  272. INT
  273. Signum(
  274.     INT nTest);
  275. VOID
  276. DrawItem(
  277.     POPENFILEINFO pOFI,
  278.     HWND hDlg,
  279.     WPARAM wParam,
  280.     LPDRAWITEMSTRUCT lpdis,
  281.     BOOL bSave);
  282. BOOL
  283. SpacesExist(
  284.     LPTSTR szFileName);
  285. void
  286. StripFileName(
  287.     HANDLE hDlg,
  288.     BOOL bWowApp);
  289. LPTSTR
  290. lstrtok(
  291.     LPTSTR lpStr,
  292.     LPTSTR lpDelim);
  293. LPTSTR
  294. ChopText(
  295.     HWND hwndDlg,
  296.     INT idStatic,
  297.     LPTSTR lpch);
  298. BOOL
  299. FillOutPath(
  300.     HWND hList,
  301.     POPENFILEINFO pOFI);
  302. INT
  303. FListAll(
  304.     POPENFILEINFO pOFI,
  305.     HWND hDlg,
  306.     LPTSTR szSpec);
  307. INT
  308. ChangeDir(
  309.     HWND hDlg,
  310.     LPCTSTR lpszDir,
  311.     BOOL bForce,
  312.     BOOL bError);
  313. BOOL
  314. IsFileSystemCasePreserving(
  315.     LPTSTR lpszDisk);
  316. BOOL
  317. IsLFNDriveX(
  318.     HWND hDlg,
  319.     LPTSTR szPath);
  320. INT
  321. DiskAddedPreviously(
  322.     TCHAR wcDrive,
  323.     LPTSTR lpszName);
  324. INT
  325. AddDisk(
  326.     TCHAR wcDrive,
  327.     LPTSTR lpName,
  328.     LPTSTR lpProvider,
  329.     DWORD dwType);
  330. VOID
  331. EnableDiskInfo(
  332.     BOOL bValid,
  333.     BOOL bDoUnc);
  334. VOID
  335. FlushDiskInfoToCmb2();
  336. VOID
  337. LoadMPR();
  338. BOOL
  339. CallNetDlg(
  340.     HWND hWnd);
  341. UINT
  342. GetDiskType(
  343.     LPTSTR lpszDisk);
  344. DWORD
  345. GetUNCDirectoryFromLB(
  346.     HWND hDlg,
  347.     WORD nLB,
  348.     POPENFILEINFO pOFI);
  349. VOID
  350. SelDisk(
  351.     HWND hDlg,
  352.     LPTSTR lpszDisk);
  353. VOID
  354. LNDSetEvent(
  355.     HWND hDlg);
  356. VOID
  357. UpdateLocalDrive(
  358.     LPTSTR szDrive,
  359.     BOOL bGetVolName);
  360. VOID
  361. GetNetDrives(
  362.     DWORD dwScope);
  363. VOID
  364. ListNetDrivesHandler();
  365. VOID
  366. LoadDrives(
  367.     HWND hDlg);
  368. DWORD
  369. GetDiskIndex(
  370.     DWORD dwDriveType);
  371. VOID
  372. CleanUpFile();
  373. VOID
  374. FileOpenAbort();
  375. VOID
  376. TermFile();
  377. #ifdef UNICODE
  378. //VOID                                 // prototype in fileopen.h
  379. //ThunkOpenFileNameA2WDelayed(
  380. //    POPENFILEINFO pOFI);
  381. //BOOL                                 // prototype in fileopen.h
  382. //ThunkOpenFileNameA2W(
  383. //    POPENFILEINFO pOFI);
  384. //BOOL                                 // prototype in fileopen.h
  385. //ThunkOpenFileNameW2A(
  386. //    POPENFILEINFO pOFI);
  387.   BOOL
  388.   GenericGetFileNameA(
  389.       LPOPENFILENAMEA pOFNA,
  390.       WNDPROC qfnDlgProc);
  391. #endif
  392. #ifdef UNICODE
  393. ////////////////////////////////////////////////////////////////////////////
  394. //
  395. //  GetFileTitleA
  396. //
  397. //  ANSI entry point for GetFileTitle when this code is built UNICODE.
  398. //
  399. ////////////////////////////////////////////////////////////////////////////
  400. SHORT WINAPI GetFileTitleA(
  401.     LPCSTR lpszFileA,
  402.     LPSTR lpszTitleA,
  403.     WORD cbBuf)
  404. {
  405.     LPWSTR lpszFileW;
  406.     LPWSTR lpszTitleW;
  407.     BOOL fResult;
  408.     DWORD cbLen;
  409.     //
  410.     //  Init File string.
  411.     //
  412.     if (lpszFileA)
  413.     {
  414.         cbLen = lstrlenA(lpszFileA) + 1;
  415.         if (!(lpszFileW = (LPWSTR)LocalAlloc(LPTR, (cbLen * sizeof(WCHAR)))))
  416.         {
  417.             StoreExtendedError(CDERR_MEMALLOCFAILURE);
  418.             return (FALSE);
  419.         }
  420.         else
  421.         {
  422.             MultiByteToWideChar( CP_ACP,
  423.                                  0,
  424.                                  (LPSTR)lpszFileA,
  425.                                  -1,
  426.                                  lpszFileW,
  427.                                  cbLen );
  428.         }
  429.     }
  430.     else
  431.     {
  432.         lpszFileW = NULL;
  433.     }
  434.     if (!(lpszTitleW = (LPWSTR)LocalAlloc(LPTR, (cbBuf * sizeof(WCHAR)))))
  435.     {
  436.         StoreExtendedError(CDERR_MEMALLOCFAILURE);
  437.         if (lpszFileW)
  438.         {
  439.             LocalFree(lpszFileW);
  440.         }
  441.         return (FALSE);
  442.     }
  443.     if (!(fResult = GetFileTitleW(lpszFileW, lpszTitleW, cbBuf)))
  444.     {
  445.         WideCharToMultiByte( CP_ACP,
  446.                              0,
  447.                              lpszTitleW,
  448.                              -1,
  449.                              lpszTitleA,
  450.                              cbBuf,
  451.                              NULL,
  452.                              NULL );
  453.     }
  454.     //
  455.     // Clean up memory.
  456.     //
  457.     LocalFree(lpszTitleW);
  458.     if (lpszFileW)
  459.     {
  460.         LocalFree(lpszFileW);
  461.     }
  462.     return (fResult);
  463. }
  464. #else
  465. ////////////////////////////////////////////////////////////////////////////
  466. //
  467. //  GetFileTitleW
  468. //
  469. //  Stub UNICODE function for GetFileTitle when this code is built ANSI.
  470. //
  471. ////////////////////////////////////////////////////////////////////////////
  472. SHORT WINAPI GetFileTitleW(
  473.     LPCWSTR lpszFileW,
  474.     LPWSTR lpszTitleW,
  475.     WORD cbBuf)
  476. {
  477.     SetLastErrorEx(SLE_WARNING, ERROR_CALL_NOT_IMPLEMENTED);
  478.     return (FALSE);
  479. }
  480. #endif
  481. ////////////////////////////////////////////////////////////////////////////
  482. //
  483. //  GetFileTitle
  484. //
  485. //  The GetFileTitle function returns the name of the file identified
  486. //  by the lpCFile parameter.  This is useful if the file name was
  487. //  received via some method other than GetOpenFileName
  488. //  (e.g. command line, drag drop).
  489. //
  490. //  Returns:  0 on success
  491. //            < 0, Parsing failure (invalid file name)
  492. //            > 0, buffer too small, size needed (including NULL terminator)
  493. //
  494. ////////////////////////////////////////////////////////////////////////////
  495. SHORT WINAPI GetFileTitle(
  496.     LPCTSTR lpCFile,
  497.     LPTSTR lpTitle,
  498.     WORD cbBuf)
  499. {
  500.     LPTSTR lpFile;
  501.     DWORD cbLen;
  502.     SHORT fResult;
  503.     //
  504.     //  Init File string.
  505.     //
  506.     if (lpCFile)
  507.     {
  508.         cbLen = lstrlen(lpCFile) + 1;
  509.         if (!(lpFile = (LPTSTR)LocalAlloc(LPTR, (cbLen * sizeof(TCHAR)))))
  510.         {
  511.             StoreExtendedError(CDERR_MEMALLOCFAILURE);
  512.             return (FALSE);
  513.         }
  514.         else
  515.         {
  516.             lstrcpy(lpFile, lpCFile);
  517.         }
  518.     }
  519.     else
  520.     {
  521.         lpFile = NULL;
  522.     }
  523.     fResult = GetFileTitleX(lpFile, lpTitle, cbBuf);
  524.     //
  525.     // Clean up memory.
  526.     //
  527.     if (lpFile)
  528.     {
  529.         LocalFree(lpFile);
  530.     }
  531.     return (fResult);
  532. }
  533. ////////////////////////////////////////////////////////////////////////////
  534. //
  535. //  GetFileTitleX
  536. //
  537. //  Worker routine for the GetFileTitle api.
  538. //
  539. //  Assumes:  lpszFile  points to NULL terminated DOS filename (may have path)
  540. //            lpszTitle points to buffer to receive NULL terminated file title
  541. //            wBufSize  is the size of buffer pointed to by lpszTitle
  542. //
  543. //  Returns:  0 on success
  544. //            < 0, Parsing failure (invalid file name)
  545. //            > 0, buffer too small, size needed (including NULL terminator)
  546. //
  547. ////////////////////////////////////////////////////////////////////////////
  548. SHORT GetFileTitleX(
  549.     LPTSTR lpszFile,
  550.     LPTSTR lpszTitle,
  551.     WORD wBufSize)
  552. {
  553.     SHORT nNeeded;
  554.     LPTSTR lpszPtr;
  555.     nNeeded = (SHORT)(INT)LOWORD(ParseFile(lpszFile, TRUE, FALSE));
  556.     if (nNeeded >= 0)
  557.     {
  558.         //
  559.         //  Is the filename valid?
  560.         //
  561.         lpszPtr = (LPTSTR)lpszFile + nNeeded;
  562.         if ((nNeeded = (SHORT)lstrlen(lpszPtr) + 1) <= (INT)wBufSize)
  563.         {
  564.             //
  565.             //  ParseFile() fails if wildcards in directory, but OK if in name.
  566.             //  Since they arent OK here, the check is needed here.
  567.             //
  568.             if (mystrchr(lpszPtr, CHAR_STAR) ||
  569.                 mystrchr(lpszPtr, CHAR_QMARK))
  570.             {
  571.                 nNeeded = PARSE_WILDCARDINFILE;
  572.             }
  573.             else
  574.             {
  575.                 lstrcpy(lpszTitle, lpszPtr);
  576.                 //
  577.                 //  Remove trailing spaces.
  578.                 //
  579.                 lpszPtr = lpszTitle + lstrlen(lpszTitle) - 1;
  580.                 while (*lpszPtr && *lpszPtr == CHAR_SPACE)
  581.                 {
  582.                     *lpszPtr-- = CHAR_NULL;
  583.                 }
  584.                 nNeeded = 0;
  585.             }
  586.         }
  587.     }
  588.     return (nNeeded);
  589. }
  590. #ifdef UNICODE
  591. ////////////////////////////////////////////////////////////////////////////
  592. //
  593. //  GetOpenFileNameA
  594. //
  595. //  ANSI entry point for GetOpenFileName when this code is built UNICODE.
  596. //
  597. ////////////////////////////////////////////////////////////////////////////
  598. BOOL WINAPI GetOpenFileNameA(
  599.     LPOPENFILENAMEA pOFNA)
  600. {
  601.     if (!pOFNA)
  602.     {
  603.         StoreExtendedError(CDERR_INITIALIZATION);
  604.         return (FALSE);
  605.     }
  606.     return ( GenericGetFileNameA(pOFNA, (WNDPROC)FileOpenDlgProc) );
  607. }
  608. #else
  609. ////////////////////////////////////////////////////////////////////////////
  610. //
  611. //  GetOpenFileNameW
  612. //
  613. //  Stub UNICODE function for GetOpenFileName when this code is built ANSI.
  614. //
  615. ////////////////////////////////////////////////////////////////////////////
  616. BOOL WINAPI GetOpenFileNameW(
  617.     LPOPENFILENAMEW pOFNW)
  618. {
  619.     SetLastErrorEx(SLE_WARNING, ERROR_CALL_NOT_IMPLEMENTED);
  620.     return (FALSE);
  621. }
  622. #endif
  623. ////////////////////////////////////////////////////////////////////////////
  624. //
  625. //  GetOpenFileName
  626. //
  627. //  The GetOpenFileName function creates a system-defined dialog box
  628. //  that enables the user to select a file to open.
  629. //
  630. //  Returns:  TRUE    if user specified name
  631. //            FALSE   if not
  632. //
  633. ////////////////////////////////////////////////////////////////////////////
  634. BOOL WINAPI GetOpenFileName(
  635.     LPOPENFILENAME pOFN)
  636. {
  637.     OPENFILEINFO OFI;
  638.     ZeroMemory(&OFI, sizeof(OPENFILEINFO));
  639.     if (!pOFN)
  640.     {
  641.         StoreExtendedError(CDERR_INITIALIZATION);
  642.         return (FALSE);
  643.     }
  644.     OFI.pOFN = pOFN;
  645.     OFI.ApiType = COMDLG_WIDE;
  646.     return ( GetFileName(&OFI, (WNDPROC)FileOpenDlgProc) );
  647. }
  648. #ifdef UNICODE
  649. ////////////////////////////////////////////////////////////////////////////
  650. //
  651. //  GetSaveFileNameA
  652. //
  653. //  ANSI entry point for GetSaveFileName when this code is built UNICODE.
  654. //
  655. ////////////////////////////////////////////////////////////////////////////
  656. BOOL WINAPI GetSaveFileNameA(
  657.     LPOPENFILENAMEA pOFNA)
  658. {
  659.     return ( GenericGetFileNameA(pOFNA, (WNDPROC)FileSaveDlgProc) );
  660. }
  661. #else
  662. ////////////////////////////////////////////////////////////////////////////
  663. //
  664. //  GetSaveFileNameW
  665. //
  666. //  Stub UNICODE function for GetSaveFileName when this code is built ANSI.
  667. //
  668. ////////////////////////////////////////////////////////////////////////////
  669. BOOL WINAPI GetSaveFileNameW(
  670.     LPOPENFILENAMEW pOFNW)
  671. {
  672.     SetLastErrorEx(SLE_WARNING, ERROR_CALL_NOT_IMPLEMENTED);
  673.     return (FALSE);
  674. }
  675. #endif
  676. ////////////////////////////////////////////////////////////////////////////
  677. //
  678. //  GetSaveFileName
  679. //
  680. //  The GetSaveFileName function creates a system-defined dialog box
  681. //  that enables the user to select a file to save.
  682. //
  683. //  Returns:  TRUE    if user desires to save file and gave a proper name
  684. //            FALSE   if not
  685. //
  686. ////////////////////////////////////////////////////////////////////////////
  687. BOOL WINAPI GetSaveFileName(
  688.     LPOPENFILENAME pOFN)
  689. {
  690.     OPENFILEINFO OFI;
  691.     ZeroMemory(&OFI, sizeof(OPENFILEINFO));
  692.     OFI.pOFN = pOFN;
  693.     OFI.ApiType = COMDLG_WIDE;
  694.     return ( GetFileName(&OFI, (WNDPROC)FileSaveDlgProc) );
  695. }
  696. ////////////////////////////////////////////////////////////////////////////
  697. //
  698. //  GetFileName
  699. //
  700. //  This is the meat of both GetOpenFileName and GetSaveFileName.
  701. //
  702. //  Returns:  TRUE    if user specified name
  703. //            FALSE   if not
  704. //
  705. ////////////////////////////////////////////////////////////////////////////
  706. BOOL GetFileName(
  707.     POPENFILEINFO pOFI,
  708.     WNDPROC qfnDlgProc)
  709. {
  710.     LPOPENFILENAME pOFN = pOFI->pOFN;
  711.     INT iRet;
  712.     LPTSTR lpDlg;
  713.     HANDLE hRes, hDlgTemplate;
  714.     WORD wErrorMode;
  715.     HDC hdcScreen;
  716.     HBITMAP hbmpTemp;
  717.     static fFirstTime = TRUE;
  718.     LPTSTR lpCurDir, lpCurThread;
  719. #ifdef UNICODE
  720.     UINT uiWOWFlag = 0;
  721. #endif
  722.     if (!pOFN)
  723.     {
  724.         StoreExtendedError(CDERR_INITIALIZATION);
  725.         return (FALSE);
  726.     }
  727.     if (pOFN->lStructSize != sizeof(OPENFILENAME))
  728.     {
  729.         StoreExtendedError(CDERR_STRUCTSIZE);
  730.         return (FALSE);
  731.     }
  732.     //
  733.     //  See if the application should get the new look.
  734.     //
  735.     //  Do not allow the new look if they have hooks, templates, or
  736.     //  multi select without the OFN_EXPLORER bit.
  737.     //
  738.     //  Also don't allow the new look if we are in the context of
  739.     //  a 16 bit process.
  740.     //
  741.     if ( ((pOFN->Flags & OFN_EXPLORER) ||
  742.           (!(pOFN->Flags & (OFN_ENABLEHOOK |
  743.                             OFN_ENABLETEMPLATE |
  744.                             OFN_ENABLETEMPLATEHANDLE |
  745.                             OFN_ALLOWMULTISELECT)))) &&
  746. #ifdef WINNT
  747.          (!(pOFN->Flags & CD_WOWAPP)) )
  748. #else
  749.          (!(GetProcessDword(GetCurrentProcessId(), GPD_FLAGS) &
  750.             GPF_WIN16_PROCESS)) )
  751. #endif
  752.     {
  753. #ifdef UNICODE
  754.         //
  755.         //  To be used by the thunking routines for multi selection.
  756.         //
  757.         pOFI->bUseNewDialog = TRUE;
  758. #endif
  759.         //
  760.         //  Show the new explorer look.
  761.         //
  762.         StoreExtendedError(0);
  763.         bUserPressedCancel = FALSE;
  764.         if (qfnDlgProc == (WNDPROC)FileOpenDlgProc)
  765.         {
  766.             return ( NewGetOpenFileName(pOFI) );
  767.         }
  768.         else
  769.         {
  770.             return ( NewGetSaveFileName(pOFI) );
  771.         }
  772.     }
  773.     if (fFirstTime)
  774.     {
  775.         //
  776.         //  Create a DC that is compatible with the screen and find the
  777.         //  handle of the null bitmap.
  778.         //
  779.         hdcScreen = GetDC(HNULL);
  780.         if (!hdcScreen)
  781.         {
  782.             goto CantInit;
  783.         }
  784.         hdcMemory = CreateCompatibleDC(hdcScreen);
  785.         if (!hdcMemory)
  786.         {
  787.             goto ReleaseScreenDC;
  788.         }
  789.         hbmpTemp = CreateCompatibleBitmap(hdcMemory, 1, 1);
  790.         if (!hbmpTemp)
  791.         {
  792.             goto ReleaseMemDC;
  793.         }
  794.         hbmpOrigMemBmp = SelectObject(hdcMemory, hbmpTemp);
  795.         if (!hbmpOrigMemBmp)
  796.         {
  797.             goto ReleaseMemDC;
  798.         }
  799.         SelectObject(hdcMemory, hbmpOrigMemBmp);
  800.         DeleteObject(hbmpTemp);
  801.         ReleaseDC(HNULL, hdcScreen);
  802.         fFirstTime = FALSE;
  803.     }
  804.     if (pOFN->Flags & OFN_ENABLEHOOK)
  805.     {
  806.         if (!pOFN->lpfnHook)
  807.         {
  808.             StoreExtendedError(CDERR_NOHOOK);
  809.             return (FALSE);
  810.         }
  811.     }
  812.     else
  813.     {
  814.         pOFN->lpfnHook = NULL;
  815.     }
  816.     HourGlass(TRUE);
  817.     StoreExtendedError(0);
  818.     //
  819.     //  Force re-compute for font changes between calls
  820.     //
  821.     dyItem = dyText = 0;
  822.     bUserPressedCancel = FALSE;
  823.     if (!FSetUpFile())
  824.     {
  825.         StoreExtendedError(CDERR_INITIALIZATION);
  826.         goto TERMINATE;
  827.     }
  828.     if (pOFN->Flags & OFN_ENABLETEMPLATE)
  829.     {
  830.         if (!(hRes = FindResource( pOFN->hInstance,
  831.                                    pOFN->lpTemplateName,
  832.                                    RT_DIALOG )))
  833.         {
  834.             StoreExtendedError(CDERR_FINDRESFAILURE);
  835.             goto TERMINATE;
  836.         }
  837.         if (!(hDlgTemplate = LoadResource(pOFN->hInstance, hRes)))
  838.         {
  839.             StoreExtendedError(CDERR_LOADRESFAILURE);
  840.             goto TERMINATE;
  841.         }
  842.     }
  843.     else if (pOFN->Flags & OFN_ENABLETEMPLATEHANDLE)
  844.     {
  845.         hDlgTemplate = pOFN->hInstance;
  846.     }
  847.     else
  848.     {
  849.         if (pOFN->Flags & OFN_ALLOWMULTISELECT)
  850.         {
  851.             lpDlg = MAKEINTRESOURCE(MULTIFILEOPENORD);
  852.         }
  853.         else
  854.         {
  855.             lpDlg = MAKEINTRESOURCE(FILEOPENORD);
  856.         }
  857.         if (!(hRes = FindResource(g_hinst, lpDlg, RT_DIALOG)))
  858.         {
  859.             StoreExtendedError(CDERR_FINDRESFAILURE);
  860.             goto TERMINATE;
  861.         }
  862.         if (!(hDlgTemplate = LoadResource(g_hinst, hRes)))
  863.         {
  864.             StoreExtendedError(CDERR_LOADRESFAILURE);
  865.             goto TERMINATE;
  866.         }
  867.     }
  868.     //
  869.     //  No kernel network error dialogs.
  870.     //
  871.     wErrorMode = (WORD)SetErrorMode(SEM_NOERROR);
  872.     SetErrorMode(SEM_NOERROR | wErrorMode);
  873.     if (LockResource(hDlgTemplate))
  874.     {
  875.         if (pOFN->Flags & OFN_ENABLEHOOK)
  876.         {
  877.             glpfnFileHook = pOFN->lpfnHook;
  878.         }
  879. #ifdef UNICODE
  880.         if (pOFN->Flags & CD_WOWAPP)
  881.         {
  882.             uiWOWFlag = SCDLG_16BIT;
  883.         }
  884.         iRet = DialogBoxIndirectParamAorW( g_hinst,
  885.                                            (LPDLGTEMPLATE)hDlgTemplate,
  886.                                            pOFN->hwndOwner,
  887.                                            (DLGPROC)qfnDlgProc,
  888.                                            (DWORD)pOFI,
  889.                                            uiWOWFlag );
  890. #else
  891.         iRet = DialogBoxIndirectParam( g_hinst,
  892.                                        (LPDLGTEMPLATE)hDlgTemplate,
  893.                                        pOFN->hwndOwner,
  894.                                        (DLGPROC)qfnDlgProc,
  895.                                        (DWORD)pOFI );
  896. #endif
  897.         if ((iRet == 0) && (!bUserPressedCancel) && (!GetStoredExtendedError()))
  898.         {
  899.             StoreExtendedError(CDERR_DIALOGFAILURE);
  900.         }
  901.         else
  902.         {
  903.             FileOpenAbort();
  904.         }
  905.         glpfnFileHook = 0;
  906.     }
  907.     else
  908.     {
  909.         StoreExtendedError(CDERR_LOCKRESFAILURE);
  910.         goto TERMINATE;
  911.     }
  912.     SetErrorMode(wErrorMode);
  913.     if (lpCurDir = (LPTSTR)TlsGetValue(g_tlsiCurDir))
  914.     {
  915.         LocalFree(lpCurDir);
  916.     }
  917.     if (lpCurThread = (LPTSTR)TlsGetValue(g_tlsiCurThread))
  918.     {
  919.         LocalFree(lpCurThread);
  920.     }
  921. TERMINATE:
  922.     CleanUpFile();
  923.     HourGlass(FALSE);
  924.     return ((DWORD)iRet == IDOK);
  925. ReleaseMemDC:
  926.     DeleteDC(hdcMemory);
  927. ReleaseScreenDC:
  928.     ReleaseDC(HNULL, hdcScreen);
  929. CantInit:
  930.     return (FALSE);
  931. }
  932. ////////////////////////////////////////////////////////////////////////////
  933. //
  934. //  FileOpenDlgProc
  935. //
  936. //  Gets the name of a file to open from the user.
  937. //
  938. //  edt1 = file name
  939. //  lst1 = list of files in current directory matching current pattern
  940. //  cmb1 = lists file patterns
  941. //  stc1 = is current directory
  942. //  lst2 = lists directories on current drive
  943. //  cmb2 = lists drives
  944. //  IDOK = is Open pushbutton
  945. //  IDCANCEL = is Cancel pushbutton
  946. //  chx1 = is for opening read only files
  947. //
  948. //  Returns the normal dialog proc values.
  949. //
  950. ////////////////////////////////////////////////////////////////////////////
  951. BOOL FileOpenDlgProc(
  952.     HWND hDlg,
  953.     UINT wMsg,
  954.     WPARAM wParam,
  955.     LPARAM lParam)
  956. {
  957.     POPENFILEINFO pOFI;
  958.     BOOL bRet, bHookRet;
  959.     if (pOFI = (POPENFILEINFO)GetProp(hDlg, FILEPROP))
  960.     {
  961.         if (pOFI->pOFN->lpfnHook)
  962.         {
  963.             bHookRet = (*pOFI->pOFN->lpfnHook)(hDlg, wMsg, wParam, lParam);
  964.             if (bHookRet)
  965.             {
  966.                 if (wMsg == WM_COMMAND)
  967.                 {
  968.                     switch (GET_WM_COMMAND_ID(wParam, lParam))
  969.                     {
  970.                         case ( IDCANCEL ) :
  971.                         {
  972.                             //
  973.                             //  Set global flag stating that the
  974.                             //  user pressed cancel.
  975.                             //
  976.                             bUserPressedCancel = TRUE;
  977.                             //  Fall Thru...
  978.                         }
  979.                         case ( IDOK ) :
  980.                         case ( IDABORT ) :
  981.                         {
  982. #ifdef UNICODE
  983.                             //
  984.                             //  Apps that side-effect these messages may
  985.                             //  not have their internal unicode strings
  986.                             //  updated.  They may also forget to gracefully
  987.                             //  exit the network enum'ing worker thread.
  988.                             //
  989.                             if (pOFI->ApiType == COMDLG_ANSI)
  990.                             {
  991.                                 ThunkOpenFileNameA2W(pOFI);
  992.                             }
  993. #endif
  994.                             break;
  995.                         }
  996.                         case ( cmb1 ) :
  997.                         case ( cmb2 ) :
  998.                         {
  999.                             switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1000.                             {
  1001.                                 case ( MYCBN_DRAW ) :
  1002.                                 case ( MYCBN_LIST ) :
  1003.                                 case ( MYCBN_REPAINT ) :
  1004.                                 case ( MYCBN_CHANGEDIR ) :
  1005.                                 {
  1006.                                     //
  1007.                                     //  In case an app has a hook, and returns
  1008.                                     //  true for processing WM_COMMAND messages,
  1009.                                     //  we still have to worry about our
  1010.                                     //  internal message that came through via
  1011.                                     //  WM_COMMAND.
  1012.                                     //
  1013.                                     FileOpenCmd( hDlg,
  1014.                                                  wParam,
  1015.                                                  lParam,
  1016.                                                  pOFI,
  1017.                                                  FALSE );
  1018.                                     break;
  1019.                                 }
  1020.                             }
  1021.                             break;
  1022.                         }
  1023.                     }
  1024.                 }
  1025.                 return (bHookRet);
  1026.             }
  1027.         }
  1028.     }
  1029.     else if ( glpfnFileHook &&
  1030.               (wMsg != WM_INITDIALOG) &&
  1031.               (bHookRet = (*glpfnFileHook)(hDlg, wMsg, wParam, lParam)) )
  1032.     {
  1033.         return (bHookRet);
  1034.     }
  1035.     switch (wMsg)
  1036.     {
  1037.         case ( WM_INITDIALOG ) :
  1038.         {
  1039.             pOFI = (POPENFILEINFO)lParam;
  1040.             SetProp(hDlg, FILEPROP, (HANDLE)pOFI);
  1041.             glpfnFileHook = 0;
  1042.             //
  1043.             //  If we are being called from a Unicode app, turn off
  1044.             //  the ES_OEMCONVERT style on the filename edit control.
  1045.             //
  1046. //          if (pOFI->ApiType == COMDLG_WIDE)
  1047.             {
  1048.                 LONG lStyle;
  1049.                 HWND hEdit = GetDlgItem (hDlg, edt1);
  1050.                 //
  1051.                 //  Grab the window style.
  1052.                 //
  1053.                 lStyle = GetWindowLong (hEdit, GWL_STYLE);
  1054.                 //
  1055.                 //  If the window style bits include ES_OEMCONVERT,
  1056.                 //  remove this flag and reset the style.
  1057.                 //
  1058.                 if (lStyle & ES_OEMCONVERT)
  1059.                 {
  1060.                     lStyle &= ~ES_OEMCONVERT;
  1061.                     SetWindowLong (hEdit, GWL_STYLE, lStyle);
  1062.                 }
  1063.             }
  1064.             bInitializing = TRUE;
  1065.             bRet = InitFileDlg(hDlg, wParam, pOFI);
  1066.             bInitializing = FALSE;
  1067.             HourGlass(FALSE);
  1068.             return (bRet);
  1069.             break;
  1070.         }
  1071.         case ( WM_ACTIVATE ) :
  1072.         {
  1073.             if (!bInChildDlg)
  1074.             {
  1075.                 if (bFirstTime == TRUE)
  1076.                 {
  1077.                     bFirstTime = FALSE;
  1078.                 }
  1079.                 else if (wParam)
  1080.                 {
  1081.                     //
  1082.                     //  If becoming active.
  1083.                     //
  1084.                     LNDSetEvent(hDlg);
  1085.                 }
  1086.             }
  1087.             return (FALSE);
  1088.             break;
  1089.         }
  1090.         case ( WM_MEASUREITEM ) :
  1091.         {
  1092.             MeasureItem(hDlg, (LPMEASUREITEMSTRUCT)lParam);
  1093.             break;
  1094.         }
  1095.         case ( WM_DRAWITEM ) :
  1096.         {
  1097.             if (wNoRedraw < 2)
  1098.             {
  1099.                 DrawItem(pOFI, hDlg, wParam, (LPDRAWITEMSTRUCT)lParam, FALSE);
  1100.             }
  1101.             break;
  1102.         }
  1103.         case ( WM_SYSCOLORCHANGE ) :
  1104.         {
  1105.             SetRGBValues();
  1106.             LoadDirDriveBitmap();
  1107.             break;
  1108.         }
  1109.         case ( WM_COMMAND ) :
  1110.         {
  1111.             return (FileOpenCmd(hDlg, wParam, lParam, pOFI, FALSE));
  1112.             break;
  1113.         }
  1114.         case ( WM_SETFOCUS ) :
  1115.         {
  1116.             //
  1117.             //  This logic used to be in CBN_SETFOCUS in fileopencmd,
  1118.             //  but CBN_SETFOCUS is called whenever there is a click on
  1119.             //  the List Drives combo.  This causes the worker thread
  1120.             //  to start up and flicker when the combo box is refreshed.
  1121.             //
  1122.             //  But, refreshes are only needed when someone focuses out of
  1123.             //  the common dialog and then back in (unless someone is logged
  1124.             //  in remote, or there is a background thread busy connecting!)
  1125.             //  so fix the flicker by moving the logic here.
  1126.             //
  1127.             if (!wNoRedraw)
  1128.             {
  1129.                 LNDSetEvent(hDlg);
  1130.             }
  1131.             return (FALSE);
  1132.             break;
  1133.         }
  1134.         default :
  1135.         {
  1136.             return (FALSE);
  1137.         }
  1138.     }
  1139.     return (TRUE);
  1140. }
  1141. ////////////////////////////////////////////////////////////////////////////
  1142. //
  1143. //  FileSaveDlgProc
  1144. //
  1145. //  Obtains the name of the file that the user wants to save.
  1146. //
  1147. //  Returns the normal dialog proc values.
  1148. //
  1149. ////////////////////////////////////////////////////////////////////////////
  1150. BOOL FileSaveDlgProc(
  1151.     HWND hDlg,
  1152.     UINT wMsg,
  1153.     WPARAM wParam,
  1154.     LPARAM lParam)
  1155. {
  1156.     POPENFILEINFO pOFI;
  1157.     BOOL bRet, bHookRet;
  1158.     TCHAR szTitle[cbCaption];
  1159.     if (pOFI = (POPENFILEINFO) GetProp(hDlg, FILEPROP))
  1160.     {
  1161.         if (pOFI->pOFN->lpfnHook)
  1162.         {
  1163.             bHookRet = (*pOFI->pOFN->lpfnHook)(hDlg, wMsg, wParam, lParam);
  1164.             if (bHookRet)
  1165.             {
  1166.                 if (wMsg == WM_COMMAND)
  1167.                 {
  1168.                     switch (GET_WM_COMMAND_ID(wParam, lParam))
  1169.                     {
  1170.                         case ( IDCANCEL ) :
  1171.                         {
  1172.                             //
  1173.                             //  Set global flag stating that the
  1174.                             //  user pressed cancel.
  1175.                             //
  1176.                             bUserPressedCancel = TRUE;
  1177.                             //  Fall Thru...
  1178.                         }
  1179.                         case ( IDOK ) :
  1180.                         case ( IDABORT ) :
  1181.                         {
  1182. #ifdef UNICODE
  1183.                             //
  1184.                             //  Apps that side-effect these messages may
  1185.                             //  not have their internal unicode strings
  1186.                             //  updated; they may also forget to gracefully
  1187.                             //  exit the network enum'ing worker thread.
  1188.                             //
  1189.                             if (pOFI->ApiType == COMDLG_ANSI)
  1190.                             {
  1191.                                 ThunkOpenFileNameA2W(pOFI);
  1192.                             }
  1193. #endif
  1194.                             break;
  1195.                         }
  1196.                         case ( cmb1 ) :
  1197.                         case ( cmb2 ) :
  1198.                         {
  1199.                             switch (GET_WM_COMMAND_CMD(wParam, lParam))
  1200.                             {
  1201.                                 case ( MYCBN_DRAW ) :
  1202.                                 case ( MYCBN_LIST ) :
  1203.                                 case ( MYCBN_REPAINT ) :
  1204.                                 case ( MYCBN_CHANGEDIR ) :
  1205.                                 {
  1206.                                     //
  1207.                                     //  In case an app has a hook, and returns
  1208.                                     //  true for processing WM_COMMAND messages,
  1209.                                     //  we still have to worry about our
  1210.                                     //  internal message that came through via
  1211.                                     //  WM_COMMAND.
  1212.                                     //
  1213.                                     FileOpenCmd( hDlg,
  1214.                                                  wParam,
  1215.                                                  lParam,
  1216.                                                  pOFI,
  1217.                                                  FALSE );
  1218.                                     break;
  1219.                                 }
  1220.                             }
  1221.                             break;
  1222.                         }
  1223.                     }
  1224.                 }
  1225.                 return (bHookRet);
  1226.             }
  1227.         }
  1228.     }
  1229.     else if ( glpfnFileHook &&
  1230.               (wMsg != WM_INITDIALOG) &&
  1231.               (bHookRet = (*glpfnFileHook)(hDlg, wMsg,wParam, lParam)) )
  1232.     {
  1233.         return (bHookRet);
  1234.     }
  1235.     switch(wMsg)
  1236.     {
  1237.         case ( WM_INITDIALOG ) :
  1238.         {
  1239.             pOFI = (POPENFILEINFO)lParam;
  1240.             if (!(pOFI->pOFN->Flags &
  1241.                   (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
  1242.             {
  1243.                 LoadString(g_hinst, iszFileSaveTitle, (LPTSTR)szTitle, cbCaption);
  1244.                 SetWindowText(hDlg, (LPTSTR)szTitle);
  1245.                 LoadString(g_hinst, iszSaveFileAsType, (LPTSTR)szTitle, cbCaption);
  1246.                 SetDlgItemText(hDlg, stc2, (LPTSTR)szTitle);
  1247.             }
  1248.             glpfnFileHook = 0;
  1249.             SetProp(hDlg, FILEPROP, (HANDLE)pOFI);
  1250.             //
  1251.             //  If we are being called from a Unicode app, turn off
  1252.             //  the ES_OEMCONVERT style on the filename edit control.
  1253.             //
  1254. //          if (pOFI->ApiType == COMDLG_WIDE)
  1255.             {
  1256.                 LONG lStyle;
  1257.                 HWND hEdit = GetDlgItem (hDlg, edt1);
  1258.                 //
  1259.                 //  Grab the window style.
  1260.                 //
  1261.                 lStyle = GetWindowLong (hEdit, GWL_STYLE);
  1262.                 //
  1263.                 //  If the window style bits include ES_OEMCONVERT,
  1264.                 //  remove this flag and reset the style.
  1265.                 //
  1266.                 if (lStyle & ES_OEMCONVERT)
  1267.                 {
  1268.                     lStyle &= ~ES_OEMCONVERT;
  1269.                     SetWindowLong (hEdit, GWL_STYLE, lStyle);
  1270.                 }
  1271.             }
  1272.             bInitializing = TRUE;
  1273.             bRet = InitFileDlg(hDlg, wParam, pOFI);
  1274.             bInitializing = FALSE;
  1275.             HourGlass(FALSE);
  1276.             return (bRet);
  1277.             break;
  1278.         }
  1279.         case ( WM_ACTIVATE ) :
  1280.         {
  1281.             if (!bInChildDlg)
  1282.             {
  1283.                 if (bFirstTime == TRUE)
  1284.                 {
  1285.                     bFirstTime = FALSE;
  1286.                 }
  1287.                 else if (wParam)
  1288.                 {
  1289.                     //
  1290.                     //  If becoming active.
  1291.                     //
  1292.                     if (!wNoRedraw)
  1293.                     {
  1294.                         LNDSetEvent(hDlg);
  1295.                     }
  1296.                 }
  1297.             }
  1298.             return (FALSE);
  1299.             break;
  1300.         }
  1301.         case ( WM_MEASUREITEM ) :
  1302.         {
  1303.             MeasureItem(hDlg, (LPMEASUREITEMSTRUCT)lParam);
  1304.             break;
  1305.         }
  1306.         case ( WM_DRAWITEM ) :
  1307.         {
  1308.             if (wNoRedraw < 2)
  1309.             {
  1310.                 DrawItem(pOFI, hDlg, wParam, (LPDRAWITEMSTRUCT)lParam, TRUE);
  1311.             }
  1312.             break;
  1313.         }
  1314.         case ( WM_SYSCOLORCHANGE ) :
  1315.         {
  1316.             SetRGBValues();
  1317.             LoadDirDriveBitmap();
  1318.             break;
  1319.         }
  1320.         case ( WM_COMMAND ) :
  1321.         {
  1322.             return (FileOpenCmd(hDlg, wParam, lParam, pOFI, TRUE));
  1323.             break;
  1324.         }
  1325.         case ( WM_SETFOCUS ) :
  1326.         {
  1327.             //
  1328.             //  This logic used to be in CBN_SETFOCUS in fileopencmd,
  1329.             //  but CBN_SETFOCUS is called whenever there is a click on
  1330.             //  the List Drives combo.  This causes the worker thread
  1331.             //  to start up and flicker when the combo box is refreshed.
  1332.             //
  1333.             //  But, refreshes are only needed when someone focuses out of
  1334.             //  the common dialog and then back in (unless someone is logged
  1335.             //  in remote, or there is a background thread busy connecting!)
  1336.             //  so fix the flicker by moving the logic here.
  1337.             //
  1338.             if (!wNoRedraw)
  1339.             {
  1340.                 LNDSetEvent(hDlg);
  1341.             }
  1342.             return (FALSE);
  1343.             break;
  1344.         }
  1345.         default :
  1346.         {
  1347.             return (FALSE);
  1348.         }
  1349.     }
  1350.     return (TRUE);
  1351. }
  1352. ////////////////////////////////////////////////////////////////////////////
  1353. //
  1354. //  InitFileDlg
  1355. //
  1356. ////////////////////////////////////////////////////////////////////////////
  1357. BOOL InitFileDlg(
  1358.     HWND hDlg,
  1359.     WPARAM wParam,
  1360.     POPENFILEINFO pOFI)
  1361. {
  1362.     DWORD lRet;
  1363.     LPOPENFILENAME pOFN = pOFI->pOFN;
  1364.     INT nFileOffset, nExtOffset;
  1365.     RECT rRect;
  1366.     RECT rLbox;
  1367.     BOOL bRet;
  1368.     if (!InitTlsValues())
  1369.     {
  1370.         //
  1371.         //  The extended error is set inside of the above call.
  1372.         //
  1373.         EndDialog(hDlg, FALSE);
  1374.         return (FALSE);
  1375.     }
  1376.     lpLBProc = (WNDPROC)GetWindowLong(GetDlgItem(hDlg, lst2), GWL_WNDPROC);
  1377.     lpOKProc = (WNDPROC)GetWindowLong(GetDlgItem(hDlg, IDOK), GWL_WNDPROC);
  1378.     if (!lpLBProc || !lpOKProc)
  1379.     {
  1380.         StoreExtendedError(FNERR_SUBCLASSFAILURE);
  1381.         EndDialog(hDlg, FALSE);
  1382.         return (FALSE);
  1383.     }
  1384.     //
  1385.     //  Save original directory for later restoration if necessary.
  1386.     //
  1387.     *pOFI->szCurDir = 0;
  1388.     GetCurrentDirectory(MAX_FULLPATHNAME + 1, pOFI->szCurDir);
  1389.     //
  1390.     //  Check out if the filename contains a path.  If so, override whatever
  1391.     //  is contained in lpstrInitialDir.  Chop off the path and put up only
  1392.     //  the filename.
  1393.     //
  1394.     if ( pOFN->lpstrFile &&
  1395.          *pOFN->lpstrFile &&
  1396.          !(pOFN->Flags & OFN_NOVALIDATE) )
  1397.     {
  1398.         if (DBL_BSLASH(pOFN->lpstrFile + 2) &&
  1399.             ((*(pOFN->lpstrFile + 1) == CHAR_COLON)))
  1400.         {
  1401.             lstrcpy(pOFN->lpstrFile , pOFN->lpstrFile + sizeof(TCHAR));
  1402.         }
  1403.         lRet = ParseFile(pOFN->lpstrFile, TRUE, pOFN->Flags & CD_WOWAPP);
  1404.         nFileOffset = (INT)(SHORT)LOWORD(lRet);
  1405.         nExtOffset  = (INT)(SHORT)HIWORD(lRet);
  1406.         //
  1407.         //  Is the filename invalid?
  1408.         //
  1409.         if ( (nFileOffset < 0) &&
  1410.              (nFileOffset != PARSE_EMPTYSTRING) &&
  1411.              (pOFN->lpstrFile[nExtOffset] != CHAR_SEMICOLON) )
  1412.         {
  1413.             StoreExtendedError(FNERR_INVALIDFILENAME);
  1414.             EndDialog(hDlg, FALSE);
  1415.             return (FALSE);
  1416.         }
  1417.     }
  1418.     pOFN->Flags &= ~(OFN_FILTERDOWN | OFN_DRIVEDOWN | OFN_DIRSELCHANGED);
  1419.     pOFI->idirSub = 0;
  1420.     if (!(pOFN->Flags & OFN_SHOWHELP))
  1421.     {
  1422.         HWND hHelp;
  1423.         EnableWindow(hHelp = GetDlgItem(hDlg, psh15), FALSE);
  1424.         //
  1425.         //  Move the window out of this spot so that no overlap will be
  1426.         //  detected.
  1427.         //
  1428.         MoveWindow(hHelp, -8000, -8000, 20, 20, FALSE);
  1429.         ShowWindow(hHelp, SW_HIDE);
  1430.     }
  1431.     if (pOFN->Flags & OFN_CREATEPROMPT)
  1432.     {
  1433.         pOFN->Flags |= (OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST);
  1434.     }
  1435.     else if (pOFN->Flags & OFN_FILEMUSTEXIST)
  1436.     {
  1437.         pOFN->Flags |= OFN_PATHMUSTEXIST;
  1438.     }
  1439.     if (pOFN->Flags & OFN_HIDEREADONLY)
  1440.     {
  1441.         HWND hReadOnly;
  1442.         EnableWindow(hReadOnly = GetDlgItem(hDlg, chx1), FALSE);
  1443.         //
  1444.         //  Move the window out of this spot so that no overlap will be
  1445.         //  detected.
  1446.         //
  1447.         MoveWindow(hReadOnly, -8000, -8000, 20, 20, FALSE);
  1448.         ShowWindow(hReadOnly, SW_HIDE);
  1449.     }
  1450.     else
  1451.     {
  1452.         CheckDlgButton(hDlg, chx1, (pOFN->Flags & OFN_READONLY) != 0);
  1453.     }
  1454.     SendDlgItemMessage(hDlg, edt1, EM_LIMITTEXT, (WPARAM) MAX_PATH, (LPARAM) 0L);
  1455.     //
  1456.     //  Insert file specs into cmb1.
  1457.     //  Custom filter first.
  1458.     //  Must also check if filter contains anything.
  1459.     //
  1460.     if ( pOFN->lpstrFile &&
  1461.          (mystrchr(pOFN->lpstrFile, CHAR_STAR) ||
  1462.           mystrchr(pOFN->lpstrFile, CHAR_QMARK)) )
  1463.     {
  1464.         lstrcpy(pOFI->szLastFilter, pOFN->lpstrFile);
  1465.     }
  1466.     else
  1467.     {
  1468.         pOFI->szLastFilter[0] = CHAR_NULL;
  1469.     }
  1470.     if (pOFN->lpstrCustomFilter && *pOFN->lpstrCustomFilter)
  1471.     {
  1472.         SHORT nLength;
  1473.         SendDlgItemMessage( hDlg,
  1474.                             cmb1,
  1475.                             CB_INSERTSTRING,
  1476.                             0,
  1477.                             (LONG)pOFN->lpstrCustomFilter );
  1478.         nLength = (SHORT)(lstrlen(pOFN->lpstrCustomFilter) + 1);
  1479.         SendDlgItemMessage( hDlg,
  1480.                             cmb1,
  1481.                             CB_SETITEMDATA,
  1482.                             0,
  1483.                             (LONG)(nLength) );
  1484.         SendDlgItemMessage( hDlg,
  1485.                             cmb1,
  1486.                             CB_LIMITTEXT,
  1487.                             (WPARAM)(pOFN->nMaxCustFilter),
  1488.                             0L );
  1489.         if (pOFI->szLastFilter[0] == CHAR_NULL)
  1490.         {
  1491.             lstrcpy(pOFI->szLastFilter, pOFN->lpstrCustomFilter + nLength);
  1492.         }
  1493.     }
  1494.     else
  1495.     {
  1496.         //
  1497.         //  Given no custom filter, the index will be off by one.
  1498.         //
  1499.         if (pOFN->nFilterIndex != 0)
  1500.         {
  1501.             pOFN->nFilterIndex--;
  1502.         }
  1503.     }
  1504.     //
  1505.     //  Listed filters next.
  1506.     //
  1507.     if (pOFN->lpstrFilter && *pOFN->lpstrFilter)
  1508.     {
  1509.         if (pOFN->nFilterIndex > InitFilterBox(hDlg, pOFN->lpstrFilter))
  1510.         {
  1511.             pOFN->nFilterIndex = 0;
  1512.         }
  1513.     }
  1514.     else
  1515.     {
  1516.         pOFN->nFilterIndex = 0;
  1517.     }
  1518.     pOFI->szSpecCur[0] = CHAR_NULL;
  1519.     //
  1520.     //  If an entry exists, select the one indicated by nFilterIndex.
  1521.     //
  1522.     if ((pOFN->lpstrFilter && *pOFN->lpstrFilter) ||
  1523.         (pOFN->lpstrCustomFilter && *pOFN->lpstrCustomFilter))
  1524.     {
  1525.         SendDlgItemMessage( hDlg,
  1526.                             cmb1,
  1527.                             CB_SETCURSEL,
  1528.                             (WPARAM)(pOFN->nFilterIndex),
  1529.                             0L );
  1530.         SendMessage( hDlg,
  1531.                      WM_COMMAND,
  1532.                      GET_WM_COMMAND_MPS( cmb1,
  1533.                                          GetDlgItem(hDlg, cmb1),
  1534.                                          MYCBN_DRAW ) );
  1535.         if (!(pOFN->lpstrFile && *pOFN->lpstrFile))
  1536.         {
  1537.             LPCTSTR lpFilter;
  1538.             if (pOFN->nFilterIndex ||
  1539.                 !(pOFN->lpstrCustomFilter && * pOFN->lpstrCustomFilter))
  1540.             {
  1541.                 lpFilter = pOFN->lpstrFilter +
  1542.                            SendDlgItemMessage( hDlg,
  1543.                                                cmb1,
  1544.                                                CB_GETITEMDATA,
  1545.                                                (WPARAM)pOFN->nFilterIndex, 0L );
  1546.             }
  1547.             else
  1548.             {
  1549.                 lpFilter = pOFN->lpstrCustomFilter +
  1550.                            lstrlen(pOFN->lpstrCustomFilter) + 1;
  1551.             }
  1552.             if (*lpFilter)
  1553.             {
  1554.                 TCHAR szText[MAX_FULLPATHNAME];
  1555.                 lstrcpy(szText, lpFilter);
  1556.                 //
  1557.                 //  Filtering is case-insensitive.
  1558.                 //
  1559.                 CharLower(szText);
  1560.                 if (pOFI->szLastFilter[0] == CHAR_NULL)
  1561.                 {
  1562.                     lstrcpy(pOFI->szLastFilter, (LPTSTR)szText);
  1563.                 }
  1564.                 SetDlgItemText(hDlg, edt1, (LPTSTR)szText);
  1565.             }
  1566.         }
  1567.     }
  1568.     InitCurrentDisk(hDlg, pOFI, cmb2);
  1569.     bFirstTime = TRUE;
  1570.     bInChildDlg = FALSE;
  1571.     SendMessage( hDlg,
  1572.                  WM_COMMAND,
  1573.                  GET_WM_COMMAND_MPS(cmb2, GetDlgItem(hDlg, cmb2), MYCBN_DRAW) );
  1574.     SendMessage( hDlg,
  1575.                  WM_COMMAND,
  1576.                  GET_WM_COMMAND_MPS(cmb2, GetDlgItem(hDlg, cmb2), MYCBN_LIST) );
  1577.     if (pOFN->lpstrFile && *pOFN->lpstrFile)
  1578.     {
  1579.         TCHAR szText[MAX_FULLPATHNAME];
  1580.         lRet = ParseFile( pOFN->lpstrFile,
  1581.                           IsLFNDriveX(hDlg, pOFN->lpstrFile),
  1582.                           pOFN->Flags & CD_WOWAPP );
  1583.         nFileOffset = (INT)(SHORT)LOWORD(lRet);
  1584.         nExtOffset  = (INT)(SHORT)HIWORD(lRet);
  1585.         //
  1586.         //  Is the filename invalid?
  1587.         //
  1588.         if ( !(pOFN->Flags & OFN_NOVALIDATE) &&
  1589.              (nFileOffset < 0) &&
  1590.              (nFileOffset != PARSE_EMPTYSTRING) &&
  1591.              (pOFN->lpstrFile[nExtOffset] != CHAR_SEMICOLON) )
  1592.         {
  1593.             StoreExtendedError(FNERR_INVALIDFILENAME);
  1594.             EndDialog(hDlg, FALSE);
  1595.             return (FALSE);
  1596.         }
  1597.         lstrcpy(szText, pOFN->lpstrFile);
  1598.         SetDlgItemText(hDlg, edt1, (LPTSTR)szText);
  1599.     }
  1600.     SetWindowLong(GetDlgItem(hDlg, lst2), GWL_WNDPROC, (LONG)dwLBSubclass);
  1601.     SetWindowLong(GetDlgItem(hDlg, IDOK), GWL_WNDPROC, (LONG)dwOKSubclass);
  1602.     if (pOFN->lpstrTitle && *pOFN->lpstrTitle)
  1603.     {
  1604.         SetWindowText(hDlg, pOFN->lpstrTitle);
  1605.     }
  1606.     //
  1607.     //  By setting dyText to rRect.bottom/8, dyText defaults to 8 items showing
  1608.     //  in the listbox.  This only matters if the applications hook function
  1609.     //  steals all WM_MEASUREITEM messages.  Otherwise, dyText will be set in
  1610.     //  the MeasureItem() routine.  Check for !dyItem in case message ordering
  1611.     //  has already sent WM_MEASUREITEM and dyText is already initialized.
  1612.     //
  1613.     if (!dyItem)
  1614.     {
  1615.         GetClientRect(GetDlgItem(hDlg, lst1), (LPRECT) &rRect);
  1616.         if (!(dyText = (rRect.bottom / 8)))
  1617.         {
  1618.             //
  1619.             //  If no size to rectangle.
  1620.             //
  1621.             dyText = 8;
  1622.         }
  1623.     }
  1624.     //  The template has changed to make it extremely clear that
  1625.     //  this is not a combobox, but rather an edit control and a listbox.  The
  1626.     //  problem is that the new templates try to align the edit box and listbox.
  1627.     //  Unfortunately, when listboxes add borders, they expand beyond their
  1628.     //  borders.  When edit controls add borders, they stay within their
  1629.     //  borders.  This makes it impossible to align the two controls strictly
  1630.     //  within the template.  The code below will align the controls, but only
  1631.     //  if they are using the standard dialog template.
  1632.     //
  1633.     if (!(pOFN->Flags & (OFN_ENABLETEMPLATE | OFN_ENABLETEMPLATEHANDLE)))
  1634.     {
  1635.         GetWindowRect(GetDlgItem(hDlg, lst1), (LPRECT)&rLbox);
  1636.         GetWindowRect(GetDlgItem(hDlg, edt1), (LPRECT)&rRect);
  1637.         rRect.left = rLbox.left;
  1638.         rRect.right = rLbox.right;
  1639.         ScreenToClient(hDlg, (LPPOINT)&(rRect.left));
  1640.         ScreenToClient(hDlg, (LPPOINT)&(rRect.right));
  1641.         SetWindowPos( GetDlgItem(hDlg, edt1),
  1642.                       0,
  1643.                       rRect.left,
  1644.                       rRect.top,
  1645.                       rRect.right - rRect.left,
  1646.                       rRect.bottom - rRect.top,
  1647.                       SWP_NOZORDER );
  1648.     }
  1649.     if (pOFN->lpfnHook)
  1650.     {
  1651. #ifdef UNICODE
  1652.         if (pOFI->ApiType == COMDLG_ANSI)
  1653.         {
  1654.             ThunkOpenFileNameW2A(pOFI);
  1655.             bRet = ((*pOFN->lpfnHook)( hDlg,
  1656.                                        WM_INITDIALOG,
  1657.                                        wParam,
  1658.                                        (LPARAM)pOFI->pOFNA ));
  1659.             //
  1660.             //  Strange win 31 example uses lCustData to
  1661.             //  hold a temporary variable that it passes back to
  1662.             //  calling function.
  1663.             //
  1664.             ThunkOpenFileNameA2W(pOFI);
  1665.         }
  1666.         else
  1667. #endif
  1668.         {
  1669.             bRet = ((*pOFN->lpfnHook)( hDlg,
  1670.                                        WM_INITDIALOG,
  1671.                                        wParam,
  1672.                                        (LPARAM)pOFN ));
  1673.         }
  1674.     }
  1675.     else
  1676.     {
  1677. #ifdef UNICODE
  1678.         //
  1679.         //  Have to thunk A version even when there isn't a hook proc so it
  1680.         //  doesn't reset W version on delayed thunk back.
  1681.         //
  1682.         if (pOFI->ApiType == COMDLG_ANSI)
  1683.         {
  1684.             pOFI->pOFNA->Flags = pOFN->Flags;
  1685.         }
  1686. #endif
  1687.         bRet = TRUE;
  1688.     }
  1689.     //
  1690.     //  At first, assume there is net support !
  1691.     //
  1692.     if ((pOFN->Flags & OFN_NONETWORKBUTTON))
  1693.     {
  1694.         HWND hNet;
  1695.         if (hNet = GetDlgItem(hDlg, psh14))
  1696.         {
  1697.             EnableWindow(hNet = GetDlgItem(hDlg, psh14), FALSE);
  1698.             ShowWindow(hNet, SW_HIDE);
  1699.         }
  1700.     }
  1701.     else
  1702.     {
  1703.         AddNetButton( hDlg,
  1704.                       ((pOFN->Flags & OFN_ENABLETEMPLATE)
  1705.                           ? pOFN->hInstance
  1706.                           : g_hinst),
  1707.                       FILE_BOTTOM_MARGIN,
  1708.                       (pOFN->Flags & (OFN_ENABLETEMPLATE |
  1709.                                        OFN_ENABLETEMPLATEHANDLE))
  1710.                           ? FALSE
  1711.                           : TRUE,
  1712.                       (pOFN->Flags & OFN_NOLONGNAMES)
  1713.                           ? FALSE
  1714.                           : TRUE,
  1715.                       FALSE);
  1716.     }
  1717.     return (bRet);
  1718. }
  1719. ////////////////////////////////////////////////////////////////////////////
  1720. //
  1721. //  InitTlsValues
  1722. //
  1723. ////////////////////////////////////////////////////////////////////////////
  1724. INT InitTlsValues()
  1725. {
  1726.     //
  1727.     //  As long as we do not call TlsGetValue before this,
  1728.     //  everything should be ok.
  1729.     //
  1730.     LPTSTR lpCurDir;
  1731.     LPDWORD lpCurThread;
  1732.     if (dwNumDlgs == MAX_THREADS)
  1733.     {
  1734.         StoreExtendedError(CDERR_INITIALIZATION);
  1735.         return (FALSE);
  1736.     }
  1737.     if (lpCurDir = (LPTSTR)LocalAlloc(LPTR, CCHNETPATH * sizeof(TCHAR)))
  1738.     {
  1739.         GetCurrentDirectory(CCHNETPATH, lpCurDir);
  1740.         if (!TlsSetValue(g_tlsiCurDir, (LPVOID)lpCurDir))
  1741.         {
  1742.             StoreExtendedError(CDERR_INITIALIZATION);
  1743.             LocalFree(lpCurDir);
  1744.             return (FALSE);
  1745.         }
  1746.     }
  1747.     else
  1748.     {
  1749.         StoreExtendedError(CDERR_MEMALLOCFAILURE);
  1750.         return (FALSE);
  1751.     }
  1752.     if (lpCurThread = (LPDWORD)LocalAlloc(LPTR, sizeof(DWORD)))
  1753.     {
  1754.         if (!TlsSetValue(g_tlsiCurThread, (LPVOID)lpCurThread))
  1755.         {
  1756.             StoreExtendedError(CDERR_INITIALIZATION);
  1757.             LocalFree(lpCurDir);
  1758.             LocalFree(lpCurThread);
  1759.             return (FALSE);
  1760.         }
  1761.     }
  1762.     else
  1763.     {
  1764.         StoreExtendedError(CDERR_MEMALLOCFAILURE);
  1765.         return (FALSE);
  1766.     }
  1767.     EnterCriticalSection(&g_csLocal);
  1768.     *lpCurThread = dwNumDlgs++;
  1769.     LeaveCriticalSection(&g_csLocal);
  1770.     return (TRUE);
  1771. }
  1772. ////////////////////////////////////////////////////////////////////////////
  1773. //
  1774. //  InitFilterBox
  1775. //
  1776. //  Places the double null terminated list of filters in the combo box.
  1777. //  The list should consist of pairs of null terminated strings, with
  1778. //  an additional null terminating the list.
  1779. //
  1780. ////////////////////////////////////////////////////////////////////////////
  1781. DWORD InitFilterBox(
  1782.     HANDLE hDlg,
  1783.     LPCTSTR lpszFilter)
  1784. {
  1785.     DWORD nOffset = 0;
  1786.     DWORD nIndex = 0;
  1787.     register WORD nLen;
  1788.     while (*lpszFilter)
  1789.     {
  1790.         //
  1791.         //  First string put in as string to show.
  1792.         //
  1793.         nIndex = SendDlgItemMessage( hDlg,
  1794.                                      cmb1,
  1795.                                      CB_ADDSTRING,
  1796.                                      0,
  1797.                                      (LONG)lpszFilter );
  1798.         nLen = (WORD)(lstrlen(lpszFilter) + 1);
  1799.         (LPTSTR)lpszFilter += nLen;
  1800.         nOffset += nLen;
  1801.         //
  1802.         //  Second string put in as itemdata.
  1803.         //
  1804.         SendDlgItemMessage( hDlg,
  1805.                             cmb1,
  1806.                             CB_SETITEMDATA,
  1807.                             (WPARAM)nIndex,
  1808.                             nOffset );
  1809.         //
  1810.         //  Advance to next element.
  1811.         //
  1812.         nLen = (WORD)(lstrlen(lpszFilter) + 1);
  1813.         (LPTSTR)lpszFilter += nLen;
  1814.         nOffset += nLen;
  1815.     }
  1816.     return (nIndex);
  1817. }
  1818. ////////////////////////////////////////////////////////////////////////////
  1819. //
  1820. //  InitCurrentDisk
  1821. //
  1822. ////////////////////////////////////////////////////////////////////////////
  1823. VOID InitCurrentDisk(
  1824.     HWND hDlg,
  1825.     POPENFILEINFO pOFI,
  1826.     WORD cmb)
  1827. {
  1828.     //
  1829.     //  Clear out stale unc stuff from disk info.
  1830.     //  Unc \servershares are persistent through one popup session
  1831.     //  and then we resync with the system.  This is to fix a bug
  1832.     //  where a user's startup dir is unc but the system no longer has
  1833.     //  a connection and hence the cmb2 appears blank.
  1834.     //
  1835.     EnableDiskInfo(FALSE, TRUE);
  1836.     if (pOFI->pOFN->lpstrInitialDir)
  1837.     {
  1838.         //
  1839.         //  Notice that we force ChangeDir to succeed here
  1840.         //  but that TlsGetValue(g_tlsiCurDir) will return "" which
  1841.         //  when fed to SheChangeDirEx means GetCurrentDir will be called.
  1842.         //  So, the default cd behavior at startup is:
  1843.         //      1. lpstrInitialDir
  1844.         //      2. GetCurrentDir
  1845.         //
  1846.         ChangeDir(hDlg, pOFI->pOFN->lpstrInitialDir, TRUE, FALSE);
  1847.     }
  1848.     else
  1849.     {
  1850.         ChangeDir(hDlg, NULL, TRUE, FALSE);
  1851.     }
  1852. }
  1853. ////////////////////////////////////////////////////////////////////////////
  1854. //
  1855. //  vDeleteDirDriveBitmap
  1856. //
  1857. //  Gets rid of bitmaps, if they exist.
  1858. //
  1859. ////////////////////////////////////////////////////////////////////////////
  1860. VOID vDeleteDirDriveBitmap()
  1861. {
  1862.     if (hbmpOrigMemBmp)
  1863.     {
  1864.         SelectObject(hdcMemory, hbmpOrigMemBmp);
  1865.         if (hbmpDirDrive != HNULL)
  1866.         {
  1867.             DeleteObject(hbmpDirDrive);
  1868.             hbmpDirDrive = HNULL;
  1869.         }
  1870.     }
  1871. }
  1872. ////////////////////////////////////////////////////////////////////////////
  1873. //
  1874. //  LoadDirDriveBitmap
  1875. //
  1876. //  Creates the drive/directory bitmap.  If an appropriate bitmap
  1877. //  already exists, it just returns immediately.  Otherwise, it
  1878. //  loads the bitmap and creates a larger bitmap with both regular
  1879. //  and highlight colors.
  1880. //
  1881. ////////////////////////////////////////////////////////////////////////////
  1882. BOOL LoadDirDriveBitmap()
  1883. {
  1884.     BITMAP bmp;
  1885.     HANDLE hbmp, hbmpOrig;
  1886.     HDC hdcTemp;
  1887.     BOOL bWorked = FALSE;
  1888.     if ( (hbmpDirDrive != HNULL) &&
  1889.          (rgbWindowColor == rgbDDWindow) &&
  1890.          (rgbHiliteColor == rgbDDHilite))
  1891.     {
  1892.         if (SelectObject(hdcMemory, hbmpDirDrive))
  1893.         {
  1894.             return (TRUE);
  1895.         }
  1896.     }
  1897.     vDeleteDirDriveBitmap();
  1898.     rgbDDWindow = rgbWindowColor;
  1899.     rgbDDHilite = rgbHiliteColor;
  1900.     if (!(hdcTemp = CreateCompatibleDC(hdcMemory)))
  1901.     {
  1902.         goto LoadExit;
  1903.     }
  1904.     if (!(hbmp = LoadAlterBitmap(bmpDirDrive, rgbSolidBlue, rgbWindowColor)))
  1905.     {
  1906.         goto DeleteTempDC;
  1907.     }
  1908.     GetObject(hbmp, sizeof(BITMAP), (LPTSTR) &bmp);
  1909.     dyDirDrive = bmp.bmHeight;
  1910.     dxDirDrive = bmp.bmWidth;
  1911.     hbmpOrig = SelectObject(hdcTemp, hbmp);
  1912.     hbmpDirDrive = CreateDiscardableBitmap(hdcTemp, dxDirDrive * 2, dyDirDrive);
  1913.     if (!hbmpDirDrive)
  1914.     {
  1915.         goto DeleteTempBmp;
  1916.     }
  1917.     if (!SelectObject(hdcMemory, hbmpDirDrive))
  1918.     {
  1919.         vDeleteDirDriveBitmap();
  1920.         goto DeleteTempBmp;
  1921.     }
  1922.     BitBlt(hdcMemory, 0, 0, dxDirDrive, dyDirDrive, hdcTemp, 0, 0, SRCCOPY);
  1923.     SelectObject(hdcTemp, hbmpOrig);
  1924.     DeleteObject(hbmp);
  1925.     if (!(hbmp = LoadAlterBitmap(bmpDirDrive, rgbSolidBlue, rgbHiliteColor)))
  1926.     {
  1927.         goto DeleteTempDC;
  1928.     }
  1929.     hbmpOrig = SelectObject(hdcTemp, hbmp);
  1930.     BitBlt(hdcMemory, dxDirDrive, 0, dxDirDrive, dyDirDrive, hdcTemp, 0, 0, SRCCOPY);
  1931.     SelectObject(hdcTemp, hbmpOrig);
  1932.     bWorked = TRUE;
  1933. DeleteTempBmp:
  1934.     DeleteObject(hbmp);
  1935. DeleteTempDC:
  1936.     DeleteDC(hdcTemp);
  1937. LoadExit:
  1938.     return (bWorked);
  1939. }
  1940. ////////////////////////////////////////////////////////////////////////////
  1941. //
  1942. //  SetRGBValues
  1943. //
  1944. //  This sets the various system colors in static variables.  It's
  1945. //  called at init time and when system colors change.
  1946. //
  1947. ////////////////////////////////////////////////////////////////////////////
  1948. void SetRGBValues()
  1949. {
  1950.     rgbWindowColor = GetSysColor(COLOR_WINDOW);
  1951.     rgbHiliteColor = GetSysColor(COLOR_HIGHLIGHT);
  1952.     rgbWindowText  = GetSysColor(COLOR_WINDOWTEXT);
  1953.     rgbHiliteText  = GetSysColor(COLOR_HIGHLIGHTTEXT);
  1954.     rgbGrayText    = GetSysColor(COLOR_GRAYTEXT);
  1955. }
  1956. ////////////////////////////////////////////////////////////////////////////
  1957. //
  1958. //  FSetUpFile
  1959. //
  1960. //  This loads in the resources & initializes the data used by the
  1961. //  file dialogs.
  1962. //
  1963. //  Returns:  TRUE    if successful
  1964. //            FALSE   if any bitmap fails
  1965. //
  1966. ////////////////////////////////////////////////////////////////////////////
  1967. BOOL FSetUpFile()
  1968. {
  1969.     if (cLock++)
  1970.     {
  1971.         return (TRUE);
  1972.     }
  1973.     SetRGBValues();
  1974.     return (LoadDirDriveBitmap());
  1975. }
  1976. ////////////////////////////////////////////////////////////////////////////
  1977. //
  1978. //  FileOpenCmd
  1979. //
  1980. //  Handles WM_COMMAND for Open & Save dlgs.
  1981. //
  1982. //  edt1 = file name
  1983. //  lst1 = list of files in current directory matching current pattern
  1984. //  cmb1 = lists file patterns
  1985. //  stc1 = is current directory
  1986. //  lst2 = lists directories on current drive
  1987. //  cmb2 = lists drives
  1988. //  IDOK = is Open pushbutton
  1989. //  IDCANCEL = is Cancel pushbutton
  1990. //  chx1 = is for opening read only files
  1991. //
  1992. //  Returns the normal dialog proc values.
  1993. //
  1994. ////////////////////////////////////////////////////////////////////////////
  1995. BOOL FileOpenCmd(
  1996.     HANDLE hDlg,
  1997.     WPARAM wP,
  1998.     DWORD lParam,
  1999.     POPENFILEINFO pOFI,
  2000.     BOOL bSave)
  2001. {
  2002.     LPOPENFILENAME pOFN;
  2003.     LPTSTR pch, pch2;
  2004.     WORD i, sCount, len;
  2005.     LRESULT wFlag;
  2006.     BOOL bRet, bHookRet;
  2007.     TCHAR szText[MAX_FULLPATHNAME];
  2008.     HWND hwnd;
  2009.     if (!pOFI)
  2010.     {
  2011.         return (FALSE);
  2012.     }
  2013.     pOFN = pOFI->pOFN;
  2014.     switch (GET_WM_COMMAND_ID(wP, lParam))
  2015.     {
  2016.         case ( IDOK ) :
  2017.         {
  2018. #ifdef UNICODE
  2019.             //
  2020.             //  Apps that side-effect this message may not have their
  2021.             //  internal unicode strings updated (eg. Corel Mosaic).
  2022.             //
  2023.             //  NOTE: Must preserve the internal flags.
  2024.             //
  2025.             if (pOFI->ApiType == COMDLG_ANSI)
  2026.             {
  2027.                 DWORD InternalFlags = pOFN->Flags & OFN_ALL_INTERNAL_FLAGS;
  2028.                 ThunkOpenFileNameA2W(pOFI);
  2029.                 pOFN->Flags |= InternalFlags;
  2030.             }
  2031. #endif
  2032.             //
  2033.             //  If the focus is on the directory box, or if the selection
  2034.             //  within the box has changed since the last listing, give a
  2035.             //  new listing.
  2036.             //
  2037.             if (bChangeDir || ((GetFocus() == GetDlgItem(hDlg, lst2)) &&
  2038.                                (pOFN->Flags & OFN_DIRSELCHANGED)))
  2039.             {
  2040.                 bChangeDir = FALSE;
  2041.                 goto ChangingDir;
  2042.             }
  2043.             else if ((GetFocus() == (hwnd = GetDlgItem(hDlg, cmb2))) &&
  2044.                      (pOFN->Flags & OFN_DRIVEDOWN))
  2045.             {
  2046.                 //
  2047.                 //  If the focus is on the drive or filter combobox, give
  2048.                 //  a new listing.
  2049.                 //
  2050.                 SendDlgItemMessage(hDlg, cmb2, CB_SHOWDROPDOWN, FALSE, 0L);
  2051.                 break;
  2052.             }
  2053.             else if ((GetFocus() == (hwnd = GetDlgItem(hDlg, cmb1))) &&
  2054.                      (pOFN->Flags & OFN_FILTERDOWN))
  2055.             {
  2056.                 SendDlgItemMessage(hDlg, cmb1, CB_SHOWDROPDOWN, FALSE, 0L);
  2057.                 lParam = (LPARAM)hwnd;
  2058.                 goto ChangingFilter;
  2059.             }
  2060.             else
  2061.             {
  2062. #ifdef UNICODE
  2063.                 //
  2064.                 //  Visual Basic passes in an uninitialized lpDefExts string.
  2065.                 //  Since we only have to use it in OKButtonPressed, update
  2066.                 //  lpstrDefExts here along with whatever else is only needed
  2067.                 //  in OKButtonPressed.
  2068.                 //
  2069.                 if (pOFI->ApiType == COMDLG_ANSI)
  2070.                 {
  2071.                     ThunkOpenFileNameA2WDelayed(pOFI);
  2072.                 }
  2073. #endif
  2074.                 if (OKButtonPressed(hDlg, pOFI, bSave))
  2075.                 {
  2076.                     bRet = TRUE;
  2077.                     if (pOFN->lpstrFile)
  2078.                     {
  2079.                         if (!(pOFN->Flags & OFN_NOVALIDATE))
  2080.                         {                  
  2081.                             if (pOFN->nMaxFile >= 3)
  2082.                             {
  2083.                                 if ((pOFN->lpstrFile[0] == 0) ||
  2084.                                     (pOFN->lpstrFile[1] == 0) ||
  2085.                                     (pOFN->lpstrFile[2] == 0))
  2086.                                 {
  2087.                                     bRet = FALSE;
  2088.                                     StoreExtendedError(FNERR_BUFFERTOOSMALL);
  2089.                                 }
  2090.                             }
  2091.                             else
  2092.                             {
  2093.                                 bRet = FALSE;
  2094.                                 StoreExtendedError(FNERR_BUFFERTOOSMALL);
  2095.                             }
  2096.                         }
  2097.                     }
  2098.                     goto AbortDialog;
  2099.                 }
  2100.             }
  2101.             SendDlgItemMessage(hDlg, edt1, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  2102.             return (TRUE);
  2103.             break;
  2104.         }
  2105.         case ( IDCANCEL ) :
  2106.         {
  2107.             bRet = FALSE;
  2108.             bUserPressedCancel = TRUE;
  2109.             goto AbortDialog;
  2110.         }
  2111.         case ( IDABORT ) :
  2112.         {
  2113.             bRet = (BYTE)lParam;
  2114. AbortDialog:
  2115.             //
  2116.             //  Return the most recently used filter.
  2117.             //
  2118.             pOFN->nFilterIndex = (WORD)SendDlgItemMessage( hDlg,
  2119.                                                            cmb1,
  2120.                                                            CB_GETCURSEL,
  2121.                                                            (WPARAM)0,
  2122.                                                            (LPARAM)0 );
  2123.             if (pOFN->lpstrCustomFilter)
  2124.             {
  2125.                 len = (WORD)(lstrlen(pOFN->lpstrCustomFilter) + 1);
  2126.                 sCount = (WORD)lstrlen(pOFI->szLastFilter);
  2127.                 if (pOFN->nMaxCustFilter > (DWORD)(sCount + len))
  2128.                 {
  2129.                     lstrcpy(pOFN->lpstrCustomFilter + len, pOFI->szLastFilter);
  2130.                 }
  2131.             }
  2132.             if (!pOFN->lpstrCustomFilter ||
  2133.                 (*pOFN->lpstrCustomFilter == CHAR_NULL))
  2134.             {
  2135.                 pOFN->nFilterIndex++;
  2136.             }
  2137.             if (((GET_WM_COMMAND_ID(wP, lParam)) == IDOK) && pOFN->lpfnHook)
  2138.             {
  2139. #ifdef UNICODE
  2140.                 if (pOFI->ApiType == COMDLG_ANSI)
  2141.                 {
  2142.                     ThunkOpenFileNameW2A(pOFI);
  2143.                     bHookRet = (*pOFN->lpfnHook)( hDlg,
  2144.                                                   msgFILEOKA,
  2145.                                                   0,
  2146.                                                   (LPARAM)pOFI->pOFNA );
  2147.                     //
  2148.                     //  For apps that side-effect pOFNA stuff and expect it to
  2149.                     //  be preserved through dialog exit, update internal
  2150.                     //  struct after the hook proc is called.
  2151.                     //
  2152.                     ThunkOpenFileNameA2W(pOFI);
  2153.                 }
  2154.                 else
  2155. #endif
  2156.                 {
  2157.                     bHookRet = (*pOFN->lpfnHook)( hDlg,
  2158.                                                   msgFILEOKW,
  2159.                                                   0,
  2160.                                                   (LPARAM)pOFI->pOFN );
  2161.                 }
  2162.                 if (bHookRet)
  2163.                 {
  2164.                     HourGlass(FALSE);
  2165.                     break;
  2166.                 }
  2167.             }
  2168.             if (pOFN->Flags & OFN_ALLOWMULTISELECT)
  2169.             {
  2170.                 LocalShrink((HANDLE)0, 0);
  2171.             }
  2172.             wNoRedraw = 0;
  2173.             if (pOFI->pOFN->Flags & OFN_ENABLEHOOK)
  2174.             {
  2175.                 glpfnFileHook = pOFN->lpfnHook;
  2176.             }
  2177.             RemoveProp(hDlg, FILEPROP);
  2178.             EndDialog(hDlg, bRet);
  2179.             if (pOFI)
  2180.             {
  2181.                 if (((pOFN->Flags & OFN_NOCHANGEDIR) && *pOFI->szCurDir) ||
  2182.                     (bUserPressedCancel))
  2183.                 {
  2184.                     ChangeDir(hDlg, pOFI->szCurDir, TRUE, FALSE);
  2185.                 }
  2186.             }
  2187.             //
  2188.             //  BUG BUG
  2189.             //  If the app subclasses ID_ABORT, the worker thread will never
  2190.             //  get exited.  This will cause problems.  Currently, there are
  2191.             //  no apps that do this, though.
  2192.             //
  2193.             return (TRUE);
  2194.             break;
  2195.         }
  2196.         case ( edt1 ) :
  2197.         {
  2198.             if (GET_WM_COMMAND_CMD(wP, lParam) == EN_CHANGE)
  2199.             {
  2200.                 INT iIndex, iCount;
  2201.                 HWND hLBox = GetDlgItem(hDlg, lst1);
  2202.                 WORD wIndex = (WORD)SendMessage(hLBox, LB_GETCARETINDEX, 0, 0);
  2203.                 szText[0] = CHAR_NULL;
  2204.                 if (wIndex == (WORD)LB_ERR)
  2205.                 {
  2206.                     break;
  2207.                 }
  2208.                 SendMessage( GET_WM_COMMAND_HWND(wP, lParam),
  2209.                              WM_GETTEXT,
  2210.                              (WPARAM)MAX_FULLPATHNAME,
  2211.                              (LPARAM)(LPTSTR)szText );
  2212.                 if ((iIndex = (INT)SendMessage( hLBox,
  2213.                                                 LB_FINDSTRING,
  2214.                                                 (WPARAM)(wIndex - 1),
  2215.                                                 (LPARAM)(LPTSTR)szText )) != LB_ERR)
  2216.                 {
  2217.                     RECT rRect;
  2218.                     iCount = (INT)SendMessage(hLBox, LB_GETTOPINDEX, 0, 0L);
  2219.                     GetClientRect(hLBox, (LPRECT)&rRect);
  2220.                     if ((iIndex < iCount) ||
  2221.                         (iIndex >= (iCount + rRect.bottom / dyText)))
  2222.                     {
  2223.                         SendMessage(hLBox, LB_SETCARETINDEX, (WPARAM)iIndex, 0);
  2224.                         SendMessage(hLBox, LB_SETTOPINDEX, (WPARAM)iIndex, 0);
  2225.                     }
  2226.                 }
  2227.                 return (TRUE);
  2228.             }
  2229.             break;
  2230.         }
  2231.         case ( lst1 ) :
  2232.         {
  2233.             //
  2234.             //  A double click means OK.
  2235.             //
  2236.             if (GET_WM_COMMAND_CMD(wP, lParam)== LBN_DBLCLK)
  2237.             {
  2238.                 SendMessage(hDlg, WM_COMMAND, GET_WM_COMMAND_MPS(IDOK, 0, 0));
  2239.                 return (TRUE);
  2240.             }
  2241.             else if (pOFN && (GET_WM_COMMAND_CMD(wP, lParam) == LBN_SELCHANGE))
  2242.             {
  2243.                 if (pOFN->Flags & OFN_ALLOWMULTISELECT)
  2244.                 {
  2245.                     int *pSelIndex;
  2246.                     //
  2247.                     //  Muliselection allowed.
  2248.                     //
  2249.                     sCount = (SHORT)SendMessage(GET_WM_COMMAND_HWND(wP, lParam),
  2250.                                                 LB_GETSELCOUNT,
  2251.                                                 0,
  2252.                                                 0L );
  2253.                     if (!sCount)
  2254.                     {
  2255.                         //
  2256.                         //  If nothing selected, clear edit control.
  2257.                         //
  2258.                         SetDlgItemText(hDlg, edt1, (LPTSTR)szNull);
  2259.                     }
  2260.                     else
  2261.                     {
  2262.                         DWORD cchMemBlockSize = 2048;
  2263.                         DWORD cchTotalLength = 0;
  2264.                         pSelIndex = (int *)LocalAlloc(LPTR, sCount * sizeof(int));
  2265.                         if (!pSelIndex)
  2266.                         {
  2267.                             goto LocalFailure1;
  2268.                         }
  2269.                         sCount = (SHORT)SendMessage(
  2270.                                             GET_WM_COMMAND_HWND(wP, lParam),
  2271.                                             LB_GETSELITEMS,
  2272.                                             (WPARAM)sCount,
  2273.                                             (LONG)(LPTSTR)pSelIndex );
  2274.                         pch2 = pch = (LPTSTR)
  2275.                              LocalAlloc(LPTR, cchMemBlockSize * sizeof(TCHAR));
  2276.                         if (!pch)
  2277.                         {
  2278.                             goto LocalFailure2;
  2279.                         }
  2280.                         for (*pch = CHAR_NULL, i = 0; i < sCount; i++)
  2281.                         {
  2282.                             len = (WORD)SendMessage(
  2283.                                             GET_WM_COMMAND_HWND(wP, lParam),
  2284.                                             LB_GETTEXTLEN,
  2285.                                             (WPARAM)(*(pSelIndex + i)),
  2286.                                             (LPARAM)0 );
  2287.                             //
  2288.                             //  Add the length of the selected file to the
  2289.                             //  total length of selected files. + 2 for the
  2290.                             //  space that goes in between files and for the
  2291.                             //  possible dot added at the end of the filename
  2292.                             //  if the file does not have an extension.
  2293.                             //
  2294.                             cchTotalLength += (len + 2);
  2295.                             if (cchTotalLength > cchMemBlockSize)
  2296.                             {
  2297.                                 UINT cchPrevLen = cchTotalLength - (len + 2);
  2298.                                 cchMemBlockSize = cchMemBlockSize << 1;
  2299.                                 pch = (LPTSTR)LocalReAlloc(
  2300.                                                  pch,
  2301.                                                  cchMemBlockSize * sizeof(TCHAR),
  2302.                                                  LMEM_MOVEABLE );
  2303.                                 if (pch)
  2304.                                 {
  2305.                                     pch2 = pch + cchPrevLen;
  2306.                                 }
  2307.                                 else
  2308.                                 {
  2309.                                     goto LocalFailure2;
  2310.                                 }
  2311.                             }
  2312.                             SendMessage( GET_WM_COMMAND_HWND(wP, lParam),
  2313.                                          LB_GETTEXT,
  2314.                                          (WPARAM)(*(pSelIndex + i)),
  2315.                                          (LONG)(LPTSTR)pch2 );
  2316.                             if (!mystrchr((LPTSTR)pch2, CHAR_DOT))
  2317.                             {
  2318.                                 *(pch2 + len++) = CHAR_DOT;
  2319.                             }
  2320.                             pch2 += len;
  2321.                             *pch2++ = CHAR_SPACE;
  2322.                         }
  2323.                         if (pch2 != pch)
  2324.                         {
  2325.                             *--pch2 = CHAR_NULL;
  2326.                         }
  2327.                         SetDlgItemText(hDlg, edt1, pch);
  2328.                         LocalFree((HANDLE)pch);
  2329. LocalFailure2:
  2330.                         LocalFree((HANDLE)pSelIndex);
  2331.                     }
  2332. LocalFailure1:
  2333.                     if (pOFN->lpfnHook)
  2334.                     {
  2335.                         i = (WORD)SendMessage( GET_WM_COMMAND_HWND(wP, lParam),
  2336.                                                LB_GETCARETINDEX,
  2337.                                                0,
  2338.                                                0L );
  2339.                         if (!(i & 0x8000))
  2340.                         {
  2341.                             wFlag = (SendMessage(
  2342.                                          GET_WM_COMMAND_HWND(wP, lParam),
  2343.                                          LB_GETSEL,
  2344.                                          (WPARAM)i,
  2345.                                          0L )
  2346.                                      ? CD_LBSELADD
  2347.                                      : CD_LBSELSUB);
  2348.                         }
  2349.                         else
  2350.                         {
  2351.                             wFlag = CD_LBSELNOITEMS;
  2352.                         }
  2353.                     }
  2354.                 }
  2355.                 else
  2356.                 {
  2357.                     //
  2358.                     //  Multiselection is not allowed.
  2359.                     //  Put the file name in the edit control.
  2360.                     //
  2361.                     szText[0] = CHAR_NULL;
  2362.                     i = (WORD)SendMessage( GET_WM_COMMAND_HWND(wP, lParam),
  2363.                                            LB_GETCURSEL,
  2364.                                            0,
  2365.                                            0L );
  2366.                     if (i != (WORD)LB_ERR)
  2367.                     {
  2368.                         i = (WORD)SendMessage( GET_WM_COMMAND_HWND(wP, lParam),
  2369.                                                LB_GETTEXT,
  2370.                                                (WPARAM)i,
  2371.                                                (LONG)(LPTSTR)szText );
  2372.                         if (!mystrchr((LPTSTR)szText, CHAR_DOT))
  2373.                         {
  2374.                             if (i < MAX_FULLPATHNAME - 1)
  2375.                             {
  2376.                                 szText[i]     = CHAR_DOT;
  2377.                                 szText[i + 1] = CHAR_NULL;
  2378.                             }
  2379.                         }
  2380.                         if (!bCasePreserved)
  2381.                         {
  2382.                             CharLower(szText);
  2383.                         }
  2384.                         SetDlgItemText(hDlg, edt1, (LPTSTR)szText);
  2385.                         if (pOFN->lpfnHook)
  2386.                         {
  2387.                             i = (WORD)SendMessage(
  2388.                                           GET_WM_COMMAND_HWND(wP, lParam),
  2389.                                           LB_GETCURSEL,
  2390.                                           0,
  2391.                                           0L );
  2392.                             wFlag = CD_LBSELCHANGE;
  2393.                         }
  2394.                     }
  2395.                 }
  2396.                 if (pOFN->lpfnHook)
  2397.                 {
  2398. #ifdef UNICODE
  2399.                     if (pOFI->ApiType == COMDLG_ANSI)
  2400.                     {
  2401.                         (*pOFN->lpfnHook)( hDlg,
  2402.                                            msgLBCHANGEA,
  2403.                                            lst1,
  2404.                                            MAKELONG(i, wFlag) );
  2405.                     }
  2406.                     else
  2407. #endif
  2408.                     {
  2409.                         (*pOFN->lpfnHook)( hDlg,
  2410.                                            msgLBCHANGEW,
  2411.                                            lst1,
  2412.                                            MAKELONG(i, wFlag) );
  2413.                     }
  2414.                 }
  2415.                 SendDlgItemMessage(hDlg, edt1, EM_SETSEL, (WPARAM)0, (LPARAM)-1);
  2416.                 return (TRUE);
  2417.             }
  2418.             break;
  2419.         }
  2420.         case ( cmb1 ) :
  2421.         {
  2422.             switch (GET_WM_COMMAND_CMD(wP, lParam))
  2423.             {
  2424.                 case ( CBN_DROPDOWN ) :
  2425.                 {
  2426.                     if (wWinVer >= 0x030A)
  2427.                     {
  2428.                         pOFN->Flags |= OFN_FILTERDOWN;
  2429.                     }
  2430.                     return (TRUE);
  2431.                     break;
  2432.                 }
  2433.                 case ( CBN_CLOSEUP ) :
  2434.                 {
  2435.                     PostMessage( hDlg,
  2436.                                  WM_COMMAND,
  2437.                                  GET_WM_COMMAND_MPS(cmb1, lParam, MYCBN_DRAW) );
  2438.                     return (TRUE);
  2439.                     break;
  2440.                 }
  2441.                 case ( CBN_SELCHANGE ) :
  2442.                 {
  2443.                     //
  2444.                     //  Need to change the file listing in lst1.
  2445.                     //
  2446.                     if (pOFN->Flags & OFN_FILTERDOWN)
  2447.                     {
  2448.                         return (TRUE);
  2449.                         break;
  2450.                     }
  2451.                 }
  2452.                 case ( MYCBN_DRAW ) :
  2453.                 {
  2454.                     SHORT nIndex;
  2455.                     LPCTSTR lpFilter;
  2456.                     HourGlass(TRUE);
  2457.                     pOFN->Flags &= ~OFN_FILTERDOWN;
  2458. ChangingFilter:
  2459.                     nIndex = (SHORT)SendDlgItemMessage( hDlg,
  2460.                                                         cmb1,
  2461.                                                         CB_GETCURSEL,
  2462.                                                         0,
  2463.                                                         0L );
  2464.                     if (nIndex < 0)
  2465.                     {
  2466.                         //
  2467.                         //  No current selection.
  2468.                         //
  2469.                         break;
  2470.                     }
  2471.                     //
  2472.                     //  Must also check if filter contains anything.
  2473.                     //
  2474.                     if (nIndex ||
  2475.                         !(pOFN->lpstrCustomFilter && *pOFN->lpstrCustomFilter))
  2476.                     {
  2477.                         lpFilter = pOFN->lpstrFilter +
  2478.                                    SendDlgItemMessage( hDlg,
  2479.                                                        cmb1,
  2480.                                                        CB_GETITEMDATA,
  2481.                                                        (WPARAM)nIndex,
  2482.                                                        0L );
  2483.                     }
  2484.                     else
  2485.                     {
  2486.                         lpFilter = pOFN->lpstrCustomFilter +
  2487.                                    lstrlen(pOFN->lpstrCustomFilter) + 1;
  2488.                     }
  2489.                     if (*lpFilter)
  2490.                     {
  2491.                         GetDlgItemText( hDlg,
  2492.                                         edt1,
  2493.                                         (LPTSTR)szText,
  2494.                                         MAX_FULLPATHNAME - 1 );
  2495.                         bRet = (!szText[0] ||
  2496.                                 (mystrchr((LPTSTR)szText, CHAR_STAR)) ||
  2497.                                 (mystrchr((LPTSTR)szText, CHAR_QMARK)));
  2498.                         lstrcpy(szText, lpFilter);
  2499.                         if (bRet)
  2500.                         {
  2501.                             CharLower(szText);
  2502.                             SetDlgItemText(hDlg, edt1, (LPTSTR)szText);
  2503.                             SendDlgItemMessage( hDlg,
  2504.                                                 edt1,
  2505.                                                 EM_SETSEL,
  2506.                                                 (WPARAM)0,
  2507.                                                 (LPARAM)-1 );
  2508.                         }
  2509.                         FListAll(pOFI, hDlg, (LPTSTR)szText);
  2510.                         if (!bInitializing)
  2511.                         {
  2512.                             lstrcpy(pOFI->szLastFilter, (LPTSTR)szText);
  2513.                             //
  2514.                             //  Provide dynamic lpstrDefExt updating
  2515.                             //  when lpstrDefExt is user initialized.
  2516.                             //
  2517.                             if (mystrchr((LPTSTR)lpFilter, CHAR_DOT) &&
  2518.                                 pOFN->lpstrDefExt)
  2519.                             {
  2520.                                 DWORD cbLen = MIN_DEFEXT_LEN - 1; // only 1st 3
  2521.                                 LPTSTR lpTemp = (LPTSTR)pOFN->lpstrDefExt;
  2522.                                 while (*lpFilter++ != CHAR_DOT);
  2523.                                 if (!(mystrchr((LPTSTR)lpFilter, CHAR_STAR)) &&
  2524.                                     !(mystrchr((LPTSTR)lpFilter, CHAR_QMARK)))
  2525.                                 {
  2526.                                     while (cbLen--)
  2527.                                     {
  2528.                                         *lpTemp++ = *lpFilter++;
  2529.                                     }
  2530.                                     *lpTemp = CHAR_NULL;
  2531.                                 }
  2532.                             }
  2533.                         }
  2534.                     }
  2535.                     if (pOFN->lpfnHook)
  2536.                     {
  2537. #ifdef UNICODE
  2538.                         if (pOFI->ApiType == COMDLG_ANSI)
  2539.                         {
  2540.                             (*pOFN->lpfnHook)( hDlg,
  2541.                                                msgLBCHANGEA,
  2542.                                                cmb1,
  2543.                                                MAKELONG(nIndex, CD_LBSELCHANGE) );
  2544.                         }
  2545.                         else
  2546. #endif
  2547.                         {
  2548.                             (*pOFN->lpfnHook)( hDlg,
  2549.                                                msgLBCHANGEW,
  2550.                                                cmb1,
  2551.                                                MAKELONG(nIndex, CD_LBSELCHANGE) );
  2552.                         }
  2553.                     }
  2554.                     HourGlass(FALSE);
  2555.                     return (TRUE);
  2556.                     break;
  2557.                 }
  2558.                 default :
  2559.                 {
  2560.                     break;
  2561.                 }
  2562.             }
  2563.             break;
  2564.         }
  2565.         case ( lst2 ) :
  2566.         {
  2567.             if (GET_WM_COMMAND_CMD(wP, lParam) == LBN_SELCHANGE)
  2568.             {
  2569.                 if (!(pOFN->Flags & OFN_DIRSELCHANGED))
  2570.                 {
  2571.                     if ((DWORD)SendDlgItemMessage( hDlg,
  2572.                                                    lst2,
  2573.                                                    LB_GETCURSEL,
  2574.                                                    0,
  2575.                                                    0L ) != pOFI->idirSub - 1)
  2576.                     {
  2577.                         StripFileName(hDlg, pOFN->Flags & CD_WOWAPP);
  2578.                         pOFN->Flags |= OFN_DIRSELCHANGED;
  2579.                     }
  2580.                 }
  2581.                 return (TRUE);
  2582.             }
  2583.             else if (GET_WM_COMMAND_CMD(wP, lParam) == LBN_SETFOCUS)
  2584.             {
  2585.                 EnableWindow(GetDlgItem(hDlg, IDOK), TRUE);
  2586.                 SendMessage( GetDlgItem(hDlg, IDCANCEL),
  2587.                              BM_SETSTYLE,
  2588.                              (WPARAM)BS_PUSHBUTTON,
  2589.                              (LPARAM)TRUE );
  2590.             }
  2591.             else if (GET_WM_COMMAND_CMD(wP, lParam) == LBN_KILLFOCUS)
  2592.             {
  2593.                 if (pOFN && (pOFN->Flags & OFN_DIRSELCHANGED))
  2594.                 {
  2595.                     pOFN->Flags &= ~OFN_DIRSELCHANGED;
  2596.                 }
  2597.                 else
  2598.                 {
  2599.                     bChangeDir = FALSE;
  2600.                 }
  2601.             }
  2602.             else if (GET_WM_COMMAND_CMD(wP, lParam) == LBN_DBLCLK)
  2603.             {
  2604.                 TCHAR szNextDir[CCHNETPATH];
  2605.                 LPTSTR lpCurDir;
  2606.                 DWORD idir;
  2607.                 DWORD idirNew;
  2608.                 INT cb;
  2609.                 LPTSTR pstrPath;
  2610. ChangingDir:
  2611.                 bChangeDir = FALSE;
  2612.                 pOFN->Flags &= ~OFN_DIRSELCHANGED;
  2613.                 idirNew = (DWORD)SendDlgItemMessage( hDlg,
  2614.                                                      lst2,
  2615.                                                      LB_GETCURSEL,
  2616.                                                      0,
  2617.                                                      0L );
  2618.                 //
  2619.                 //  Can use relative path name.
  2620.                 //
  2621.                 *pOFI->szPath = 0;
  2622.                 if (idirNew >= pOFI->idirSub)
  2623.                 {
  2624.                     cb = SendDlgItemMessage( hDlg,
  2625.                                              lst2,
  2626.                                              LB_GETTEXT,
  2627.                                              (WPARAM)idirNew,
  2628.                                              (LONG)(LPTSTR)pOFI->szPath );
  2629.                     //
  2630.                     //  sanity check
  2631.                     //
  2632.                     if (!(lpCurDir = (LPTSTR)TlsGetValue(g_tlsiCurDir)))
  2633.                     {
  2634.                         break;
  2635.                     }
  2636.                     lstrcpy((LPTSTR)szNextDir, lpCurDir);
  2637.                     //
  2638.                     //  Fix phenom with c:\foobar - cz of incnstncy in dir
  2639.                     //  dsply guaranteed to have a valid lpCurDir here, right?
  2640.                     //
  2641.                     if (szNextDir[lstrlen(lpCurDir) - 1] != CHAR_BSLASH)
  2642.                     {
  2643.                         lstrcat((LPTSTR)szNextDir, TEXT("\"));
  2644.                     }
  2645.                     lstrcat((LPTSTR)szNextDir, pOFI->szPath);
  2646.                     pstrPath = (LPTSTR)szNextDir;
  2647.                     idirNew = pOFI->idirSub;    // for msgLBCHANGE message
  2648.                 }
  2649.                 else
  2650.                 {
  2651.                     //
  2652.                     //  Need full path name.
  2653.                     //
  2654.                     cb = SendDlgItemMessage( hDlg,
  2655.                                              lst2,
  2656.                                              LB_GETTEXT,
  2657.                                              0,
  2658.                                              (LONG)(LPTSTR)pOFI->szPath );
  2659.                     //
  2660.                     //  The following condition is necessary because wb displays
  2661.                     //  \servershare (the disk resource name) for unc, but
  2662.                     //  for root paths (eg. c:) for device conns, this in-
  2663.                     //  consistency is hacked around here and in FillOutPath.
  2664.                     //
  2665.                     if (DBL_BSLASH((LPTSTR)pOFI->szPath))
  2666.                     {
  2667.                         lstrcat((LPTSTR)pOFI->szPath, TEXT("\"));
  2668.                         cb++;
  2669.                     }
  2670.                     for (idir = 1; idir <= idirNew; ++idir)
  2671.                     {
  2672.                         cb += SendDlgItemMessage(
  2673.                                      hDlg,
  2674.                                      lst2,
  2675.                                      LB_GETTEXT,
  2676.                                      (WPARAM)idir,
  2677.                                      (LONG)(LPTSTR)&pOFI->szPath[cb] );
  2678.                         pOFI->szPath[cb++] = CHAR_BSLASH;
  2679.                     }
  2680.                     //
  2681.                     //  The root is a special case.
  2682.                     //
  2683.                     if (idirNew)
  2684.                     {
  2685.                         pOFI->szPath[cb - 1] = CHAR_NULL;
  2686.                     }
  2687.                     pstrPath = pOFI->szPath;
  2688.                 }
  2689.                 if (!*pstrPath ||
  2690.                     (ChangeDir(hDlg, pstrPath, FALSE, TRUE) == CHANGEDIR_FAILED))
  2691.                 {
  2692.                     break;
  2693.                 }
  2694.                 //
  2695.                 //  List all directories under this one.
  2696.                 //
  2697.                 UpdateListBoxes(hDlg, pOFI, (LPTSTR) NULL, mskDirectory);
  2698.                 if (pOFN->lpfnHook)
  2699.                 {
  2700. #ifdef UNICODE
  2701.                     if (pOFI->ApiType == COMDLG_ANSI)
  2702.                     {
  2703.                         (*pOFN->lpfnHook)( hDlg,
  2704.                                            msgLBCHANGEA,
  2705.                                            lst2,
  2706.                                            MAKELONG(LOWORD(idirNew), CD_LBSELCHANGE) );
  2707.                     }
  2708.                     else
  2709. #endif
  2710.                     {
  2711.                         (*pOFN->lpfnHook)( hDlg,
  2712.                                            msgLBCHANGEW,
  2713.                                            lst2,
  2714.                                            MAKELONG(LOWORD(idirNew), CD_LBSELCHANGE) );
  2715.                     }
  2716.                 }
  2717.                 return (TRUE);
  2718.             }
  2719.             break;
  2720.         }
  2721.         case ( cmb2 ) :
  2722.         {
  2723.             switch (GET_WM_COMMAND_CMD(wP, lParam))
  2724.             {
  2725.                 case ( CBN_DROPDOWN ) :
  2726.                 {
  2727.                     pOFN->Flags |= OFN_DRIVEDOWN;
  2728.                     return (TRUE);
  2729.                     break;
  2730.                 }
  2731.                 case ( CBN_CLOSEUP ) :
  2732.                 {
  2733.                     //
  2734.                     //  It would seem reasonable to merely do the update
  2735.                     //  at this point, but that would rely on message
  2736.                     //  ordering, which isnt a smart move.  In fact, if
  2737.                     //  you hit ALT-DOWNARROW, DOWNARROW, ALT-DOWNARROW,
  2738.                     //  you receive CBN_DROPDOWN, CBN_SELCHANGE, and then
  2739.                     //  CBN_CLOSEUP.  But if you use the mouse to choose
  2740.                     //  the same element, the last two messages trade
  2741.                     //  places.  PostMessage allows all messages in the
  2742.                     //  sequence to be processed, and then updates are
  2743.                     //  done as needed.
  2744.                     //
  2745.                     PostMessage( hDlg,
  2746.                                  WM_COMMAND,
  2747.                                  GET_WM_COMMAND_MPS(
  2748.                                      cmb2,
  2749.                                      GET_WM_COMMAND_HWND(wP, lParam),
  2750.                                      MYCBN_DRAW ) );
  2751.                     return (TRUE);
  2752.                     break;
  2753.                 }
  2754.                 case ( MYCBN_LIST ) :
  2755.                 {
  2756.                     LoadDrives(hDlg);
  2757.                     break;
  2758.                 }
  2759.                 case ( MYCBN_REPAINT ) :
  2760.                 {
  2761.                     TCHAR szRepaintDir[CCHNETPATH];
  2762.                     LPTSTR lpCurDir;
  2763.                     DWORD cchCurDir;
  2764.                     HWND hCmb2 = (HWND)lParam;
  2765.                     // sanity
  2766.                     if (!(lpCurDir = (LPTSTR)TlsGetValue(g_tlsiCurDir)))
  2767.                     {
  2768.                         break;
  2769.                     }
  2770.                     lstrcpy(szRepaintDir, lpCurDir);
  2771.                     // BUG BUG: Only Unicode
  2772.                     cchCurDir = SheGetPathOffsetW((LPWSTR)szRepaintDir);
  2773.                     szRepaintDir[cchCurDir] = CHAR_NULL;
  2774.                     // Should always succeed
  2775.                     SendMessage( hCmb2,