Source code of Windows XP (NT5)
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.

1475 lines
35 KiB

  1. //
  2. // Copyright (c) Microsoft Corporation 1993-1995
  3. //
  4. // common.c
  5. //
  6. // This files contains common utility and helper functions.
  7. //
  8. // History:
  9. // 08-06-93 ScottH Transferred from twin code
  10. // 04-26-95 ScottH Transferred and expanded from Briefcase code
  11. //
  12. #include "proj.h"
  13. #include "common.h"
  14. #ifdef NORTL
  15. // Some of these are replacements for the C runtime routines.
  16. // This is so we don't have to link to the CRT libs.
  17. //
  18. /*----------------------------------------------------------
  19. Purpose: memset
  20. Swiped from the C 7.0 runtime sources.
  21. Returns:
  22. Cond:
  23. */
  24. LPSTR PUBLIC lmemset(
  25. LPSTR dst,
  26. char val,
  27. UINT count)
  28. {
  29. LPSTR start = dst;
  30. while (count--)
  31. *dst++ = val;
  32. return(start);
  33. }
  34. /*----------------------------------------------------------
  35. Purpose: memmove
  36. Swiped from the C 7.0 runtime sources.
  37. Returns:
  38. Cond:
  39. */
  40. LPSTR PUBLIC lmemmove(
  41. LPSTR dst,
  42. LPCSTR src,
  43. int count)
  44. {
  45. LPSTR ret = dst;
  46. if (dst <= src || dst >= (src + count)) {
  47. /*
  48. * Non-Overlapping Buffers
  49. * copy from lower addresses to higher addresses
  50. */
  51. while (count--)
  52. *dst++ = *src++;
  53. }
  54. else {
  55. /*
  56. * Overlapping Buffers
  57. * copy from higher addresses to lower addresses
  58. */
  59. dst += count - 1;
  60. src += count - 1;
  61. while (count--)
  62. *dst-- = *src--;
  63. }
  64. return(ret);
  65. }
  66. #endif // NORTL
  67. #ifndef NOSTRING
  68. // WARNING: all of these APIs do not setup DS, so you can not access
  69. // any data in the default data seg of this DLL.
  70. //
  71. // do not create any global variables... talk to chrisg if you don't
  72. // understand this
  73. #define FASTCALL _fastcall
  74. /*----------------------------------------------------------
  75. Purpose: Case sensitive character comparison for DBCS
  76. Returns: FALSE if they match, TRUE if no match
  77. Cond: --
  78. */
  79. BOOL PRIVATE ChrCmp(
  80. WORD w1,
  81. WORD wMatch)
  82. {
  83. /* Most of the time this won't match, so test it first for speed.
  84. */
  85. if (LOBYTE(w1) == LOBYTE(wMatch))
  86. {
  87. if (IsDBCSLeadByte(LOBYTE(w1)))
  88. {
  89. return(w1 != wMatch);
  90. }
  91. return FALSE;
  92. }
  93. return TRUE;
  94. }
  95. /*----------------------------------------------------------
  96. Purpose: Case insensitive character comparison for DBCS
  97. Returns: FALSE if match, TRUE if not
  98. Cond: --
  99. */
  100. BOOL PRIVATE ChrCmpI(
  101. WORD w1,
  102. WORD wMatch)
  103. {
  104. char sz1[3], sz2[3];
  105. if (IsDBCSLeadByte(sz1[0] = LOBYTE(w1)))
  106. {
  107. sz1[1] = HIBYTE(w1);
  108. sz1[2] = '\0';
  109. }
  110. else
  111. sz1[1] = '\0';
  112. *(WORD FAR *)sz2 = wMatch;
  113. sz2[2] = '\0';
  114. return lstrcmpi(sz1, sz2);
  115. }
  116. /*----------------------------------------------------------
  117. Purpose: strnicmp
  118. Swiped from the C 7.0 runtime sources.
  119. Returns:
  120. Cond:
  121. */
  122. int PUBLIC lstrnicmp(
  123. LPCSTR psz1,
  124. LPCSTR psz2,
  125. UINT count)
  126. {
  127. int ch1;
  128. int ch2;
  129. int result = 0;
  130. LPCSTR pszTmp;
  131. if (count)
  132. {
  133. do
  134. {
  135. pszTmp = CharLower((LPSTR)LongToPtr(MAKELONG(*psz1, 0)));
  136. ch1 = *pszTmp;
  137. pszTmp = CharLower((LPSTR)LongToPtr(MAKELONG(*psz2, 0)));
  138. ch2 = *pszTmp;
  139. psz1 = AnsiNext(psz1);
  140. psz2 = AnsiNext(psz2);
  141. } while (--count && ch1 && ch2 && !ChrCmp((WORD)ch1, (WORD)ch2));
  142. result = ch1 - ch2;
  143. }
  144. return(result);
  145. }
  146. /*----------------------------------------------------------
  147. Purpose: My verion of atoi. Supports hexadecimal too.
  148. Returns: integer
  149. Cond: --
  150. */
  151. int PUBLIC AnsiToInt(
  152. LPCSTR pszString)
  153. {
  154. #define IS_DIGIT(ch) InRange(ch, '0', '9')
  155. int n;
  156. BOOL bNeg = FALSE;
  157. LPCSTR psz;
  158. LPCSTR pszAdj;
  159. // Skip leading whitespace
  160. //
  161. for (psz = pszString; *psz == ' ' || *psz == '\n' || *psz == '\t'; psz = AnsiNext(psz))
  162. ;
  163. // Determine possible explicit signage
  164. //
  165. if (*psz == '+' || *psz == '-')
  166. {
  167. bNeg = (*psz == '+') ? FALSE : TRUE;
  168. psz = AnsiNext(psz);
  169. }
  170. // Or is this hexadecimal?
  171. //
  172. pszAdj = AnsiNext(psz);
  173. if (*psz == '0' && (*pszAdj == 'x' || *pszAdj == 'X'))
  174. {
  175. bNeg = FALSE; // Never allow negative sign with hexadecimal numbers
  176. psz = AnsiNext(pszAdj);
  177. // Do the conversion
  178. //
  179. for (n = 0; ; psz = AnsiNext(psz))
  180. {
  181. if (IS_DIGIT(*psz))
  182. n = 0x10 * n + *psz - '0';
  183. else
  184. {
  185. char ch = *psz;
  186. int n2;
  187. if (ch >= 'a')
  188. ch -= 'a' - 'A';
  189. n2 = ch - 'A' + 0xA;
  190. if (n2 >= 0xA && n2 <= 0xF)
  191. n = 0x10 * n + n2;
  192. else
  193. break;
  194. }
  195. }
  196. }
  197. else
  198. {
  199. for (n = 0; IS_DIGIT(*psz); psz = AnsiNext(psz))
  200. n = 10 * n + *psz - '0';
  201. }
  202. return bNeg ? -n : n;
  203. }
  204. /*----------------------------------------------------------
  205. Purpose: Find first occurrence of character in string
  206. Returns: Pointer to the first occurrence of ch in
  207. Cond: --
  208. */
  209. LPSTR PUBLIC AnsiChr(
  210. LPCSTR psz,
  211. WORD wMatch)
  212. {
  213. for ( ; *psz; psz = AnsiNext(psz))
  214. {
  215. if (!ChrCmp(*(WORD FAR *)psz, wMatch))
  216. return (LPSTR)psz;
  217. }
  218. return NULL;
  219. }
  220. #endif // NOSTRING
  221. #ifndef NODIALOGHELPER
  222. /*----------------------------------------------------------
  223. Purpose: General front end to invoke dialog boxes
  224. Returns: result from EndDialog
  225. Cond: --
  226. */
  227. int PUBLIC DoModal(
  228. HWND hwndParent, // owner of dialog
  229. DLGPROC lpfnDlgProc, // dialog proc
  230. UINT uID, // dialog template ID
  231. LPARAM lParam) // extra parm to pass to dialog (may be NULL)
  232. {
  233. int nResult = -1;
  234. nResult = DialogBoxParam(g_hinst, MAKEINTRESOURCE(uID), hwndParent,
  235. lpfnDlgProc, lParam);
  236. return nResult;
  237. }
  238. /*----------------------------------------------------------
  239. Purpose: Sets the rectangle with the bounding extent of the given string.
  240. Returns: Rectangle
  241. Cond: --
  242. */
  243. void PUBLIC SetRectFromExtent(
  244. HDC hdc,
  245. LPRECT lprect,
  246. LPCSTR lpcsz)
  247. {
  248. SIZE size;
  249. GetTextExtentPoint(hdc, lpcsz, lstrlen(lpcsz), &size);
  250. SetRect(lprect, 0, 0, size.cx, size.cy);
  251. }
  252. #endif // NODIALOGHELPER
  253. #ifndef NODRAWTEXT
  254. #pragma data_seg(DATASEG_READONLY)
  255. char const FAR c_szEllipses[] = "...";
  256. #pragma data_seg()
  257. // Global variables
  258. int g_cxLabelMargin = 0;
  259. int g_cxBorder = 0;
  260. int g_cyBorder = 0;
  261. COLORREF g_clrHighlightText = 0;
  262. COLORREF g_clrHighlight = 0;
  263. COLORREF g_clrWindowText = 0;
  264. COLORREF g_clrWindow = 0;
  265. HBRUSH g_hbrHighlight = 0;
  266. HBRUSH g_hbrWindow = 0;
  267. /*----------------------------------------------------------
  268. Purpose: Get the system metrics we need
  269. Returns: --
  270. Cond: --
  271. */
  272. void PUBLIC GetCommonMetrics(
  273. WPARAM wParam) // wParam from WM_WININICHANGE
  274. {
  275. if ((wParam == 0) || (wParam == SPI_SETNONCLIENTMETRICS))
  276. {
  277. g_cxBorder = GetSystemMetrics(SM_CXBORDER);
  278. g_cyBorder = GetSystemMetrics(SM_CYBORDER);
  279. g_cxLabelMargin = (g_cxBorder * 2);
  280. }
  281. }
  282. /*----------------------------------------------------------
  283. Purpose: Sees whether the entire string will fit in *prc.
  284. If not, compute the numbder of chars that will fit
  285. (including ellipses). Returns length of string in
  286. *pcchDraw.
  287. Taken from COMMCTRL.
  288. Returns: TRUE if the string needed ellipses
  289. Cond: --
  290. */
  291. BOOL PRIVATE NeedsEllipses(
  292. HDC hdc,
  293. LPCSTR pszText,
  294. RECT * prc,
  295. int * pcchDraw,
  296. int cxEllipses)
  297. {
  298. int cchText;
  299. int cxRect;
  300. int ichMin, ichMax, ichMid;
  301. SIZE siz;
  302. cxRect = prc->right - prc->left;
  303. cchText = lstrlen(pszText);
  304. if (cchText == 0)
  305. {
  306. *pcchDraw = cchText;
  307. return FALSE;
  308. }
  309. GetTextExtentPoint(hdc, pszText, cchText, &siz);
  310. if (siz.cx <= cxRect)
  311. {
  312. *pcchDraw = cchText;
  313. return FALSE;
  314. }
  315. cxRect -= cxEllipses;
  316. // If no room for ellipses, always show first character.
  317. //
  318. ichMax = 1;
  319. if (cxRect > 0)
  320. {
  321. // Binary search to find character that will fit
  322. ichMin = 0;
  323. ichMax = cchText;
  324. while (ichMin < ichMax)
  325. {
  326. // Be sure to round up, to make sure we make progress in
  327. // the loop if ichMax == ichMin + 1.
  328. //
  329. ichMid = (ichMin + ichMax + 1) / 2;
  330. GetTextExtentPoint(hdc, &pszText[ichMin], ichMid - ichMin, &siz);
  331. if (siz.cx < cxRect)
  332. {
  333. ichMin = ichMid;
  334. cxRect -= siz.cx;
  335. }
  336. else if (siz.cx > cxRect)
  337. {
  338. ichMax = ichMid - 1;
  339. }
  340. else
  341. {
  342. // Exact match up up to ichMid: just exit.
  343. //
  344. ichMax = ichMid;
  345. break;
  346. }
  347. }
  348. // Make sure we always show at least the first character...
  349. //
  350. if (ichMax < 1)
  351. ichMax = 1;
  352. }
  353. *pcchDraw = ichMax;
  354. return TRUE;
  355. }
  356. #define CCHELLIPSES 3
  357. #define DT_LVWRAP (DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_EDITCONTROL)
  358. /*----------------------------------------------------------
  359. Purpose: Draws text the shell's way.
  360. Taken from COMMCTRL.
  361. Returns: --
  362. Cond: This function requires TRANSPARENT background mode
  363. and a properly selected font.
  364. */
  365. void PUBLIC MyDrawText(
  366. HDC hdc,
  367. LPCSTR pszText,
  368. RECT FAR* prc,
  369. UINT flags,
  370. int cyChar,
  371. int cxEllipses,
  372. COLORREF clrText,
  373. COLORREF clrTextBk)
  374. {
  375. int cchText;
  376. COLORREF clrSave;
  377. COLORREF clrSaveBk;
  378. UINT uETOFlags = 0;
  379. RECT rc;
  380. char ach[MAX_PATH + CCHELLIPSES];
  381. // REVIEW: Performance idea:
  382. // We could cache the currently selected text color
  383. // so we don't have to set and restore it each time
  384. // when the color is the same.
  385. //
  386. if (!pszText)
  387. return;
  388. rc = *prc;
  389. // If needed, add in a little extra margin...
  390. //
  391. if (IsFlagSet(flags, MDT_EXTRAMARGIN))
  392. {
  393. rc.left += g_cxLabelMargin * 3;
  394. rc.right -= g_cxLabelMargin * 3;
  395. }
  396. else
  397. {
  398. rc.left += g_cxLabelMargin;
  399. rc.right -= g_cxLabelMargin;
  400. }
  401. if (IsFlagSet(flags, MDT_ELLIPSES) &&
  402. NeedsEllipses(hdc, pszText, &rc, &cchText, cxEllipses))
  403. {
  404. hmemcpy(ach, pszText, cchText);
  405. lstrcpy(ach + cchText, c_szEllipses);
  406. pszText = ach;
  407. // Left-justify, in case there's no room for all of ellipses
  408. //
  409. ClearFlag(flags, (MDT_RIGHT | MDT_CENTER));
  410. SetFlag(flags, MDT_LEFT);
  411. cchText += CCHELLIPSES;
  412. }
  413. else
  414. {
  415. cchText = lstrlen(pszText);
  416. }
  417. if (IsFlagSet(flags, MDT_TRANSPARENT))
  418. {
  419. clrSave = SetTextColor(hdc, 0x000000);
  420. }
  421. else
  422. {
  423. uETOFlags |= ETO_OPAQUE;
  424. if (IsFlagSet(flags, MDT_SELECTED))
  425. {
  426. clrSave = SetTextColor(hdc, g_clrHighlightText);
  427. clrSaveBk = SetBkColor(hdc, g_clrHighlight);
  428. if (IsFlagSet(flags, MDT_DRAWTEXT))
  429. {
  430. FillRect(hdc, prc, g_hbrHighlight);
  431. }
  432. }
  433. else
  434. {
  435. if (clrText == CLR_DEFAULT && clrTextBk == CLR_DEFAULT)
  436. {
  437. clrSave = SetTextColor(hdc, g_clrWindowText);
  438. clrSaveBk = SetBkColor(hdc, g_clrWindow);
  439. if (IsFlagSet(flags, MDT_DRAWTEXT | MDT_DESELECTED))
  440. {
  441. FillRect(hdc, prc, g_hbrWindow);
  442. }
  443. }
  444. else
  445. {
  446. HBRUSH hbr;
  447. if (clrText == CLR_DEFAULT)
  448. clrText = g_clrWindowText;
  449. if (clrTextBk == CLR_DEFAULT)
  450. clrTextBk = g_clrWindow;
  451. clrSave = SetTextColor(hdc, clrText);
  452. clrSaveBk = SetBkColor(hdc, clrTextBk);
  453. if (IsFlagSet(flags, MDT_DRAWTEXT | MDT_DESELECTED))
  454. {
  455. hbr = CreateSolidBrush(GetNearestColor(hdc, clrTextBk));
  456. if (hbr)
  457. {
  458. FillRect(hdc, prc, hbr);
  459. DeleteObject(hbr);
  460. }
  461. else
  462. FillRect(hdc, prc, GetStockObject(WHITE_BRUSH));
  463. }
  464. }
  465. }
  466. }
  467. // If we want the item to display as if it was depressed, we will
  468. // offset the text rectangle down and to the left
  469. if (IsFlagSet(flags, MDT_DEPRESSED))
  470. OffsetRect(&rc, g_cxBorder, g_cyBorder);
  471. if (IsFlagSet(flags, MDT_DRAWTEXT))
  472. {
  473. UINT uDTFlags = DT_LVWRAP;
  474. if (IsFlagClear(flags, MDT_CLIPPED))
  475. uDTFlags |= DT_NOCLIP;
  476. DrawText(hdc, pszText, cchText, &rc, uDTFlags);
  477. }
  478. else
  479. {
  480. if (IsFlagClear(flags, MDT_LEFT))
  481. {
  482. SIZE siz;
  483. GetTextExtentPoint(hdc, pszText, cchText, &siz);
  484. if (IsFlagSet(flags, MDT_CENTER))
  485. rc.left = (rc.left + rc.right - siz.cx) / 2;
  486. else
  487. {
  488. ASSERT(IsFlagSet(flags, MDT_RIGHT));
  489. rc.left = rc.right - siz.cx;
  490. }
  491. }
  492. if (IsFlagSet(flags, MDT_VCENTER))
  493. {
  494. // Center vertically
  495. rc.top += (rc.bottom - rc.top - cyChar) / 2;
  496. }
  497. if (IsFlagSet(flags, MDT_CLIPPED))
  498. uETOFlags |= ETO_CLIPPED;
  499. ExtTextOut(hdc, rc.left, rc.top, uETOFlags, prc, pszText, cchText, NULL);
  500. }
  501. if (flags & (MDT_SELECTED | MDT_DESELECTED | MDT_TRANSPARENT))
  502. {
  503. SetTextColor(hdc, clrSave);
  504. if (IsFlagClear(flags, MDT_TRANSPARENT))
  505. SetBkColor(hdc, clrSaveBk);
  506. }
  507. }
  508. #endif // NODRAWTEXT
  509. #ifndef NOFILEINFO
  510. /*----------------------------------------------------------
  511. Purpose: Takes a DWORD value and converts it to a string, adding
  512. commas on the way.
  513. This was taken from the shell.
  514. Returns: Pointer to buffer
  515. Cond: --
  516. */
  517. LPSTR PRIVATE AddCommas(
  518. DWORD dw,
  519. LPSTR pszBuffer,
  520. UINT cbBuffer)
  521. {
  522. char szTemp[30];
  523. char szSep[5];
  524. NUMBERFMT nfmt;
  525. nfmt.NumDigits=0;
  526. nfmt.LeadingZero=0;
  527. GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, sizeof(szSep));
  528. nfmt.Grouping = AnsiToInt(szSep);
  529. GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, sizeof(szSep));
  530. nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
  531. nfmt.NegativeOrder= 0;
  532. wsprintf(szTemp, "%lu", dw);
  533. GetNumberFormatA(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszBuffer, cbBuffer);
  534. return pszBuffer;
  535. }
  536. const short s_rgidsOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB, IDS_ORDERGB, IDS_ORDERTB};
  537. /*----------------------------------------------------------
  538. Purpose: Converts a number into a short, string format.
  539. This code was taken from the shell.
  540. 532 -> 523 bytes
  541. 1340 -> 1.3KB
  542. 23506 -> 23.5KB
  543. -> 2.4MB
  544. -> 5.2GB
  545. Returns: pointer to buffer
  546. Cond: --
  547. */
  548. LPSTR PRIVATE ShortSizeFormat64(
  549. __int64 dw64,
  550. LPSTR szBuf)
  551. {
  552. int i;
  553. UINT wInt, wLen, wDec;
  554. char szTemp[10], szOrder[20], szFormat[5];
  555. if (dw64 < 1000)
  556. {
  557. wsprintf(szTemp, "%d", LODWORD(dw64));
  558. i = 0;
  559. goto AddOrder;
  560. }
  561. for (i = 1; i < ARRAY_ELEMENTS(s_rgidsOrders)-1 && dw64 >= 1000L * 1024L; dw64 >>= 10, i++);
  562. /* do nothing */
  563. wInt = LODWORD(dw64 >> 10);
  564. AddCommas(wInt, szTemp, sizeof(szTemp));
  565. wLen = lstrlen(szTemp);
  566. if (wLen < 3)
  567. {
  568. wDec = LODWORD(dw64 - (__int64)wInt * 1024L) * 1000 / 1024;
  569. // At this point, wDec should be between 0 and 1000
  570. // we want get the top one (or two) digits.
  571. wDec /= 10;
  572. if (wLen == 2)
  573. wDec /= 10;
  574. // Note that we need to set the format before getting the
  575. // intl char.
  576. lstrcpy(szFormat, "%02d");
  577. szFormat[2] = '0' + 3 - wLen;
  578. GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
  579. szTemp+wLen, sizeof(szTemp)-wLen);
  580. wLen = lstrlen(szTemp);
  581. wLen += wsprintf(szTemp+wLen, szFormat, wDec);
  582. }
  583. AddOrder:
  584. LoadString(g_hinst, s_rgidsOrders[i], szOrder, sizeof(szOrder));
  585. wsprintf(szBuf, szOrder, (LPSTR)szTemp);
  586. return szBuf;
  587. }
  588. /*----------------------------------------------------------
  589. Purpose: Converts a number into a short, string format.
  590. This code was taken from the shell.
  591. 532 -> 523 bytes
  592. 1340 -> 1.3KB
  593. 23506 -> 23.5KB
  594. -> 2.4MB
  595. -> 5.2GB
  596. Returns: pointer to buffer
  597. Cond: --
  598. */
  599. LPSTR PRIVATE ShortSizeFormat(DWORD dw, LPSTR szBuf)
  600. {
  601. return(ShortSizeFormat64((__int64)dw, szBuf));
  602. }
  603. /*----------------------------------------------------------
  604. Purpose: Gets the file info given a path. If the path refers
  605. to a directory, then simply the path field is filled.
  606. If himl != NULL, then the function will add the file's
  607. image to the provided image list and set the image index
  608. field in the *ppfi.
  609. Returns: standard hresult
  610. Cond: --
  611. */
  612. HRESULT PUBLIC FICreate(
  613. LPCSTR pszPath,
  614. FileInfo ** ppfi,
  615. UINT uFlags)
  616. {
  617. HRESULT hres = ResultFromScode(E_OUTOFMEMORY);
  618. int cchPath;
  619. SHFILEINFO sfi;
  620. UINT uInfoFlags = SHGFI_DISPLAYNAME | SHGFI_ATTRIBUTES;
  621. DWORD dwAttr;
  622. ASSERT(pszPath);
  623. ASSERT(ppfi);
  624. // Get shell file info
  625. if (IsFlagSet(uFlags, FIF_ICON))
  626. uInfoFlags |= SHGFI_ICON;
  627. if (IsFlagSet(uFlags, FIF_DONTTOUCH))
  628. {
  629. uInfoFlags |= SHGFI_USEFILEATTRIBUTES;
  630. // Today, FICreate is not called for folders, so this is ifdef'd out
  631. #ifdef SUPPORT_FOLDERS
  632. dwAttr = IsFlagSet(uFlags, FIF_FOLDER) ? FILE_ATTRIBUTE_DIRECTORY : 0;
  633. #else
  634. dwAttr = 0;
  635. #endif
  636. }
  637. else
  638. dwAttr = 0;
  639. if (SHGetFileInfo(pszPath, dwAttr, &sfi, sizeof(sfi), uInfoFlags))
  640. {
  641. // Allocate enough for the structure, plus buffer for the fully qualified
  642. // path and buffer for the display name (and extra null terminator).
  643. cchPath = lstrlen(pszPath);
  644. *ppfi = GAlloc(sizeof(FileInfo)+cchPath+1-sizeof((*ppfi)->szPath)+lstrlen(sfi.szDisplayName)+1);
  645. if (*ppfi)
  646. {
  647. FileInfo * pfi = *ppfi;
  648. pfi->pszDisplayName = pfi->szPath+cchPath+1;
  649. lstrcpy(pfi->pszDisplayName, sfi.szDisplayName);
  650. if (IsFlagSet(uFlags, FIF_ICON))
  651. pfi->hicon = sfi.hIcon;
  652. pfi->dwAttributes = sfi.dwAttributes;
  653. // Does the path refer to a directory?
  654. if (FIIsFolder(pfi))
  655. {
  656. // Yes; just fill in the path field
  657. lstrcpy(pfi->szPath, pszPath);
  658. hres = NOERROR;
  659. }
  660. else
  661. {
  662. // No; assume the file exists?
  663. if (IsFlagClear(uFlags, FIF_DONTTOUCH))
  664. {
  665. // Yes; get the time, date and size of the file
  666. HANDLE hfile = CreateFile(pszPath, GENERIC_READ,
  667. FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  668. NULL);
  669. if (hfile == INVALID_HANDLE_VALUE)
  670. {
  671. GFree(*ppfi);
  672. *ppfi = NULL;
  673. hres = ResultFromScode(E_HANDLE);
  674. }
  675. else
  676. {
  677. hres = NOERROR;
  678. lstrcpy(pfi->szPath, pszPath);
  679. pfi->dwSize = GetFileSize(hfile, NULL);
  680. GetFileTime(hfile, NULL, NULL, &pfi->ftMod);
  681. CloseHandle(hfile);
  682. }
  683. }
  684. else
  685. {
  686. // No; use what we have
  687. hres = NOERROR;
  688. lstrcpy(pfi->szPath, pszPath);
  689. }
  690. }
  691. }
  692. }
  693. else if (!WPPathExists(pszPath))
  694. {
  695. // Differentiate between out of memory and file not found
  696. hres = E_FAIL;
  697. }
  698. return hres;
  699. }
  700. /*----------------------------------------------------------
  701. Purpose: Get some file info of the given path.
  702. The returned string is of the format "# bytes <date>"
  703. If the path is a folder, the string is empty.
  704. Returns: FALSE if path is not found
  705. Cond: --
  706. */
  707. BOOL PUBLIC FIGetInfoString(
  708. FileInfo * pfi,
  709. LPSTR pszBuf,
  710. int cchBuf)
  711. {
  712. BOOL bRet;
  713. ASSERT(pfi);
  714. ASSERT(pszBuf);
  715. *pszBuf = NULL_CHAR;
  716. if (pfi)
  717. {
  718. // Is this a file?
  719. if ( !FIIsFolder(pfi) )
  720. {
  721. // Yes
  722. char szSize[MAX_BUF_MED];
  723. char szDate[MAX_BUF_MED];
  724. char szTime[MAX_BUF_MED];
  725. LPSTR pszMsg;
  726. SYSTEMTIME st;
  727. FILETIME ftLocal;
  728. // Construct the string
  729. FileTimeToLocalFileTime(&pfi->ftMod, &ftLocal);
  730. FileTimeToSystemTime(&ftLocal, &st);
  731. GetDateFormatA(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szDate, sizeof(szDate));
  732. GetTimeFormatA(LOCALE_USER_DEFAULT, 0, &st, NULL, szTime, sizeof(szTime));
  733. if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(IDS_DATESIZELINE),
  734. ShortSizeFormat(FIGetSize(pfi), szSize), szDate, szTime))
  735. {
  736. lstrcpy(pszBuf, pszMsg);
  737. GFree(pszMsg);
  738. }
  739. else
  740. *pszBuf = 0;
  741. bRet = TRUE;
  742. }
  743. else
  744. bRet = FALSE;
  745. }
  746. else
  747. bRet = FALSE;
  748. return bRet;
  749. }
  750. /*----------------------------------------------------------
  751. Purpose: Set the path entry. This can move the pfi.
  752. Returns: FALSE on out of memory
  753. Cond: --
  754. */
  755. BOOL PUBLIC FISetPath(
  756. FileInfo ** ppfi,
  757. LPCSTR pszPathNew,
  758. UINT uFlags)
  759. {
  760. ASSERT(ppfi);
  761. ASSERT(pszPathNew);
  762. FIFree(*ppfi);
  763. return SUCCEEDED(FICreate(pszPathNew, ppfi, uFlags));
  764. }
  765. /*----------------------------------------------------------
  766. Purpose: Free our file info struct
  767. Returns: --
  768. Cond: --
  769. */
  770. void PUBLIC FIFree(
  771. FileInfo * pfi)
  772. {
  773. if (pfi)
  774. {
  775. if (pfi->hicon)
  776. DestroyIcon(pfi->hicon);
  777. GFree(pfi); // This macro already checks for NULL pfi condition
  778. }
  779. }
  780. /*----------------------------------------------------------
  781. Purpose: Convert FILETIME struct to a readable string
  782. Returns: String
  783. Cond: --
  784. */
  785. void PUBLIC FileTimeToDateTimeString(
  786. LPFILETIME pft,
  787. LPSTR pszBuf,
  788. int cchBuf)
  789. {
  790. SYSTEMTIME st;
  791. FILETIME ftLocal;
  792. FileTimeToLocalFileTime(pft, &ftLocal);
  793. FileTimeToSystemTime(&ftLocal, &st);
  794. GetDateFormatA(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuf, cchBuf/2);
  795. pszBuf += lstrlen(pszBuf);
  796. *pszBuf++ = ' ';
  797. GetTimeFormatA(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszBuf, cchBuf/2);
  798. }
  799. #endif // NOFILEINFO
  800. #ifndef NOSYNC
  801. CRITICAL_SECTION g_csCommon = { 0 };
  802. DEBUG_CODE( UINT g_cRefCommonCS = 0; )
  803. /*----------------------------------------------------------
  804. Purpose: Waits for on object to signal. This function "does
  805. the right thing" to prevent deadlocks which can occur
  806. because the calculation thread calls SendMessage.
  807. Returns: value of MsgWaitForMultipleObjects
  808. Cond: --
  809. */
  810. DWORD PUBLIC MsgWaitObjectsSendMessage(
  811. DWORD cObjects,
  812. LPHANDLE phObjects,
  813. DWORD dwTimeout)
  814. {
  815. DWORD dwRet;
  816. while (TRUE)
  817. {
  818. dwRet = MsgWaitForMultipleObjects(cObjects, phObjects, FALSE,
  819. dwTimeout, QS_SENDMESSAGE);
  820. // If it is not a message, return
  821. if ((WAIT_OBJECT_0 + cObjects) != dwRet)
  822. {
  823. return dwRet;
  824. }
  825. else
  826. {
  827. // Process all the sent messages
  828. MSG msg;
  829. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  830. }
  831. }
  832. }
  833. /*----------------------------------------------------------
  834. Purpose: Initialize the critical section.
  835. Returns: --
  836. Cond: Note that critical sections differ between Win95
  837. and NT. On Win95, critical sections synchronize
  838. across processes. On NT, they are per-process.
  839. */
  840. void PUBLIC Common_InitExclusive(void)
  841. {
  842. ReinitializeCriticalSection(&g_csCommon);
  843. ASSERT(0 != *((LPDWORD)&g_csCommon));
  844. #ifdef DEBUG
  845. g_cRefCommonCS = 0;
  846. #endif
  847. }
  848. /*----------------------------------------------------------
  849. Purpose: Enter a critical section
  850. Returns: --
  851. Cond: Note that critical sections differ between Win95
  852. and NT. On Win95, critical sections synchronize
  853. across processes. On NT, they are per-process.
  854. */
  855. void PUBLIC Common_EnterExclusive(void)
  856. {
  857. EnterCriticalSection(&g_csCommon);
  858. #ifdef DEBUG
  859. g_cRefCommonCS++;
  860. #endif
  861. }
  862. /*----------------------------------------------------------
  863. Purpose: Leave a critical section
  864. Returns: --
  865. Cond: Note that critical sections differ between Win95
  866. and NT. On Win95, critical sections synchronize
  867. across processes. On NT, they are per-process.
  868. */
  869. void PUBLIC Common_LeaveExclusive(void)
  870. {
  871. #ifdef DEBUG
  872. g_cRefCommonCS--;
  873. #endif
  874. LeaveCriticalSection(&g_csCommon);
  875. }
  876. #endif // NOSYNC
  877. #ifndef NOMESSAGESTRING
  878. /*----------------------------------------------------------
  879. Purpose: Load the string (if necessary) and format the string
  880. properly.
  881. Returns: A pointer to the allocated string containing the formatted
  882. message or
  883. NULL if out of memory
  884. Cond: free pointer with LocalFree()
  885. */
  886. LPSTR PUBLIC ConstructVMessageString(
  887. HINSTANCE hinst,
  888. LPCSTR pszMsg,
  889. va_list *ArgList)
  890. {
  891. char szTemp[MAX_BUF];
  892. LPSTR pszRet;
  893. LPSTR pszRes;
  894. if (HIWORD(pszMsg))
  895. pszRes = (LPSTR)pszMsg;
  896. else if (LOWORD(pszMsg) && LoadString(hinst, LOWORD(pszMsg), szTemp, sizeof(szTemp)))
  897. pszRes = szTemp;
  898. else
  899. pszRes = NULL;
  900. if (pszRes)
  901. {
  902. if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  903. pszRes, 0, 0, (LPTSTR)&pszRet, 0, ArgList))
  904. {
  905. pszRet = NULL;
  906. }
  907. }
  908. else
  909. {
  910. // Bad parameter
  911. pszRet = NULL;
  912. }
  913. return pszRet; // free with LocalFree()
  914. }
  915. /*----------------------------------------------------------
  916. Purpose: Constructs a formatted string. The returned string
  917. must be freed using GFree().
  918. Returns: TRUE on success
  919. Cond: Free pointer with GFree()
  920. */
  921. BOOL PUBLIC ConstructMessage(
  922. LPSTR * ppsz,
  923. HINSTANCE hinst,
  924. LPCSTR pszMsg, ...)
  925. {
  926. BOOL bRet;
  927. LPSTR pszRet;
  928. va_list ArgList;
  929. va_start(ArgList, pszMsg);
  930. pszRet = ConstructVMessageString(hinst, pszMsg, &ArgList);
  931. va_end(ArgList);
  932. *ppsz = NULL;
  933. if (pszRet)
  934. {
  935. bRet = GSetString(ppsz, pszRet);
  936. LocalFree(pszRet);
  937. }
  938. else
  939. bRet = FALSE;
  940. return bRet;
  941. }
  942. /*----------------------------------------------------------
  943. Purpose: Invoke a message box.
  944. Returns: ID of button that terminated the dialog
  945. Cond: --
  946. */
  947. int PUBLIC MsgBox(
  948. HINSTANCE hinst,
  949. HWND hwndOwner,
  950. LPCSTR pszText,
  951. LPCSTR pszCaption,
  952. HICON hicon, // May be NULL
  953. DWORD dwStyle, ...)
  954. {
  955. int iRet = -1;
  956. int ids;
  957. char szCaption[MAX_BUF];
  958. LPSTR pszRet;
  959. va_list ArgList;
  960. va_start(ArgList, dwStyle);
  961. pszRet = ConstructVMessageString(hinst, pszText, &ArgList);
  962. va_end(ArgList);
  963. if (pszRet)
  964. {
  965. // Is pszCaption a resource ID?
  966. if (0 == HIWORD(pszCaption))
  967. {
  968. // Yes; load it
  969. ids = LOWORD(pszCaption);
  970. SzFromIDS(hinst, ids, szCaption, sizeof(szCaption));
  971. pszCaption = szCaption;
  972. }
  973. // Invoke dialog
  974. if (pszCaption)
  975. {
  976. MSGBOXPARAMS mbp;
  977. mbp.cbSize = sizeof(mbp);
  978. mbp.hwndOwner = hwndOwner;
  979. mbp.hInstance = hinst;
  980. mbp.lpszText = pszRet;
  981. mbp.lpszCaption = pszCaption;
  982. mbp.dwStyle = dwStyle | MB_SETFOREGROUND;
  983. mbp.lpszIcon = MAKEINTRESOURCE(hicon);
  984. mbp.lpfnMsgBoxCallback = NULL;
  985. mbp.dwLanguageId = LANG_NEUTRAL;
  986. iRet = MessageBoxIndirect(&mbp);
  987. }
  988. LocalFree(pszRet);
  989. }
  990. return iRet;
  991. }
  992. #endif // NOMESSAGESTRING
  993. #ifndef NODEBUGHELP
  994. #ifdef DEBUG
  995. // Globals
  996. DWORD g_dwBreakFlags = 0;
  997. DWORD g_dwDumpFlags = 0;
  998. DWORD g_dwTraceFlags = 0;
  999. #pragma data_seg(DATASEG_READONLY)
  1000. char const FAR c_szNewline[] = "\r\n";
  1001. char const FAR c_szTrace[] = "t " SZ_MODULE " ";
  1002. char const FAR c_szDbg[] = SZ_MODULE " ";
  1003. char const FAR c_szAssertFailed[] = SZ_MODULE " Assertion failed in %s on line %d\r\n";
  1004. #ifdef WANT_OLE_SUPPORT
  1005. struct _RIIDMAP
  1006. {
  1007. REFIID riid;
  1008. LPCSTR psz;
  1009. } const c_rgriidmap[] = {
  1010. { &IID_IUnknown, "IID_IUnknown" },
  1011. { &IID_IBriefcaseStg, "IID_IBriefcaseStg" },
  1012. { &IID_IEnumUnknown, "IID_IEnumUnknown" },
  1013. { &IID_IShellBrowser, "IID_IShellBrowser" },
  1014. { &IID_IShellView, "IID_IShellView" },
  1015. { &IID_IContextMenu, "IID_IContextMenu" },
  1016. { &IID_IShellFolder, "IID_IShellFolder" },
  1017. { &IID_IShellExtInit, "IID_IShellExtInit" },
  1018. { &IID_IShellPropSheetExt, "IID_IShellPropSheetExt" },
  1019. { &IID_IPersistFolder, "IID_IPersistFolder" },
  1020. { &IID_IExtractIcon, "IID_IExtractIcon" },
  1021. { &IID_IShellDetails, "IID_IShellDetails" },
  1022. { &IID_IDelayedRelease, "IID_IDelayedRelease" },
  1023. { &IID_IShellLink, "IID_IShellLink" },
  1024. };
  1025. #endif // WANT_OLE_SUPPORT
  1026. struct _SCODEMAP
  1027. {
  1028. SCODE sc;
  1029. LPCSTR psz;
  1030. } const c_rgscodemap[] = {
  1031. { S_OK, "S_OK" },
  1032. { S_FALSE, "S_FALSE" },
  1033. { E_UNEXPECTED, "E_UNEXPECTED" },
  1034. { E_NOTIMPL, "E_NOTIMPL" },
  1035. { E_OUTOFMEMORY, "E_OUTOFMEMORY" },
  1036. { E_INVALIDARG, "E_INVALIDARG" },
  1037. { E_NOINTERFACE, "E_NOINTERFACE" },
  1038. { E_POINTER, "E_POINTER" },
  1039. { E_HANDLE, "E_HANDLE" },
  1040. { E_ABORT, "E_ABORT" },
  1041. { E_FAIL, "E_FAIL" },
  1042. { E_ACCESSDENIED, "E_ACCESSDENIED" },
  1043. };
  1044. #pragma data_seg()
  1045. /*----------------------------------------------------------
  1046. Purpose: Return English reason for the debug break
  1047. Returns: String
  1048. Cond: --
  1049. */
  1050. LPCSTR PRIVATE GetReasonString(
  1051. DWORD flag) // One of BF_ flags
  1052. {
  1053. LPCSTR psz;
  1054. if (IsFlagSet(flag, BF_ONOPEN))
  1055. psz = "BREAK ON OPEN\r\n";
  1056. else if (IsFlagSet(flag, BF_ONCLOSE))
  1057. psz = "BREAK ON CLOSE\r\n";
  1058. else if (IsFlagSet(flag, BF_ONVALIDATE))
  1059. psz = "BREAK ON VALIDATION FAILURE\r\n";
  1060. else if (IsFlagSet(flag, BF_ONTHREADATT))
  1061. psz = "BREAK ON THREAD ATTACH\r\n";
  1062. else if (IsFlagSet(flag, BF_ONTHREADDET))
  1063. psz = "BREAK ON THREAD DETACH\r\n";
  1064. else if (IsFlagSet(flag, BF_ONPROCESSATT))
  1065. psz = "BREAK ON PROCESS ATTACH\r\n";
  1066. else if (IsFlagSet(flag, BF_ONPROCESSDET))
  1067. psz = "BREAK ON PROCESS DETACH\r\n";
  1068. else
  1069. psz = c_szNewline;
  1070. return psz;
  1071. }
  1072. /*----------------------------------------------------------
  1073. Purpose: Perform a debug break based on the flag
  1074. Returns: --
  1075. Cond: --
  1076. */
  1077. void PUBLIC CommonDebugBreak(
  1078. DWORD flag) // One of BF_ flags
  1079. {
  1080. if (IsFlagSet(g_dwBreakFlags, flag))
  1081. {
  1082. TRACE_MSG(TF_ALWAYS, GetReasonString(flag));
  1083. DebugBreak();
  1084. }
  1085. }
  1086. /*----------------------------------------------------------
  1087. Purpose: Assert failed
  1088. Returns: --
  1089. Cond: --
  1090. */
  1091. void PUBLIC CommonAssertFailed(
  1092. LPCSTR pszFile,
  1093. int line)
  1094. {
  1095. LPCSTR psz;
  1096. char ach[256];
  1097. // Strip off path info from filename string, if present.
  1098. //
  1099. for (psz = pszFile + lstrlen(pszFile); psz != pszFile; psz=AnsiPrev(pszFile, psz))
  1100. {
  1101. #ifdef DBCS
  1102. if ((AnsiPrev(pszFile, psz) != (psz-2)) && *(psz - 1) == '\\')
  1103. #else
  1104. if (*(psz - 1) == '\\')
  1105. #endif
  1106. break;
  1107. }
  1108. wsprintf(ach, c_szAssertFailed, psz, line);
  1109. OutputDebugString(ach);
  1110. if (IsFlagSet(g_dwBreakFlags, BF_ONVALIDATE))
  1111. DebugBreak();
  1112. }
  1113. /*----------------------------------------------------------
  1114. Purpose: Assert failed message only
  1115. Returns: --
  1116. Cond: --
  1117. */
  1118. void CPUBLIC CommonAssertMsg(
  1119. BOOL f,
  1120. LPCSTR pszMsg, ...)
  1121. {
  1122. char ach[MAX_PATH+40]; // Largest path plus extra
  1123. if (!f)
  1124. {
  1125. lstrcpy(ach, c_szTrace);
  1126. wvsprintf(&ach[sizeof(c_szTrace)-1], pszMsg, (va_list)(&pszMsg + 1));
  1127. OutputDebugString(ach);
  1128. OutputDebugString(c_szNewline);
  1129. }
  1130. }
  1131. /*----------------------------------------------------------
  1132. Purpose: Debug spew
  1133. Returns: --
  1134. Cond: --
  1135. */
  1136. void CPUBLIC CommonDebugMsg(
  1137. DWORD flag,
  1138. LPCSTR pszMsg, ...)
  1139. {
  1140. char ach[MAX_PATH+40]; // Largest path plus extra
  1141. if (TF_ALWAYS == flag || IsFlagSet(g_dwTraceFlags, flag))
  1142. {
  1143. lstrcpy(ach, c_szTrace);
  1144. wvsprintf(&ach[sizeof(c_szTrace)-1], pszMsg, (va_list)(&pszMsg + 1));
  1145. OutputDebugString(ach);
  1146. OutputDebugString(c_szNewline);
  1147. }
  1148. }
  1149. #ifdef WANT_OLE_SUPPORT
  1150. /*----------------------------------------------------------
  1151. Purpose: Returns the string form of an known interface ID.
  1152. Returns: String ptr
  1153. Cond: --
  1154. */
  1155. LPCSTR PUBLIC Dbg_GetRiidName(
  1156. REFIID riid)
  1157. {
  1158. int i;
  1159. for (i = 0; i < ARRAY_ELEMENTS(c_rgriidmap); i++)
  1160. {
  1161. if (IsEqualIID(riid, c_rgriidmap[i].riid))
  1162. return c_rgriidmap[i].psz;
  1163. }
  1164. return "Unknown riid";
  1165. }
  1166. #endif
  1167. /*----------------------------------------------------------
  1168. Purpose: Returns the string form of an scode given an hresult.
  1169. Returns: String ptr
  1170. Cond: --
  1171. */
  1172. LPCSTR PUBLIC Dbg_GetScode(
  1173. HRESULT hres)
  1174. {
  1175. int i;
  1176. SCODE sc;
  1177. sc = GetScode(hres);
  1178. for (i = 0; i < ARRAY_ELEMENTS(c_rgscodemap); i++)
  1179. {
  1180. if (sc == c_rgscodemap[i].sc)
  1181. return c_rgscodemap[i].psz;
  1182. }
  1183. return "Unknown scode";
  1184. }
  1185. /*----------------------------------------------------------
  1186. Purpose: Returns a string safe enough to print...and I don't
  1187. mean swear words.
  1188. Returns: String ptr
  1189. Cond: --
  1190. */
  1191. LPCSTR PUBLIC Dbg_SafeStr(
  1192. LPCSTR psz)
  1193. {
  1194. if (psz)
  1195. return psz;
  1196. else
  1197. return "NULL";
  1198. }
  1199. #endif // DEBUG
  1200. #endif // NODEBUGHELP