Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1204 lines
38 KiB

  1. #include "ctlspriv.h"
  2. #pragma hdrstop
  3. #include "usrctl32.h"
  4. #include "listbox.h"
  5. //---------------------------------------------------------------------------//
  6. //
  7. // Directory ListBox Routines
  8. //
  9. //---------------------------------------------------------------------------//
  10. //
  11. // ListBox_CreateLine
  12. //
  13. // This creates a character string that contains all the required
  14. // details of a file;( Name)
  15. //
  16. VOID ListBox_CreateLine(PWIN32_FIND_DATA pffd, LPWSTR pszBuffer, DWORD cchBuffer)
  17. {
  18. BOOL fDirectory = TESTFLAG(pffd->dwFileAttributes, DDL_DIRECTORY);
  19. StringCchPrintf(pszBuffer,
  20. cchBuffer,
  21. TEXT("%s%s%s"),
  22. fDirectory ? TEXT("[") : TEXT(""),
  23. pffd->cFileName,
  24. fDirectory ? TEXT("]") : TEXT(""));
  25. }
  26. //---------------------------------------------------------------------------//
  27. //
  28. // ListBox_DirHandler
  29. //
  30. // Note that these FILE_ATTRIBUTE_* values map directly with
  31. // their DDL_* counterparts, with the exception of FILE_ATTRIBUTE_NORMAL.
  32. //
  33. #define FIND_ATTR ( \
  34. FILE_ATTRIBUTE_NORMAL | \
  35. FILE_ATTRIBUTE_DIRECTORY | \
  36. FILE_ATTRIBUTE_HIDDEN | \
  37. FILE_ATTRIBUTE_SYSTEM | \
  38. FILE_ATTRIBUTE_ARCHIVE | \
  39. FILE_ATTRIBUTE_READONLY )
  40. #define EXCLUDE_ATTR ( \
  41. FILE_ATTRIBUTE_DIRECTORY | \
  42. FILE_ATTRIBUTE_HIDDEN | \
  43. FILE_ATTRIBUTE_SYSTEM )
  44. INT ListBox_DirHandler(PLBIV plb, UINT attrib, LPWSTR pszFileSpec)
  45. {
  46. INT result;
  47. BOOL fWasVisible, bRet;
  48. WCHAR szBuffer[MAX_PATH + 1];
  49. WCHAR szBuffer2[MAX_PATH + 1];
  50. HANDLE hFind;
  51. WIN32_FIND_DATA ffd;
  52. UINT attribFile;
  53. DWORD mDrives;
  54. INT cDrive;
  55. UINT attribInclMask, attribExclMask;
  56. //
  57. // Make sure the buffer is valid and copy it onto the stack. Why? Because
  58. // there is a chance that pszFileSpec is pointing to an invalid string
  59. // because some app posted a CB_DIR or LB_DIR without the DDL_POSTMSGS
  60. // bit set.
  61. //
  62. try
  63. {
  64. StringCchCopy(szBuffer2, ARRAYSIZE(szBuffer2), pszFileSpec);
  65. pszFileSpec = szBuffer2;
  66. }
  67. except (UnhandledExceptionFilter( GetExceptionInformation() ))
  68. {
  69. return -1;
  70. }
  71. __endexcept
  72. result = -1;
  73. fWasVisible = IsLBoxVisible(plb);
  74. if (fWasVisible)
  75. {
  76. SendMessage(plb->hwnd, WM_SETREDRAW, FALSE, 0);
  77. }
  78. //
  79. // First we add the files then the directories and drives.
  80. // If they only wanted drives then skip the file query
  81. // Also under Windows specifing only 0x8000 (DDL_EXCLUSIVE) adds no files).
  82. //
  83. // if ((attrib != (DDL_EXCLUSIVE | DDL_DRIVES)) && (attrib != DDL_EXCLUSIVE) &&
  84. if (attrib != (DDL_EXCLUSIVE | DDL_DRIVES | DDL_NOFILES))
  85. {
  86. hFind = FindFirstFile(pszFileSpec, &ffd);
  87. if (hFind != INVALID_HANDLE_VALUE)
  88. {
  89. //
  90. // If this is not an exclusive search, include normal files.
  91. //
  92. attribInclMask = attrib & FIND_ATTR;
  93. if (!(attrib & DDL_EXCLUSIVE))
  94. {
  95. attribInclMask |= FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_READONLY |
  96. FILE_ATTRIBUTE_ARCHIVE;
  97. }
  98. //
  99. // Make a mask of the attributes to be excluded from
  100. // the search.
  101. //
  102. attribExclMask = ~attrib & EXCLUDE_ATTR;
  103. //
  104. // LATER BUG - scottlu
  105. // Win3 assumes doing a LoadCursor here will return the same wait cursor that
  106. // has already been created, whereas calling ServerLoadCursor creates a new
  107. // one every time!
  108. // hCursorT = NtUserSetCursor(ServerLoadCursor(NULL, IDC_WAIT));
  109. // FindFirst/Next works different in NT then DOS. Under DOS you passed in
  110. // a set of attributes under NT you get back a set of attributes and have
  111. // to test for those attributes (Dos input attributes were Hidden, System
  112. // and Directoy) the dos find first always returned ReadOnly and archive files
  113. // we are going to select a file in one of two cases.
  114. // 1) if any of the attrib bits are set on the file.
  115. // 2) if we want normal files and the file is a notmal file (the file attrib
  116. // bits don't contain any NOEXCLBITS
  117. //
  118. do
  119. {
  120. attribFile = (UINT)ffd.dwFileAttributes;
  121. if (attribFile == FILE_ATTRIBUTE_COMPRESSED)
  122. {
  123. attribFile = FILE_ATTRIBUTE_NORMAL;
  124. }
  125. attribFile &= ~FILE_ATTRIBUTE_COMPRESSED;
  126. //
  127. // Accept those files that have only the
  128. // attributes that we are looking for.
  129. //
  130. if ((attribFile & attribInclMask) != 0 &&
  131. (attribFile & attribExclMask) == 0)
  132. {
  133. BOOL fCreate = TRUE;
  134. if (attribFile & DDL_DIRECTORY)
  135. {
  136. //
  137. // Don't include '.' (current directory) in list.
  138. //
  139. if (*((LPDWORD)&ffd.cFileName[0]) == 0x0000002E)
  140. {
  141. fCreate = FALSE;
  142. }
  143. //
  144. // If we're not looking for dirs, ignore it
  145. //
  146. if (!(attrib & DDL_DIRECTORY))
  147. {
  148. fCreate = FALSE;
  149. }
  150. }
  151. else if (attrib & DDL_NOFILES)
  152. {
  153. //
  154. // Don't include files if DDL_NOFILES is set.
  155. //
  156. fCreate = FALSE;
  157. }
  158. if (fCreate)
  159. {
  160. ListBox_CreateLine(&ffd, szBuffer, ARRAYSIZE(szBuffer));
  161. result = ListBox_InsertItem(plb, szBuffer, 0, LBI_ADD);
  162. }
  163. }
  164. bRet = FindNextFile(hFind, &ffd);
  165. }
  166. while (result >= -1 && bRet);
  167. FindClose(hFind);
  168. // LATER see above comment
  169. // NtUserSetCursor(hCursorT);
  170. }
  171. }
  172. //
  173. // If drive bit set, include drives in the list.
  174. //
  175. if (result != LB_ERRSPACE && (attrib & DDL_DRIVES))
  176. {
  177. ffd.cFileName[0] = TEXT('[');
  178. ffd.cFileName[1] = ffd.cFileName[3] = TEXT('-');
  179. ffd.cFileName[4] = TEXT(']');
  180. ffd.cFileName[5] = 0;
  181. mDrives = GetLogicalDrives();
  182. for (cDrive = 0; mDrives; mDrives >>= 1, cDrive++)
  183. {
  184. if (mDrives & 1)
  185. {
  186. ffd.cFileName[2] = (WCHAR)(TEXT('A') + cDrive);
  187. //
  188. // We have to set the SPECIAL_THUNK bit because we are
  189. // adding a server side string to a list box that may not
  190. // be HASSTRINGS so we have to force the server-client
  191. // string thunk.
  192. //
  193. if ((result = ListBox_InsertItem(plb, CharLower(ffd.cFileName), -1,
  194. 0)) < 0)
  195. {
  196. break;
  197. }
  198. }
  199. }
  200. }
  201. if (result == LB_ERRSPACE)
  202. {
  203. ListBox_NotifyOwner(plb, LB_ERRSPACE);
  204. }
  205. if (fWasVisible)
  206. {
  207. SendMessage(plb->hwnd, WM_SETREDRAW, TRUE, 0);
  208. }
  209. ListBox_ShowHideScrollBars(plb);
  210. ListBox_CheckRedraw(plb, FALSE, 0);
  211. if (result != LB_ERRSPACE)
  212. {
  213. //
  214. // Return index of last item in the listbox. We can't just return
  215. // result because that is the index of the last item added which may
  216. // be in the middle somewhere if the LBS_SORT style is on.
  217. //
  218. return plb->cMac - 1;
  219. }
  220. else
  221. {
  222. return result;
  223. }
  224. }
  225. //---------------------------------------------------------------------------//
  226. //
  227. // ListBox_InsertFile
  228. //
  229. // Yet another CraigC shell hack... This responds to LB_ADDFILE messages
  230. // sent to directory windows in the file system as a response to the
  231. // WM_FILESYSCHANGE message. That way, we don't reread the whole
  232. // directory when we copy files.
  233. //
  234. INT ListBox_InsertFile(PLBIV plb, LPWSTR lpFile)
  235. {
  236. WCHAR szBuffer[MAX_PATH + 1];
  237. INT result = -1;
  238. HANDLE hFind;
  239. WIN32_FIND_DATA ffd;
  240. hFind = FindFirstFile(lpFile, &ffd);
  241. if (hFind != INVALID_HANDLE_VALUE)
  242. {
  243. FindClose(hFind);
  244. ListBox_CreateLine(&ffd, szBuffer, ARRAYSIZE(szBuffer));
  245. result = ListBox_InsertItem(plb, szBuffer, 0, LBI_ADD);
  246. }
  247. if (result == LB_ERRSPACE)
  248. {
  249. ListBox_NotifyOwner(plb, result);
  250. }
  251. ListBox_CheckRedraw(plb, FALSE, 0);
  252. return result;
  253. }
  254. //---------------------------------------------------------------------------//
  255. //
  256. // Public ListBox APIs support.
  257. //
  258. // Uncomment the following to include support for these
  259. //#define INCLUDE_LISTBOX_FUNCTIONS
  260. #ifdef INCLUDE_LISTBOX_FUNCTIONS
  261. //---------------------------------------------------------------------------//
  262. //
  263. // Defines and common macros
  264. //
  265. #define TABCHAR TEXT('\t')
  266. #define DDL_PRIVILEGES (DDL_READONLY | DDL_HIDDEN | DDL_SYSTEM | DDL_ARCHIVE)
  267. #define DDL_TYPE (DDL_DRIVES | DDL_DIRECTORY | DDL_POSTMSGS)
  268. #define CHARSTOBYTES(cch) ((cch) * sizeof(TCHAR))
  269. #define CCH_CHOPTEXT_EXTRA 7
  270. #define AWCHLEN(a) ((sizeof(a)/sizeof(a[0])) - 1)
  271. //---------------------------------------------------------------------------//
  272. //
  273. // Globals
  274. //
  275. WCHAR awchSlashStar[] = L"\\*";
  276. CHAR achSlashStar[] = "\\*";
  277. WCHAR szSLASHSTARDOTSTAR[] = TEXT("\\*"); /* This is a single "\" */
  278. //---------------------------------------------------------------------------//
  279. //
  280. // ChopText
  281. //
  282. // Chops the given path at 'lpchBuffer' + CCH_CHOPTEXT_EXTRA to fit in the
  283. // field of the static control with id 'idStatic' in the dialog box 'hwndDlg'.
  284. // If the path is too long, an ellipsis prefix is added to the beginning of the
  285. // chopped text ("x:\...\")
  286. //
  287. // If the supplied path does not fit and the last directory appended to
  288. // ellipsis (i.e. "c:\...\eee" in the case of "c:\aaa\bbb\ccc\ddd\eee")
  289. // does not fit, then "x:\..." is returned.
  290. //
  291. // Pathological case:
  292. // "c:\SW\MW\R2\LIB\SERVICES\NT" almost fits into static control, while
  293. // "c:\...\MW\R2\LIB\SERVICES\NT" does fit - although it is more characters.
  294. // In this case, ChopText substitutes the first 'n' characters of the path with
  295. // a prefix containing MORE than 'n' characters! The extra characters will
  296. // be put in front of lpch, so there must be space reserved for them or they
  297. // will trash the stack. lpch contains CCH_CHOPTEXT_EXTRA chars followed by
  298. // the path.
  299. //
  300. // In practice CCH_CHOPTEXT_EXTRA probably never has to be more than 1 or 2,
  301. // but in case the font is weird, set it to the number of chars in the prefix.
  302. // This guarantees enough space to prepend the prefix.
  303. //
  304. LPWSTR ChopText(HWND hwndDlg, INT idStatic, LPWSTR lpchBuffer)
  305. {
  306. HWND hwndStatic;
  307. LPWSTR lpszRet;
  308. lpszRet = NULL;
  309. //
  310. // Get length of static field.
  311. //
  312. hwndStatic = GetDlgItem(hwndDlg, idStatic);
  313. if (hwndStatic)
  314. {
  315. //
  316. // Declaring szPrefix this way ensures CCH_CHOPTEXT_EXTRA is big enough
  317. //
  318. WCHAR szPrefix[CCH_CHOPTEXT_EXTRA + 1] = L"x:\\...\\";
  319. INT cxField;
  320. RECT rc;
  321. SIZE size;
  322. PSTAT pstat;
  323. HDC hdc;
  324. HFONT hOldFont;
  325. INT cchPath;
  326. LPWSTR lpch;
  327. LPWSTR lpchPath;
  328. TCHAR szClassName[MAX_PATH];
  329. GetClientRect(hwndStatic, &rc);
  330. cxField = rc.right - rc.left;
  331. //
  332. // Set up DC appropriately for the static control.
  333. //
  334. hdc = GetDC(hwndStatic);
  335. //
  336. // Only assume this is a static window if this window uses the
  337. // static window wndproc.
  338. //
  339. hOldFont = NULL;
  340. if (GetClassName(hwndStatic, szClassName, ARRAYSIZE(szClassName) &&
  341. lstrcmpi(WC_STATIC, szClassName) == 0))
  342. {
  343. pstat = Static_GetPtr(hwndStatic);
  344. if (pstat != NULL && pstat != (PSTAT)-1 && pstat->hFont)
  345. {
  346. hOldFont = SelectObject(hdc, pstat->hFont);
  347. }
  348. }
  349. //
  350. // Check horizontal extent of string.
  351. //
  352. lpch = lpchPath = lpchBuffer + CCH_CHOPTEXT_EXTRA;
  353. cchPath = wcslen(lpchPath);
  354. GetTextExtentPoint(hdc, lpchPath, cchPath, &size);
  355. if (size.cx > cxField)
  356. {
  357. //
  358. // String is too long to fit in the static control; chop it.
  359. // Set up new prefix and determine remaining space in control.
  360. //
  361. szPrefix[0] = *lpchPath;
  362. GetTextExtentPoint(hdc, szPrefix, AWCHLEN(szPrefix), &size);
  363. //
  364. // If the field is too small to display all of the prefix,
  365. // copy only the prefix.
  366. //
  367. if (cxField < size.cx)
  368. {
  369. RtlCopyMemory(lpch, szPrefix, sizeof(szPrefix));
  370. }
  371. else
  372. {
  373. cxField -= size.cx;
  374. //
  375. // Advance a directory at a time until the remainder
  376. // of the string fits into the static control after
  377. // the "x:\...\" prefix.
  378. //
  379. while (TRUE)
  380. {
  381. INT cchT;
  382. while (*lpch && (*lpch++ != L'\\'));
  383. cchT = cchPath - (INT)(lpch - lpchPath);
  384. GetTextExtentPoint(hdc, lpch, cchT, &size);
  385. if (*lpch == 0 || size.cx <= cxField)
  386. {
  387. if (*lpch == 0)
  388. {
  389. //
  390. // Nothing could fit after the prefix; remove
  391. // the final "\" from the prefix
  392. //
  393. szPrefix[AWCHLEN(szPrefix) - 1] = 0;
  394. }
  395. //
  396. // rest of string fits -- back up and stick
  397. // prefix on front. We are guaranteed to have
  398. // at least CCH_CHOPTEXT_EXTRA chars backing up
  399. // space, so we won't trash any stack. #26453
  400. //
  401. lpch -= AWCHLEN(szPrefix);
  402. UserAssert(lpch >= lpchBuffer);
  403. RtlCopyMemory(lpch, szPrefix, sizeof(szPrefix) - sizeof(WCHAR));
  404. break;
  405. }
  406. }
  407. }
  408. }
  409. if (hOldFont)
  410. {
  411. SelectObject(hdc, hOldFont);
  412. }
  413. ReleaseDC(hwndStatic, hdc);
  414. lpszRet = lpch;
  415. }
  416. return lpszRet;
  417. }
  418. //---------------------------------------------------------------------------//
  419. //
  420. // DlgDirListHelper
  421. //
  422. // NOTE: If idStaticPath is < 0, then that parameter contains the details
  423. // about what should be in each line of the list box
  424. //
  425. DWORD FindCharPosition(LPWSTR lpString, WCHAR ch)
  426. {
  427. DWORD dwPos = 0L;
  428. while (*lpString && *lpString != ch)
  429. {
  430. ++lpString;
  431. ++dwPos;
  432. }
  433. return dwPos;
  434. }
  435. //---------------------------------------------------------------------------//
  436. BOOL DlgDirListHelper(
  437. HWND hwndDlg,
  438. LPWSTR lpszPathSpec,
  439. LPBYTE lpszPathSpecClient,
  440. INT idListBox,
  441. INT idStaticPath,
  442. UINT attrib,
  443. BOOL fListBox) // Listbox or ComboBox?
  444. {
  445. HWND hwndLB;
  446. BOOL fDir = TRUE;
  447. BOOL fRoot, bRet;
  448. BOOL fPostIt;
  449. INT cch;
  450. WCHAR ch;
  451. WCHAR szStaticPath[CCH_CHOPTEXT_EXTRA + MAX_PATH];
  452. LPWSTR pszCurrentDir;
  453. UINT wDirMsg;
  454. LPWSTR lpchFile;
  455. LPWSTR lpchDirectory;
  456. PLBIV plb;
  457. BOOL fWasVisible = FALSE;
  458. BOOL fWin40Compat;
  459. PCBOX pcbox;
  460. BOOL bResult;
  461. bResult = FALSE;
  462. //
  463. // Strip the private bit DDL_NOFILES out - KidPix passes it in my mistake!
  464. //
  465. if (attrib & ~DDL_VALID)
  466. {
  467. TraceMsg(TF_STANDARD, "Invalid flags, %x & ~%x != 0", attrib, DDL_VALID);
  468. bResult = FALSE;
  469. }
  470. else
  471. {
  472. if (attrib & DDL_NOFILES)
  473. {
  474. TraceMsg(TF_STANDARD, "DlgDirListHelper: stripping DDL_NOFILES");
  475. attrib &= ~DDL_NOFILES;
  476. }
  477. //
  478. // Case:Works is an app that calls DlgDirList with a NULL has hwndDlg;
  479. // This is allowed because he uses NULL for idStaticPath and idListBox.
  480. // So, the validation layer has been modified to allow a NULL for hwndDlg.
  481. // But, we catch the bad apps with the following check.
  482. // Fix for Bug #11864 --SANKAR-- 08/22/91 --
  483. //
  484. if (!hwndDlg && (idStaticPath || idListBox))
  485. {
  486. TraceMsg(TF_STANDARD, "Passed NULL hwnd but valide control id");
  487. bResult = FALSE;
  488. }
  489. else
  490. {
  491. plb = NULL;
  492. //
  493. // Do we need to add date, time, size or attribute info?
  494. // Windows checks the Atom but misses if the class has been sub-classed
  495. // as in VB.
  496. //
  497. hwndLB = GetDlgItem(hwndDlg, idListBox);
  498. if (hwndLB)
  499. {
  500. TCHAR szClassName[MAX_PATH];
  501. szClassName[0] = 0;
  502. GetClassName(hwndLB, szClassName, ARRAYSIZE(szClassName));
  503. if (((lstrcmpi(WC_LISTBOX, szClassName) == 0) && fListBox) ||
  504. ((lstrcmpi(WC_COMBOBOX, szClassName) == 0) && !fListBox))
  505. {
  506. if (fListBox)
  507. {
  508. plb = ListBox_GetPtr(hwndLB);
  509. }
  510. else
  511. {
  512. pcbox = ComboBox_GetPtr(hwndLB);
  513. plb = ListBox_GetPtr(pcbox->hwndList);
  514. }
  515. }
  516. else
  517. {
  518. TraceMsg(TF_STANDARD, "Listbox not found in hwnd = %#.4x", hwndDlg);
  519. }
  520. }
  521. else if (idListBox != 0)
  522. {
  523. //
  524. // Yell if the app passed an invalid list box id and keep from using a
  525. // bogus plb. PLB is NULLed above.
  526. //
  527. TraceMsg(TF_STANDARD, "Listbox control id = %d not found in hwnd = %#.4x",
  528. idListBox, hwndDlg);
  529. }
  530. if (idStaticPath < 0 && plb != NULL)
  531. {
  532. //
  533. // Clear idStaticPath because its purpose is over.
  534. //
  535. idStaticPath = 0;
  536. }
  537. fPostIt = (attrib & DDL_POSTMSGS);
  538. if (lpszPathSpec)
  539. {
  540. cch = lstrlenW(lpszPathSpec);
  541. if (!cch)
  542. {
  543. if (lpszPathSpecClient != (LPBYTE)lpszPathSpec)
  544. {
  545. lpszPathSpecClient = achSlashStar;
  546. }
  547. lpszPathSpec = awchSlashStar;
  548. }
  549. else
  550. {
  551. //
  552. // Make sure we won't overflow our buffers...
  553. //
  554. if (cch > MAX_PATH)
  555. {
  556. return FALSE;
  557. }
  558. //
  559. // Convert lpszPathSpec into an upper case, OEM string.
  560. //
  561. CharUpper(lpszPathSpec);
  562. lpchDirectory = lpszPathSpec;
  563. lpchFile = szSLASHSTARDOTSTAR + 1;
  564. if (*lpchDirectory)
  565. {
  566. cch = wcslen(lpchDirectory);
  567. //
  568. // If the directory name has a * or ? in it, don't bother trying
  569. // the (slow) SetCurrentDirectory.
  570. //
  571. if (((INT)FindCharPosition(lpchDirectory, TEXT('*')) != cch) ||
  572. ((INT)FindCharPosition(lpchDirectory, TEXT('?')) != cch) ||
  573. !SetCurrentDirectory(lpchDirectory))
  574. {
  575. //
  576. // Set 'fDir' and 'fRoot' accordingly.
  577. //
  578. lpchFile = lpchDirectory + cch;
  579. fDir = *(lpchFile - 1) == TEXT('\\');
  580. fRoot = 0;
  581. while (cch--)
  582. {
  583. ch = *(lpchFile - 1);
  584. if (ch == TEXT('*') || ch == TEXT('?'))
  585. {
  586. fDir = TRUE;
  587. }
  588. if (ch == TEXT('\\') || ch == TEXT('/') || ch == TEXT(':'))
  589. {
  590. fRoot = (cch == 0 || *(lpchFile - 2) == TEXT(':') ||
  591. (ch == TEXT(':')));
  592. break;
  593. }
  594. lpchFile--;
  595. }
  596. //
  597. // To remove Bug #16, the following error return is to be removed.
  598. // In order to prevent the existing apps from breaking up, it is
  599. // decided that the bug will not be fixed and will be mentioned
  600. // in the documentation.
  601. // --SANKAR-- Sep 21
  602. //
  603. //
  604. // If no wildcard characters, return error.
  605. //
  606. if (!fDir)
  607. {
  608. TraceMsg(TF_ERROR, "No Wildcard characters");
  609. return FALSE;
  610. }
  611. //
  612. // Special case for lpchDirectory == "\"
  613. //
  614. if (fRoot)
  615. {
  616. lpchFile++;
  617. }
  618. //
  619. // Do we need to change directories?
  620. //
  621. if (fRoot || cch >= 0)
  622. {
  623. //
  624. // Replace the Filename's first char with a nul.
  625. //
  626. ch = *--lpchFile;
  627. *lpchFile = TEXT('\0');
  628. //
  629. // Change the current directory.
  630. //
  631. if (*lpchDirectory)
  632. {
  633. bRet = SetCurrentDirectory(lpchDirectory);
  634. if (!bRet)
  635. {
  636. //
  637. // Restore the filename before we return...
  638. //
  639. *((LPWSTR)lpchFile)++ = ch;
  640. return FALSE;
  641. }
  642. }
  643. //
  644. // Restore the filename's first character.
  645. //
  646. *lpchFile++ = ch;
  647. }
  648. //
  649. // Undo damage caused by special case above.
  650. //
  651. if (fRoot)
  652. {
  653. lpchFile--;
  654. }
  655. }
  656. }
  657. //
  658. // This is copying on top of the data the client passed us! Since
  659. // the LB_DIR or CB_DIR could be posted, and since we need to
  660. // pass a client side string pointer when we do that, we need
  661. // to copy this new data back to the client!
  662. //
  663. if (fPostIt && lpszPathSpecClient != (LPBYTE)lpszPathSpec)
  664. {
  665. WCSToMB(lpchFile, -1, &lpszPathSpecClient, MAXLONG, FALSE);
  666. }
  667. // REVIEW: API assumes lpszPathSpec is large enough buffer
  668. StringCchCopy(lpszPathSpec, lstrlen(lpchFile)+1, lpchFile);
  669. }
  670. }
  671. //
  672. // In some cases, the ChopText requires extra space ahead of the path:
  673. // Give it CCH_CHOPTEXT_EXTRA extra spaces. (See ChopText() above).
  674. //
  675. pszCurrentDir = szStaticPath + CCH_CHOPTEXT_EXTRA;
  676. GetCurrentDirectory(ARRAYSIZE(szStaticPath)-CCH_CHOPTEXT_EXTRA, pszCurrentDir);
  677. //
  678. // Fill in the static path item.
  679. //
  680. if (idStaticPath)
  681. {
  682. //
  683. // To fix a bug OemToAnsi() call is inserted; SANKAR--Sep 16th
  684. //
  685. // OemToChar(szCurrentDir, szCurrentDir);
  686. CharLower(pszCurrentDir);
  687. SetDlgItemText(hwndDlg, idStaticPath, ChopText(hwndDlg, idStaticPath, szStaticPath));
  688. }
  689. //
  690. // Fill in the directory List/ComboBox if it exists.
  691. //
  692. if (idListBox && hwndLB != NULL)
  693. {
  694. wDirMsg = (UINT)(fListBox ? LB_RESETCONTENT : CB_RESETCONTENT);
  695. if (fPostIt)
  696. {
  697. PostMessage(hwndLB, wDirMsg, 0, 0L);
  698. }
  699. else
  700. {
  701. if (plb != NULL && (fWasVisible = IsLBoxVisible(plb)))
  702. {
  703. SendMessage(hwndLB, WM_SETREDRAW, FALSE, 0L);
  704. }
  705. SendMessage(hwndLB, wDirMsg, 0, 0L);
  706. }
  707. wDirMsg = (UINT)(fListBox ? LB_DIR : CB_DIR);
  708. if (attrib == DDL_DRIVES)
  709. {
  710. attrib |= DDL_EXCLUSIVE;
  711. }
  712. //
  713. // Hack for DDL_EXCLUSIVE to REALLY work.
  714. //
  715. fWin40Compat = TestWF(hwndLB, WFWIN40COMPAT);
  716. //
  717. // BACKWARDS COMPATIBILITY HACK
  718. //
  719. // We want DDL_EXCLUSIVE to _really_ work for new apps. I.E., we
  720. // want apps to be able to specify DDL_DRIVES/DDL_VOLUMES with
  721. // DDL_EXCLUSIVE and privilege bits -- and have only those items
  722. // matching show up, w/out files.
  723. //
  724. if (attrib & DDL_EXCLUSIVE)
  725. {
  726. if (fWin40Compat)
  727. {
  728. if (attrib & (DDL_DRIVES | DDL_DIRECTORY))
  729. attrib |= DDL_NOFILES;
  730. }
  731. else
  732. {
  733. if (attrib == (DDL_DRIVES | DDL_EXCLUSIVE))
  734. attrib |= DDL_NOFILES;
  735. }
  736. }
  737. if (!(attrib & DDL_NOFILES))
  738. {
  739. //
  740. // Add everything except the subdirectories and disk drives.
  741. //
  742. if (fPostIt)
  743. {
  744. //
  745. // Post lpszPathSpecClient, the client side pointer.
  746. //
  747. #ifdef WASWIN31
  748. PostMessage(hwndLB, wDirMsg, attrib &
  749. ~(DDL_DIRECTORY | DDL_DRIVES | DDL_POSTMSGS),
  750. (LPARAM)lpszPathSpecClient);
  751. #else
  752. //
  753. // On NT, keep DDL_POSTMSGS in wParam because we need to know
  754. // in the wndproc whether the pointer is clientside or server
  755. // side.
  756. //
  757. PostMessage(hwndLB, wDirMsg,
  758. attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
  759. (LPARAM)lpszPathSpecClient);
  760. #endif
  761. }
  762. else
  763. {
  764. // IanJa: #ifndef WIN16 (32-bit Windows), attrib gets extended
  765. // to LONG wParam automatically by the compiler
  766. SendMessage(hwndLB, wDirMsg,
  767. attrib & ~(DDL_DIRECTORY | DDL_DRIVES),
  768. (LPARAM)lpszPathSpec);
  769. }
  770. #ifdef WASWIN31
  771. //
  772. // Strip out just the subdirectory and drive bits.
  773. //
  774. attrib &= (DDL_DIRECTORY | DDL_DRIVES);
  775. #else
  776. //
  777. // B#1433
  778. // The old code stripped out read-only, hidden, system, and archive
  779. // information for subdirectories, making it impossible to have
  780. // a listbox w/ hidden directories!
  781. //
  782. //
  783. // Strip out just the subdirectory and drive bits. ON NT, keep
  784. // the DDL_POSTMSG bit so we know how to thunk this message.
  785. //
  786. if (!fWin40Compat)
  787. {
  788. attrib &= DDL_TYPE;
  789. }
  790. else
  791. {
  792. attrib &= (DDL_TYPE | (attrib & DDL_PRIVILEGES));
  793. attrib |= DDL_NOFILES;
  794. }
  795. // attrib &= (DDL_DIRECTORY | DDL_DRIVES | DDL_POSTMSGS);
  796. #endif
  797. }
  798. //
  799. // Add directories and volumes to the listbox.
  800. //
  801. if (attrib & DDL_TYPE)
  802. {
  803. //
  804. // Add the subdirectories and disk drives.
  805. //
  806. lpszPathSpec = szSLASHSTARDOTSTAR + 1;
  807. attrib |= DDL_EXCLUSIVE;
  808. if (fPostIt)
  809. {
  810. // Post lpszPathSpecClient, the client side pointer (see text
  811. // above).
  812. PostMessage(hwndLB, wDirMsg, attrib, (LPARAM)lpszPathSpecClient);
  813. }
  814. else
  815. {
  816. SendMessage(hwndLB, wDirMsg, attrib, (LPARAM)lpszPathSpec);
  817. }
  818. }
  819. if (!fPostIt && fWasVisible)
  820. {
  821. SendMessage(hwndLB, WM_SETREDRAW, TRUE, 0L);
  822. InvalidateRect(hwndLB, NULL, TRUE);
  823. }
  824. }
  825. bResult = TRUE;
  826. }
  827. }
  828. return bResult;
  829. }
  830. //---------------------------------------------------------------------------//
  831. BOOL DlgDirListA(
  832. HWND hwndDlg,
  833. LPSTR lpszPathSpecClient,
  834. INT idListBox,
  835. INT idStaticPath,
  836. UINT attrib)
  837. {
  838. LPWSTR lpszPathSpec;
  839. BOOL fRet;
  840. fRet = FALSE;
  841. if (hwndDlg)
  842. {
  843. lpszPathSpec = NULL;
  844. if (lpszPathSpecClient && (!MBToWCS(lpszPathSpecClient, -1, &lpszPathSpec, -1, TRUE)) )
  845. {
  846. fRet = FALSE;
  847. }
  848. else
  849. {
  850. //
  851. // The last parameter is TRUE to indicate ListBox (not ComboBox)
  852. //
  853. fRet = DlgDirListHelper(hwndDlg, lpszPathSpec, lpszPathSpecClient,
  854. idListBox, idStaticPath, attrib, TRUE);
  855. if (lpszPathSpec)
  856. {
  857. if (fRet)
  858. {
  859. //
  860. // Non-zero retval means some text to copy out. Copy out up to
  861. // the nul terminator (buffer will be big enough).
  862. //
  863. WCSToMB(lpszPathSpec, -1, &lpszPathSpecClient, MAXLONG, FALSE);
  864. }
  865. UserLocalFree(lpszPathSpec);
  866. }
  867. }
  868. }
  869. return fRet;
  870. }
  871. //---------------------------------------------------------------------------//
  872. BOOL DlgDirListW(
  873. HWND hwndDlg,
  874. LPWSTR lpszPathSpecClient,
  875. INT idListBox,
  876. INT idStaticPath,
  877. UINT attrib)
  878. {
  879. LPWSTR lpszPathSpec;
  880. BOOL fRet;
  881. fRet = FALSE;
  882. if (hwndDlg)
  883. {
  884. lpszPathSpec = lpszPathSpecClient;
  885. //
  886. // The last parameter is TRUE to indicate ListBox (not ComboBox)
  887. //
  888. fRet = DlgDirListHelper(hwndDlg, lpszPathSpec, (LPBYTE)lpszPathSpecClient,
  889. idListBox, idStaticPath, attrib, TRUE);
  890. }
  891. return fRet;
  892. }
  893. //---------------------------------------------------------------------------//
  894. BOOL DlgDirSelectHelper(
  895. LPWSTR lpszPathSpec,
  896. INT chCount,
  897. HWND hwndListBox)
  898. {
  899. INT cch;
  900. LPWSTR lpchFile;
  901. BOOL fDir;
  902. INT sItem;
  903. LPWSTR lpchT;
  904. WCHAR rgch[MAX_PATH + 2];
  905. INT cchT;
  906. LARGE_UNICODE_STRING str;
  907. BOOL bRet;
  908. bRet = FALSE;
  909. //
  910. // Callers such as DlgDirSelectEx do not validate the existance
  911. // of hwndListBox
  912. //
  913. if (hwndListBox == NULL)
  914. {
  915. TraceMsg(TF_STANDARD, "Controls Id not found");
  916. bRet = FALSE;
  917. }
  918. else
  919. {
  920. sItem = (INT)SendMessage(hwndListBox, LB_GETCURSEL, 0, 0L);
  921. if (sItem < 0)
  922. {
  923. bRet = FALSE;
  924. }
  925. else
  926. {
  927. cchT = (INT)SendMessage(hwndListBox, LB_GETTEXT, sItem, (LPARAM)rgch);
  928. UserAssert(cchT < (sizeof(rgch)/sizeof(rgch[0])));
  929. lpchFile = rgch;
  930. fDir = (*rgch == TEXT('['));
  931. //
  932. // Check if all details along with file name are to be returned. Make sure
  933. // we can find the listbox because with drop down combo boxes, the
  934. // GetDlgItem will fail.
  935. //
  936. // Make sure this window has been using the listbox window proc because
  937. // we store some data as a window long.
  938. //
  939. //
  940. // Only the file name is to be returned. Find the end of the filename.
  941. //
  942. lpchT = lpchFile;
  943. while ((*lpchT) && (*lpchT != TABCHAR))
  944. {
  945. lpchT++;
  946. }
  947. *lpchT = TEXT('\0');
  948. cch = wcslen(lpchFile);
  949. //
  950. // Selection is drive or directory.
  951. //
  952. if (fDir)
  953. {
  954. lpchFile++;
  955. cch--;
  956. *(lpchFile + cch - 1) = TEXT('\\');
  957. //
  958. // Selection is drive
  959. //
  960. if (rgch[1] == TEXT('-'))
  961. {
  962. lpchFile++;
  963. cch--;
  964. *(lpchFile + 1) = TEXT(':');
  965. *(lpchFile + 2) = 0;
  966. }
  967. }
  968. else
  969. {
  970. //
  971. // Selection is file. If filename has no extension, append '.'
  972. //
  973. lpchT = lpchFile;
  974. for (; (cch > 0) && (*lpchT != TABCHAR); cch--, lpchT++)
  975. {
  976. if (*lpchT == TEXT('.'))
  977. {
  978. break;
  979. }
  980. }
  981. if (*lpchT == TABCHAR)
  982. {
  983. _memmove(lpchT + 1, lpchT, CHARSTOBYTES(cch + 1));
  984. *lpchT = TEXT('.');
  985. }
  986. else if (cch <= 0)
  987. {
  988. *lpchT++ = TEXT('.');
  989. *lpchT = 0;
  990. }
  991. }
  992. bRet = fDir;
  993. }
  994. }
  995. RtlInitLargeUnicodeString(&str, lpchFile, (UINT)-1);
  996. TextCopy(&str, lpszPathSpec, (UINT)chCount);
  997. return bRet;
  998. }
  999. //---------------------------------------------------------------------------//
  1000. BOOL DlgDirSelectExA(
  1001. HWND hwndDlg,
  1002. LPSTR lpszPathSpec,
  1003. INT chCount,
  1004. INT idListBox)
  1005. {
  1006. LPWSTR lpwsz;
  1007. BOOL fRet;
  1008. lpwsz = (LPWSTR)UserLocalAlloc(HEAP_ZERO_MEMORY, chCount * sizeof(WCHAR));
  1009. if (!lpwsz)
  1010. {
  1011. fRet = FALSE;
  1012. }
  1013. else
  1014. {
  1015. fRet = DlgDirSelectHelper(lpwsz, chCount, GetDlgItem(hwndDlg, idListBox));
  1016. WCSToMB(lpwsz, -1, &lpszPathSpec, chCount, FALSE);
  1017. UserLocalFree(lpwsz);
  1018. }
  1019. return fRet;
  1020. }
  1021. //---------------------------------------------------------------------------//
  1022. BOOL DlgDirSelectExW(
  1023. HWND hwndDlg,
  1024. LPWSTR lpszPathSpec,
  1025. INT chCount,
  1026. INT idListBox)
  1027. {
  1028. return DlgDirSelectHelper(lpszPathSpec, chCount, GetDlgItem(hwndDlg, idListBox));
  1029. }
  1030. #endif // INCLUDE_LISTBOX_FUNCTIONS