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

Windows Kernel

Development Platform:

Visual C++

  1.                         cb += (int) SendDlgItemMessage(
  2.                                              hDlg,
  3.                                              lst2,
  4.                                              LB_GETTEXT,
  5.                                              (WPARAM)idir,
  6.                                              (LPARAM)&pOFI->szPath[cb] );
  7.                         pOFI->szPath[cb++] = CHAR_BSLASH;
  8.                     }
  9.                     //
  10.                     //  The root is a special case.
  11.                     //
  12.                     if (idirNew)
  13.                     {
  14.                         pOFI->szPath[cb - 1] = CHAR_NULL;
  15.                     }
  16.                     pstrPath = pOFI->szPath;
  17.                 }
  18.                 if (!*pstrPath ||
  19.                     (ChangeDir(hDlg, pstrPath, FALSE, TRUE) == CHANGEDIR_FAILED))
  20.                 {
  21.                     break;
  22.                 }
  23.                 //
  24.                 //  List all directories under this one.
  25.                 //
  26.                 UpdateListBoxes(hDlg, pOFI, NULL, mskDirectory);
  27.                 if (pOFN->lpfnHook)
  28.                 {
  29.                     LPOFNHOOKPROC lpfnHook = GETHOOKFN(pOFN);
  30. #ifdef UNICODE
  31.                     if (pOFI->ApiType == COMDLG_ANSI)
  32.                     {
  33.                         (*lpfnHook)( hDlg,
  34.                                      msgLBCHANGEA,
  35.                                      lst2,
  36.                                      MAKELONG(LOWORD(idirNew), CD_LBSELCHANGE) );
  37.                     }
  38.                     else
  39. #endif
  40.                     {
  41.                         (*lpfnHook)( hDlg,
  42.                                      msgLBCHANGEW,
  43.                                      lst2,
  44.                                      MAKELONG(LOWORD(idirNew), CD_LBSELCHANGE) );
  45.                     }
  46.                 }
  47.                 return (TRUE);
  48.             }
  49.             break;
  50.         }
  51.         case ( cmb2 ) :
  52.         {
  53.             switch (GET_WM_COMMAND_CMD(wParam, lParam))
  54.             {
  55.                 case ( CBN_DROPDOWN ) :
  56.                 {
  57.                     pOFN->Flags |= OFN_DRIVEDOWN;
  58.                     return (TRUE);
  59.                     break;
  60.                 }
  61.                 case ( CBN_CLOSEUP ) :
  62.                 {
  63.                     //
  64.                     //  It would seem reasonable to merely do the update
  65.                     //  at this point, but that would rely on message
  66.                     //  ordering, which isnt a smart move.  In fact, if
  67.                     //  you hit ALT-DOWNARROW, DOWNARROW, ALT-DOWNARROW,
  68.                     //  you receive CBN_DROPDOWN, CBN_SELCHANGE, and then
  69.                     //  CBN_CLOSEUP.  But if you use the mouse to choose
  70.                     //  the same element, the last two messages trade
  71.                     //  places.  PostMessage allows all messages in the
  72.                     //  sequence to be processed, and then updates are
  73.                     //  done as needed.
  74.                     //
  75.                     PostMessage( hDlg,
  76.                                  WM_COMMAND,
  77.                                  GET_WM_COMMAND_MPS(
  78.                                      cmb2,
  79.                                      GET_WM_COMMAND_HWND(wParam, lParam),
  80.                                      MYCBN_DRAW ) );
  81.                     return (TRUE);
  82.                     break;
  83.                 }
  84.                 case ( MYCBN_LIST ) :
  85.                 {
  86.                     LoadDrives(hDlg);
  87.                     break;
  88.                 }
  89.                 case ( MYCBN_REPAINT ) :
  90.                 {
  91.                     int cchCurDir;
  92.                     LPTSTR lpCurDir;
  93.                     // sanity
  94.                     if (!(lpCurDlg = (LPCURDLG)TlsGetValue(g_tlsiCurDlg)) ||
  95.                         !(lpCurDir = lpCurDlg->lpstrCurDir))
  96.                     {
  97.                         break;
  98.                     }
  99.                     cchCurDir = GetPathOffset(lpCurDir);
  100.                     if (cchCurDir != -1)
  101.                     {
  102.                         TCHAR szRepaintDir[CCHNETPATH];
  103.                         HWND hCmb2 = (HWND)lParam;
  104.                         lstrcpy(szRepaintDir, lpCurDir);
  105.                         szRepaintDir[cchCurDir] = CHAR_NULL;
  106.                         SendMessage( hCmb2,
  107.                                      CB_SELECTSTRING,
  108.                                      (WPARAM)-1,
  109.                                      (LPARAM)szRepaintDir );
  110.                     }
  111.                     break;
  112.                 }
  113.                 case ( CBN_SELCHANGE ) :
  114.                 {
  115.                     StripFileName(hDlg, IS16BITWOWAPP(pOFN));
  116.                     //
  117.                     //  Version check not needed, since flag never set
  118.                     //  for versions not supporting CBN_CLOSEUP. Putting
  119.                     //  check at CBN_DROPDOWN is more efficient since it
  120.                     //  is less frequent than CBN_SELCHANGE.
  121.                     if (pOFN->Flags & OFN_DRIVEDOWN)
  122.                     {
  123.                         //
  124.                         //  Don't fill lst2 while the combobox is down.
  125.                         //
  126.                         return (TRUE);
  127.                         break;
  128.                     }
  129.                 }
  130.                 case ( MYCBN_CHANGEDIR ) :
  131.                 case ( MYCBN_DRAW ) :
  132.                 {
  133.                     TCHAR szTitle[WARNINGMSGLENGTH];
  134.                     LPTSTR lpFilter;
  135.                     int nDiskInd, nInd;
  136.                     DWORD dwType;
  137.                     LPTSTR lpszPath = NULL;
  138.                     LPTSTR lpszDisk = NULL;
  139.                     HWND hCmb2;
  140.                     OFN_DISKINFO *pofndiDisk = NULL;
  141.                     static szDrawDir[CCHNETPATH];
  142.                     int nRet;
  143.                     HourGlass(TRUE);
  144.                     //
  145.                     //  Clear Flag for future CBN_SELCHANGE messeges.
  146.                     //
  147.                     pOFN->Flags &= ~OFN_DRIVEDOWN;
  148.                     //
  149.                     //  Change the drive.
  150.                     //
  151.                     szText[0] = CHAR_NULL;
  152.                     hCmb2 = (HWND)lParam;
  153.                     if (hCmb2 != NULL)
  154.                     {
  155.                         nInd = (int) SendMessage(hCmb2, CB_GETCURSEL, 0, 0L);
  156.                         if (nInd != CB_ERR)
  157.                         {
  158.                             SendMessage( hCmb2,
  159.                                          CB_GETLBTEXT,
  160.                                          nInd,
  161.                                          (LPARAM)(LPTSTR)szDrawDir );
  162.                         }
  163.                         if ((nInd == CB_ERR) || ((INT_PTR)pofndiDisk == CB_ERR))
  164.                         {
  165.                             if (lpCurDlg = (LPCURDLG)TlsGetValue(g_tlsiCurDlg))
  166.                             {
  167.                                 if (lpCurDlg->lpstrCurDir)
  168.                                 {
  169.                                     lstrcpy((LPTSTR)szDrawDir,
  170.                                             lpCurDlg->lpstrCurDir);
  171.                                 }
  172.                             }
  173.                         }
  174.                         CharLower((LPTSTR)szDrawDir);
  175.                         //
  176.                         //  Should always succeed.
  177.                         //
  178.                         nDiskInd = DiskAddedPreviously(0, (LPTSTR)szDrawDir);
  179.                         if (nDiskInd != 0xFFFFFFFF)
  180.                         {
  181.                             pofndiDisk = &gaDiskInfo[nDiskInd];
  182.                         }
  183.                         else
  184.                         {
  185.                             //
  186.                             //  Skip update in the case where it fails.
  187.                             //
  188.                             return (TRUE);
  189.                         }
  190.                         dwType = pofndiDisk->dwType;
  191.                         lpszDisk = pofndiDisk->lpPath;
  192.                     }
  193.                     if ((GET_WM_COMMAND_CMD(wParam, lParam)) == MYCBN_CHANGEDIR)
  194.                     {
  195.                         if (lpNetDriveSync)
  196.                         {
  197.                             lpszPath = lpNetDriveSync;
  198.                             lpNetDriveSync = NULL;
  199.                         }
  200.                         else
  201.                         {
  202.                             if (lpCurDlg = (LPCURDLG)TlsGetValue(g_tlsiCurDlg))
  203.                             {
  204.                                 if (lpCurDlg->lpstrCurDir)
  205.                                 {
  206.                                     lstrcpy((LPTSTR)szDrawDir,
  207.                                             lpCurDlg->lpstrCurDir);
  208.                                     lpszPath = (LPTSTR)szDrawDir;
  209.                                 }
  210.                             }
  211.                         }
  212.                     }
  213.                     else
  214.                     {
  215.                         lpszPath = lpszDisk;
  216.                     }
  217.                     if (bInitializing)
  218.                     {
  219.                         lpFilter = szTitle;
  220.                         if (pOFN->lpstrFile &&
  221.                             (StrChr(pOFN->lpstrFile, CHAR_STAR) ||
  222.                              StrChr(pOFN->lpstrFile, CHAR_QMARK)))
  223.                         {
  224.                             lstrcpy(lpFilter, pOFN->lpstrFile);
  225.                         }
  226.                         else
  227.                         {
  228.                             HWND hcmb1 = GetDlgItem(hDlg, cmb1);
  229.                             nInd = (int) SendMessage(hcmb1, CB_GETCURSEL, 0, 0L);
  230.                             if (nInd == CB_ERR)
  231.                             {
  232.                                 //
  233.                                 //  No current selection.
  234.                                 //
  235.                                 goto NullSearch;
  236.                             }
  237.                             //
  238.                             //  Must also check if filter contains anything.
  239.                             //
  240.                             if (nInd ||
  241.                                 !(pOFN->lpstrCustomFilter &&
  242.                                   *pOFN->lpstrCustomFilter))
  243.                             {
  244.                                 lpFilter = (LPTSTR)(pOFN->lpstrFilter);
  245.                                 lpFilter += SendMessage( hcmb1,
  246.                                                          CB_GETITEMDATA,
  247.                                                          (WPARAM)nInd,
  248.                                                          0 );
  249.                             }
  250.                             else
  251.                             {
  252.                                 lpFilter = pOFN->lpstrCustomFilter;
  253.                                 lpFilter += lstrlen(pOFN->lpstrCustomFilter) + 1;
  254.                             }
  255.                         }
  256.                     }
  257.                     else
  258.                     {
  259. NullSearch:
  260.                         lpFilter = NULL;
  261.                     }
  262.                     //
  263.                     //  UpdateListBoxes cuts up filter string in place.
  264.                     //
  265.                     if (lpFilter)
  266.                     {
  267.                         lstrcpy(szTitle, lpFilter);
  268.                         CharLower(szTitle);
  269.                     }
  270.                     if (dwType == REMDRVBMP)
  271.                     {
  272.                         DWORD err = WNetRestoreConnection(hDlg, lpszDisk);
  273.                         if (err != WN_SUCCESS)
  274.                         {
  275.                             HourGlass(FALSE);
  276.                             return (TRUE);
  277.                         }
  278.                         pofndiDisk->dwType = NETDRVBMP;
  279.                         SendMessage(
  280.                             hCmb2,
  281.                             CB_SETITEMDATA,
  282.                             (WPARAM)SendMessage(
  283.                                    hCmb2,
  284.                                    CB_SELECTSTRING,
  285.                                    (WPARAM)-1,
  286.                                    (LPARAM)(LPTSTR)pofndiDisk->lpAbbrName ),
  287.                             (LPARAM)NETDRVBMP );
  288.                     }
  289.                     //
  290.                     //  Calls to ChangeDir will call SelDisk, so no need
  291.                     //  to update cmb2 on our own here (used to be after
  292.                     //  updatelistboxes).
  293.                     //
  294.                     if ((nRet = ChangeDir( hDlg,
  295.                                            lpszPath,
  296.                                            FALSE,
  297.                                            FALSE )) == CHANGEDIR_FAILED)
  298.                     {
  299.                         int mbRet;
  300.                         while (nRet == CHANGEDIR_FAILED)
  301.                         {
  302.                             if (dwType == FLOPPYBMP)
  303.                             {
  304.                                 mbRet = InvalidFileWarning(
  305.                                                hDlg,
  306.                                                lpszPath,
  307.                                                ERROR_NO_DISK_IN_DRIVE,
  308.                                                (UINT)(MB_RETRYCANCEL |
  309.                                                       MB_ICONEXCLAMATION));
  310.                             }
  311.                             else if (dwType == CDDRVBMP)
  312.                             {
  313.                                 mbRet = InvalidFileWarning(
  314.                                                hDlg,
  315.                                                lpszPath,
  316.                                                ERROR_NO_DISK_IN_CDROM,
  317.                                                (UINT)(MB_RETRYCANCEL |
  318.                                                       MB_ICONEXCLAMATION) );
  319.                             }
  320.                             else
  321.                             {
  322.                                 //
  323.                                 //  See if it's a RAW volume.
  324.                                 //
  325.                                 if (dwType == HARDDRVBMP &&
  326.                                     GetLastError() == ERROR_UNRECOGNIZED_VOLUME)
  327.                                 {
  328.                                     mbRet = InvalidFileWarning(
  329.                                                    hDlg,
  330.                                                    lpszPath,
  331.                                                    ERROR_UNRECOGNIZED_VOLUME,
  332.                                                    (UINT)(MB_OK |
  333.                                                           MB_ICONEXCLAMATION) );
  334.                                 }
  335.                                 else
  336.                                 {
  337.                                     mbRet = InvalidFileWarning(
  338.                                                    hDlg,
  339.                                                    lpszPath,
  340.                                                    ERROR_DIR_ACCESS_DENIED,
  341.                                                    (UINT)(MB_RETRYCANCEL |
  342.                                                           MB_ICONEXCLAMATION) );
  343.                                 }
  344.                             }
  345.                             if (bFirstTime || (mbRet != IDRETRY))
  346.                             {
  347.                                 lpszPath = NULL;
  348.                                 nRet = ChangeDir(hDlg, lpszPath, TRUE, FALSE);
  349.                             }
  350.                             else
  351.                             {
  352.                                 nRet = ChangeDir(hDlg, lpszPath, FALSE, FALSE);
  353.                             }
  354.                         }
  355.                     }
  356.                     UpdateListBoxes( hDlg,
  357.                                      pOFI,
  358.                                      lpFilter ? szTitle : lpFilter,
  359.                                      (WORD)(mskDrives | mskDirectory) );
  360.                     if (pOFN->lpfnHook)
  361.                     {
  362.                         LPOFNHOOKPROC lpfnHook = GETHOOKFN(pOFN);
  363.                         nInd = (int) SendDlgItemMessage( hDlg,
  364.                                                          cmb2,
  365.                                                          CB_GETCURSEL,
  366.                                                          0,
  367.                                                          0 );
  368. #ifdef UNICODE
  369.                         if (pOFI->ApiType == COMDLG_ANSI)
  370.                         {
  371.                             (*lpfnHook)( hDlg,
  372.                                          msgLBCHANGEA,
  373.                                          cmb2,
  374.                                          MAKELONG(LOWORD(nInd),
  375.                                                   CD_LBSELCHANGE) );
  376.                         }
  377.                         else
  378. #endif
  379.                         {
  380.                             (*lpfnHook)( hDlg,
  381.                                          msgLBCHANGEW,
  382.                                          cmb2,
  383.                                          MAKELONG(LOWORD(nInd),
  384.                                                   CD_LBSELCHANGE) );
  385.                         }
  386.                     }
  387.                     HourGlass(FALSE);
  388.                     return (TRUE);
  389.                     break;
  390.                 }
  391.                 default :
  392.                 {
  393.                     break;
  394.                 }
  395.             }
  396.             break;
  397.         }
  398.         case ( pshHelp ) :
  399.         {
  400. #ifdef UNICODE
  401.             if (pOFI->ApiType == COMDLG_ANSI)
  402.             {
  403.                 if (msgHELPA && pOFN->hwndOwner)
  404.                 {
  405.                     SendMessage( pOFN->hwndOwner,
  406.                                  msgHELPA,
  407.                                  (WPARAM)hDlg,
  408.                                  (DWORD_PTR)pOFN );
  409.                 }
  410.             }
  411.             else
  412. #endif
  413.             {
  414.                 if (msgHELPW && pOFN->hwndOwner)
  415.                 {
  416.                     SendMessage( pOFN->hwndOwner,
  417.                                  msgHELPW,
  418.                                  (WPARAM)hDlg,
  419.                                  (DWORD_PTR)pOFN );
  420.                 }
  421.             }
  422.             break;
  423.         }
  424.         case ( psh14 ) :
  425.         {
  426.             bGetNetDrivesSync = TRUE;
  427.             if (CallNetDlg(hDlg))
  428.             {
  429.                 LNDSetEvent(hDlg);
  430.             }
  431.             else
  432.             {
  433.                 bGetNetDrivesSync = FALSE;
  434.             }
  435.             break;
  436.         }
  437.         default :
  438.         {
  439.             break;
  440.         }
  441.     }
  442.     return (FALSE);
  443. }
  444. ////////////////////////////////////////////////////////////////////////////
  445. //
  446. //  UpdateListBoxes
  447. //
  448. //  Fills out File and Directory List Boxes in a single pass
  449. //  given (potentially) multiple filters
  450. //
  451. //  It assumes the string of extensions are delimited by semicolons.
  452. //
  453. //  hDlg        Handle to File Open/Save dialog
  454. //  pOFI        pointer to OPENFILEINFO structure
  455. //  lpszFilter  pointer to filter, if NULL, use pOFI->szSpecCur
  456. //  wMask       mskDirectory and/or mskDrives, or NULL
  457. //
  458. //  Returns:  TRUE   if match
  459. //            FALSE  if not
  460. //
  461. ////////////////////////////////////////////////////////////////////////////
  462. BOOL UpdateListBoxes(
  463.     HWND hDlg,
  464.     POPENFILEINFO pOFI,
  465.     LPTSTR lpszFilter,
  466.     WORD wMask)
  467. {
  468.     LPTSTR lpszF[MAXFILTERS + 1];
  469.     LPTSTR lpszTemp;
  470.     SHORT i, nFilters;
  471.     HWND hFileList = GetDlgItem(hDlg, lst1);
  472.     HWND hDirList = GetDlgItem(hDlg, lst2);
  473.     BOOL bRet = FALSE;
  474.     TCHAR szSpec[MAX_FULLPATHNAME];
  475.     BOOL bDriveChange;
  476.     BOOL bFindAll = FALSE;
  477.     RECT rDirLBox;
  478.     BOOL bLFN;
  479.     HANDLE hff;
  480.     DWORD dwErr;
  481.     WIN32_FIND_DATA FindFileData;
  482.     TCHAR szBuffer[MAX_FULLPATHNAME];       // add one for CHAR_DOT
  483.     WORD wCount;
  484.     LPCURDLG lpCurDlg;
  485.     //
  486.     //  Save the drive bit and then clear it out.
  487.     //
  488.     bDriveChange = wMask & mskDrives;
  489.     wMask &= ~mskDrives;
  490.     if (!lpszFilter)
  491.     {
  492.         GetDlgItemText( hDlg,
  493.                         edt1,
  494.                         lpszFilter = szSpec,
  495.                         MAX_FULLPATHNAME - 1 );
  496.         //
  497.         //  If any directory or drive characters are in there, or if there
  498.         //  are no wildcards, use the default spec.
  499.         //
  500.         if ( StrChr(szSpec, CHAR_BSLASH) ||
  501.              StrChr(szSpec, CHAR_SLASH)  ||
  502.              StrChr(szSpec, CHAR_COLON)  ||
  503.              (!((StrChr(szSpec, CHAR_STAR)) ||
  504.                 (StrChr(szSpec, CHAR_QMARK)))) )
  505.         {
  506.             lstrcpy(szSpec, pOFI->szSpecCur);
  507.         }
  508.         else
  509.         {
  510.             lstrcpy(pOFI->szLastFilter, szSpec);
  511.         }
  512.     }
  513.     //
  514.     //  We need to find out what kind of a drive we are running
  515.     //  on in order to determine if spaces are valid in a filename
  516.     //  or not.
  517.     //
  518.     bLFN = IsLFNDriveX(hDlg, TEXT(""));
  519.     //
  520.     //  Find the first filter in the string, and add it to the
  521.     //  array.
  522.     //
  523.     if (bLFN)
  524.     {
  525.         lpszF[nFilters = 0] = lstrtok(lpszFilter, szSemiColonTab);
  526.     }
  527.     else
  528.     {
  529.         lpszF[nFilters = 0] = lstrtok(lpszFilter, szSemiColonSpaceTab);
  530.     }
  531.     //
  532.     //  Now we are going to loop through all the filters in the string
  533.     //  parsing the one we already have, and then finding the next one
  534.     //  and starting the loop over again.
  535.     //
  536.     while (lpszF[nFilters] && (nFilters < MAXFILTERS))
  537.     {
  538.         //
  539.         //  Check to see if the first character is a space.
  540.         //  If so, remove the spaces, and save the pointer
  541.         //  back into the same spot.  Why?  because the
  542.         //  FindFirstFile/Next api will _still_ work on
  543.         //  filenames that begin with a space because
  544.         //  they also look at the short names.  The
  545.         //  short names will begin with the same first
  546.         //  real letter as the long filename.  For
  547.         //  example, the long filename is "  my document"
  548.         //  the first letter of this short name is "m",
  549.         //  so searching on "m*.*" or " m*.*" will yield
  550.         //  the same results.
  551.         //
  552.         if (bLFN && (*lpszF[nFilters] == CHAR_SPACE))
  553.         {
  554.             lpszTemp = lpszF[nFilters];
  555.             while ((*lpszTemp == CHAR_SPACE) && *lpszTemp)
  556.             {
  557.                 lpszTemp = CharNext(lpszTemp);
  558.             }
  559.             lpszF[nFilters] = lpszTemp;
  560.         }
  561.         //
  562.         //  The original code used to do a CharUpper here to put the
  563.         //  filter strings in upper case.  EG:  *.TXT  However, this
  564.         //  is not a good thing to do for Turkish.  Capital 'i' does
  565.         //  not equal 'I', so the CharUpper is being removed.
  566.         //
  567.         //  CharUpper(lpszF[nFilters]);
  568.         //
  569.         //  Compare the filter with *.*.  If we find *.* then
  570.         //  set the boolean bFindAll, and this will cause the
  571.         //  files listbox to be filled in at the same time the
  572.         //  directories listbox is filled.  This saves time
  573.         //  from walking the directory twice (once for the directory
  574.         //  names and once for the filenames).
  575.         //
  576.         if (!lstrcmpi(lpszF[nFilters], szStarDotStar))
  577.         {
  578.             bFindAll = TRUE;
  579.         }
  580.         //
  581.         //  Now we need to check if this filter is a duplicate
  582.         //  of an already existing filter.
  583.         //
  584.         for (wCount = 0; wCount < nFilters; wCount++)
  585.         {
  586.             //
  587.             //  If we find a duplicate, decrement the current
  588.             //  index pointer by one so that the last location
  589.             //  is written over (thus removing the duplicate),
  590.             //  and break out of this loop.
  591.             //
  592.             if (!lstrcmpi(lpszF[nFilters], lpszF[wCount]))
  593.             {
  594.                 nFilters--;
  595.                 break;
  596.             }
  597.         }
  598.         //
  599.         //  Ready to move on to the next filter.  Find the next
  600.         //  filter based upon the type of file system we're using.
  601.         //
  602.         if (bLFN)
  603.         {
  604.             lpszF[++nFilters] = lstrtok(NULL, szSemiColonTab);
  605.         }
  606.         else
  607.         {
  608.             lpszF[++nFilters] = lstrtok(NULL, szSemiColonSpaceTab);
  609.         }
  610.         //
  611.         //  In case we found a pointer to NULL, then look for the
  612.         //  next filter.
  613.         //
  614.         while (lpszF[nFilters] && !*lpszF[nFilters])
  615.         {
  616.             if (bLFN)
  617.             {
  618.                 lpszF[nFilters] = lstrtok(NULL, szSemiColonTab);
  619.             }
  620.             else
  621.             {
  622.                 lpszF[nFilters] = lstrtok(NULL, szSemiColonSpaceTab);
  623.             }
  624.         }
  625.     }
  626.     //
  627.     //  Add NULL terminator only if needed.
  628.     //
  629.     if (nFilters >= MAXFILTERS)
  630.     {
  631.         lpszF[MAXFILTERS] = 0;
  632.     }
  633.     HourGlass(TRUE);
  634.     SendMessage(hFileList, WM_SETREDRAW, FALSE, 0L);
  635.     SendMessage(hFileList, LB_RESETCONTENT, 0, 0L);
  636.     if (wMask & mskDirectory)
  637.     {
  638.         wNoRedraw |= 2;     // HACK!!! WM_SETREDRAW isn't complete
  639.         SendMessage(hDirList, WM_SETREDRAW, FALSE, 0L);
  640.         //
  641.         //  LB_RESETCONTENT causes InvalidateRect(hDirList, 0, TRUE) to be
  642.         //  sent as well as repositioning the scrollbar thumb and drawing
  643.         //  it immediately.  This causes flicker when the LB_SETCURSEL is
  644.         //  made, as it clears out the listbox by erasing the background of
  645.         //  each item.
  646.         //
  647.         SendMessage(hDirList, LB_RESETCONTENT, 0, 0L);
  648.     }
  649.     //
  650.     //  Always open enumeration for *.*
  651.     //
  652.     lpCurDlg = (LPCURDLG)TlsGetValue(g_tlsiCurDlg);
  653.     SetCurrentDirectory(lpCurDlg ? lpCurDlg->lpstrCurDir : NULL);
  654.     hff = FindFirstFile(szStarDotStar, &FindFileData);
  655.     if ( hff == INVALID_HANDLE_VALUE)
  656.     {
  657.         //
  658.         //  Error.  Call GetLastError to determine what happened.
  659.         //
  660.         dwErr = GetLastError();
  661.         //
  662.         //  With the ChangeDir logic handling AccessDenied for cds,
  663.         //  if we are not allowed to enum files, that's ok, just get out.
  664.         //
  665.         if (dwErr == ERROR_ACCESS_DENIED)
  666.         {
  667.             wMask = mskDirectory;
  668.             goto Func4EFailure;
  669.         }
  670.         //
  671.         //  For bad path of bad filename.
  672.         //
  673.         if (dwErr != ERROR_FILE_NOT_FOUND)
  674.         {
  675.             wMask = mskDrives;
  676.             goto Func4EFailure;
  677.         }
  678.     }
  679.     //
  680.     //  A listing was made, even if empty.
  681.     //
  682.     bRet = TRUE;
  683.     wMask &= mskDirectory;
  684.     //
  685.     //  GetLastError says no more files.
  686.     //
  687.     if (hff == INVALID_HANDLE_VALUE  && dwErr == ERROR_FILE_NOT_FOUND)
  688.     {
  689.         //
  690.         //  Things went well, but there are no files.
  691.         //
  692.         goto NoMoreFilesFound;
  693.     }
  694.     do
  695.     {
  696.         if (pOFI->pOFN->Flags & OFN_NOLONGNAMES)
  697.         {
  698. #ifdef UNICODE
  699.             UNICODE_STRING Name;
  700.             BOOLEAN fSpace = FALSE;
  701.             RtlInitUnicodeString(&Name, FindFileData.cFileName);
  702.             if (RtlIsNameLegalDOS8Dot3(&Name, NULL, &fSpace) && !fSpace)
  703.             {
  704.                 //
  705.                 //  Legal 8.3 name and no spaces, so use the principal
  706.                 //  file name.
  707.                 //
  708.                 lstrcpy(szBuffer, (LPTSTR)FindFileData.cFileName);
  709.             }
  710.             else
  711. #endif
  712.             {
  713. #ifdef WINNT
  714.                 if (FindFileData.cAlternateFileName[0] == CHAR_NULL)
  715.                 {
  716.                     continue;
  717.                 }
  718.                 //
  719.                 //  Use the alternate file name.
  720.                 //
  721.                 lstrcpy(szBuffer, (LPTSTR)FindFileData.cAlternateFileName);
  722. #else
  723.                 if (FindFileData.cAlternateFileName[0])
  724.                 {
  725.                     //
  726.                     //  Use the alternate file name.
  727.                     //
  728.                     lstrcpy(szBuffer, (LPTSTR)FindFileData.cAlternateFileName);
  729.                 }
  730.                 else
  731.                 {
  732.                     //
  733.                     //  Use the main file name.
  734.                     //
  735.                     lstrcpy(szBuffer, (LPTSTR)FindFileData.cFileName);
  736.                 }
  737. #endif
  738.             }
  739.         }
  740.         else
  741.         {
  742.             lstrcpy(szBuffer, (LPTSTR)FindFileData.cFileName);
  743.         }
  744.         if ((FindFileData.dwFileAttributes & EXCLBITS))
  745.         {
  746.             continue;
  747.         }
  748.         if ((pOFI->pOFN->Flags & OFN_ALLOWMULTISELECT))
  749.         {
  750.             if (StrChr(szBuffer, CHAR_SPACE))
  751.             {
  752.                 //
  753.                 //  HPFS does not support alternate filenames
  754.                 //  for multiselect, bump all spacey filenames.
  755.                 //
  756.                 if (FindFileData.cAlternateFileName[0] == CHAR_NULL)
  757.                 {
  758.                     continue;
  759.                 }
  760.                 lstrcpy(szBuffer, (LPTSTR)FindFileData.cAlternateFileName);
  761.             }
  762.         }
  763.         if (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
  764.         {
  765.             if (wMask & mskDirectory)
  766.             {
  767.                 //
  768.                 //  Don't include the subdirectories "." and "..".
  769.                 //
  770.                 if (szBuffer[0] == CHAR_DOT)
  771.                 {
  772.                     if ((szBuffer[1] == CHAR_NULL) ||
  773.                         ((szBuffer[1] == CHAR_DOT) && (szBuffer[2] == CHAR_NULL)))
  774.                     {
  775.                         continue;
  776.                     }
  777.                 }
  778.                 if (!bCasePreserved)
  779.                 {
  780.                     CharLower(szBuffer);
  781.                 }
  782.                 i = (WORD)SendMessage( hDirList,
  783.                                        LB_ADDSTRING,
  784.                                        0,
  785.                                        (DWORD_PTR)szBuffer );
  786.             }
  787.         }
  788.         else if (bFindAll)
  789.         {
  790.             if (!bCasePreserved)
  791.             {
  792.                 CharLower(szBuffer);
  793.             }
  794.             SendMessage(hFileList, LB_ADDSTRING, 0, (DWORD_PTR)szBuffer);
  795.         }
  796.     } while (FindNextFile(hff, &FindFileData));
  797.     if (hff == INVALID_HANDLE_VALUE)
  798.     {
  799.         goto Func4EFailure;
  800.     }
  801.     FindClose(hff);
  802.     if (!bFindAll)
  803.     {
  804.         for (i = 0; lpszF[i]; i++)
  805.         {
  806.             if (!lstrcmpi(lpszF[i], szStarDotStar))
  807.             {
  808.                 continue;
  809.             }
  810.             //
  811.             //  Find First for each filter.
  812.             //
  813.             hff = FindFirstFile(lpszF[i], &FindFileData);
  814.             if (hff == INVALID_HANDLE_VALUE)
  815.             {
  816.                 DWORD dwErr = GetLastError();
  817.                 if ((dwErr == ERROR_FILE_NOT_FOUND) ||
  818.                     (dwErr == ERROR_INVALID_NAME))
  819.                 {
  820.                     //
  821.                     //  Things went well, but there are no files.
  822.                     //
  823.                     continue;
  824.                 }
  825.                 else
  826.                 {
  827.                     wMask = mskDrives;
  828.                     goto Func4EFailure;
  829.                 }
  830.             }
  831.             do
  832.             {
  833.                 if (pOFI->pOFN->Flags & OFN_NOLONGNAMES)
  834.                 {
  835. #ifdef UNICODE
  836.                     UNICODE_STRING Name;
  837.                     BOOLEAN fSpace = FALSE;
  838.                     RtlInitUnicodeString(&Name, FindFileData.cFileName);
  839.                     if (RtlIsNameLegalDOS8Dot3(&Name, NULL, &fSpace) && !fSpace)
  840.                     {
  841.                         //
  842.                         //  Legal 8.3 name and no spaces, so use the principal
  843.                         //  file name.
  844.                         //
  845.                         lstrcpy(szBuffer, (LPTSTR)FindFileData.cFileName);
  846.                     }
  847.                     else
  848. #endif
  849.                     {
  850. #ifdef WINNT
  851.                         if (FindFileData.cAlternateFileName[0] == CHAR_NULL)
  852.                         {
  853.                             continue;
  854.                         }
  855.                         //
  856.                         //  Use the alternate file name.
  857.                         //
  858.                         lstrcpy( szBuffer,
  859.                                  (LPTSTR)FindFileData.cAlternateFileName );
  860. #else
  861.                         if (FindFileData.cAlternateFileName[0])
  862.                         {
  863.                             //
  864.                             //  Use the alternate file name.
  865.                             //
  866.                             lstrcpy( szBuffer,
  867.                                      (LPTSTR)FindFileData.cAlternateFileName );
  868.                         }
  869.                         else
  870.                         {
  871.                             //
  872.                             //  Use the main file name.
  873.                             //
  874.                             lstrcpy(szBuffer, (LPTSTR)FindFileData.cFileName);
  875.                         }
  876. #endif
  877.                     }
  878.                 }
  879.                 else
  880.                 {
  881.                     lstrcpy(szBuffer, (LPTSTR)FindFileData.cFileName);
  882.                     if (pOFI->pOFN->Flags & OFN_ALLOWMULTISELECT)
  883.                     {
  884.                         if (StrChr(szBuffer, CHAR_SPACE))
  885.                         {
  886.                             //
  887.                             //  HPFS does not support alternate filenames
  888.                             //  for multiselect, bump all spacey filenames.
  889.                             //
  890.                             if (FindFileData.cAlternateFileName[0] == CHAR_NULL)
  891.                             {
  892.                                 continue;
  893.                             }
  894.                             lstrcpy( szBuffer,
  895.                                      (LPTSTR)FindFileData.cAlternateFileName );
  896.                         }
  897.                     }
  898.                 }
  899.                 if ((FindFileData.dwFileAttributes & EXCLBITS) ||
  900.                     (FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  901.                 {
  902.                     continue;
  903.                 }
  904.                 if (!bCasePreserved)
  905.                 {
  906.                     CharLower(szBuffer);
  907.                 }
  908.                 SendMessage(hFileList, LB_ADDSTRING, 0, (DWORD_PTR)szBuffer);
  909.             } while (FindNextFile(hff, &FindFileData));
  910.             if (hff != INVALID_HANDLE_VALUE)
  911.             {
  912.                 FindClose(hff);
  913.             }
  914.         }
  915.     }
  916. NoMoreFilesFound:
  917. Func4EFailure:
  918.     if (wMask)
  919.     {
  920.         if (wMask == mskDirectory)
  921.         {
  922.             LPTSTR lpCurDir = NULL;
  923.             if (lpCurDlg = (LPCURDLG)TlsGetValue(g_tlsiCurDlg))
  924.             {
  925.                 lpCurDir = lpCurDlg->lpstrCurDir;
  926.             }
  927.             FillOutPath(hDirList, pOFI);
  928.             //
  929.             //  The win31 way of chopping the text by just passing
  930.             //  it on to user doesn't work for unc names since user
  931.             //  doesn't see the drivelessness of them (thinks drive is
  932.             //  a bslash char).  So, special case it here.
  933.             //
  934.             lstrcpy(pOFI->szPath, lpCurDir);
  935.             if (DBL_BSLASH(pOFI->szPath))
  936.             {
  937.                 SetDlgItemText(hDlg, stc1, ChopText(hDlg, stc1, pOFI->szPath));
  938.             }
  939.             else
  940.             {
  941.                 DlgDirList(hDlg, pOFI->szPath, 0, stc1, DDL_READONLY);
  942.             }
  943.             SendMessage(hDirList, LB_SETCURSEL, pOFI->idirSub - 1, 0L);
  944.             if (bDriveChange)
  945.             {
  946.                 //
  947.                 //  The design here is to show the selected drive whenever the
  948.                 //  user changes drives, or whenever the number of
  949.                 //  subdirectories is sufficiently low to allow them to be
  950.                 //  shown along with the drive.  Otherwise, show the
  951.                 //  immediate parent and all the children that can be shown.
  952.                 //  This all was done to meet the UITF spec.
  953.                 //
  954.                 i = 0;
  955.             }
  956.             else
  957.             {
  958.                 //
  959.                 //  Show as many children as possible.
  960.                 //
  961.                 if ((i = (SHORT)(pOFI->idirSub - 2)) < 0)
  962.                 {
  963.                     i = 0;
  964.                 }
  965.             }
  966.             //
  967.             //  LB_SETTOPINDEX must be after LB_SETCURSEL, as LB_SETCURSEL will
  968.             //  alter the top index to bring the current selection into view.
  969.             //
  970.             SendMessage(hDirList, LB_SETTOPINDEX, (WPARAM)i, 0L);
  971.         }
  972.         else
  973.         {
  974.             SetDlgItemText(hDlg, stc1, szNull);
  975.         }
  976.         wNoRedraw &= ~2;
  977.         SendMessage(hDirList, WM_SETREDRAW, TRUE, 0L);
  978.         GetWindowRect(hDirList, (LPRECT)&rDirLBox);
  979.         rDirLBox.left++, rDirLBox.top++;
  980.         rDirLBox.right--, rDirLBox.bottom--;
  981.         MapWindowPoints(NULL, hDlg, (LPPOINT)&rDirLBox, 2);
  982.         //
  983.         //  If there are less than enough directories to fill the listbox,
  984.         //  Win 3.0 doesn't clear out the bottom.  Pass TRUE as the last
  985.         //  parameter to demand a WM_ERASEBACKGROUND message.
  986.         //
  987.         InvalidateRect(hDlg, (LPRECT)&rDirLBox, (BOOL)(wWinVer < 0x030A));
  988.     }
  989.     SendMessage(hFileList, WM_SETREDRAW, TRUE, 0L);
  990.     InvalidateRect(hFileList, (LPRECT)0, (BOOL)TRUE);
  991. #ifndef WIN32
  992.    ResetDTAAddress();
  993. #endif
  994.    HourGlass(FALSE);
  995.    return (bRet);
  996. }
  997. ////////////////////////////////////////////////////////////////////////////
  998. //
  999. //  OKButtonPressed
  1000. //
  1001. //  Note:  There are 4 cases for validation of a file name:
  1002. //    1)  OFN_NOVALIDATE        allows invalid characters
  1003. //    2)  No validation flags   No invalid characters, but path need not exist
  1004. //    3)  OFN_PATHMUSTEXIST     No invalid characters, path must exist
  1005. //    4)  OFN_FILEMUSTEXIST     No invalid characters, path & file must exist
  1006. //
  1007. ////////////////////////////////////////////////////////////////////////////
  1008. BOOL OKButtonPressed(
  1009.     HWND hDlg,
  1010.     POPENFILEINFO pOFI,
  1011.     BOOL bSave)
  1012. {
  1013.     DWORD nErrCode = 0;
  1014.     DWORD cch;
  1015.     DWORD cchSearchPath;
  1016.     LPOPENFILENAME pOFN = pOFI->pOFN;
  1017.     int nFileOffset, nExtOffset;
  1018.     HANDLE hFile;
  1019.     BOOL bAddExt = FALSE;
  1020.     BOOL bUNCName = FALSE;
  1021.     int nTempOffset;
  1022.     TCHAR szPathName[MAX_FULLPATHNAME];
  1023.     DWORD lRet;
  1024.     BOOL blfn;
  1025.     LPCURDLG lpCurDlg;
  1026.     TCHAR ch = 0;
  1027.     if (cch = GetUNCDirectoryFromLB(hDlg, lst2, pOFI))
  1028.     {
  1029.         nTempOffset = (WORD)(DWORD)SendDlgItemMessage( hDlg,
  1030.                                                        lst2,
  1031.                                                        LB_GETTEXTLEN,
  1032.                                                        0,
  1033.                                                        0 );
  1034.     }
  1035.     else
  1036.     {
  1037.         nTempOffset = 0;
  1038.     }
  1039.     GetDlgItemText(hDlg, edt1, pOFI->szPath + cch, MAX_FULLPATHNAME - 1);
  1040.     if (cch)
  1041.     {
  1042.         //
  1043.         //  If a drive or new UNC was specified, forget the old UNC.
  1044.         //
  1045.         if ((pOFI->szPath[cch + 1] == CHAR_COLON) ||
  1046.             (DBL_BSLASH(pOFI->szPath + cch)) )
  1047.         {
  1048.             lstrcpy(pOFI->szPath, pOFI->szPath + cch);
  1049.         }
  1050.         else if ((ISBACKSLASH(pOFI->szPath, cch)) ||
  1051.                  (pOFI->szPath[cch] == CHAR_SLASH))
  1052.         {
  1053.             //
  1054.             //  If a directory from the root is given, put it immediately
  1055.             //  after the \servershare listing.
  1056.             //
  1057.             lstrcpy(pOFI->szPath + nTempOffset, pOFI->szPath + cch);
  1058.         }
  1059.     }
  1060.     if (pOFN->Flags & OFN_NOLONGNAMES)
  1061.     {
  1062.         blfn = FALSE;
  1063.     }
  1064.     else
  1065.     {
  1066.         blfn = IsLFNDriveX(hDlg, pOFI->szPath);
  1067.     }
  1068.     lRet = ParseFile(pOFI->szPath, blfn, IS16BITWOWAPP(pOFN), FALSE);
  1069.     nFileOffset = (int)(SHORT)LOWORD(lRet);
  1070.     nExtOffset  = (int)(SHORT)HIWORD(lRet);
  1071.     if (nFileOffset == PARSE_EMPTYSTRING)
  1072.     {
  1073.         UpdateListBoxes(hDlg, pOFI, NULL, 0);
  1074.         return (FALSE);
  1075.     }
  1076.     else if ((nFileOffset != PARSE_DIRECTORYNAME) &&
  1077.              (pOFN->Flags & OFN_NOVALIDATE))
  1078.     {
  1079.         pOFN->nFileOffset = (WORD)nFileOffset;
  1080.         pOFN->nFileExtension = (WORD)nExtOffset;
  1081.         if (pOFN->lpstrFile)
  1082.         {
  1083.             cch = lstrlen(pOFI->szPath);
  1084.             if (cch < pOFN->nMaxFile)
  1085.             {
  1086.                 lstrcpy(pOFN->lpstrFile, pOFI->szPath);
  1087.             }
  1088.             else
  1089.             {
  1090.                 //
  1091.                 //  For single file requests, we will never go over 64K
  1092.                 //  because the filesystem is limited to 256.
  1093.                 //
  1094.                 if (cch > 0x0000FFFF)
  1095.                 {
  1096.                     pOFN->lpstrFile[0] = (TCHAR)0xFFFF;
  1097.                 }
  1098.                 else
  1099.                 {
  1100.                     pOFN->lpstrFile[0] = (TCHAR)LOWORD(cch);
  1101.                 }
  1102.                 pOFN->lpstrFile[1] = CHAR_NULL;
  1103.             }
  1104.         }
  1105.         return (TRUE);
  1106.     }
  1107.     else if ((pOFN->Flags & OFN_ALLOWMULTISELECT) &&
  1108.              SpacesExist(pOFI->szPath))
  1109.     {
  1110.         return (MultiSelectOKButton(hDlg, pOFI, bSave));
  1111.     }
  1112.     else if (pOFI->szPath[nExtOffset] == CHAR_SEMICOLON)
  1113.     {
  1114.         pOFI->szPath[nExtOffset] = CHAR_NULL;
  1115.         nFileOffset = (int)(SHORT)LOWORD(ParseFile( pOFI->szPath,
  1116.                                                     blfn,
  1117.                                                     IS16BITWOWAPP(pOFN),
  1118.                                                     FALSE ));
  1119.         pOFI->szPath[nExtOffset] = CHAR_SEMICOLON;
  1120.         if ( (nFileOffset >= 0) &&
  1121.              (StrChr(pOFI->szPath + nFileOffset, CHAR_STAR) ||
  1122.               StrChr(pOFI->szPath + nFileOffset, CHAR_QMARK)) )
  1123.         {
  1124.             lstrcpy(pOFI->szLastFilter, pOFI->szPath + nFileOffset);
  1125.             if (FListAll(pOFI, hDlg, pOFI->szPath) == CHANGEDIR_FAILED)
  1126.             {
  1127.                 //
  1128.                 //  Conform with cchSearchPath error code settings in
  1129.                 //  PathCheck.
  1130.                 //
  1131.                 cchSearchPath = 2;
  1132.                 goto PathCheck;
  1133.             }
  1134.             return (FALSE);
  1135.         }
  1136.         else
  1137.         {
  1138.             nFileOffset = PARSE_INVALIDCHAR;
  1139.             goto Warning;
  1140.         }
  1141.     }
  1142.     else if (nFileOffset == PARSE_DIRECTORYNAME)
  1143.     {
  1144.         //
  1145.         //  End with slash?
  1146.         //
  1147.         if ((ISBACKSLASH(pOFI->szPath, nExtOffset - 1)) ||
  1148.             (pOFI->szPath[nExtOffset - 1] == CHAR_SLASH))
  1149.         {
  1150.             //
  1151.             //  ... and is not the root, get rid of the slash.
  1152.             //
  1153.             if ( (nExtOffset != 1) &&
  1154.                  (pOFI->szPath[nExtOffset - 2] != CHAR_COLON) &&
  1155.                  (nExtOffset != nTempOffset + 1) )
  1156.             {
  1157.                 pOFI->szPath[nExtOffset - 1] = CHAR_NULL;
  1158.             }
  1159.         }
  1160.         else if ((pOFI->szPath[nExtOffset - 1] == CHAR_DOT) &&
  1161.                  ((pOFI->szPath[nExtOffset - 2] == CHAR_DOT) ||
  1162.                   (ISBACKSLASH(pOFI->szPath, nExtOffset - 2)) ||
  1163.                   (pOFI->szPath[nExtOffset - 2] == CHAR_SLASH)) &&
  1164.                  ((DBL_BSLASH(pOFI->szPath)) ||
  1165.                   ((*(pOFI->szPath + 1) == CHAR_COLON) &&
  1166.                    (DBL_BSLASH(pOFI->szPath + 2)))))
  1167.         {
  1168.             pOFI->szPath[nExtOffset] = CHAR_BSLASH;
  1169.             pOFI->szPath[nExtOffset + 1] = CHAR_NULL;
  1170.         }
  1171.         //
  1172.         //  Fall through to Directory Checking.
  1173.         //
  1174.     }
  1175.     else if (nFileOffset < 0)
  1176.     {
  1177.         //
  1178.         //  Put in nErrCode so that call can be used from other points.
  1179.         //
  1180.         nErrCode = (DWORD)nFileOffset;
  1181. Warning:
  1182.         //
  1183.         //  If the disk is not a floppy and they tell me there's no
  1184.         //  disk in the drive, dont believe it.  Instead, put up the error
  1185.         //  message that they should have given us.
  1186.         //  (Note that the error message is checked first since checking
  1187.         //  the drive type is slower.)
  1188.         //
  1189.         if (nErrCode == ERROR_ACCESS_DENIED)
  1190.         {
  1191.             if (bUNCName)
  1192.             {
  1193.                 nErrCode = ERROR_NETWORK_ACCESS_DENIED;
  1194.             }
  1195.             else
  1196.             {
  1197.                 szPathName[0] = (TCHAR)CharLower((LPTSTR)(DWORD)szPathName[0]);
  1198.                 if (GetDiskType(szPathName) == DRIVE_REMOTE)
  1199.                 {
  1200.                     nErrCode = ERROR_NETWORK_ACCESS_DENIED;
  1201.                 }
  1202.                 else if (GetDiskType(szPathName) == DRIVE_REMOVABLE)
  1203.                 {
  1204.                     nErrCode = ERROR_NO_DISK_IN_DRIVE;
  1205.                 }
  1206.                 else if (GetDiskType(szPathName) == DRIVE_CDROM)
  1207.                 {
  1208.                     nErrCode = ERROR_NO_DISK_IN_CDROM;
  1209.                 }
  1210.             }
  1211.         }
  1212.         if ((nErrCode == ERROR_WRITE_PROTECT) ||
  1213.             (nErrCode == ERROR_CANNOT_MAKE) ||
  1214.             (nErrCode == ERROR_NO_DISK_IN_DRIVE) ||
  1215.             (nErrCode == ERROR_NO_DISK_IN_CDROM))
  1216.         {
  1217.             pOFI->szPath[0] = szPathName[0];
  1218.         }
  1219.         InvalidFileWarning(hDlg, pOFI->szPath, nErrCode, 0);
  1220.         //
  1221.         //  Can't cd case (don't want WM_ACTIVATE to setevent to GetNetDrives!).
  1222.         //  Reset wNoRedraw.
  1223.         //
  1224.         wNoRedraw &= ~1;
  1225.         return (FALSE);
  1226.     }
  1227.     bUNCName = ((DBL_BSLASH(pOFI->szPath)) ||
  1228.                 ((*(pOFI->szPath + 1) == CHAR_COLON) &&
  1229.                 (DBL_BSLASH(pOFI->szPath + 2))));
  1230.     nTempOffset = nFileOffset;
  1231.     //
  1232.     //  Get the fully-qualified path.
  1233.     //
  1234.     {
  1235.         BOOL bSlash;
  1236.         BOOL bRet;
  1237.         WORD nNullOffset;
  1238.         if (nFileOffset != PARSE_DIRECTORYNAME)
  1239.         {
  1240.             ch = *(pOFI->szPath + nFileOffset);
  1241.             *(pOFI->szPath + nFileOffset) = CHAR_NULL;
  1242.             nNullOffset = (WORD) nFileOffset;
  1243.         }
  1244.         //
  1245.         //  For files of the format c:filename where c is not the
  1246.         //  current directory, SearchPath does not return the curdir of c
  1247.         //  so, prefetch it - should searchpath be changed?
  1248.         //
  1249.         if (nFileOffset)
  1250.         {
  1251.             if (*(pOFI->szPath + nFileOffset - 1) == CHAR_COLON)
  1252.             {
  1253.                 //
  1254.                 //  If it fails, fall through to the error generated below.
  1255.                 //
  1256.                 if (ChangeDir(hDlg, pOFI->szPath, FALSE, FALSE) != CHANGEDIR_FAILED)
  1257.                 {
  1258.                     //
  1259.                     //  Replace old null offset.
  1260.                     //
  1261.                     *(pOFI->szPath + nFileOffset) = ch;
  1262.                     ch = *pOFI->szPath;
  1263.                     //
  1264.                     //  Don't pass drive-colon into search path.
  1265.                     //
  1266.                     *pOFI->szPath = CHAR_NULL;
  1267.                     nNullOffset = 0;
  1268.                 }
  1269.             }
  1270.         }
  1271.         if (bSlash = (*pOFI->szPath == CHAR_SLASH))
  1272.         {
  1273.             *pOFI->szPath = CHAR_BSLASH;
  1274.         }
  1275.         szPathName[0] = CHAR_NULL;
  1276.         HourGlass(TRUE);
  1277.         //
  1278.         //  BUGBUG:
  1279.         //  Each wow thread can change the current directory.
  1280.         //  Since searchpath doesn't check current dirs on a per thread basis,
  1281.         //  reset it here and hope that we don't get interrupted between
  1282.         //  setting and searching...
  1283.         //
  1284.         lpCurDlg = (LPCURDLG)TlsGetValue(g_tlsiCurDlg);
  1285.         SetCurrentDirectory(lpCurDlg ? lpCurDlg->lpstrCurDir : NULL);
  1286.         if (pOFI->szPath[0] == TEXT(''))  // space for name (pretend it's valid for now)
  1287.         {
  1288.             lstrcpy(szPathName, (lpCurDlg ? lpCurDlg->lpstrCurDir : NULL));
  1289.             bRet = 1;
  1290.         }
  1291.         else
  1292.         {
  1293.             bRet = GetFullPathName( pOFI->szPath,
  1294.                                     MAX_FULLPATHNAME,
  1295.                                     szPathName,
  1296.                                     NULL );
  1297.         }
  1298.         if (!bRet && (pOFI->szPath[1] == CHAR_COLON))
  1299.         {
  1300.             int nDriveIndex = DiskAddedPreviously(pOFI->szPath[0], NULL);
  1301.             //
  1302.             //  If it's a remembered connection, try to reconnect it.
  1303.             //
  1304.             if (nDriveIndex != 0xFFFFFFFF  &&
  1305.                 gaDiskInfo[nDriveIndex].dwType == REMDRVBMP)
  1306.             {
  1307.                 DWORD err = WNetRestoreConnection( hDlg,
  1308.                                                    gaDiskInfo[nDriveIndex].lpPath );
  1309.                 if (err == WN_SUCCESS)
  1310.                 {
  1311.                     gaDiskInfo[nDriveIndex].dwType = NETDRVBMP;
  1312.                     nDriveIndex = (int) SendDlgItemMessage(
  1313.                            hDlg,
  1314.                            cmb2,
  1315.                            CB_SELECTSTRING,
  1316.                            (WPARAM)-1,
  1317.                            (LPARAM)(LPTSTR)gaDiskInfo[nDriveIndex].lpPath );
  1318.                     SendDlgItemMessage( hDlg,
  1319.                                         cmb2,
  1320.                                         CB_SETITEMDATA,
  1321.                                         (WPARAM)nDriveIndex,
  1322.                                         (LPARAM)NETDRVBMP );
  1323.                     bRet = GetFullPathName( pOFI->szPath,
  1324.                                             MAX_FULLPATHNAME,
  1325.                                             szPathName,
  1326.                                             NULL);
  1327.                 }
  1328.             }
  1329.         }
  1330.         HourGlass(FALSE);
  1331.         if (nFileOffset != PARSE_DIRECTORYNAME)
  1332.         {
  1333.             *(pOFI->szPath + nNullOffset) = ch;
  1334.         }
  1335.         if (bSlash)
  1336.         {
  1337.             *pOFI->szPath = CHAR_SLASH;
  1338.         }
  1339.         if (bRet)
  1340.         {
  1341.             cchSearchPath = 0;
  1342.             if (nFileOffset != PARSE_DIRECTORYNAME)
  1343.             {
  1344.                 ch = *(szPathName + lstrlen(szPathName) - 1);
  1345.                 if (!ISBACKSLASH(szPathName, lstrlen(szPathName) - 1))
  1346.                 {
  1347.                     lstrcat(szPathName, TEXT("\"));
  1348.                 }
  1349.                 lstrcat(szPathName, (LPTSTR)(pOFI->szPath + nFileOffset));
  1350.             }
  1351.             else
  1352.             {
  1353.                 //
  1354.                 //  Hack to get around SearchPath inconsistencies.
  1355.                 //
  1356.                 //  searching for c: returns c:
  1357.                 //  searching for server share dir1 .. returns  server share
  1358.                 //  in these two cases bypass the regular ChangeDir call that
  1359.                 //  uses szPathName and use the original pOFI->szPath instead
  1360.                 //  OKButtonPressed needs to be simplified!
  1361.                 //
  1362.                 int cch = GetPathOffset(pOFI->szPath);
  1363.                 if (cch > 0)
  1364.                 {
  1365.                     if (bUNCName)
  1366.                     {
  1367.                         //
  1368.                         //  If this fails, how is szPathName used?
  1369.                         //  szPathName's disk should equal pOFI->szPath's
  1370.                         //  so the cch will be valid.
  1371.                         //
  1372.                         szPathName[cch] = CHAR_BSLASH;
  1373.                         szPathName[cch + 1] = CHAR_NULL;
  1374.                         if (ChangeDir( hDlg,
  1375.                                        pOFI->szPath,
  1376.                                        FALSE,
  1377.                                        TRUE ) != CHANGEDIR_FAILED)
  1378.                         {
  1379.                             goto ChangedDir;
  1380.                         }
  1381.                     }
  1382.                     else
  1383.                     {
  1384.                         if (!pOFI->szPath[cch])
  1385.                         {
  1386.                             if (ChangeDir( hDlg,
  1387.                                            pOFI->szPath,
  1388.                                            FALSE,
  1389.                                            TRUE) != CHANGEDIR_FAILED)
  1390.                             {
  1391.                                 goto ChangedDir;
  1392.                             }
  1393.                         }
  1394.                     }
  1395.                 }
  1396.             }
  1397.         }
  1398.         else
  1399.         {
  1400.             if (!(pOFN->Flags & OFN_PATHMUSTEXIST))
  1401.             {
  1402.                 lstrcpy(szPathName, pOFI->szPath);
  1403.             }
  1404.             if (((nErrCode = GetLastError()) == ERROR_INVALID_DRIVE) ||
  1405.                 (pOFI->szPath[1] == CHAR_COLON))
  1406.             {
  1407.                 cchSearchPath = 1;
  1408.             }
  1409.             else
  1410.             {
  1411.                 cchSearchPath = 2;
  1412.             }
  1413.         }
  1414.     }
  1415.     //
  1416.     //  Full pattern?
  1417.     //
  1418.     if ( !cchSearchPath &&
  1419.          ((StrChr(pOFI->szPath + nFileOffset, CHAR_STAR)) ||
  1420.           (StrChr(pOFI->szPath + nFileOffset, CHAR_QMARK))) )
  1421.     {
  1422.         TCHAR szSameDirFile[MAX_FULLPATHNAME];
  1423.         if (nTempOffset)
  1424.         {
  1425.             //
  1426.             //  Must restore character in case it is part of the filename,
  1427.             //  e.g. nTempOffset is 1 for "foo.txt".
  1428.             //
  1429.             ch = pOFI->szPath[nTempOffset];
  1430.             pOFI->szPath[nTempOffset] = 0;
  1431.             ChangeDir(hDlg, pOFI->szPath, FALSE, TRUE);
  1432.             pOFI->szPath[nTempOffset] = ch;
  1433.         }
  1434.         if (!nExtOffset)
  1435.         {
  1436.             lstrcat(pOFI->szPath + nFileOffset, TEXT("."));
  1437.         }
  1438.         lstrcpy(szSameDirFile, pOFI->szPath + nFileOffset);
  1439.         lstrcpy(pOFI->szLastFilter, pOFI->szPath + nFileOffset);
  1440.         if (FListAll(pOFI, hDlg, szSameDirFile) < 0)
  1441.         {
  1442.             MessageBeep(0);
  1443.         }
  1444.         return (FALSE);
  1445.     }
  1446.     //
  1447.     //  We either have a file pattern or a real file.
  1448.     //  If its a directory
  1449.     //       (1) Add on default pattern
  1450.     //       (2) Act like its a pattern (goto pattern (1))
  1451.     //  Else if its a pattern
  1452.     //       (1) Update everything
  1453.     //       (2) display files in whatever dir were now in
  1454.     //  Else if its a file name!
  1455.     //       (1) Check out the syntax
  1456.     //       (2) End the dialog given OK
  1457.     //       (3) Beep/message otherwise
  1458.     //
  1459.     //
  1460.     //  Drive-letter:dirpath ??
  1461.     //
  1462.     if (!cchSearchPath)
  1463.     {
  1464.         DWORD dwFileAttr;
  1465.         if ((dwFileAttr = GetFileAttributes(szPathName)) != 0xFFFFFFFF)
  1466.         {
  1467.             if (dwFileAttr & FILE_ATTRIBUTE_DIRECTORY)
  1468.             {
  1469.                 if (ChangeDir(hDlg, szPathName, FALSE, TRUE) != CHANGEDIR_FAILED)
  1470.                 {
  1471. ChangedDir:
  1472.                     SendDlgItemMessage(hDlg, edt1, WM_SETREDRAW, FALSE, 0L);
  1473.                     if (*pOFI->szLastFilter)
  1474.                     {
  1475.                         SetDlgItemText(hDlg, edt1, pOFI->szLastFilter);
  1476.                     }
  1477.                     else
  1478.                     {
  1479.                         SetDlgItemText(hDlg, edt1, szStarDotStar);
  1480.                     }
  1481.                     SendMessage( hDlg,
  1482.                                  WM_COMMAND,
  1483.                                  GET_WM_COMMAND_MPS( cmb1,
  1484.                                                      GetDlgItem(hDlg, cmb1),
  1485.                                                      CBN_CLOSEUP ) );
  1486.                     SendMessage( hDlg,
  1487.                                  WM_COMMAND,
  1488.                                  GET_WM_COMMAND_MPS( cmb2,
  1489.                                                      GetDlgItem(hDlg, cmb2),
  1490.                                                      MYCBN_CHANGEDIR ) );
  1491.                     SendDlgItemMessage(hDlg, edt1, WM_SETREDRAW, TRUE, 0L);
  1492.                     InvalidateRect(GetDlgItem(hDlg, edt1), NULL, FALSE);
  1493.                 }
  1494.                 return (FALSE);
  1495.             }
  1496.         }
  1497.     }
  1498.     //
  1499.     //  Was there a path and did it fail?
  1500.     //
  1501.     if (nFileOffset && cchSearchPath && (pOFN->Flags & OFN_PATHMUSTEXIST))
  1502.     {
  1503. PathCheck:
  1504.         if (cchSearchPath == 2)
  1505.         {
  1506.             nErrCode = ERROR_PATH_NOT_FOUND;
  1507.         }
  1508.         else if (cchSearchPath == 1)
  1509.         {
  1510.             int nDriveIndex;
  1511.             //
  1512.             //  Lowercase drive letters since DiskAddedPreviously is case
  1513.             //  sensitive.
  1514.             //
  1515.             CharLower(pOFI->szPath);
  1516.             //  We can get here without performing an OpenFile call.  As such
  1517.             //  the szPathName can be filled with random garbage.  Since we
  1518.             //  only need one character for the error message, set
  1519.             //  szPathName[0] to the drive letter.
  1520.             //
  1521.             if (pOFI->szPath[1] == CHAR_COLON)
  1522.             {
  1523.                 nDriveIndex = DiskAddedPreviously(pOFI->szPath[0], NULL);
  1524.             }
  1525.             else
  1526.             {
  1527.                 nDriveIndex = DiskAddedPreviously(0, pOFI->szPath);
  1528.             }
  1529.             if (nDriveIndex == 0xFFFFFFFF)
  1530.             {
  1531.                 nErrCode = ERROR_NO_DRIVE;
  1532.             }
  1533.             else
  1534.             {
  1535.                 if (bUNCName)
  1536.                 {
  1537.                     nErrCode = ERROR_NO_DRIVE;
  1538.                 }
  1539.                 else
  1540.                 {
  1541.                     switch (GetDiskType(pOFI->szPath))
  1542.                     {
  1543.                         case ( DRIVE_REMOVABLE ) :
  1544.                         {
  1545.                             szPathName[0] = pOFI->szPath[0];
  1546.                             nErrCode = ERROR_NO_DISK_IN_DRIVE;
  1547.                             break;
  1548.                         }
  1549.                         case ( DRIVE_CDROM ) :
  1550.                         {
  1551.                            szPathName[0] = pOFI->szPath[0];
  1552.                            nErrCode = ERROR_NO_DISK_IN_CDROM;
  1553.                            break;
  1554.                         }
  1555.                         default :
  1556.                         {
  1557.                            nErrCode = ERROR_PATH_NOT_FOUND;
  1558.                         }
  1559.                     }
  1560.                 }
  1561.             }
  1562.         }
  1563.         else
  1564.         {
  1565.             nErrCode = ERROR_FILE_NOT_FOUND;
  1566.         }
  1567.         //
  1568.         //  If we don't set wNoRedraw here, then WM_ACTIVATE will set the
  1569.         //  GetNetDrives event.
  1570.         //
  1571.         wNoRedraw |= 1;
  1572.         goto Warning;
  1573.     }
  1574.     if (PortName(pOFI->szPath + nFileOffset))
  1575.     {
  1576.         nErrCode = ERROR_PORTNAME;
  1577.         goto Warning;
  1578.     }
  1579. #if 0
  1580.     //
  1581.     //  Check if we've received a string in the form "C:filename.ext".
  1582.     //  If we have, convert it to the form "C:.filename.ext".  This is done
  1583.     //  because the kernel will search the entire path, ignoring the drive
  1584.     //  specification after the initial search.  Making it include a slash
  1585.     //  causes kernel to only search at that location.
  1586.     //  Note:  Only increment nExtOffset, not nFileOffset.  This is done
  1587.     //  because only nExtOffset is used later, and nFileOffset can then be
  1588.     //  used at the Warning: label to determine if this hack has occurred,
  1589.     //  and thus it can strip out the "." when putting out the error.
  1590.     //
  1591.     if ((nFileOffset == 2) && (pOFI->szPath[1] == CHAR_COLON))
  1592.     {
  1593.         lstrcpy(szWarning, pOFI->szPath + 2);
  1594.         lstrcpy(pOFI->szPath + 4, szWarning);
  1595.         pOFI->szPath[2] = CHAR_DOT;
  1596.         pOFI->szPath[3] = CHAR_BSLASH;
  1597.         nExtOffset += 2;
  1598.     }
  1599. #endif
  1600.     //
  1601.     //  Add the default extension unless filename ends with period or no
  1602.     //  default extension exists.  If the file exists, consider asking
  1603.     //  permission to overwrite the file.
  1604.     //
  1605.     //  NOTE:  When no extension given, default extension is tried 1st.
  1606.     //
  1607.     if ( (nFileOffset != PARSE_DIRECTORYNAME) &&
  1608.          nExtOffset &&
  1609.          !pOFI->szPath[nExtOffset] &&
  1610.          pOFN->lpstrDefExt &&
  1611.          *pOFN->lpstrDefExt &&
  1612.          (((DWORD)nExtOffset + lstrlen(pOFN->lpstrDefExt)) < pOFN->nMaxFile) )
  1613.     {
  1614.         DWORD dwFileAttr;
  1615.         int nExtOffset2 = lstrlen(szPathName);
  1616.         bAddExt = TRUE;
  1617.         AppendExt(pOFI->szPath, pOFN->lpstrDefExt, FALSE);
  1618.         AppendExt(szPathName, pOFN->lpstrDefExt, FALSE);
  1619.         //
  1620.         //  Directory may match default extension.  Change to it as if it had
  1621.         //  been typed in.  A dir w/o the extension would have been switched
  1622.         //  to in the logic above.
  1623.         //
  1624.         if ((dwFileAttr = GetFileAttributes(pOFI->szPath)) != 0xFFFFFFFF)
  1625.         {
  1626.             if (dwFileAttr & FILE_ATTRIBUTE_DIRECTORY)
  1627.             {
  1628.                 if (ChangeDir(hDlg, szPathName, FALSE, TRUE) != CHANGEDIR_FAILED)
  1629.                 {
  1630.                     goto ChangedDir;
  1631.                 }
  1632.             }
  1633.         }
  1634.         hFile = CreateFile( szPathName,
  1635.                             GENERIC_READ,
  1636.                             FILE_SHARE_READ | FILE_SHARE_WRITE,
  1637.                             NULL,
  1638.                             OPEN_EXISTING,
  1639.                             FILE_ATTRIBUTE_NORMAL,
  1640.                             NULL );
  1641.         if (hFile == INVALID_HANDLE_VALUE)
  1642.         {
  1643.             nErrCode = GetLastError();
  1644.             //
  1645.             //  Fix bug where progman cannot OK a file being browsed for new
  1646.             //  item because it has Execute only permission.
  1647.             //
  1648.             if (nErrCode == ERROR_ACCESS_DENIED)
  1649.             {
  1650.                 hFile = CreateFile( szPathName,
  1651.                                     GENERIC_EXECUTE,
  1652.                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
  1653.                                     NULL,
  1654.                                     OPEN_EXISTING,
  1655.                                     FILE_ATTRIBUTE_NORMAL,
  1656.                                     NULL );
  1657.                 if (hFile == INVALID_HANDLE_VALUE)
  1658.                 {
  1659.                     nErrCode = GetLastError();
  1660.                 }
  1661.             }
  1662.         }
  1663.         if (nErrCode == ERROR_SHARING_VIOLATION)
  1664.         {
  1665.             goto SharingViolationInquiry;
  1666.         }
  1667.         if (hFile != INVALID_HANDLE_VALUE)
  1668.         {
  1669.             if (!CloseHandle(hFile))
  1670.             {
  1671.                 nErrCode = GetLastError();
  1672.                 goto Warning;
  1673.             }
  1674. AskPermission:
  1675.             //
  1676.             //  Is the file read-only?
  1677.             //
  1678.             if (pOFN->Flags & OFN_NOREADONLYRETURN)
  1679.             {
  1680.                 int nRet;
  1681.                 if ((nRet = GetFileAttributes(szPathName)) != -1)
  1682.                 {
  1683.                     if (nRet & ATTR_READONLY)
  1684.                     {
  1685.                         nErrCode = ERROR_LAZY_READONLY;
  1686.                         goto Warning;
  1687.                     }
  1688.                 }
  1689.                 else
  1690.                 {
  1691.                     nErrCode = GetLastError();
  1692.                     goto Warning;
  1693.                 }
  1694.             }
  1695.             if ((bSave || (pOFN->Flags & OFN_NOREADONLYRETURN)) &&
  1696.                 (nErrCode == ERROR_ACCESS_DENIED))
  1697.             {
  1698.                 goto Warning;
  1699.             }
  1700.             if (pOFN->Flags & OFN_OVERWRITEPROMPT)
  1701.             {
  1702.                 if (bSave && !FOkToWriteOver(hDlg, szPathName))
  1703.                 {
  1704.                     PostMessage( hDlg,
  1705.                                  WM_NEXTDLGCTL,
  1706.                                  (WPARAM)GetDlgItem(hDlg, edt1),
  1707.                                  (LPARAM)1L );
  1708.                     return (FALSE);
  1709.                 }
  1710.             }
  1711.             if (nErrCode == ERROR_SHARING_VIOLATION)
  1712.             {
  1713.                 goto SharingViolationInquiry;
  1714.             }
  1715.             goto FileNameAccepted;
  1716.         }
  1717.         else
  1718.         {
  1719.             *(pOFI->szPath + nExtOffset) = CHAR_NULL;
  1720.             szPathName[nExtOffset2] = CHAR_NULL;
  1721.         }
  1722.     }
  1723.     else
  1724.     {
  1725.         //
  1726.         //  Extension should not be added.
  1727.         //
  1728.         bAddExt = FALSE;
  1729.     }
  1730.     hFile = CreateFile( szPathName,
  1731.                         GENERIC_READ,
  1732.                         FILE_SHARE_READ | FILE_SHARE_WRITE,
  1733.                         NULL,
  1734.                         OPEN_EXISTING,
  1735.                         FILE_ATTRIBUTE_NORMAL,
  1736.                         NULL );
  1737.     if (hFile == INVALID_HANDLE_VALUE)
  1738.     {
  1739.         nErrCode = GetLastError();
  1740.         //
  1741.         //  Fix bug where progman cannot OK a file being browsed for new item
  1742.         //  because it has Execute only permission.
  1743.         //
  1744.         if (nErrCode == ERROR_ACCESS_DENIED)
  1745.         {
  1746.             hFile = CreateFile( szPathName,
  1747.                                 GENERIC_EXECUTE,
  1748.                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
  1749.                                 NULL,
  1750.                                 OPEN_EXISTING,
  1751.                                 FILE_ATTRIBUTE_NORMAL,
  1752.                                 NULL );
  1753.             if (hFile == INVALID_HANDLE_VALUE)
  1754.             {
  1755.                 nErrCode = GetLastError();
  1756.             }
  1757.         }
  1758.     }
  1759.     if (hFile != INVALID_HANDLE_VALUE)
  1760.     {
  1761.         if (!CloseHandle(hFile))
  1762.         {
  1763.             nErrCode = GetLastError();
  1764.             goto Warning;
  1765.         }
  1766.         goto AskPermission;
  1767.     }
  1768.     else
  1769.     {
  1770.         if ((nErrCode == ERROR_FILE_NOT_FOUND) ||
  1771.             (nErrCode == ERROR_PATH_NOT_FOUND))
  1772.         {
  1773.             //
  1774.             //  Figure out if the default extension should be tacked on.
  1775.             //
  1776.             if (bAddExt)
  1777.             {
  1778.                 AppendExt(pOFI->szPath, pOFN->lpstrDefExt, FALSE);
  1779.                 AppendExt(szPathName, pOFN->lpstrDefExt, FALSE);
  1780.             }
  1781.         }
  1782.         else if (nErrCode == ERROR_SHARING_VIOLATION)
  1783.         {
  1784. SharingViolationInquiry:
  1785.             //
  1786.             //  If the app is "share aware", fall through.
  1787.             //  Otherwise, ask the hook function.
  1788.             //
  1789.             if (!(pOFN->Flags & OFN_SHAREAWARE))
  1790.             {
  1791.                 if (pOFN->lpfnHook)
  1792.                 {
  1793.                     LPOFNHOOKPROC lpfnHook = GETHOOKFN(pOFN);
  1794. #ifdef UNICODE
  1795.                     if (pOFI->ApiType == COMDLG_ANSI)
  1796.                     {
  1797.                         CHAR szPathNameA[MAX_FULLPATHNAME];
  1798.                         RtlUnicodeToMultiByteSize(
  1799.                               &cch,
  1800.                               szPathName,
  1801.                               lstrlenW(szPathName) * sizeof(TCHAR) );
  1802.                         SHUnicodeToAnsi(szPathName,(LPSTR)&szPathNameA[0],cch + 1);
  1803.                         cch = (DWORD)(*lpfnHook)( hDlg,
  1804.                                            msgSHAREVIOLATIONA,
  1805.                                            0,
  1806.                                            (LONG_PTR)(LPSTR)szPathNameA );
  1807.                     }
  1808.                     else
  1809. #endif
  1810.                     {
  1811.                         cch = (DWORD)(*lpfnHook)( hDlg,
  1812.                                            msgSHAREVIOLATIONW,
  1813.                                            0,
  1814.                                            (LONG_PTR)szPathName );
  1815.                     }
  1816.                     if (cch == OFN_SHARENOWARN)
  1817.                     {
  1818.                         return (FALSE);
  1819.                     }
  1820.                     else if (cch != OFN_SHAREFALLTHROUGH)
  1821.                     {
  1822.                         goto Warning;
  1823.                     }
  1824.                 }
  1825.                 else
  1826.                 {
  1827.                     goto Warning;
  1828.                 }
  1829.             }
  1830.             goto FileNameAccepted;
  1831.         }
  1832.         if (!bSave)
  1833.         {
  1834.             if ((nErrCode == ERROR_FILE_NOT_FOUND) ||
  1835.                 (nErrCode == ERROR_PATH_NOT_FOUND))
  1836.             {
  1837.                 if (pOFN->Flags & OFN_FILEMUSTEXIST)
  1838.                 {
  1839.                     if (pOFN->Flags & OFN_CREATEPROMPT)
  1840.                     {
  1841.                         //
  1842.                         //  Don't alter pOFI->szPath.
  1843.                         //
  1844.                         bInChildDlg = TRUE;
  1845.                         cch = (DWORD)CreateFileDlg(hDlg, pOFI->szPath);
  1846.                         bInChildDlg = FALSE;
  1847.                         if (cch == IDYES)
  1848.                         {
  1849.                             goto TestCreation;
  1850.                         }
  1851.                         else
  1852.                         {
  1853.                             return (FALSE);
  1854.                         }
  1855.                     }
  1856.                     goto Warning;
  1857.                 }
  1858.             }
  1859.             else
  1860.             {
  1861.                 goto Warning;
  1862.             }
  1863.         }
  1864.         //
  1865.         //  The file doesn't exist.  Can it be created?  This is needed because
  1866.         //  there are many extended characters which are invalid that won't be
  1867.         //  caught by ParseFile.
  1868.         //  Two more good reasons:  Write-protected disks & full disks.
  1869.         //
  1870.         //  BUT, if they dont want the test creation, they can request that we
  1871.         //  not do it using the OFN_NOTESTFILECREATE flag.  If they want to
  1872.         //  create files on a share that has create-but-no-modify privileges,
  1873.         //  they should set this flag but be ready for failures that couldn't
  1874.         //  be caught, such as no create privileges, invalid extended
  1875.         //  characters, a full disk, etc.
  1876.         //
  1877. TestCreation:
  1878.         if ((pOFN->Flags & OFN_PATHMUSTEXIST) &&
  1879.             (!(pOFN->Flags & OFN_NOTESTFILECREATE)))
  1880.         {
  1881.             //
  1882.             //  Must use the FILE_FLAG_DELETE_ON_CLOSE flag so that the
  1883.             //  file is automatically deleted when the handle is closed
  1884.             //  (no need to call DeleteFile).  This is necessary in the
  1885.             //  event that the directory only has Add & Read access.
  1886.             //  The CreateFile call will succeed, but the DeleteFile call
  1887.             //  will fail.  By adding the above flag to the CreateFile
  1888.             //  call, it overrides the access rights and deletes the file
  1889.             //  during the call to CloseHandle.
  1890.             //
  1891. #ifdef WINNT
  1892.             hFile = CreateFile( szPathName,
  1893.                                 FILE_ADD_FILE,
  1894.                                 0,
  1895.                                 NULL,
  1896.                                 CREATE_NEW,
  1897.                                 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
  1898.                                 NULL );
  1899. #else
  1900.             // Win95/Memphis don't support FILE_ADD_FILE flag, use GENERIC_READ instead.
  1901.             hFile = CreateFile( szPathName,
  1902.                                 GENERIC_READ,
  1903.                                 0,
  1904.                                 NULL,
  1905.                                 CREATE_NEW,
  1906.                                 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_DELETE_ON_CLOSE,
  1907.                                 NULL );
  1908. #endif
  1909.             if (hFile == INVALID_HANDLE_VALUE)
  1910.             {
  1911.                 nErrCode = GetLastError();
  1912.             }
  1913.             if (hFile != INVALID_HANDLE_VALUE)
  1914.             {
  1915.                 if (!CloseHandle(hFile))
  1916.                 {
  1917.                     nErrCode = GetLastError();
  1918.                     goto Warning;
  1919.                 }
  1920.             }
  1921.             else
  1922.             {
  1923.                 //
  1924.                 //  Unable to create it.
  1925.                 //
  1926.                 //  If it's not write-protection, a full disk,
  1927.                 //  network protection, or the user popping the drive door
  1928.                 //  open, assume that the filename is invalid.
  1929.                 //
  1930.                 if ( (nErrCode != ERROR_WRITE_PROTECT) &&
  1931.                      (nErrCode != ERROR_CANNOT_MAKE) &&
  1932.                      (nErrCode != ERROR_NETWORK_ACCESS_DENIED) &&
  1933.                      (nErrCode != ERROR_ACCESS_DENIED) )
  1934.                 {
  1935.                     nErrCode = 0;
  1936.                 }
  1937.                 goto Warning;
  1938.             }
  1939.         }
  1940.     }
  1941. FileNameAccepted:
  1942.     HourGlass(TRUE);
  1943.     lRet = ParseFile(szPathName, blfn, IS16BITWOWAPP(pOFN), FALSE);
  1944.     nFileOffset = (int)(SHORT)LOWORD(lRet);
  1945.     cch = (DWORD)HIWORD(lRet);
  1946.     pOFN->nFileOffset = (WORD)nFileOffset;
  1947.     if (nExtOffset || bAddExt)
  1948.     {
  1949.         pOFN->nFileExtension = LOWORD(cch);
  1950.     }
  1951.     else
  1952.     {
  1953.         pOFN->nFileExtension = 0;
  1954.     }
  1955.     pOFN->Flags &= ~OFN_EXTENSIONDIFFERENT;
  1956.     if (pOFN->lpstrDefExt && pOFN->nFileExtension)
  1957.     {
  1958.         TCHAR szPrivateExt[4];
  1959.         SHORT i;
  1960.         for (i = 0; i < 3; i++)
  1961.         {
  1962.             szPrivateExt[i] = *(pOFN->lpstrDefExt + i);
  1963.         }
  1964.         szPrivateExt[3] = CHAR_NULL;
  1965.         if (lstrcmpi(szPrivateExt, szPathName + cch))
  1966.         {
  1967.             pOFN->Flags |= OFN_EXTENSIONDIFFERENT;
  1968.         }
  1969.     }
  1970.     //
  1971.     //  If we're called from wow, and the user hasn't changed
  1972.     //  directories, shorten the path to abbreviated 8.3 format.
  1973.     //
  1974.     if (pOFN->Flags & OFN_NOLONGNAMES)
  1975.     {
  1976.         ShortenThePath(szPathName);
  1977.         //
  1978.         //  If the path was shortened, the offset might have changed so
  1979.         //  we must parse the file again.
  1980.         //
  1981.         lRet = ParseFile(szPathName, blfn, IS16BITWOWAPP(pOFN), FALSE);
  1982.         nFileOffset = (int)(SHORT)LOWORD(lRet);
  1983.         cch  = (DWORD)HIWORD(lRet);
  1984.         //
  1985.         //  When in Save dialog, the file may not exist yet, so the file
  1986.         //  name cannot be shortened.  So, we need to test if it's an
  1987.         //  8.3 filename and popup an error message if not.
  1988.         //
  1989.         if (bSave)
  1990.         {
  1991.             LPTSTR lptmp;
  1992.             LPTSTR lpExt = NULL;
  1993.             for (lptmp = szPathName + nFileOffset; *lptmp; lptmp++)
  1994.             {
  1995.                 if (*lptmp == CHAR_DOT)
  1996.                 {
  1997.                     if (lpExt)
  1998.                     {
  1999.                         //
  2000.                         //  There's more than one dot in the file, so it is
  2001.                         //  invalid.
  2002.                         //
  2003.                         nErrCode = FNERR_INVALIDFILENAME;
  2004.                         goto Warning;
  2005.                     }
  2006.                     lpExt = lptmp;
  2007.                 }
  2008.                 if (*lptmp == CHAR_SPACE)
  2009.                 {
  2010.                     nErrCode = FNERR_INVALIDFILENAME;
  2011.                     goto Warning;
  2012.                 }
  2013.             }
  2014.             if (lpExt)
  2015.             {
  2016.                 //
  2017.                 //  There's an extension.
  2018.                 //
  2019.                 *lpExt = 0;
  2020.             }
  2021.             if ((lstrlen(szPathName + nFileOffset) > 8) ||
  2022.                 (lpExt && lstrlen(lpExt + 1) > 3))
  2023.             {
  2024.                 if (lpExt)
  2025.                 {
  2026.                     *lpExt = CHAR_DOT;
  2027.                 }
  2028.                 nErrCode = FNERR_INVALIDFILENAME;
  2029.                 goto Warning;
  2030.             }
  2031.             if (lpExt)
  2032.             {
  2033.                 *lpExt = CHAR_DOT;
  2034.             }
  2035.         }
  2036.     }
  2037.     if (pOFN->lpstrFile)
  2038.     {
  2039.         DWORD cchLen = lstrlen(szPathName);
  2040.         if (cchLen < pOFN->nMaxFile)
  2041.         {
  2042.             lstrcpy(pOFN->lpstrFile, szPathName);
  2043.         }
  2044.         else
  2045.         {
  2046.             //
  2047.             //  Buffer is too small, so return the size of the buffer
  2048.             //  required to hold the string.
  2049.             //
  2050.             //  For single file requests, we will never go over 64K
  2051.             //  because the filesystem is limited to 256.
  2052.             //
  2053. #ifdef UNICODE
  2054.             pOFN->lpstrFile[0] = (TCHAR)LOWORD(cchLen);
  2055.             if (pOFN->nMaxFile >= 2)
  2056.             {
  2057.                 pOFN->lpstrFile[1] = CHAR_NULL;
  2058.             }
  2059. #else
  2060.             pOFN->lpstrFile[0] = LOBYTE(cchLen);
  2061.             pOFN->lpstrFile[1] = HIBYTE(cchLen);
  2062.             pOFN->lpstrFile[2] = CHAR_NULL;
  2063. #endif
  2064.         }
  2065.     }
  2066.     //
  2067.     //  File Title.  Note that it's cut off at whatever the buffer length
  2068.     //               is, so if the buffer is too small, no notice is given.
  2069.     //
  2070.     if (pOFN->lpstrFileTitle && pOFN->nMaxFileTitle)
  2071.     {
  2072.         cch = lstrlen(szPathName + nFileOffset);
  2073.         if (cch > pOFN->nMaxFileTitle)
  2074.         {
  2075.             szPathName[nFileOffset + pOFN->nMaxFileTitle - 1] = CHAR_NULL;
  2076.         }
  2077.         lstrcpy(pOFN->lpstrFileTitle, szPathName + nFileOffset);
  2078.     }
  2079.     if (pOFN->Flags | OFN_READONLY)
  2080.     {
  2081.         if (IsDlgButtonChecked(hDlg, chx1))
  2082.         {
  2083.             pOFN->Flags |= OFN_READONLY;
  2084.         }
  2085.         else
  2086.         {
  2087.             pOFN->Flags &= ~OFN_READONLY;
  2088.         }
  2089.     }
  2090.     return (TRUE);
  2091. }
  2092. ////////////////////////////////////////////////////////////////////////////
  2093. //
  2094. //  MultiSelectOKButton
  2095. //
  2096. ////////////////////////////////////////////////////////////////////////////
  2097. BOOL MultiSelectOKButton(
  2098.     HWND hDlg,
  2099.     POPENFILEINFO pOFI,
  2100.     BOOL bSave)
  2101. {
  2102.     DWORD nErrCode;
  2103.     LPTSTR lpCurDir;
  2104.     LPTSTR lpchStart;                  // start of an individual filename
  2105.     LPTSTR lpchEnd;                    // end of an individual filename
  2106.     DWORD cch;
  2107.     HANDLE hFile;
  2108.     LPOPENFILENAME pOFN;
  2109.     BOOL EOS = FALSE;                  // end of string flag
  2110.     BOOL bRet;
  2111.     TCHAR szPathName[MAX_FULLPATHNAME - 1];
  2112.     LPCURDLG lpCurDlg;
  2113.     pOFN = pOFI->pOFN;
  2114.     //
  2115.     //  Check for space for first full path element.
  2116.     //
  2117.     if(!(lpCurDlg = (LPCURDLG)TlsGetValue(g_tlsiCurDlg)) ||
  2118.        !(lpCurDir = lpCurDlg->lpstrCurDir))
  2119.     {
  2120.         return (FALSE);
  2121.     }
  2122.     lstrcpy(pOFI->szPath, lpCurDir);
  2123.     if (StrChr(pOFI->szPath, CHAR_SPACE))
  2124.     {
  2125.         GetShortPathName(pOFI->szPath, pOFI->szPath, MAX_FULLPATHNAME);
  2126.     }
  2127.     if (!bCasePreserved)
  2128.     {
  2129.         CharLower(pOFI->szPath);
  2130.     }
  2131.     cch = (DWORD) ( lstrlen(pOFI->szPath) +
  2132.             sizeof(TCHAR) +
  2133.             SendDlgItemMessage(hDlg, edt1, WM_GETTEXTLENGTH, 0, 0L) );
  2134.     if (pOFN->lpstrFile)
  2135.     {
  2136.         if (cch > pOFN->nMaxFile)
  2137.         {
  2138.             //
  2139.             //  Buffer is too small, so return the size of the buffer
  2140.             //  required to hold the string (if possible).
  2141.             //
  2142.             if (pOFN->nMaxFile >= 3)
  2143.             {
  2144. #ifdef UNICODE
  2145.                 pOFN->lpstrFile[0] = (TCHAR)LOWORD(cch);
  2146.                 pOFN->lpstrFile[1] = (TCHAR)HIWORD(cch);
  2147. #else
  2148.                 pOFN->lpstrFile[0] = (TCHAR)LOBYTE(cch);
  2149.                 pOFN->lpstrFile[1] = (TCHAR)HIBYTE(cch);
  2150. #endif
  2151.                 pOFN->lpstrFile[2] = CHAR_NULL;
  2152.             }
  2153.             else
  2154.             {
  2155. #ifdef UNICODE
  2156.                 pOFN->lpstrFile[0] = (TCHAR)LOWORD(cch);
  2157.                 if (pOFN->nMaxFile == 2)
  2158.                 {
  2159.                     pOFN->lpstrFile[1] = (TCHAR)HIWORD(cch);
  2160.                 }
  2161. #else
  2162.                 pOFN->lpstrFile[0] = LOBYTE(cch);
  2163.                 pOFN->lpstrFile[1] = HIBYTE(cch);
  2164.                 pOFN->lpstrFile[2] = CHAR_NULL;
  2165. #endif
  2166.             }
  2167.         }
  2168.         else
  2169.         {
  2170.             //
  2171.             //  Copy in the full path as the first element.
  2172.             //
  2173.             lstrcpy(pOFN->lpstrFile, pOFI->szPath);
  2174.             lstrcat(pOFN->lpstrFile, TEXT(" "));
  2175.             //
  2176.             //  Get the other files here.
  2177.             //
  2178.             cch = lstrlen(pOFN->lpstrFile);
  2179.             //
  2180.             //  The path is guaranteed to be less than 64K (actually, < 260).
  2181.             //
  2182.             pOFN->nFileOffset = LOWORD(cch);
  2183.             lpchStart = pOFN->lpstrFile + cch;
  2184.             GetDlgItemText( hDlg,
  2185.                             edt1,
  2186.                             lpchStart,
  2187.                             (int)(pOFN->nMaxFile - cch - 1) );
  2188.             while (*lpchStart == CHAR_SPACE)
  2189.             {
  2190.                 lpchStart = CharNext(lpchStart);
  2191.             }
  2192.             if (*lpchStart == CHAR_NULL)
  2193.             {
  2194.                 return (FALSE);
  2195.             }
  2196.             //
  2197.             //  Go along file path looking for multiple filenames delimited by
  2198.             //  spaces.  For each filename found, try to open it to make sure
  2199.             //  it's a valid file.
  2200.             //
  2201.             while (!EOS)
  2202.             {
  2203.                 //
  2204.                 //  Find the end of the filename.
  2205.                 //
  2206.                 lpchEnd = lpchStart;
  2207.                 while (*lpchEnd && *lpchEnd != CHAR_SPACE)
  2208.                 {
  2209.                     lpchEnd = CharNext(lpchEnd);
  2210.                 }
  2211.                 //
  2212.                 //  Mark the end of the filename with a NULL.
  2213.                 //
  2214.                 if (*lpchEnd == CHAR_SPACE)
  2215.                 {
  2216.                     *lpchEnd = CHAR_NULL;
  2217.                 }
  2218.                 else
  2219.                 {
  2220.                     //
  2221.                     //  Already NULL, found the end of the string.
  2222.                     //
  2223.                     EOS = TRUE;
  2224.                 }
  2225.                 //
  2226.                 //  Check that the filename is valid.
  2227.                 //
  2228.                 bRet = GetFullPathName( lpchStart,
  2229.                                         MAX_FULLPATHNAME,
  2230.                                         szPathName,
  2231.                                         NULL);
  2232.                 if (!bRet)
  2233.                 {
  2234.                     nErrCode = ERROR_FILE_NOT_FOUND;
  2235.                     goto MultiFileNotFound;
  2236.                 }
  2237.                 hFile = CreateFile( szPathName,
  2238.                                     GENERIC_READ,
  2239.                                     FILE_SHARE_READ | FILE_SHARE_WRITE,
  2240.                                     NULL,
  2241.                                     OPEN_EXISTING,
  2242.                                     FILE_ATTRIBUTE_NORMAL,
  2243.                                     NULL );
  2244.                 //
  2245.                 //  Fix bug where progman cannot OK a file being browsed for
  2246.                 //  new item because it has Execute only permission.
  2247.                 //
  2248.                 if (hFile == INVALID_HANDLE_VALUE)
  2249.                 {
  2250.                     nErrCode = GetLastError();
  2251.                     if (nErrCode == ERROR_ACCESS_DENIED)
  2252.                     {
  2253.                         hFile = CreateFile( szPathName,
  2254.                                             GENERIC_EXECUTE,
  2255.                                             FILE_SHARE_READ | FILE_SHARE_WRITE,
  2256.                                             NULL,
  2257.                                             OPEN_EXISTING,
  2258.                                             FILE_ATTRIBUTE_NORMAL,
  2259.                                             NULL );
  2260.                     }
  2261.                     else
  2262.                     {
  2263.                         goto MultiFileNotFound;
  2264.                     }
  2265.                 }
  2266.                 if (hFile == INVALID_HANDLE_VALUE)
  2267.                 {
  2268.                     nErrCode = GetLastError();
  2269. MultiFileNotFound:
  2270.                     if ( ((pOFN->Flags & OFN_FILEMUSTEXIST) ||
  2271.                           (nErrCode != ERROR_FILE_NOT_FOUND)) &&
  2272.                          ((pOFN->Flags & OFN_PATHMUSTEXIST) ||
  2273.                           (nErrCode != ERROR_PATH_NOT_FOUND)) &&
  2274.                          (!(pOFN->Flags & OFN_SHAREAWARE) ||
  2275.                           (nErrCode != ERROR_SHARING_VIOLATION)) )
  2276.                     {
  2277.                         if ( (nErrCode == ERROR_SHARING_VIOLATION) &&
  2278.                              pOFN->lpfnHook )
  2279.                         {
  2280.                             LPOFNHOOKPROC lpfnHook = GETHOOKFN(pOFN);
  2281. #ifdef UNICODE
  2282.                             if (pOFI->ApiType == COMDLG_ANSI)
  2283.                             {
  2284.                                 CHAR szPathNameA[MAX_FULLPATHNAME];
  2285.                                 RtlUnicodeToMultiByteSize(
  2286.                                      &cch,
  2287.                                      szPathName,
  2288.                                      lstrlenW(szPathName) * sizeof(TCHAR) );
  2289.                                 SHUnicodeToAnsi(szPathName,(LPSTR)&szPathNameA[0],cch + 1);
  2290.                                 cch = (DWORD)(*lpfnHook)( hDlg,
  2291.                                                    msgSHAREVIOLATIONA,
  2292.                                                    0,
  2293.                                                    (LONG_PTR)(LPSTR)szPathNameA );
  2294.                             }
  2295.                             else
  2296. #endif
  2297.                             {
  2298.                                 cch = (DWORD)(*lpfnHook)( hDlg,
  2299.                                                    msgSHAREVIOLATIONW,
  2300.                                                    0,
  2301.                                                    (LONG_PTR)szPathName );
  2302.                             }
  2303.                             if (cch == OFN_SHARENOWARN)
  2304.                             {
  2305.                                 return (FALSE);
  2306.                             }
  2307.                             else if (cch == OFN_SHAREFALLTHROUGH)
  2308.                             {
  2309.                                 goto EscapedThroughShare;
  2310.                             }
  2311.                         }
  2312.                         else if (nErrCode == ERROR_ACCESS_DENIED)
  2313.                         {
  2314.                             szPathName[0] =
  2315.                                (TCHAR)CharLower((LPTSTR)(DWORD)szPathName[0]);
  2316.                             if (GetDiskType(szPathName) != DRIVE_REMOVABLE)
  2317.                             {
  2318.                                 nErrCode = ERROR_NETWORK_ACCESS_DENIED;
  2319.                             }
  2320.                         }
  2321.                         if ((nErrCode == ERROR_WRITE_PROTECT) ||
  2322.                             (nErrCode == ERROR_CANNOT_MAKE)   ||
  2323.                             (nErrCode == ERROR_ACCESS_DENIED))
  2324.                         {
  2325.                             *lpchStart = szPathName[0];
  2326.                         }
  2327. MultiWarning:
  2328.                         InvalidFileWarning(hDlg, lpchStart, nErrCode, 0);
  2329.                         return (FALSE);
  2330.                     }
  2331.                 }
  2332. EscapedThroughShare:
  2333.                 if (hFile != INVALID_HANDLE_VALUE)
  2334.                 {
  2335.                     if (!CloseHandle(hFile))
  2336.                     {
  2337.                         nErrCode = GetLastError();
  2338.                         goto MultiWarning;
  2339.                     }
  2340.                     if ((pOFN->Flags & OFN_NOREADONLYRETURN) &&
  2341.                         (GetFileAttributes(szPathName) & FILE_ATTRIBUTE_READONLY))
  2342.                     {
  2343.                         nErrCode = ERROR_LAZY_READONLY;
  2344.                         goto MultiWarning;
  2345.                     }
  2346.                     if ((bSave || (pOFN->Flags & OFN_NOREADONLYRETURN)) &&
  2347.                         (nErrCode == ERROR_ACCESS_DENIED))
  2348.                     {
  2349.                         goto MultiWarning;
  2350.                     }
  2351.                     if (pOFN->Flags & OFN_OVERWRITEPROMPT)
  2352.                     {
  2353.                         if (bSave && !FOkToWriteOver(hDlg, szPathName))
  2354.                         {
  2355.                             PostMessage( hDlg,
  2356.                                          WM_NEXTDLGCTL,
  2357.                                          (WPARAM)GetDlgItem(hDlg, edt1),
  2358.                                          (LPARAM)1L );
  2359.                             return (FALSE);
  2360.                         }
  2361.                     }
  2362.                 }
  2363.                 //
  2364.                 //  This file is valid, so check the next one.
  2365.                 //
  2366.                 if (!EOS)
  2367.                 {
  2368.                     lpchStart = lpchEnd + 1;
  2369.                     while (*lpchStart == CHAR_SPACE)
  2370.                     {
  2371.                         lpchStart = CharNext(lpchStart);
  2372.                     }
  2373.                     if (*lpchStart == CHAR_NULL)
  2374.                     {
  2375.                         EOS = TRUE;
  2376.                     }
  2377.                     else
  2378.                     {
  2379.                         //
  2380.                         //  Not at end, replace NULL with SPACE.
  2381.                         //
  2382.                         *lpchEnd = CHAR_SPACE;
  2383.                     }
  2384.                 }
  2385.             }
  2386.             //
  2387.             //  Limit String.
  2388.             //
  2389.             *lpchEnd = CHAR_NULL;
  2390.         }
  2391.     }
  2392.     //
  2393.     //  This doesn't really mean anything for multiselection.
  2394.     //
  2395.     pOFN->nFileExtension = 0;
  2396.     pOFN->nFilterIndex = (int) SendDlgItemMessage(hDlg, cmb1, CB_GETCURSEL, 0, 0L);
  2397.     return (TRUE);
  2398. }
  2399. ////////////////////////////////////////////////////////////////////////////
  2400. //
  2401. //  dwOKSubclass
  2402. //
  2403. //  Simulates a double click if the user presses OK with the mouse
  2404. //  and the focus was on the directory listbox.
  2405. //
  2406. //  The problem is that the UITF demands that when the directory
  2407. //  listbox loses the focus, the selected directory should return
  2408. //  to the current directory.  But when the user changes the item
  2409. //  selected with a single click, and then clicks the OK button to
  2410. //  have the change take effect, the focus is lost before the OK button
  2411. //  knows it was pressed.  By setting the global flag bChangeDir
  2412. //  when the directory listbox loses the focus and clearing it when
  2413. //  the OK button loses the focus, we can check whether a mouse
  2414. //  click should update the directory.
  2415. //
  2416. //  Returns:  Return value from default listbox proceedure.
  2417. //
  2418. ////////////////////////////////////////////////////////////////////////////
  2419. LRESULT WINAPI dwOKSubclass(
  2420.     HWND hOK,
  2421.     UINT msg,
  2422.     WPARAM wParam,
  2423.     LPARAM lParam)
  2424. {
  2425.     HANDLE hDlg;
  2426.     POPENFILEINFO pOFI;
  2427.     if (msg == WM_KILLFOCUS)
  2428.     {
  2429.         if (bChangeDir)
  2430.         {
  2431.             if (pOFI = (POPENFILEINFO)GetProp(hDlg = GetParent(hOK), FILEPROP))
  2432.             {
  2433.                 SendDlgItemMessage( hDlg,
  2434.                                     lst2,
  2435.                                     LB_SETCURSEL,
  2436.                                     (WPARAM)(pOFI->idirSub - 1),
  2437.                                     0L );
  2438.             }
  2439.             bChangeDir = FALSE;
  2440.         }
  2441.     }
  2442.     return (CallWindowProc(lpOKProc, hOK, msg, wParam, lParam));
  2443. }
  2444. ////////////////////////////////////////////////////////////////////////////
  2445. //
  2446. //  dwLBSubclass
  2447. //
  2448. //  Simulates a double click if the user presses OK with the mouse.
  2449. //
  2450. //  The problem is that the UITF demands that when the directory
  2451. //  listbox loses the focus, the selected directory should return
  2452. //  to the current directory.  But when the user changes the item
  2453. //  selected with a single click, and then clicks the OK button to
  2454. //  have the change take effect, the focus is lost before the OK button
  2455. //  knows it was pressed.  By simulating a double click, the change
  2456. //  takes place.
  2457. //
  2458. //  Returns:  Return value from default listbox proceedure.
  2459. //
  2460. ////////////////////////////////////////////////////////////////////////////
  2461. LRESULT WINAPI dwLBSubclass(
  2462.     HWND hLB,
  2463.     UINT msg,
  2464.     WPARAM wParam,
  2465.     LPARAM lParam)
  2466. {
  2467.     HANDLE hDlg;
  2468.     POPENFILEINFO pOFI;
  2469.     if (msg == WM_KILLFOCUS)
  2470.     {
  2471.         hDlg = GetParent(hLB);
  2472.         bChangeDir = (GetDlgItem(hDlg, IDOK) == (HWND)wParam) ? TRUE : FALSE;
  2473.         if (!bChangeDir)
  2474.         {
  2475.             if (pOFI = (POPENFILEINFO)GetProp(hDlg, FILEPROP))
  2476.             {
  2477.                 SendMessage( hLB,
  2478.                              LB_SETCURSEL,
  2479.                              (WPARAM)(pOFI->idirSub - 1),
  2480.                              0L );
  2481.             }
  2482.         }
  2483.     }
  2484.     return (CallWindowProc(lpLBProc, hLB, msg, wParam, lParam));
  2485. }
  2486. ////////////////////////////////////////////////////////////////////////////
  2487. //
  2488. //  InvalidFileWarning
  2489. //
  2490. ////////////////////////////////////////////////////////////////////////////
  2491. int InvalidFileWarning(
  2492.     HWND hDlg,
  2493.     LPTSTR szFile,
  2494.     DWORD wErrCode,
  2495.     UINT mbType)
  2496. {
  2497.     SHORT isz;
  2498.     BOOL bDriveLetter = FALSE;
  2499.     int nRet = 0;
  2500.     if (lstrlen(szFile) > TOOLONGLIMIT)
  2501.     {
  2502.         *(szFile + TOOLONGLIMIT) = CHAR_NULL;
  2503.     }
  2504.     switch (wErrCode)
  2505.     {
  2506.         case ( ERROR_NO_DISK_IN_DRIVE ) :
  2507.         {
  2508.             isz = iszNoDiskInDrive;
  2509.             bDriveLetter = TRUE;
  2510.             break;
  2511.         }
  2512.         case ( ERROR_NO_DISK_IN_CDROM ) :
  2513.         {
  2514.             isz = iszNoDiskInCDRom;
  2515.             bDriveLetter = TRUE;
  2516.             break;
  2517.         }
  2518.         case ( ERROR_NO_DRIVE ) :
  2519.         {
  2520.             isz = iszDriveDoesNotExist;
  2521.             bDriveLetter = TRUE;
  2522.             break;
  2523.         }
  2524.         case ( ERROR_TOO_MANY_OPEN_FILES ) :
  2525.         {
  2526.             isz = iszNoFileHandles;
  2527.             break;
  2528.         }
  2529.         case ( ERROR_PATH_NOT_FOUND ) :
  2530.         {
  2531.             isz = iszPathNotFound;
  2532.             break;
  2533.         }
  2534.         case ( ERROR_FILE_NOT_FOUND ) :
  2535.         {
  2536.             isz = iszFileNotFound;
  2537.             break;
  2538.         }
  2539.         case ( ERROR_CANNOT_MAKE ) :
  2540.         case ( ERROR_DISK_FULL ) :
  2541.         {
  2542.             isz = iszDiskFull;
  2543.             bDriveLetter = TRUE;
  2544.             break;
  2545.         }
  2546.         case ( ERROR_WRITE_PROTECT ) :
  2547.         {
  2548.             isz = iszWriteProtection;
  2549.             bDriveLetter = TRUE;
  2550.             break;
  2551.         }
  2552.         case ( ERROR_SHARING_VIOLATION ) :
  2553.         {
  2554.             isz = iszSharingViolation;
  2555.             break;
  2556.         }
  2557.         case ( ERROR_CREATE_NO_MODIFY ) :
  2558.         {
  2559.             isz = iszCreateNoModify;
  2560.             break;
  2561.         }
  2562.         case ( ERROR_NETWORK_ACCESS_DENIED ) :
  2563.         {
  2564.             isz = iszNetworkAccessDenied;
  2565.             break;
  2566.         }
  2567.         case ( ERROR_PORTNAME ) :
  2568.         {
  2569.             isz = iszPortName;
  2570.             break;
  2571.         }
  2572.         case ( ERROR_LAZY_READONLY ) :
  2573.         {
  2574.             isz = iszReadOnly;
  2575.             break;
  2576.         }
  2577.         case ( ERROR_DIR_ACCESS_DENIED ) :
  2578.         {
  2579.             isz = iszDirAccessDenied;
  2580.             break;
  2581.         }
  2582.         case ( ERROR_FILE_ACCESS_DENIED ) :
  2583.         case ( ERROR_ACCESS_DENIED ) :
  2584.         {
  2585.             isz = iszFileAccessDenied;
  2586.             break;
  2587.         }
  2588.         case ( ERROR_UNRECOGNIZED_VOLUME ) :
  2589.         {
  2590.             FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM |
  2591.                                FORMAT_MESSAGE_IGNORE_INSERTS |
  2592.                                FORMAT_MESSAGE_MAX_WIDTH_MASK,
  2593.                            NULL,
  2594.                            wErrCode,
  2595.                            GetUserDefaultLCID(),
  2596.                            szWarning,
  2597.                            WARNINGMSGLENGTH,
  2598.                            NULL );
  2599.             goto DisplayError;
  2600.         }
  2601.         default :
  2602.         {
  2603.             isz = iszInvalidFileName;
  2604.             break;
  2605.         }
  2606.     }
  2607.     if (!CDLoadString( g_hinst,
  2608.                      isz,
  2609.                      szCaption,
  2610.                      WARNINGMSGLENGTH ))
  2611.     {
  2612.         wsprintf( szWarning,
  2613.                   TEXT("Error occurred, but error resource cannot be loaded.") );
  2614.     }
  2615.     else
  2616.     {
  2617.         wsprintf( szWarning,
  2618.                   szCaption,
  2619.                   bDriveLetter ? (LPTSTR)(CHAR)*szFile : szFile );
  2620. DisplayError:
  2621.         GetWindowText(hDlg, szCaption, WARNINGMSGLENGTH);
  2622.         if (!mbType)
  2623.         {
  2624.             mbType = MB_OK | MB_ICONEXCLAMATION;
  2625.         }
  2626.         nRet = MessageBox(hDlg, szWarning, szCaption, mbType);
  2627.     }
  2628.     if (isz == iszInvalidFileName)
  2629.     {
  2630.         PostMessage( hDlg,
  2631.                      WM_NEXTDLGCTL,
  2632.                      (WPARAM)GetDlgItem(hDlg, edt1),
  2633.                      (LPARAM)1L );
  2634.     }
  2635.     return (nRet);
  2636. }
  2637. ////////////////////////////////////////////////////////////////////////////
  2638. //
  2639. //  MeasureItem
  2640. //
  2641. ////////////////////////////////////////////////////////////////////////////
  2642. VOID MeasureItem(
  2643.     HWND hDlg,
  2644.     LPMEASUREITEMSTRUCT mis)
  2645. {
  2646.     if (!dyItem)
  2647.     {
  2648.         HDC hDC = GetDC(hDlg);
  2649.         TEXTMETRIC TM;
  2650.         HANDLE hFont;
  2651.         hFont = (HANDLE)SendMessage(hDlg, WM_GETFONT, 0, 0L);
  2652.         if (!hFont)
  2653.         {
  2654.             hFont = GetStockObject(SYSTEM_FONT);
  2655.         }
  2656.         hFont = SelectObject(hDC, hFont);
  2657.         GetTextMetrics(hDC, &TM);
  2658.         SelectObject(hDC, hFont);
  2659.         ReleaseDC(hDlg, hDC);
  2660.         dyText = TM.tmHeight;
  2661.         dyItem = max(dyDirDrive, dyText);
  2662.     }
  2663.     if (mis->CtlID == lst1)
  2664.     {
  2665.         mis->itemHeight = dyText;
  2666.     }
  2667.     else
  2668.     {
  2669.         mis->itemHeight = dyItem;
  2670.     }
  2671. }
  2672. ////////////////////////////////////////////////////////////////////////////
  2673. //
  2674. //  Signum
  2675. //
  2676. //  Returns the sign of an integer:
  2677. //           -1 if integer < 0
  2678. //            0 if integer = 0
  2679. //            1 if integer > 0
  2680. //
  2681. //  Note:  Signum *could* be defined as an inline macro, but that causes
  2682. //         the C compiler to disable Loop optimization, Global register
  2683. //         optimization, and Global optimizations for common subexpressions
  2684. //         in any function that the macro would appear.  The cost of a call
  2685. //         to the function seemed worth the optimizations.
  2686. //
  2687. ////////////////////////////////////////////////////////////////////////////
  2688. int Signum(
  2689.     int nTest)
  2690. {
  2691.     return ((nTest == 0) ? 0 : (nTest > 0) ? 1 : -1);
  2692. }
  2693. ////////////////////////////////////////////////////////////////////////////
  2694. //
  2695. //  DrawItem
  2696. //
  2697. //  Draws the drive/directory pictures in the respective combo list boxes.
  2698. //
  2699. //  lst1 is listbox for files
  2700. //  lst2 is listbox for directories
  2701. //  cmb1 is combobox for filters
  2702. //  cmb2 is combobox for drives
  2703. //
  2704. ////////////////////////////////////////////////////////////////////////////
  2705. VOID DrawItem(
  2706.     POPENFILEINFO pOFI,
  2707.     HWND hDlg,
  2708.     WPARAM wParam,
  2709.     LPDRAWITEMSTRUCT lpdis,
  2710.     BOOL bSave)
  2711. {
  2712.     HDC hdcList;
  2713.     RECT rc;
  2714. //  RECT rcCmb2;
  2715.     TCHAR szText[MAX_FULLPATHNAME + 1];
  2716.     int dxAcross;
  2717.     LONG nHeight;
  2718.     LONG rgbBack, rgbText, rgbOldBack, rgbOldText;
  2719.     SHORT nShift = 1;             // to shift directories right in lst2
  2720.     BOOL bSel;
  2721.     int BltItem;
  2722.     int nBackMode;
  2723.     if ((int)lpdis->itemID < 0)
  2724.     {
  2725.         DefWindowProc(hDlg, WM_DRAWITEM, wParam, (LPARAM)lpdis);
  2726.         return;
  2727.     }
  2728.     *szText = CHAR_NULL;
  2729.     if (lpdis->CtlID != lst1 && lpdis->CtlID != lst2 && lpdis->CtlID != cmb2)
  2730.     {
  2731.         return;
  2732.     }
  2733.     if (!pOFI)
  2734.     {
  2735.         return;
  2736.     }
  2737.     hdcList = lpdis->hDC;
  2738.     if (lpdis->CtlID != cmb2)
  2739.     {
  2740.         SendDlgItemMessage( hDlg,
  2741.                             (int)lpdis->CtlID,
  2742.                             LB_GETTEXT ,
  2743.                             (WPARAM)lpdis->itemID,
  2744.                             (LONG_PTR)szText );
  2745.         if (*szText == 0)
  2746.         {
  2747.             //
  2748.             //  If empty listing.
  2749.             //
  2750.             DefWindowProc(hDlg, WM_DRAWITEM, wParam, (LONG_PTR)lpdis);
  2751.             return;
  2752.         }
  2753.         if (!bCasePreserved)
  2754.         {
  2755.             CharLower(szText);
  2756.         }
  2757.     }
  2758.     nHeight = (lpdis->CtlID == lst1) ? dyText : dyItem;
  2759.     CopyRect((LPRECT)&rc, (LPRECT)&lpdis->rcItem);
  2760.     rc.bottom = rc.top + nHeight;
  2761.     if (bSave && (lpdis->CtlID == lst1))
  2762.     {
  2763.         rgbBack = rgbWindowColor;
  2764.         rgbText = rgbGrayText;
  2765.     }
  2766.     else
  2767.     {
  2768.         //
  2769.         //  Careful checking of bSel is needed here.  Since the file
  2770.         //  listbox (lst1) can allow multiselect, only ODS_SELECTED needs
  2771.         //  to be set.  But for the directory listbox (lst2), ODS_FOCUS
  2772.         //  also needs to be set.
  2773.         //
  2774.         bSel = (lpdis->itemState & (ODS_SELECTED | ODS_FOCUS));
  2775.         if ((bSel & ODS_SELECTED) &&
  2776.             ((lpdis->CtlID != lst2) || (bSel & ODS_FOCUS)))
  2777.         {
  2778.             rgbBack = rgbHiliteColor;
  2779.             rgbText = rgbHiliteText;
  2780.         }
  2781.         else
  2782.         {
  2783.             rgbBack = rgbWindowColor;
  2784.             rgbText = rgbWindowText;
  2785.         }
  2786.     }
  2787.     rgbOldBack = SetBkColor(hdcList, rgbBack);
  2788.     rgbOldText = SetTextColor(hdcList, rgbText);
  2789.     //
  2790.     //  Drives -- text is now in UI style, c: VolumeName/Server-Sharename.
  2791.     //
  2792.     if (lpdis->CtlID == cmb2)
  2793.     {
  2794.         HANDLE hCmb2 = GetDlgItem(hDlg, cmb2);
  2795.         dxAcross = dxDirDrive / BMPHIOFFSET;
  2796.         BltItem = (int) SendMessage(hCmb2, CB_GETITEMDATA, lpdis->itemID, 0);
  2797.         SendMessage(hCmb2, CB_GETLBTEXT, lpdis->itemID, (LPARAM)szText);
  2798.         if (bSel & ODS_SELECTED)
  2799.         {
  2800.             BltItem += BMPHIOFFSET;
  2801.         }
  2802.     }
  2803.     else if (lpdis->CtlID == lst2)
  2804.     {
  2805.         //
  2806.         //  Directories.
  2807.         //
  2808.         dxAcross = dxDirDrive / BMPHIOFFSET;
  2809.         if (lpdis->itemID > pOFI->idirSub)
  2810.         {
  2811.             nShift = (SHORT)pOFI->idirSub;
  2812.         }
  2813.         else
  2814.         {
  2815.             nShift = (SHORT)lpdis->itemID;
  2816.         }
  2817.         //
  2818.         //  Must be at least 1.
  2819.         //
  2820.         nShift++;
  2821.         BltItem = 1 + Signum(lpdis->itemID + 1 - pOFI->idirSub);
  2822.         if (bSel & ODS_FOCUS)
  2823.         {
  2824.             BltItem += BMPHIOFFSET;
  2825.         }
  2826.     }
  2827.     else if (lpdis->CtlID == lst1)
  2828.     {
  2829.         //
  2830.         //  Prep for TextOut below.
  2831.         //
  2832.         dxAcross = -dxSpace;
  2833.     }
  2834.     if (bSave && (lpdis->CtlID == lst1) && !rgbText)
  2835.     {
  2836.         HBRUSH hBrush = CreateSolidBrush(rgbBack);
  2837.         HBRUSH hOldBrush;
  2838.         nBackMode = SetBkMode(hdcList, TRANSPARENT);
  2839.         hOldBrush = SelectObject( lpdis->hDC,
  2840.                                   hBrush
  2841.                                       ? hBrush
  2842.                                       : GetStockObject(WHITE_BRUSH) );
  2843.         FillRect(lpdis->hDC, (LPRECT)(&(lpdis->rcItem)), hBrush);
  2844.         SelectObject(lpdis->hDC, hOldBrush);
  2845.         if (hBrush)
  2846.         {
  2847.             DeleteObject(hBrush);
  2848.         }
  2849.         GrayString( lpdis->hDC,
  2850.                     GetStockObject(BLACK_BRUSH),
  2851.                     NULL,
  2852.                     (LPARAM)szText,
  2853.                     0,
  2854.                     lpdis->rcItem.left + dxSpace,
  2855.                     lpdis->rcItem.top,
  2856.                     0,
  2857.                     0 );
  2858.         SetBkMode(hdcList, nBackMode);
  2859.     }
  2860. #if 0
  2861.     else if (lpdis->CtlID == cmb2)
  2862.     {
  2863.         rcCmb2.right = rc.right;
  2864.         rcCmb2.left = rc.left + (WORD)(dxSpace + dxAcross) + (dxSpace * nShift);
  2865.         rcCmb2.top = rc.top + (dyItem - dyText) / 2;
  2866.         rcCmb2.bottom = rc.top + nHeight;
  2867.         DrawText( hdcList,
  2868.                   szText,
  2869.                   -1,
  2870.                   &rcCmb2,
  2871.                   DT_LEFT | DT_EXPANDTABS | DT_NOPREFIX );
  2872.     }
  2873. #endif
  2874.     else
  2875.     {
  2876.         //
  2877.         //  Draw the name.
  2878.         //
  2879.         ExtTextOut( hdcList,
  2880.                     rc.left + (WORD)(dxSpace + dxAcross) + dxSpace * nShift,
  2881.                     rc.top + (nHeight - dyText) / 2,
  2882.                     ETO_OPAQUE | ETO_CLIPPED,
  2883.                     (LPRECT)&rc,
  2884.                     szText,
  2885.                     lstrlen(szText),
  2886.                     NULL );
  2887.     }
  2888.     //
  2889.     //  Draw the picture.
  2890.     //
  2891.     if (lpdis->CtlID != lst1)
  2892.     {
  2893.         BitBlt( hdcList,
  2894.                 rc.left + dxSpace * nShift,
  2895.                 rc.top + (dyItem - dyDirDrive) / 2,
  2896.                 dxAcross,
  2897.                 dyDirDrive,
  2898.                 hdcMemory,
  2899.                 BltItem * dxAcross,
  2900.                 0,
  2901.                 SRCCOPY );
  2902.     }
  2903.     SetTextColor(hdcList, rgbOldText);
  2904.     SetBkColor(hdcList, rgbBack);
  2905.     if (lpdis->itemState & ODS_FOCUS)
  2906.     {
  2907.         DrawFocusRect(hdcList, (LPRECT)&lpdis->rcItem);
  2908.     }
  2909. }
  2910. ////////////////////////////////////////////////////////////////////////////
  2911. //
  2912. //  SpacesExist
  2913. //
  2914. ////////////////////////////////////////////////////////////////////////////
  2915. BOOL SpacesExist(
  2916.     LPTSTR szFileName)
  2917. {
  2918.     while (*szFileName)
  2919.     {
  2920.         if (*szFileName == CHAR_SPACE)
  2921.         {
  2922.             return (TRUE);
  2923.         }
  2924.         else
  2925.         {
  2926.             szFileName++;
  2927.         }
  2928.     }
  2929.     return (FALSE);
  2930. }
  2931. ////////////////////////////////////////////////////////////////////////////
  2932. //
  2933. //  StripFileName
  2934. //
  2935. //  Removes all but the filename from editbox contents.
  2936. //  This is to be called before the user makes directory or drive
  2937. //  changes by selecting them instead of typing them.
  2938. //
  2939. ////////////////////////////////////////////////////////////////////////////
  2940. void StripFileName(
  2941.     HANDLE hDlg,
  2942.     BOOL bWowApp)
  2943. {
  2944.     TCHAR szText[MAX_FULLPATHNAME];
  2945.     SHORT nFileOffset, cb;
  2946.     if (GetDlgItemText(hDlg, edt1, szText, MAX_FULLPATHNAME - 1))
  2947.     {
  2948.         DWORD lRet;
  2949.         lRet = ParseFile(szText, IsLFNDriveX(hDlg, szText), bWowApp, FALSE);
  2950.         nFileOffset = LOWORD(lRet);
  2951.         cb = HIWORD(lRet);
  2952.         if (nFileOffset < 0)
  2953.         {
  2954.             //
  2955.             //  If there was a parsing error, check for CHAR_SEMICOLON
  2956.             //  delimeter.
  2957.             //
  2958.             if (szText[cb] == CHAR_SEMICOLON)
  2959.             {
  2960.                 szText[cb] = CHAR_NULL;
  2961.                 nFileOffset = (WORD)ParseFile( szText,
  2962.                                                IsLFNDriveX(hDlg, szText),
  2963.                                                bWowApp,
  2964.                                                FALSE );
  2965.                 szText[cb] = CHAR_SEMICOLON;
  2966.                 if (nFileOffset < 0)
  2967.                 {
  2968.                     //
  2969.                     //  Still trouble, so Exit.
  2970.                     //
  2971.                     szText[0] = CHAR_NULL;
  2972.                 }
  2973.             }
  2974.             else
  2975.             {
  2976.                 szText[0] = CHAR_NULL;
  2977.             }
  2978.         }
  2979.         if (nFileOffset > 0)
  2980.         {
  2981.             lstrcpy(szText, (LPTSTR)(szText + nFileOffset));
  2982.         }
  2983.         if (nFileOffset)
  2984.         {
  2985.             SetDlgItemText(hDlg, edt1, szText);
  2986.         }
  2987.     }
  2988. }
  2989. ////////////////////////////////////////////////////////////////////////////
  2990. //
  2991. //  lstrtok
  2992. //
  2993. ////////////////////////////////////////////////////////////////////////////
  2994. LPTSTR lstrtok(
  2995.     LPTSTR lpStr,
  2996.     LPCTSTR lpDelim)
  2997. {
  2998.     static LPTSTR lpString;
  2999.     LPTSTR lpRetVal, lpTemp;
  3000.     //
  3001.     //  If we are passed new string skip leading delimiters.
  3002.     //
  3003.     if (lpStr)
  3004.     {
  3005.         lpString = lpStr;
  3006.         while (*lpString && StrChr(lpDelim, *lpString))
  3007.         {
  3008.             lpString = CharNext(lpString);
  3009.         }
  3010.     }
  3011.     //
  3012.     //  If there are no more tokens, return NULL.
  3013.     //
  3014.     if (!*lpString)
  3015.     {
  3016.         return (CHAR_NULL);
  3017.     }
  3018.     //
  3019.     //  Save head of token.
  3020.     //
  3021.     lpRetVal = lpString;
  3022.     //
  3023.     //  Find delimiter or end of string.
  3024.     //
  3025.     while (*lpString && !StrChr(lpDelim, *lpString))
  3026.     {
  3027.         lpString = CharNext(lpString);
  3028.     }
  3029.     //
  3030.     //  If we found a delimiter insert string terminator and skip.
  3031.     //
  3032.     if (*lpString)
  3033.     {
  3034.         lpTemp = CharNext(lpString);
  3035.         *lpString = CHAR_NULL;
  3036.         lpString = lpTemp;
  3037.     }
  3038.     //
  3039.     //  Return token.
  3040.     //
  3041.     return (lpRetVal);
  3042. }
  3043. ////////////////////////////////////////////////////////////////////////////
  3044. //
  3045. //  ChopText
  3046. //
  3047. ////////////////////////////////////////////////////////////////////////////
  3048. LPTSTR ChopText(
  3049.     HWND hwndDlg,
  3050.     int idStatic,
  3051.     LPTSTR lpch)
  3052. {
  3053.     RECT rc;
  3054.     register int cxField;
  3055.     BOOL fChop = FALSE;
  3056.     HWND hwndStatic;
  3057.     HDC hdc;
  3058.     TCHAR chDrv;
  3059.     HANDLE hOldFont;
  3060.     LPTSTR lpstrStart = lpch;
  3061.     SIZE Size;
  3062.     BOOL bRet;
  3063.     //
  3064.     //  Get length of static field.
  3065.     //
  3066.     hwndStatic = GetDlgItem(hwndDlg, idStatic);
  3067.     GetClientRect(hwndStatic, (LPRECT)&rc);
  3068.     cxField = rc.right - rc.left;
  3069.     //
  3070.     //  Chop characters off front end of text until short enough.
  3071.     //
  3072.     hdc = GetDC(hwndStatic);
  3073.     hOldFont = NULL;
  3074.     while ((bRet = GetTextExtentPoint(hdc, lpch, lstrlen(lpch), &Size)) &&
  3075.            (cxField < Size.cx))
  3076.     {
  3077.         if (!fChop)
  3078.         {
  3079.             chDrv = *lpch;
  3080.             //
  3081.             //  Proportional font support.
  3082.             //
  3083.             if (bRet = GetTextExtentPoint(hdc, lpch, 7, &Size))
  3084.             {
  3085.                 cxField -= Size.cx;
  3086.             }
  3087.             else
  3088.             {
  3089.                 break;
  3090.             }
  3091.             if (cxField <= 0)
  3092.             {
  3093.                break;
  3094.             }
  3095.             lpch += 7;
  3096.         }
  3097.         while (*lpch && (!ISBACKSLASH_P(lpstrStart, lpch)))
  3098.         {
  3099.             lpch++;
  3100.         }
  3101.         //Skip the backslash 
  3102.         lpch++;
  3103.         fChop = TRUE;
  3104.     }
  3105.     ReleaseDC(hwndStatic, hdc);
  3106.     //
  3107.     //  If any characters chopped off, replace first three characters in
  3108.     //  remaining text string with ellipsis.
  3109.     //
  3110.     if (fChop)
  3111.     {
  3112.         //Skip back to include the backslash
  3113.         lpch--;
  3114.         *--lpch = CHAR_DOT;
  3115.         *--lpch = CHAR_DOT;
  3116.         *--lpch = CHAR_DOT;
  3117.         *--lpch = *(lpstrStart + 2);
  3118.         *--lpch = *(lpstrStart + 1);
  3119.         *--lpch = *lpstrStart;
  3120.     }
  3121.     return (lpch);
  3122. }
  3123. ////////////////////////////////////////////////////////////////////////////
  3124. //
  3125. //  FillOutPath
  3126. //
  3127. //  Fills out lst2 given that the current directory has been set.
  3128. //
  3129. //  Returns:  TRUE    if they DO NOT match
  3130. //            FALSE   if match
  3131. //
  3132. ////////////////////////////////////////////////////////////////////////////
  3133. BOOL FillOutPath(
  3134.     HWND hList,
  3135.     POPENFILEINFO pOFI)
  3136. {
  3137.     TCHAR szPath[CCHNETPATH];
  3138.     LPTSTR lpCurDir;
  3139.     LPTSTR lpB, lpF;
  3140.     TCHAR wc;
  3141.     int cchPathOffset;
  3142.     LPCURDLG lpCurDlg;
  3143.     if(!(lpCurDlg = (LPCURDLG)TlsGetValue(g_tlsiCurDlg)) ||
  3144.        !(lpCurDir = lpCurDlg->lpstrCurDir))
  3145.     {
  3146.         return (FALSE);
  3147.     }
  3148.     lpF = szPath;    
  3149.     lstrcpy(lpF, lpCurDir);
  3150.     //
  3151.     //  Wow apps started from lfn dirs will set the current directory to an
  3152.     //  lfn, but only in the case where it is less than 8 chars.
  3153.     //
  3154.     if (pOFI->pOFN->Flags & OFN_NOLONGNAMES)
  3155.     {
  3156.         ShortenThePath(lpF);
  3157.     }
  3158.     *lpF = (TCHAR)CharLower((LPTSTR)*lpF);
  3159.     cchPathOffset = GetPathOffset(lpF);
  3160.     if (cchPathOffset == -1)
  3161.     {
  3162.         cchPathOffset = 0;
  3163.     }
  3164.     lpB = (lpF + cchPathOffset);
  3165.     //
  3166.     //  Hack to retain Winball display functionality.
  3167.     //  Drived disks are displayed as C: (the root dir).
  3168.     //  whereas unc disks are displayed as \servershare (the disk).
  3169.     //  Hence, extend display of drived disks by one char.
  3170.     //
  3171.     if (*(lpF + 1) == CHAR_COLON)
  3172.     {
  3173.         wc = *(++lpB);
  3174.         *lpB = CHAR_NULL;
  3175.     }
  3176.     else