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.

908 lines
23 KiB

  1. #include "pch.h"
  2. #ifndef CSC_ON_NT
  3. #define MyStrChr StrChr
  4. #define MyPathIsUNC(lpT) PathIsUNC(lpT)
  5. #endif
  6. #include "extra.h"
  7. // System colors
  8. COLORREF g_clrHighlightText = 0;
  9. COLORREF g_clrHighlight = 0;
  10. COLORREF g_clrWindowText = 0;
  11. COLORREF g_clrWindow = 0;
  12. HBRUSH g_hbrHighlight = 0;
  13. HBRUSH g_hbrWindow = 0;
  14. char const FAR c_szEllipses[] = "...";
  15. BOOL PUBLIC PathExists(
  16. LPCSTR pszPath);
  17. /*----------------------------------------------------------
  18. Purpose: Get the system metrics we need
  19. Returns: --
  20. Cond: --
  21. */
  22. void PRIVATE GetMetrics(
  23. WPARAM wParam) // wParam from WM_WININICHANGE
  24. {
  25. if ((wParam == 0) || (wParam == SPI_SETNONCLIENTMETRICS))
  26. {
  27. g_cxIconSpacing = GetSystemMetrics( SM_CXICONSPACING );
  28. g_cyIconSpacing = GetSystemMetrics( SM_CYICONSPACING );
  29. g_cxBorder = GetSystemMetrics(SM_CXBORDER);
  30. g_cyBorder = GetSystemMetrics(SM_CYBORDER);
  31. g_cxIcon = GetSystemMetrics(SM_CXICON);
  32. g_cyIcon = GetSystemMetrics(SM_CYICON);
  33. g_cxIconMargin = g_cxBorder * 8;
  34. g_cyIconMargin = g_cyBorder * 2;
  35. g_cyLabelSpace = g_cyIconMargin + (g_cyBorder * 2);
  36. g_cxLabelMargin = (g_cxBorder * 2);
  37. g_cxMargin = g_cxBorder * 5;
  38. }
  39. }
  40. /*----------------------------------------------------------
  41. Purpose: Initializes colors
  42. Returns: --
  43. Cond: --
  44. */
  45. void PRIVATE InitGlobalColors()
  46. {
  47. g_clrWindowText = GetSysColor(COLOR_WINDOWTEXT);
  48. g_clrWindow = GetSysColor(COLOR_WINDOW);
  49. g_clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
  50. g_clrHighlight = GetSysColor(COLOR_HIGHLIGHT);
  51. g_hbrWindow = GetSysColorBrush(COLOR_WINDOW);
  52. g_hbrHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
  53. }
  54. /*----------------------------------------------------------
  55. Purpose: Sets up a bunch of necessary globals
  56. Returns: nothing.
  57. Cond: --
  58. */
  59. void InitializeAll(WPARAM wParam)
  60. {
  61. GetMetrics(wParam); // wParam from WM_WININICHANGE
  62. InitGlobalColors();
  63. }
  64. /*----------------------------------------------------------
  65. Purpose: Load the string (if necessary) and format the string
  66. properly.
  67. Returns: A pointer to the allocated string containing the formatted
  68. message or
  69. NULL if out of memory
  70. Cond: --
  71. */
  72. LPSTR PUBLIC _ConstructMessageString(
  73. HINSTANCE hinst,
  74. LPCSTR pszMsg,
  75. va_list *ArgList)
  76. {
  77. char szTemp[MAXBUFLEN];
  78. LPSTR pszRet;
  79. LPSTR pszRes;
  80. if (HIWORD(pszMsg))
  81. pszRes = (LPSTR)pszMsg;
  82. else if (LOWORD(pszMsg) && LoadString(hinst, LOWORD(pszMsg), szTemp, sizeof(szTemp)))
  83. pszRes = szTemp;
  84. else
  85. pszRes = NULL;
  86. if (pszRes)
  87. {
  88. if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  89. pszRes, 0, 0, (LPTSTR)&pszRet, 0, ArgList))
  90. {
  91. pszRet = NULL;
  92. }
  93. }
  94. else
  95. {
  96. // Bad parameter
  97. pszRet = NULL;
  98. }
  99. return pszRet; // free with LocalFree()
  100. }
  101. /*----------------------------------------------------------
  102. Purpose: Constructs a formatted string. The returned string
  103. must be freed using GFree().
  104. Returns: TRUE on success
  105. Cond: --
  106. */
  107. BOOL PUBLIC ConstructMessage(
  108. LPSTR * ppsz,
  109. HINSTANCE hinst,
  110. LPCSTR pszMsg, ...)
  111. {
  112. BOOL bRet;
  113. LPSTR pszRet;
  114. va_list ArgList;
  115. va_start(ArgList, pszMsg);
  116. pszRet = _ConstructMessageString(hinst, pszMsg, &ArgList);
  117. va_end(ArgList);
  118. *ppsz = NULL;
  119. if (pszRet)
  120. {
  121. bRet = GSetString(ppsz, pszRet);
  122. LocalFree(pszRet);
  123. }
  124. else
  125. bRet = FALSE;
  126. return bRet;
  127. }
  128. #if 0
  129. /*----------------------------------------------------------
  130. Purpose: Gets the locality of the path, relative to any
  131. briefcase. If PL_ROOT or PL_INSIDE is returned,
  132. pszBuf will contain the path to the root of the
  133. briefcase.
  134. This function may hit the file-system to achieve
  135. its goal.
  136. Worst case: performs 2*n GetFileAttributes, where
  137. n is the number of components in pszPath.
  138. Returns: Path locality (PL_FALSE, PL_ROOT, PL_INSIDE)
  139. Cond: --
  140. */
  141. UINT PUBLIC PathGetLocality(
  142. LPCSTR pszPath,
  143. LPSTR pszBuf) // Buffer for root path
  144. {
  145. UINT uRet;
  146. ASSERT(pszPath);
  147. ASSERT(pszBuf);
  148. *pszBuf = NULL_CHAR;
  149. // pszPath may be:
  150. // 1) a path to the briefcase folder itself
  151. // 2) a path to a file or folder beneath the briefcase
  152. // 3) a path to something unrelated to a briefcase
  153. // We perform our search by first looking in our cache
  154. // of known briefcase paths (CPATH). If we don't find
  155. // anything, then we proceed to iterate thru each
  156. // component of the path, checking for these two things:
  157. //
  158. // 1) A directory with the system attribute
  159. // 2) The existence of a brfcase.dat file in the directory.
  160. //
  161. uRet = CPATH_GetLocality(pszPath, pszBuf);
  162. if (PL_FALSE == uRet)
  163. {
  164. int cnt = 0;
  165. lstrcpy(pszBuf, pszPath);
  166. do
  167. {
  168. if (PathCheckForBriefcase(pszBuf, (DWORD)-1))
  169. {
  170. int atom;
  171. uRet = cnt > 0 ? PL_INSIDE : PL_ROOT;
  172. // Add this briefcase path to our cache
  173. //
  174. atom = Atom_Add(pszBuf);
  175. if (ATOM_ERR != atom)
  176. CPATH_Replace(atom);
  177. break; // Done
  178. }
  179. cnt++;
  180. } while (PathRemoveFileSpec(pszBuf));
  181. if (PL_FALSE == uRet)
  182. *pszBuf = NULL_CHAR;
  183. }
  184. return uRet;
  185. }
  186. #endif
  187. /*----------------------------------------------------------
  188. Purpose: Convert FILETIME struct to a readable string
  189. Returns: String
  190. Cond: --
  191. */
  192. void PUBLIC FileTimeToDateTimeString(
  193. LPFILETIME pft,
  194. LPSTR pszBuf,
  195. int cchBuf)
  196. {
  197. SYSTEMTIME st;
  198. FILETIME ftLocal;
  199. FileTimeToLocalFileTime(pft, &ftLocal);
  200. FileTimeToSystemTime(&ftLocal, &st);
  201. GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuf, cchBuf/2);
  202. pszBuf += lstrlen(pszBuf);
  203. *pszBuf++ = ' ';
  204. GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszBuf, cchBuf/2);
  205. }
  206. /*----------------------------------------------------------
  207. Purpose: Sees whether the entire string will fit in *prc.
  208. If not, compute the numbder of chars that will fit
  209. (including ellipses). Returns length of string in
  210. *pcchDraw.
  211. Taken from COMMCTRL.
  212. Returns: TRUE if the string needed ellipses
  213. Cond: --
  214. */
  215. BOOL PRIVATE NeedsEllipses(
  216. HDC hdc,
  217. LPCSTR pszText,
  218. RECT * prc,
  219. int * pcchDraw,
  220. int cxEllipses)
  221. {
  222. int cchText;
  223. int cxRect;
  224. int ichMin, ichMax, ichMid;
  225. SIZE siz;
  226. cxRect = prc->right - prc->left;
  227. cchText = lstrlen(pszText);
  228. if (cchText == 0)
  229. {
  230. *pcchDraw = cchText;
  231. return FALSE;
  232. }
  233. GetTextExtentPoint(hdc, pszText, cchText, &siz);
  234. if (siz.cx <= cxRect)
  235. {
  236. *pcchDraw = cchText;
  237. return FALSE;
  238. }
  239. cxRect -= cxEllipses;
  240. // If no room for ellipses, always show first character.
  241. //
  242. ichMax = 1;
  243. if (cxRect > 0)
  244. {
  245. // Binary search to find character that will fit
  246. ichMin = 0;
  247. ichMax = cchText;
  248. while (ichMin < ichMax)
  249. {
  250. // Be sure to round up, to make sure we make progress in
  251. // the loop if ichMax == ichMin + 1.
  252. //
  253. ichMid = (ichMin + ichMax + 1) / 2;
  254. GetTextExtentPoint(hdc, &pszText[ichMin], ichMid - ichMin, &siz);
  255. if (siz.cx < cxRect)
  256. {
  257. ichMin = ichMid;
  258. cxRect -= siz.cx;
  259. }
  260. else if (siz.cx > cxRect)
  261. {
  262. ichMax = ichMid - 1;
  263. }
  264. else
  265. {
  266. // Exact match up up to ichMid: just exit.
  267. //
  268. ichMax = ichMid;
  269. break;
  270. }
  271. }
  272. // Make sure we always show at least the first character...
  273. //
  274. if (ichMax < 1)
  275. ichMax = 1;
  276. }
  277. *pcchDraw = ichMax;
  278. return TRUE;
  279. }
  280. #define CCHELLIPSES 3
  281. #define DT_LVWRAP (DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_EDITCONTROL)
  282. /*----------------------------------------------------------
  283. Purpose: Draws text the shell's way.
  284. Taken from COMMCTRL.
  285. Returns: --
  286. Cond: This function requires TRANSPARENT background mode
  287. and a properly selected font.
  288. */
  289. void PUBLIC MyDrawText(
  290. HDC hdc,
  291. LPCSTR pszText,
  292. RECT FAR* prc,
  293. UINT flags,
  294. int cyChar,
  295. int cxEllipses,
  296. COLORREF clrText,
  297. COLORREF clrTextBk)
  298. {
  299. int cchText;
  300. COLORREF clrSave;
  301. COLORREF clrSaveBk;
  302. UINT uETOFlags = 0;
  303. RECT rc;
  304. char ach[MAX_PATH + CCHELLIPSES];
  305. // REVIEW: Performance idea:
  306. // We could cache the currently selected text color
  307. // so we don't have to set and restore it each time
  308. // when the color is the same.
  309. //
  310. if (!pszText)
  311. return;
  312. rc = *prc;
  313. // If needed, add in a little extra margin...
  314. //
  315. if (IsFlagSet(flags, MDT_EXTRAMARGIN))
  316. {
  317. rc.left += g_cxLabelMargin * 3;
  318. rc.right -= g_cxLabelMargin * 3;
  319. }
  320. else
  321. {
  322. rc.left += g_cxLabelMargin;
  323. rc.right -= g_cxLabelMargin;
  324. }
  325. if (IsFlagSet(flags, MDT_ELLIPSES) &&
  326. NeedsEllipses(hdc, pszText, &rc, &cchText, cxEllipses))
  327. {
  328. hmemcpy(ach, pszText, cchText);
  329. lstrcpy(ach + cchText, c_szEllipses);
  330. pszText = ach;
  331. // Left-justify, in case there's no room for all of ellipses
  332. //
  333. ClearFlag(flags, (MDT_RIGHT | MDT_CENTER));
  334. SetFlag(flags, MDT_LEFT);
  335. cchText += CCHELLIPSES;
  336. }
  337. else
  338. {
  339. cchText = lstrlen(pszText);
  340. }
  341. if (IsFlagSet(flags, MDT_TRANSPARENT))
  342. {
  343. clrSave = SetTextColor(hdc, 0x000000);
  344. }
  345. else
  346. {
  347. uETOFlags |= ETO_OPAQUE;
  348. if (IsFlagSet(flags, MDT_SELECTED))
  349. {
  350. clrSave = SetTextColor(hdc, g_clrHighlightText);
  351. clrSaveBk = SetBkColor(hdc, g_clrHighlight);
  352. if (IsFlagSet(flags, MDT_DRAWTEXT))
  353. {
  354. FillRect(hdc, prc, g_hbrHighlight);
  355. }
  356. }
  357. else
  358. {
  359. if (clrText == CLR_DEFAULT && clrTextBk == CLR_DEFAULT)
  360. {
  361. clrSave = SetTextColor(hdc, g_clrWindowText);
  362. clrSaveBk = SetBkColor(hdc, g_clrWindow);
  363. if (IsFlagSet(flags, MDT_DRAWTEXT | MDT_DESELECTED))
  364. {
  365. FillRect(hdc, prc, g_hbrWindow);
  366. }
  367. }
  368. else
  369. {
  370. HBRUSH hbr;
  371. if (clrText == CLR_DEFAULT)
  372. clrText = g_clrWindowText;
  373. if (clrTextBk == CLR_DEFAULT)
  374. clrTextBk = g_clrWindow;
  375. clrSave = SetTextColor(hdc, clrText);
  376. clrSaveBk = SetBkColor(hdc, clrTextBk);
  377. if (IsFlagSet(flags, MDT_DRAWTEXT | MDT_DESELECTED))
  378. {
  379. hbr = CreateSolidBrush(GetNearestColor(hdc, clrTextBk));
  380. if (hbr)
  381. {
  382. FillRect(hdc, prc, hbr);
  383. DeleteObject(hbr);
  384. }
  385. else
  386. FillRect(hdc, prc, GetStockObject(WHITE_BRUSH));
  387. }
  388. }
  389. }
  390. }
  391. // If we want the item to display as if it was depressed, we will
  392. // offset the text rectangle down and to the left
  393. if (IsFlagSet(flags, MDT_DEPRESSED))
  394. OffsetRect(&rc, g_cxBorder, g_cyBorder);
  395. if (IsFlagSet(flags, MDT_DRAWTEXT))
  396. {
  397. UINT uDTFlags = DT_LVWRAP;
  398. if (IsFlagClear(flags, MDT_CLIPPED))
  399. uDTFlags |= DT_NOCLIP;
  400. DrawText(hdc, pszText, cchText, &rc, uDTFlags);
  401. }
  402. else
  403. {
  404. if (IsFlagClear(flags, MDT_LEFT))
  405. {
  406. SIZE siz;
  407. GetTextExtentPoint(hdc, pszText, cchText, &siz);
  408. if (IsFlagSet(flags, MDT_CENTER))
  409. rc.left = (rc.left + rc.right - siz.cx) / 2;
  410. else
  411. {
  412. ASSERT(IsFlagSet(flags, MDT_RIGHT));
  413. rc.left = rc.right - siz.cx;
  414. }
  415. }
  416. if (IsFlagSet(flags, MDT_VCENTER))
  417. {
  418. // Center vertically
  419. rc.top += (rc.bottom - rc.top - cyChar) / 2;
  420. }
  421. if (IsFlagSet(flags, MDT_CLIPPED))
  422. uETOFlags |= ETO_CLIPPED;
  423. ExtTextOut(hdc, rc.left, rc.top, uETOFlags, prc, pszText, cchText, NULL);
  424. }
  425. if (flags & (MDT_SELECTED | MDT_DESELECTED | MDT_TRANSPARENT))
  426. {
  427. SetTextColor(hdc, clrSave);
  428. if (IsFlagClear(flags, MDT_TRANSPARENT))
  429. SetBkColor(hdc, clrSaveBk);
  430. }
  431. }
  432. //---------------------------------------------------------------------------
  433. // Given a pointer to a point in a path - return a ptr the start of the
  434. // next path component. Path components are delimted by slashes or the
  435. // null at the end.
  436. // There's special handling for UNC names.
  437. // This returns NULL if you pass in a pointer to a NULL ie if you're about
  438. // to go off the end of the path.
  439. LPSTR PUBLIC PathFindNextComponentI(LPCSTR lpszPath)
  440. {
  441. LPSTR lpszLastSlash;
  442. // Are we at the end of a path.
  443. if (!*lpszPath)
  444. {
  445. // Yep, quit.
  446. return NULL;
  447. }
  448. // Find the next slash.
  449. // REVIEW UNDONE - can slashes be quoted?
  450. lpszLastSlash = MyStrChr(lpszPath, '\\');
  451. // Is there a slash?
  452. if (!lpszLastSlash)
  453. {
  454. // No - Return a ptr to the NULL.
  455. return (LPSTR) (lpszPath+lstrlen(lpszPath));
  456. }
  457. else
  458. {
  459. // Is it a UNC style name?
  460. if ('\\' == *(lpszLastSlash+1))
  461. {
  462. // Yep, skip over the second slash.
  463. return lpszLastSlash+2;
  464. }
  465. else
  466. {
  467. // Nope. just skip over one slash.
  468. return lpszLastSlash+1;
  469. }
  470. }
  471. }
  472. /*----------------------------------------------------------
  473. Purpose: Convert a file spec to make it look a bit better
  474. if it is all upper case chars.
  475. Returns: --
  476. Cond: --
  477. */
  478. BOOL PRIVATE PathMakeComponentPretty(LPSTR lpPath)
  479. {
  480. LPSTR lp;
  481. // REVIEW: INTL need to deal with lower case chars in (>127) range?
  482. // check for all uppercase
  483. for (lp = lpPath; *lp; lp = AnsiNext(lp)) {
  484. if ((*lp >= 'a') && (*lp <= 'z'))
  485. return FALSE; // this is a LFN, dont mess with it
  486. }
  487. AnsiLower(lpPath);
  488. AnsiUpperBuff(lpPath, 1);
  489. return TRUE; // did the conversion
  490. }
  491. /*----------------------------------------------------------
  492. Purpose: Takes the path and makes it presentable.
  493. The rules are:
  494. If the LFN name is simply the short name (all caps),
  495. then convert to lowercase with first letter capitalized
  496. Returns: --
  497. Cond: --
  498. */
  499. void PUBLIC PathMakePresentable(
  500. LPSTR pszPath)
  501. {
  502. LPSTR pszComp; // pointers to begining and
  503. LPSTR pszEnd; // end of path component
  504. LPSTR pch;
  505. int cComponent = 0;
  506. BOOL bUNCPath;
  507. char ch;
  508. bUNCPath = MyPathIsUNC(pszPath);
  509. pszComp = pszPath;
  510. while (pszEnd = PathFindNextComponentI(pszComp))
  511. {
  512. // pszEnd may be pointing to the right of the backslash
  513. // beyond the path component, so back up one
  514. //
  515. ch = *pszEnd;
  516. *pszEnd = 0; // temporary null
  517. // pszComp points to the path component
  518. //
  519. pch = AnsiNext(pszComp);
  520. if (':' == *pch)
  521. {
  522. // Simply capitalize the drive-portion of the path
  523. //
  524. AnsiUpper(pszComp);
  525. }
  526. else if (bUNCPath && cComponent++ < 3)
  527. {
  528. // Network server or share name
  529. // BUGBUG: handle LFN network names
  530. //
  531. AnsiUpper(pszComp);
  532. PathMakeComponentPretty(pszComp);
  533. }
  534. else
  535. {
  536. // Normal path component
  537. //
  538. PathMakeComponentPretty(pszComp);
  539. }
  540. *pszEnd = ch;
  541. pszComp = pszEnd;
  542. }
  543. }
  544. /*----------------------------------------------------------
  545. Purpose: Get a string from the resource string table. Returned
  546. ptr is a ptr to static memory. The next call to this
  547. function will wipe out the prior contents.
  548. Returns: Ptr to string
  549. Cond: --
  550. */
  551. LPSTR PUBLIC SzFromIDS(
  552. UINT ids, // resource ID
  553. LPSTR pszBuf,
  554. UINT cchBuf)
  555. {
  556. ASSERT(pszBuf);
  557. *pszBuf = NULL_CHAR;
  558. LoadString(vhinstCur, ids, pszBuf, cchBuf);
  559. return pszBuf;
  560. }
  561. /*----------------------------------------------------------
  562. Purpose: Sets the rectangle with the bounding extent of the given string.
  563. Returns: Rectangle
  564. Cond: --
  565. */
  566. void PUBLIC SetRectFromExtent(
  567. HDC hdc,
  568. LPRECT lprect,
  569. LPCSTR lpcsz)
  570. {
  571. SIZE size;
  572. GetTextExtentPoint(hdc, lpcsz, lstrlen(lpcsz), &size);
  573. SetRect(lprect, 0, 0, size.cx, size.cy);
  574. }
  575. /*----------------------------------------------------------
  576. Purpose: Copies psz into *ppszBuf. Will alloc or realloc *ppszBuf
  577. accordingly.
  578. Returns: TRUE on success
  579. Cond: --
  580. */
  581. BOOL PUBLIC GSetString(
  582. LPSTR * ppszBuf,
  583. LPCSTR psz)
  584. {
  585. BOOL bRet = FALSE;
  586. DWORD cb;
  587. ASSERT(ppszBuf);
  588. ASSERT(psz);
  589. cb = CbFromCch(lstrlen(psz)+CCH_NUL);
  590. if (*ppszBuf)
  591. {
  592. // Need to reallocate?
  593. if (cb > GGetSize(*ppszBuf))
  594. {
  595. // Yes
  596. LPSTR pszT = GReAlloc(*ppszBuf, cb);
  597. if (pszT)
  598. {
  599. *ppszBuf = pszT;
  600. bRet = TRUE;
  601. }
  602. }
  603. else
  604. {
  605. // No
  606. bRet = TRUE;
  607. }
  608. }
  609. else
  610. {
  611. *ppszBuf = (LPSTR)GAlloc(cb);
  612. if (*ppszBuf)
  613. {
  614. bRet = TRUE;
  615. }
  616. }
  617. if (bRet)
  618. {
  619. ASSERT(*ppszBuf);
  620. lstrcpy(*ppszBuf, psz);
  621. }
  622. return bRet;
  623. }
  624. /*----------------------------------------------------------
  625. Purpose: Gets the file info given a path. If the path refers
  626. to a directory, then simply the path field is filled.
  627. If himl != NULL, then the function will add the file's
  628. image to the provided image list and set the image index
  629. field in the *ppfi.
  630. Returns: standard hresult
  631. Cond: --
  632. */
  633. HRESULT PUBLIC FICreate(
  634. LPCSTR pszPath,
  635. FileInfo ** ppfi,
  636. UINT uFlags)
  637. {
  638. HRESULT hres = ResultFromScode(E_OUTOFMEMORY);
  639. int cchPath;
  640. SHFILEINFO sfi;
  641. UINT uInfoFlags = SHGFI_DISPLAYNAME | SHGFI_ATTRIBUTES;
  642. DWORD dwAttr;
  643. ASSERT(pszPath);
  644. ASSERT(ppfi);
  645. // Get shell file info
  646. if (IsFlagSet(uFlags, FIF_ICON))
  647. uInfoFlags |= SHGFI_ICON;
  648. if (IsFlagSet(uFlags, FIF_DONTTOUCH))
  649. {
  650. uInfoFlags |= SHGFI_USEFILEATTRIBUTES;
  651. // Today, FICreate is not called for folders, so this is ifdef'd out
  652. #ifdef SUPPORT_FOLDERS
  653. dwAttr = IsFlagSet(uFlags, FIF_FOLDER) ? FILE_ATTRIBUTE_DIRECTORY : 0;
  654. #else
  655. dwAttr = 0;
  656. #endif
  657. }
  658. else
  659. dwAttr = 0;
  660. if (SHGetFileInfo(pszPath, dwAttr, &sfi, sizeof(sfi), uInfoFlags))
  661. {
  662. // Allocate enough for the structure, plus buffer for the fully qualified
  663. // path and buffer for the display name (and extra null terminator).
  664. cchPath = lstrlen(pszPath);
  665. *ppfi = GAlloc(sizeof(FileInfo)+cchPath+1-sizeof((*ppfi)->szPath)+lstrlen(sfi.szDisplayName)+1);
  666. if (*ppfi)
  667. {
  668. FileInfo * pfi = *ppfi;
  669. pfi->pszDisplayName = pfi->szPath+cchPath+1;
  670. lstrcpy(pfi->pszDisplayName, sfi.szDisplayName);
  671. if (IsFlagSet(uFlags, FIF_ICON))
  672. pfi->hicon = sfi.hIcon;
  673. pfi->dwAttributes = sfi.dwAttributes;
  674. // Does the path refer to a directory?
  675. if (FIIsFolder(pfi))
  676. {
  677. // Yes; just fill in the path field
  678. lstrcpy(pfi->szPath, pszPath);
  679. hres = NOERROR;
  680. }
  681. else
  682. {
  683. // No; assume the file exists?
  684. if (IsFlagClear(uFlags, FIF_DONTTOUCH))
  685. {
  686. // Yes; get the time, date and size of the file
  687. HANDLE hfile = CreateFile(pszPath, GENERIC_READ,
  688. FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  689. NULL);
  690. if (hfile == INVALID_HANDLE_VALUE)
  691. {
  692. GFree(*ppfi);
  693. hres = ResultFromScode(E_HANDLE);
  694. }
  695. else
  696. {
  697. hres = NOERROR;
  698. lstrcpy(pfi->szPath, pszPath);
  699. pfi->dwSize = GetFileSize(hfile, NULL);
  700. GetFileTime(hfile, NULL, NULL, &pfi->ftMod);
  701. CloseHandle(hfile);
  702. }
  703. }
  704. else
  705. {
  706. // No; use what we have
  707. hres = NOERROR;
  708. lstrcpy(pfi->szPath, pszPath);
  709. }
  710. }
  711. }
  712. }
  713. else if (!PathExists(pszPath))
  714. {
  715. // Differentiate between out of memory and file not found
  716. hres = E_FAIL;
  717. }
  718. return hres;
  719. }
  720. /*----------------------------------------------------------
  721. Purpose: Set the path entry. This can move the pfi.
  722. Returns: FALSE on out of memory
  723. Cond: --
  724. */
  725. BOOL PUBLIC FISetPath(
  726. FileInfo ** ppfi,
  727. LPCSTR pszPathNew,
  728. UINT uFlags)
  729. {
  730. ASSERT(ppfi);
  731. ASSERT(pszPathNew);
  732. FIFree(*ppfi);
  733. return SUCCEEDED(FICreate(pszPathNew, ppfi, uFlags));
  734. }
  735. /*----------------------------------------------------------
  736. Purpose: Free our file info struct
  737. Returns: --
  738. Cond: --
  739. */
  740. void PUBLIC FIFree(
  741. FileInfo * pfi)
  742. {
  743. if (pfi)
  744. {
  745. if (pfi->hicon)
  746. DestroyIcon(pfi->hicon);
  747. GFree(pfi); // This macro already checks for NULL pfi condition
  748. }
  749. }
  750. /*----------------------------------------------------------
  751. Purpose: Returns TRUE if the file/directory exists.
  752. Returns: see above
  753. Cond: --
  754. */
  755. BOOL PUBLIC PathExists(
  756. LPCSTR pszPath)
  757. {
  758. return GetFileAttributes(pszPath) != 0xFFFFFFFF;
  759. }