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.

1088 lines
27 KiB

  1. //---------------------------------------------------------------------------
  2. //
  3. // Copyright (c) Microsoft Corporation 1993-1994
  4. //
  5. // File: comm.c
  6. //
  7. // This files contains all common utility routines
  8. //
  9. // History:
  10. // 08-06-93 ScottH Transferred from twin code
  11. //
  12. //---------------------------------------------------------------------------
  13. ///////////////////////////////////////////////////// INCLUDES
  14. #include "brfprv.h" // common s
  15. #include "res.h"
  16. // Some of these are replacements for the C runtime routines.
  17. // This is so we don't have to link to the CRT libs.
  18. //
  19. /*----------------------------------------------------------
  20. Purpose: memset
  21. Swiped from the C 7.0 runtime sources.
  22. Returns:
  23. Cond:
  24. */
  25. CHAR * PUBLIC lmemset( // DO NO UNICODIZE
  26. CHAR * dst,
  27. CHAR val,
  28. UINT count)
  29. {
  30. CHAR * start = dst;
  31. while (count--)
  32. *dst++ = val;
  33. return(start);
  34. }
  35. /*----------------------------------------------------------
  36. Purpose: memmove
  37. Swiped from the C 7.0 runtime sources.
  38. Returns:
  39. Cond:
  40. */
  41. CHAR * PUBLIC lmemmove(
  42. CHAR * dst,
  43. CHAR * src,
  44. int count)
  45. {
  46. CHAR * ret = dst;
  47. if (dst <= src || dst >= (src + count)) {
  48. /*
  49. * Non-Overlapping Buffers
  50. * copy from lower addresses to higher addresses
  51. */
  52. while (count--)
  53. *dst++ = *src++;
  54. }
  55. else {
  56. /*
  57. * Overlapping Buffers
  58. * copy from higher addresses to lower addresses
  59. */
  60. dst += count - 1;
  61. src += count - 1;
  62. while (count--)
  63. *dst-- = *src--;
  64. }
  65. return(ret);
  66. }
  67. /*----------------------------------------------------------
  68. Purpose: My verion of atoi. Supports hexadecimal too.
  69. Returns: integer
  70. Cond: --
  71. */
  72. int PUBLIC AnsiToInt(
  73. LPCTSTR pszString)
  74. {
  75. int n;
  76. BOOL bNeg = FALSE;
  77. LPCTSTR psz;
  78. LPCTSTR pszAdj;
  79. // Skip leading whitespace
  80. //
  81. for (psz = pszString; *psz == TEXT(' ') || *psz == TEXT('\n') || *psz == TEXT('\t'); psz = CharNext(psz))
  82. ;
  83. // Determine possible explicit signage
  84. //
  85. if (*psz == TEXT('+') || *psz == TEXT('-'))
  86. {
  87. bNeg = (*psz == TEXT('+')) ? FALSE : TRUE;
  88. psz = CharNext(psz);
  89. }
  90. // Or is this hexadecimal?
  91. //
  92. pszAdj = CharNext(psz);
  93. if (*psz == TEXT('0') && (*pszAdj == TEXT('x') || *pszAdj == TEXT('X')))
  94. {
  95. bNeg = FALSE; // Never allow negative sign with hexadecimal numbers
  96. psz = CharNext(pszAdj);
  97. // Do the conversion
  98. //
  99. for (n = 0; ; psz = CharNext(psz))
  100. {
  101. if (*psz >= TEXT('0') && *psz <= TEXT('9'))
  102. n = 0x10 * n + *psz - TEXT('0');
  103. else
  104. {
  105. TCHAR ch = *psz;
  106. int n2;
  107. if (ch >= TEXT('a'))
  108. ch -= TEXT('a') - TEXT('A');
  109. n2 = ch - TEXT('A') + 0xA;
  110. if (n2 >= 0xA && n2 <= 0xF)
  111. n = 0x10 * n + n2;
  112. else
  113. break;
  114. }
  115. }
  116. }
  117. else
  118. {
  119. for (n = 0; *psz >= TEXT('0') && *psz <= TEXT('9'); psz = CharNext(psz))
  120. n = 10 * n + *psz - TEXT('0');
  121. }
  122. return bNeg ? -n : n;
  123. }
  124. /*----------------------------------------------------------
  125. Purpose: General front end to invoke dialog boxes
  126. Returns: result from EndDialog
  127. Cond: --
  128. */
  129. INT_PTR PUBLIC DoModal(
  130. HWND hwndParent, // owner of dialog
  131. DLGPROC lpfnDlgProc, // dialog proc
  132. UINT uID, // dialog template ID
  133. LPARAM lParam) // extra parm to pass to dialog (may be NULL)
  134. {
  135. INT_PTR nResult = -1;
  136. nResult = DialogBoxParam(g_hinst, MAKEINTRESOURCE(uID), hwndParent,
  137. lpfnDlgProc, lParam);
  138. return nResult;
  139. }
  140. /*----------------------------------------------------------
  141. Purpose: Sets the rectangle with the bounding extent of the given string.
  142. Returns: Rectangle
  143. Cond: --
  144. */
  145. void PUBLIC SetRectFromExtent(
  146. HDC hdc,
  147. LPRECT lprect,
  148. LPCTSTR lpcsz)
  149. {
  150. SIZE size;
  151. GetTextExtentPoint(hdc, lpcsz, lstrlen(lpcsz), &size);
  152. SetRect(lprect, 0, 0, size.cx, size.cy);
  153. }
  154. /*----------------------------------------------------------
  155. Purpose: Sees whether the entire string will fit in *prc.
  156. If not, compute the numbder of chars that will fit
  157. (including ellipses). Returns length of string in
  158. *pcchDraw.
  159. Taken from COMMCTRL.
  160. Returns: TRUE if the string needed ellipses
  161. Cond: --
  162. */
  163. BOOL PRIVATE NeedsEllipses(
  164. HDC hdc,
  165. LPCTSTR pszText,
  166. RECT * prc,
  167. int * pcchDraw,
  168. int cxEllipses)
  169. {
  170. int cchText;
  171. int cxRect;
  172. int ichMin, ichMax, ichMid;
  173. SIZE siz;
  174. cxRect = prc->right - prc->left;
  175. cchText = lstrlen(pszText);
  176. if (cchText == 0)
  177. {
  178. *pcchDraw = cchText;
  179. return FALSE;
  180. }
  181. GetTextExtentPoint(hdc, pszText, cchText, &siz);
  182. if (siz.cx <= cxRect)
  183. {
  184. *pcchDraw = cchText;
  185. return FALSE;
  186. }
  187. cxRect -= cxEllipses;
  188. // If no room for ellipses, always show first character.
  189. //
  190. ichMax = 1;
  191. if (cxRect > 0)
  192. {
  193. // Binary search to find character that will fit
  194. ichMin = 0;
  195. ichMax = cchText;
  196. while (ichMin < ichMax)
  197. {
  198. // Be sure to round up, to make sure we make progress in
  199. // the loop if ichMax == ichMin + 1.
  200. //
  201. ichMid = (ichMin + ichMax + 1) / 2;
  202. GetTextExtentPoint(hdc, &pszText[ichMin], ichMid - ichMin, &siz);
  203. if (siz.cx < cxRect)
  204. {
  205. ichMin = ichMid;
  206. cxRect -= siz.cx;
  207. }
  208. else if (siz.cx > cxRect)
  209. {
  210. ichMax = ichMid - 1;
  211. }
  212. else
  213. {
  214. // Exact match up up to ichMid: just exit.
  215. //
  216. ichMax = ichMid;
  217. break;
  218. }
  219. }
  220. // Make sure we always show at least the first character...
  221. //
  222. if (ichMax < 1)
  223. ichMax = 1;
  224. }
  225. *pcchDraw = ichMax;
  226. return TRUE;
  227. }
  228. #define CCHELLIPSES 3
  229. #define DT_LVWRAP (DT_CENTER | DT_WORDBREAK | DT_NOPREFIX | DT_EDITCONTROL)
  230. /*----------------------------------------------------------
  231. Purpose: Draws text the shell's way.
  232. Taken from COMMCTRL.
  233. Returns: --
  234. Cond: This function requires TRANSPARENT background mode
  235. and a properly selected font.
  236. */
  237. void PUBLIC MyDrawText(
  238. HDC hdc,
  239. LPCTSTR pszText,
  240. RECT * prc,
  241. UINT flags,
  242. int cyChar,
  243. int cxEllipses,
  244. COLORREF clrText,
  245. COLORREF clrTextBk)
  246. {
  247. int cchText;
  248. COLORREF clrSave;
  249. COLORREF clrSaveBk;
  250. UINT uETOFlags = 0;
  251. RECT rc;
  252. TCHAR ach[MAX_PATH + CCHELLIPSES];
  253. // REVIEW: Performance idea:
  254. // We could cache the currently selected text color
  255. // so we don't have to set and restore it each time
  256. // when the color is the same.
  257. //
  258. if (!pszText)
  259. return;
  260. rc = *prc;
  261. // If needed, add in a little extra margin...
  262. //
  263. if (IsFlagSet(flags, MDT_EXTRAMARGIN))
  264. {
  265. rc.left += g_cxLabelMargin * 3;
  266. rc.right -= g_cxLabelMargin * 3;
  267. }
  268. else
  269. {
  270. rc.left += g_cxLabelMargin;
  271. rc.right -= g_cxLabelMargin;
  272. }
  273. if (IsFlagSet(flags, MDT_ELLIPSES) &&
  274. NeedsEllipses(hdc, pszText, &rc, &cchText, cxEllipses))
  275. {
  276. hmemcpy(ach, pszText, cchText * sizeof(TCHAR));
  277. lstrcpyn(ach + cchText, c_szEllipses, ARRAYSIZE(ach) - cchText);
  278. pszText = ach;
  279. // Left-justify, in case there's no room for all of ellipses
  280. //
  281. ClearFlag(flags, (MDT_RIGHT | MDT_CENTER));
  282. SetFlag(flags, MDT_LEFT);
  283. cchText += CCHELLIPSES;
  284. }
  285. else
  286. {
  287. cchText = lstrlen(pszText);
  288. }
  289. if (IsFlagSet(flags, MDT_TRANSPARENT))
  290. {
  291. clrSave = SetTextColor(hdc, 0x000000);
  292. }
  293. else
  294. {
  295. uETOFlags |= ETO_OPAQUE;
  296. if (IsFlagSet(flags, MDT_SELECTED))
  297. {
  298. clrSave = SetTextColor(hdc, g_clrHighlightText);
  299. clrSaveBk = SetBkColor(hdc, g_clrHighlight);
  300. if (IsFlagSet(flags, MDT_DRAWTEXT))
  301. {
  302. FillRect(hdc, prc, g_hbrHighlight);
  303. }
  304. }
  305. else
  306. {
  307. if (clrText == CLR_DEFAULT && clrTextBk == CLR_DEFAULT)
  308. {
  309. clrSave = SetTextColor(hdc, g_clrWindowText);
  310. clrSaveBk = SetBkColor(hdc, g_clrWindow);
  311. if (IsFlagSet(flags, MDT_DRAWTEXT | MDT_DESELECTED))
  312. {
  313. FillRect(hdc, prc, g_hbrWindow);
  314. }
  315. }
  316. else
  317. {
  318. HBRUSH hbr;
  319. if (clrText == CLR_DEFAULT)
  320. clrText = g_clrWindowText;
  321. if (clrTextBk == CLR_DEFAULT)
  322. clrTextBk = g_clrWindow;
  323. clrSave = SetTextColor(hdc, clrText);
  324. clrSaveBk = SetBkColor(hdc, clrTextBk);
  325. if (IsFlagSet(flags, MDT_DRAWTEXT | MDT_DESELECTED))
  326. {
  327. hbr = CreateSolidBrush(GetNearestColor(hdc, clrTextBk));
  328. if (hbr)
  329. {
  330. FillRect(hdc, prc, hbr);
  331. DeleteObject(hbr);
  332. }
  333. else
  334. FillRect(hdc, prc, GetStockObject(WHITE_BRUSH));
  335. }
  336. }
  337. }
  338. }
  339. // If we want the item to display as if it was depressed, we will
  340. // offset the text rectangle down and to the left
  341. if (IsFlagSet(flags, MDT_DEPRESSED))
  342. OffsetRect(&rc, g_cxBorder, g_cyBorder);
  343. if (IsFlagSet(flags, MDT_DRAWTEXT))
  344. {
  345. UINT uDTFlags = DT_LVWRAP;
  346. if (IsFlagClear(flags, MDT_CLIPPED))
  347. uDTFlags |= DT_NOCLIP;
  348. DrawText(hdc, pszText, cchText, &rc, uDTFlags);
  349. }
  350. else
  351. {
  352. if (IsFlagClear(flags, MDT_LEFT))
  353. {
  354. SIZE siz;
  355. GetTextExtentPoint(hdc, pszText, cchText, &siz);
  356. if (IsFlagSet(flags, MDT_CENTER))
  357. rc.left = (rc.left + rc.right - siz.cx) / 2;
  358. else
  359. {
  360. ASSERT(IsFlagSet(flags, MDT_RIGHT));
  361. rc.left = rc.right - siz.cx;
  362. }
  363. }
  364. if (IsFlagSet(flags, MDT_VCENTER))
  365. {
  366. // Center vertically
  367. rc.top += (rc.bottom - rc.top - cyChar) / 2;
  368. }
  369. if (IsFlagSet(flags, MDT_CLIPPED))
  370. uETOFlags |= ETO_CLIPPED;
  371. ExtTextOut(hdc, rc.left, rc.top, uETOFlags, prc, pszText, cchText, NULL);
  372. }
  373. if (flags & (MDT_SELECTED | MDT_DESELECTED | MDT_TRANSPARENT))
  374. {
  375. SetTextColor(hdc, clrSave);
  376. if (IsFlagClear(flags, MDT_TRANSPARENT))
  377. SetBkColor(hdc, clrSaveBk);
  378. }
  379. }
  380. /*----------------------------------------------------------
  381. Purpose: Takes a DWORD value and converts it to a string, adding
  382. commas on the way.
  383. This was taken from the shell.
  384. Returns: Pointer to buffer
  385. Cond: --
  386. */
  387. // REARCHITECT The shell has an AddCommas. Can it be used instead?
  388. LPTSTR PRIVATE BrfAddCommas(
  389. DWORD dw,
  390. LPTSTR pszBuffer,
  391. UINT cbBuffer)
  392. {
  393. TCHAR szTemp[30];
  394. TCHAR szSep[5];
  395. NUMBERFMT nfmt;
  396. nfmt.NumDigits=0;
  397. nfmt.LeadingZero=0;
  398. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SGROUPING, szSep, ARRAYSIZE(szSep));
  399. nfmt.Grouping = StrToInt(szSep);
  400. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STHOUSAND, szSep, ARRAYSIZE(szSep));
  401. nfmt.lpDecimalSep = nfmt.lpThousandSep = szSep;
  402. nfmt.NegativeOrder= 0;
  403. wnsprintf(szTemp, ARRAYSIZE(szTemp), TEXT("%lu"), dw);
  404. GetNumberFormat(LOCALE_USER_DEFAULT, 0, szTemp, &nfmt, pszBuffer, cbBuffer);
  405. return pszBuffer;
  406. }
  407. const short s_rgidsOrders[] = {IDS_BYTES, IDS_ORDERKB, IDS_ORDERMB, IDS_ORDERGB, IDS_ORDERTB};
  408. // REARCHITECT This is in the shell too, isn't it?
  409. /*----------------------------------------------------------
  410. Purpose: Converts a number into a short, string format.
  411. This code was taken from the shell.
  412. 532 -> 523 bytes
  413. 1340 -> 1.3KB
  414. 23506 -> 23.5KB
  415. -> 2.4MB
  416. -> 5.2GB
  417. Returns: pointer to buffer
  418. Cond: --
  419. */
  420. LPTSTR PRIVATE ShortSizeFormat64(
  421. __int64 dw64,
  422. LPTSTR pszBuf,
  423. UINT cchMax)
  424. {
  425. int i;
  426. UINT wInt, wLen, wDec;
  427. TCHAR szTemp[10], szOrder[20], szFormat[5];
  428. if (dw64 < 1000)
  429. {
  430. wnsprintf(szTemp, ARRAYSIZE(szTemp), TEXT("%d"), LODWORD(dw64));
  431. i = 0;
  432. goto AddOrder;
  433. }
  434. for (i = 1; i<ARRAYSIZE(s_rgidsOrders)-1 && dw64 >= 1000L * 1024L; dw64 >>= 10, i++);
  435. /* do nothing */
  436. wInt = LODWORD(dw64 >> 10);
  437. BrfAddCommas(wInt, szTemp, ARRAYSIZE(szTemp));
  438. wLen = lstrlen(szTemp);
  439. if (wLen < 3)
  440. {
  441. wDec = LODWORD(dw64 - (__int64)wInt * 1024L) * 1000 / 1024;
  442. // At this point, wDec should be between 0 and 1000
  443. // we want get the top one (or two) digits.
  444. wDec /= 10;
  445. if (wLen == 2)
  446. wDec /= 10;
  447. // Note that we need to set the format before getting the
  448. // intl char.
  449. lstrcpyn(szFormat, TEXT("%02d"), ARRAYSIZE(szFormat));
  450. szFormat[2] = TEXT('0') + 3 - wLen;
  451. GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SDECIMAL,
  452. szTemp+wLen, ARRAYSIZE(szTemp)-wLen);
  453. wLen = lstrlen(szTemp);
  454. wLen += wnsprintf(szTemp+wLen, ARRAYSIZE(szTemp) - wLen, szFormat, wDec);
  455. }
  456. AddOrder:
  457. LoadString(g_hinst, s_rgidsOrders[i], szOrder, ARRAYSIZE(szOrder));
  458. wnsprintf(pszBuf, cchMax, szOrder, (LPTSTR)szTemp);
  459. return pszBuf;
  460. }
  461. /*----------------------------------------------------------
  462. Purpose: Converts a number into a short, string format.
  463. This code was taken from the shell.
  464. 532 -> 523 bytes
  465. 1340 -> 1.3KB
  466. 23506 -> 23.5KB
  467. -> 2.4MB
  468. -> 5.2GB
  469. Returns: pointer to buffer
  470. Cond: --
  471. */
  472. LPTSTR PRIVATE ShortSizeFormatPriv(DWORD dw, LPTSTR pszBuf, int cchMax)
  473. {
  474. return(ShortSizeFormat64((__int64)dw, pszBuf, cchMax));
  475. }
  476. /*----------------------------------------------------------
  477. Purpose: Gets the file info given a path. If the path refers
  478. to a directory, then simply the path field is filled.
  479. If himl != NULL, then the function will add the file's
  480. image to the provided image list and set the image index
  481. field in the *ppfi.
  482. Returns: standard hresult
  483. Cond: --
  484. */
  485. HRESULT PUBLIC FICreate(
  486. LPCTSTR pszPath,
  487. FileInfo ** ppfi,
  488. UINT uFlags)
  489. {
  490. HRESULT hres = ResultFromScode(E_OUTOFMEMORY);
  491. int cchPath;
  492. SHFILEINFO sfi;
  493. UINT uInfoFlags = SHGFI_DISPLAYNAME | SHGFI_ATTRIBUTES;
  494. DWORD dwAttr;
  495. ASSERT(pszPath);
  496. ASSERT(ppfi);
  497. // Get shell file info
  498. if (IsFlagSet(uFlags, FIF_ICON))
  499. uInfoFlags |= SHGFI_ICON;
  500. if (IsFlagSet(uFlags, FIF_DONTTOUCH))
  501. {
  502. uInfoFlags |= SHGFI_USEFILEATTRIBUTES;
  503. // Today, FICreate is not called for folders, so this is ifdef'd out
  504. #ifdef SUPPORT_FOLDERS
  505. dwAttr = IsFlagSet(uFlags, FIF_FOLDER) ? FILE_ATTRIBUTE_DIRECTORY : 0;
  506. #else
  507. dwAttr = 0;
  508. #endif
  509. }
  510. else
  511. dwAttr = 0;
  512. if (SHGetFileInfo(pszPath, dwAttr, &sfi, sizeof(sfi), uInfoFlags))
  513. {
  514. // Allocate enough for the structure, plus buffer for the fully qualified
  515. // path and buffer for the display name (and extra null terminator).
  516. cchPath = lstrlen(pszPath);
  517. *ppfi = GAlloc(sizeof(FileInfo) +
  518. (cchPath+1) * sizeof(TCHAR) -
  519. sizeof((*ppfi)->szPath) +
  520. (lstrlen(sfi.szDisplayName)+1) * sizeof(TCHAR));
  521. if (*ppfi)
  522. {
  523. FileInfo * pfi = *ppfi;
  524. // lstrcpy: Enough memory is allocated above so no need for
  525. // bounded copy
  526. pfi->pszDisplayName = pfi->szPath+cchPath+1;
  527. lstrcpy(pfi->pszDisplayName, sfi.szDisplayName);
  528. if (IsFlagSet(uFlags, FIF_ICON))
  529. pfi->hicon = sfi.hIcon;
  530. pfi->dwAttributes = sfi.dwAttributes;
  531. // Does the path refer to a directory?
  532. if (FIIsFolder(pfi))
  533. {
  534. // Yes; just fill in the path field
  535. lstrcpy(pfi->szPath, pszPath);
  536. hres = NOERROR;
  537. }
  538. else
  539. {
  540. // No; assume the file exists?
  541. if (IsFlagClear(uFlags, FIF_DONTTOUCH))
  542. {
  543. // Yes; get the time, date and size of the file
  544. HANDLE hfile = CreateFile(pszPath, GENERIC_READ,
  545. FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  546. NULL);
  547. if (hfile == INVALID_HANDLE_VALUE)
  548. {
  549. GFree(*ppfi);
  550. hres = ResultFromScode(E_HANDLE);
  551. }
  552. else
  553. {
  554. hres = NOERROR;
  555. lstrcpy(pfi->szPath, pszPath);
  556. pfi->dwSize = GetFileSize(hfile, NULL);
  557. GetFileTime(hfile, NULL, NULL, &pfi->ftMod);
  558. CloseHandle(hfile);
  559. }
  560. }
  561. else
  562. {
  563. // No; use what we have
  564. hres = NOERROR;
  565. lstrcpy(pfi->szPath, pszPath);
  566. }
  567. }
  568. }
  569. }
  570. else if (!PathExists(pszPath))
  571. {
  572. // Differentiate between out of memory and file not found
  573. hres = E_FAIL;
  574. }
  575. return hres;
  576. }
  577. /*----------------------------------------------------------
  578. Purpose: Get some file info of the given path.
  579. The returned string is of the format "# bytes <date>"
  580. If the path is a folder, the string is empty.
  581. Returns: FALSE if path is not found
  582. Cond: --
  583. */
  584. BOOL PUBLIC FIGetInfoString(
  585. FileInfo * pfi,
  586. LPTSTR pszBuf,
  587. int cchBuf)
  588. {
  589. BOOL bRet;
  590. ASSERT(pfi);
  591. ASSERT(pszBuf);
  592. *pszBuf = NULL_CHAR;
  593. if (pfi)
  594. {
  595. // Is this a file?
  596. if ( !FIIsFolder(pfi) )
  597. {
  598. // Yes
  599. TCHAR szSize[MAXMEDLEN];
  600. TCHAR szDate[MAXMEDLEN];
  601. TCHAR szTime[MAXMEDLEN];
  602. LPTSTR pszMsg;
  603. SYSTEMTIME st;
  604. FILETIME ftLocal;
  605. // Construct the string
  606. FileTimeToLocalFileTime(&pfi->ftMod, &ftLocal);
  607. FileTimeToSystemTime(&ftLocal, &st);
  608. GetDateFormat(LOCALE_USER_DEFAULT, DATE_LONGDATE, &st, NULL, szDate, ARRAYSIZE(szDate));
  609. GetTimeFormat(LOCALE_USER_DEFAULT, 0, &st, NULL, szTime, ARRAYSIZE(szTime));
  610. if (ConstructMessage(&pszMsg, g_hinst, MAKEINTRESOURCE(IDS_DATESIZELINE),
  611. ShortSizeFormatPriv(FIGetSize(pfi), szSize, ARRAYSIZE(szSize)), szDate, szTime))
  612. {
  613. lstrcpyn(pszBuf, pszMsg, cchBuf);
  614. GFree(pszMsg);
  615. }
  616. else
  617. *pszBuf = 0;
  618. bRet = TRUE;
  619. }
  620. else
  621. bRet = FALSE;
  622. }
  623. else
  624. bRet = FALSE;
  625. return bRet;
  626. }
  627. /*----------------------------------------------------------
  628. Purpose: Set the path entry. This can move the pfi.
  629. Returns: FALSE on out of memory
  630. Cond: --
  631. */
  632. BOOL PUBLIC FISetPath(
  633. FileInfo ** ppfi,
  634. LPCTSTR pszPathNew,
  635. UINT uFlags)
  636. {
  637. ASSERT(ppfi);
  638. ASSERT(pszPathNew);
  639. FIFree(*ppfi);
  640. return SUCCEEDED(FICreate(pszPathNew, ppfi, uFlags));
  641. }
  642. /*----------------------------------------------------------
  643. Purpose: Free our file info struct
  644. Returns: --
  645. Cond: --
  646. */
  647. void PUBLIC FIFree(
  648. FileInfo * pfi)
  649. {
  650. if (pfi)
  651. {
  652. if (pfi->hicon)
  653. DestroyIcon(pfi->hicon);
  654. GFree(pfi); // This macro already checks for NULL pfi condition
  655. }
  656. }
  657. /*----------------------------------------------------------
  658. Purpose: Convert FILETIME struct to a readable string
  659. Returns: String
  660. Cond: --
  661. */
  662. void PUBLIC FileTimeToDateTimeString(
  663. LPFILETIME pft,
  664. LPTSTR pszBuf,
  665. int cchBuf)
  666. {
  667. SYSTEMTIME st;
  668. FILETIME ftLocal;
  669. FileTimeToLocalFileTime(pft, &ftLocal);
  670. FileTimeToSystemTime(&ftLocal, &st);
  671. // REARCHITECT: how do you know date comes before time???
  672. GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, &st, NULL, pszBuf, cchBuf/2);
  673. pszBuf += lstrlen(pszBuf);
  674. *pszBuf++ = TEXT(' ');
  675. GetTimeFormat(LOCALE_USER_DEFAULT, TIME_NOSECONDS, &st, NULL, pszBuf, cchBuf/2);
  676. }
  677. /*----------------------------------------------------------
  678. Purpose: Copies psz into *ppszBuf. Will alloc or realloc *ppszBuf
  679. accordingly.
  680. Returns: TRUE on success
  681. Cond: --
  682. */
  683. BOOL PUBLIC GSetString(
  684. LPTSTR * ppszBuf,
  685. LPCTSTR psz)
  686. {
  687. BOOL bRet = FALSE;
  688. DWORD cb;
  689. ASSERT(ppszBuf);
  690. ASSERT(psz);
  691. cb = CbFromCch(lstrlen(psz)+CCH_NUL);
  692. if (*ppszBuf)
  693. {
  694. // Need to reallocate?
  695. if (cb > GGetSize(*ppszBuf))
  696. {
  697. // Yes
  698. LPTSTR pszT = GReAlloc(*ppszBuf, cb);
  699. if (pszT)
  700. {
  701. *ppszBuf = pszT;
  702. bRet = TRUE;
  703. }
  704. }
  705. else
  706. {
  707. // No
  708. bRet = TRUE;
  709. }
  710. }
  711. else
  712. {
  713. *ppszBuf = (LPTSTR)GAlloc(cb);
  714. if (*ppszBuf)
  715. {
  716. bRet = TRUE;
  717. }
  718. }
  719. if (bRet)
  720. {
  721. ASSERT(*ppszBuf);
  722. // lstrcpy: Enough memory is allocated above so no need for bounded copy
  723. lstrcpy(*ppszBuf, psz);
  724. }
  725. return bRet;
  726. }
  727. /*----------------------------------------------------------
  728. Purpose: Concatenates psz onto *ppszBuf. Will alloc or realloc *ppszBuf
  729. accordingly.
  730. Returns: TRUE on success
  731. Cond: --
  732. */
  733. BOOL PUBLIC GCatString(
  734. LPTSTR * ppszBuf,
  735. LPCTSTR psz)
  736. {
  737. BOOL bRet = FALSE;
  738. DWORD cb;
  739. ASSERT(ppszBuf);
  740. ASSERT(psz);
  741. cb = CbFromCch(lstrlen(psz)+CCH_NUL);
  742. if (*ppszBuf)
  743. {
  744. // (Don't need to count nul because it is already counted in cb)
  745. DWORD cbExisting = CbFromCch(lstrlen(*ppszBuf));
  746. // Need to reallocate?
  747. if ((cb+cbExisting) > GGetSize(*ppszBuf))
  748. {
  749. // Yes; realloc at least MAXBUFLEN to cut down on the amount
  750. // of calls in the future
  751. LPTSTR pszT = GReAlloc(*ppszBuf, cbExisting+max(cb, MAXBUFLEN));
  752. if (pszT)
  753. {
  754. *ppszBuf = pszT;
  755. bRet = TRUE;
  756. }
  757. }
  758. else
  759. {
  760. // No
  761. bRet = TRUE;
  762. }
  763. }
  764. else
  765. {
  766. *ppszBuf = (LPTSTR)GAlloc(max(cb, MAXBUFLEN));
  767. if (*ppszBuf)
  768. {
  769. bRet = TRUE;
  770. }
  771. }
  772. if (bRet)
  773. {
  774. ASSERT(*ppszBuf);
  775. StrCatBuff(*ppszBuf, psz, (int)GGetSize(*ppszBuf)/SIZEOF(TCHAR));
  776. }
  777. return bRet;
  778. }
  779. /*----------------------------------------------------------
  780. Purpose: Waits for on object to signal. This function "does
  781. the right thing" to prevent deadlocks which can occur
  782. because the calculation thread calls SendMessage.
  783. Returns: value of MsgWaitForMultipleObjects
  784. Cond: --
  785. */
  786. DWORD PUBLIC MsgWaitObjectsSendMessage(
  787. DWORD cObjects,
  788. LPHANDLE phObjects,
  789. DWORD dwTimeout)
  790. {
  791. DWORD dwRet;
  792. while (TRUE)
  793. {
  794. dwRet = MsgWaitForMultipleObjects(cObjects, phObjects, FALSE,
  795. dwTimeout, QS_SENDMESSAGE);
  796. // If it is not a message, return
  797. if ((WAIT_OBJECT_0 + cObjects) != dwRet)
  798. {
  799. return dwRet;
  800. }
  801. else
  802. {
  803. // Process all the sent messages
  804. MSG msg;
  805. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  806. }
  807. }
  808. }
  809. /*----------------------------------------------------------
  810. Purpose: Call this if PeekMessage is going to be called during
  811. an expensive operation and a new window has (or is)
  812. appeared.
  813. Details: simply calling SetCursor to change the cursor
  814. to an hourglass, then calling an expensive operation
  815. which will call PeekMessage, will result in the cursor
  816. changing back prematurely. The reason is because SetCursorPos
  817. inserts a fake WM_MOUSEMOVE to set the cursor to the
  818. window class when a window appears for the first time.
  819. Since PeekMessage is processing this message, the cursor
  820. gets changed to the window class cursor.
  821. The trick is to remove the WM_MOUSEMOVE messages from
  822. the queue.
  823. Returns: Previous cursor
  824. Cond: --
  825. */
  826. HCURSOR PUBLIC SetCursorRemoveWigglies(
  827. HCURSOR hcur)
  828. {
  829. MSG msg;
  830. // Remove any mouse moves
  831. while (PeekMessage(&msg, NULL, WM_MOUSEMOVE, WM_MOUSEMOVE, PM_REMOVE))
  832. ;
  833. return SetCursor(hcur);
  834. }
  835. /*----------------------------------------------------------
  836. Purpose: Load the string (if necessary) and format the string
  837. properly.
  838. Returns: A pointer to the allocated string containing the formatted
  839. message or
  840. NULL if out of memory
  841. Cond: --
  842. */
  843. LPTSTR PUBLIC _ConstructMessageString(
  844. HINSTANCE hinst,
  845. LPCTSTR pszMsg,
  846. va_list *ArgList)
  847. {
  848. TCHAR szTemp[MAXBUFLEN];
  849. LPTSTR pszRet;
  850. LPTSTR pszRes;
  851. if (HIWORD(pszMsg))
  852. pszRes = (LPTSTR)pszMsg;
  853. else if (LOWORD(pszMsg) && LoadString(hinst, LOWORD(pszMsg), szTemp, ARRAYSIZE(szTemp)))
  854. pszRes = szTemp;
  855. else
  856. pszRes = NULL;
  857. if (pszRes)
  858. {
  859. if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  860. pszRes, 0, 0, (LPTSTR)&pszRet, 0, ArgList))
  861. {
  862. pszRet = NULL;
  863. }
  864. }
  865. else
  866. {
  867. // Bad parameter
  868. pszRet = NULL;
  869. }
  870. return pszRet; // free with LocalFree()
  871. }
  872. /*----------------------------------------------------------
  873. Purpose: Constructs a formatted string. The returned string
  874. must be freed using GFree().
  875. Returns: TRUE on success
  876. Cond: --
  877. */
  878. BOOL PUBLIC ConstructMessage(
  879. LPTSTR * ppsz,
  880. HINSTANCE hinst,
  881. LPCTSTR pszMsg, ...)
  882. {
  883. BOOL bRet;
  884. LPTSTR pszRet;
  885. va_list ArgList;
  886. va_start(ArgList, pszMsg);
  887. pszRet = _ConstructMessageString(hinst, pszMsg, &ArgList);
  888. va_end(ArgList);
  889. *ppsz = NULL;
  890. if (pszRet)
  891. {
  892. bRet = GSetString(ppsz, pszRet);
  893. LocalFree(pszRet);
  894. }
  895. else
  896. bRet = FALSE;
  897. return bRet;
  898. }