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

Windows Kernel

Development Platform:

Visual C++

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