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.

660 lines
13 KiB

  1. //-----------------------------------------------------------------------------
  2. // File: useful.cpp
  3. //
  4. // Desc: Contains various utility classes and functions to help the
  5. // UI carry its operations more easily.
  6. //
  7. // Copyright (C) 1999-2000 Microsoft Corporation. All Rights Reserved.
  8. //-----------------------------------------------------------------------------
  9. #include <windows.h>
  10. #include <tchar.h>
  11. #include <wchar.h>
  12. #include <stdio.h>
  13. #include <stdarg.h>
  14. // assert include (make sure assert actually works with build)
  15. #ifdef DBG
  16. #undef NDEBUG
  17. #endif
  18. #include <assert.h>
  19. #include "useful.h"
  20. #include "collections.h"
  21. /*--------- \/ stuff for collections.h \/ ---------*/
  22. BOOL AfxIsValidAddress( const void* lp, UINT nBytes, BOOL bReadWrite)
  23. {
  24. // return lp != NULL;
  25. // simple version using Win-32 APIs for pointer validation.
  26. return (lp != NULL && !IsBadReadPtr(lp, nBytes) &&
  27. (!bReadWrite || !IsBadWritePtr((LPVOID)lp, nBytes)));
  28. }
  29. CPlex* PASCAL CPlex::Create(CPlex*& pHead, UINT nMax, UINT cbElement)
  30. {
  31. assert(nMax > 0 && cbElement > 0);
  32. CPlex* p = (CPlex*) new BYTE[sizeof(CPlex) + nMax * cbElement];
  33. // may throw exception
  34. if (p)
  35. {
  36. p->pNext = pHead;
  37. pHead = p; // change head (adds in reverse order for simplicity)
  38. }
  39. return p;
  40. }
  41. void CPlex::FreeDataChain() // free this one and links
  42. {
  43. CPlex* p = this;
  44. while (p != NULL)
  45. {
  46. BYTE* bytes = (BYTE*) p;
  47. CPlex* pNext = p->pNext;
  48. delete[] bytes;
  49. p = pNext;
  50. }
  51. }
  52. /*--------- /\ stuff for collections.h /\ ---------*/
  53. int ConvertVal(int x, int a1, int a2, int b1, int b2)
  54. {
  55. assert(a1 != a2 && a2 - a1);
  56. return MulDiv(x - a1, b2 - b1, a2 - a1) + b1;
  57. }
  58. double dConvertVal(double x, double a1, double a2, double b1, double b2)
  59. {
  60. assert(a1 != a2 && a2 - a1);
  61. return (x - a1) * (b2 - b1) / (a2 - a1) + b1;
  62. }
  63. SIZE GetRectSize(const RECT &rect)
  64. {
  65. SIZE size = {
  66. rect.right - rect.left,
  67. rect.bottom - rect.top};
  68. return size;
  69. }
  70. SIZE GetTextSize(LPCTSTR tszText, HFONT hFont)
  71. {
  72. if (!tszText)
  73. {
  74. SIZE z = {0, 0};
  75. return z;
  76. }
  77. RECT trect = {0, 0, 1, 1};
  78. HDC hDC = CreateCompatibleDC(NULL);
  79. if (hDC != NULL)
  80. {
  81. HGDIOBJ hOld = NULL;
  82. if (hFont)
  83. hOld = SelectObject(hDC, hFont);
  84. DrawText(hDC, tszText, -1, &trect, DT_CALCRECT | DT_NOPREFIX);
  85. if (hFont)
  86. SelectObject(hDC, hOld);
  87. DeleteDC(hDC);
  88. }
  89. SIZE size = {trect.right - trect.left, trect.bottom - trect.top};
  90. return size;
  91. }
  92. int GetTextHeight(HFONT hFont)
  93. {
  94. static const TCHAR str[] = _T("Happy Test! :D");
  95. SIZE size = GetTextSize(str, hFont);
  96. return size.cy;
  97. }
  98. int vFormattedMsgBox(HINSTANCE hInstance, HWND hParent, UINT uType, UINT uTitle, UINT uMsg, va_list args)
  99. {
  100. int i;
  101. const int len = 1024;
  102. static TCHAR title[len], format[len], msg[len];
  103. if (!LoadString(hInstance, uTitle, title, len))
  104. _tcscpy(title, _T("(could not load title string)"));
  105. if (!LoadString(hInstance, uMsg, format, len))
  106. return MessageBox(hParent, _T("(could not load message/format string)"), title, uType);
  107. #ifdef WIN95
  108. {
  109. char *psz = NULL;
  110. char szDfs[1024]={0};
  111. strcpy(szDfs,format); // make a local copy of format string
  112. while (psz = strstr(szDfs,"%p")) // find each %p
  113. *(psz+1) = 'x'; // replace each %p with %x
  114. i = _vsntprintf(msg, len, szDfs, args); // use the local format string
  115. }
  116. #else
  117. {
  118. i = _vsntprintf(msg, len, format, args);
  119. }
  120. #endif
  121. if (i < 0)
  122. return MessageBox(hParent, _T("(could not format message)"), title, uType);
  123. if (i < 1)
  124. msg[0] = 0;
  125. return MessageBox(hParent, msg, title, uType);
  126. }
  127. int FormattedMsgBox(HINSTANCE hInstance, HWND hParent, UINT uType, UINT uTitle, UINT uMsg, ...)
  128. {
  129. va_list args;
  130. va_start(args, uMsg);
  131. int i = vFormattedMsgBox(hInstance, hParent, uType, uTitle, uMsg, args);
  132. va_end(args);
  133. return i;
  134. }
  135. BOOL UserConfirm(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, ...)
  136. {
  137. va_list args;
  138. va_start(args, uMsg);
  139. int i = vFormattedMsgBox(hInstance, hParent, MB_ICONQUESTION | MB_YESNO, uTitle, uMsg, args);
  140. va_end(args);
  141. return i == IDYES;
  142. }
  143. int FormattedErrorBox(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, ...)
  144. {
  145. va_list args;
  146. va_start(args, uMsg);
  147. int i = vFormattedMsgBox(hInstance, hParent, MB_OK | MB_ICONSTOP, uTitle, uMsg, args);
  148. va_end(args);
  149. return i;
  150. }
  151. int FormattedLastErrorBox(HINSTANCE hInstance, HWND hParent, UINT uTitle, UINT uMsg, DWORD dwError)
  152. {
  153. // format an error message from GetLastError().
  154. LPVOID lpMsgBuf = NULL;
  155. DWORD result = FormatMessage(
  156. FORMAT_MESSAGE_ALLOCATE_BUFFER |
  157. FORMAT_MESSAGE_FROM_SYSTEM |
  158. FORMAT_MESSAGE_IGNORE_INSERTS,
  159. NULL,
  160. dwError,
  161. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  162. (LPTSTR) &lpMsgBuf,
  163. 0,
  164. NULL);
  165. if (!result || lpMsgBuf == NULL)
  166. return FormattedErrorBox(hInstance, hParent, uTitle, uMsg,
  167. _T("An unknown error occured (could not format the error code)."));
  168. int i = FormattedErrorBox(hInstance, hParent, uTitle, uMsg, (LPCTSTR)lpMsgBuf);
  169. LocalFree(lpMsgBuf);
  170. return i;
  171. }
  172. LPTSTR AllocLPTSTR(LPCWSTR wstr)
  173. {
  174. if (wstr == NULL)
  175. return NULL;
  176. #ifdef UNICODE
  177. return _tcsdup(wstr);
  178. #else
  179. int len = wcslen(wstr) * 2 + 1;
  180. char *ret = (char *)malloc(len);
  181. if (!ret)
  182. return NULL;
  183. WideCharToMultiByte(CP_ACP, 0, wstr, -1, ret, len, NULL, NULL);
  184. ret[len-1] = '\0';
  185. return ret;
  186. #endif
  187. }
  188. LPTSTR AllocLPTSTR(LPCSTR str)
  189. {
  190. if (str == NULL)
  191. return NULL;
  192. #ifndef UNICODE
  193. return _tcsdup(str);
  194. #else
  195. int len = strlen(str);
  196. WCHAR *ret = (WCHAR *)malloc((len + 1) * sizeof(WCHAR));
  197. if (!ret)
  198. return NULL;
  199. mbstowcs(ret, str, len);
  200. ret[len] = L'\0';
  201. return ret;
  202. #endif
  203. }
  204. void CopyStr(LPWSTR dest, LPCWSTR src, size_t max)
  205. {
  206. if (dest == NULL || src == NULL)
  207. return;
  208. wcsncpy(dest, src, max);
  209. }
  210. void CopyStr(LPSTR dest, LPCSTR src, size_t max)
  211. {
  212. if (dest == NULL || src == NULL)
  213. return;
  214. strncpy(dest, src, max);
  215. }
  216. void CopyStr(LPWSTR dest, LPCSTR src, size_t max)
  217. {
  218. if (dest == NULL || src == NULL)
  219. return;
  220. mbstowcs(dest, src, max);
  221. }
  222. void CopyStr(LPSTR dest, LPCWSTR src, size_t max)
  223. {
  224. if (dest == NULL || src == NULL)
  225. return;
  226. WideCharToMultiByte(CP_ACP, 0, src, -1, dest, max, NULL, NULL);
  227. }
  228. LPWSTR AllocLPWSTR(LPCWSTR wstr)
  229. {
  230. if (wstr == NULL)
  231. return NULL;
  232. return _wcsdup(wstr);
  233. }
  234. LPWSTR AllocLPWSTR(LPCSTR str)
  235. {
  236. if (str == NULL)
  237. return NULL;
  238. size_t len = strlen(str);
  239. size_t retsize = mbstowcs(NULL, str, len);
  240. WCHAR *ret = (WCHAR *)malloc((retsize + 1) * sizeof(WCHAR));
  241. if (!ret)
  242. return NULL;
  243. mbstowcs(ret, str, len);
  244. ret[retsize] = L'\0';
  245. return ret;
  246. }
  247. LPSTR AllocLPSTR(LPCWSTR wstr)
  248. {
  249. if (wstr == NULL)
  250. return NULL;
  251. size_t len = wcslen(wstr);
  252. size_t retsize = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
  253. CHAR *ret = (CHAR *)malloc((retsize + 1) * sizeof(CHAR));
  254. if (!ret)
  255. return NULL;
  256. WideCharToMultiByte(CP_ACP, 0, wstr, -1, ret, retsize, NULL, NULL);
  257. ret[retsize] = '\0';
  258. return ret;
  259. }
  260. LPSTR AllocLPSTR(LPCSTR str)
  261. {
  262. if (str == NULL)
  263. return NULL;
  264. return _strdup(str);
  265. }
  266. LPTSTR AllocFileNameNoPath(LPTSTR path)
  267. {
  268. TCHAR fname[_MAX_FNAME];
  269. TCHAR ext[_MAX_EXT];
  270. if (path == NULL) return NULL;
  271. _tsplitpath(path, NULL, NULL, fname, ext);
  272. LPTSTR ret = (LPTSTR)malloc(sizeof(TCHAR) * (_tcslen(fname) + _tcslen(ext) + 1));
  273. if (ret != NULL)
  274. {
  275. _tcscpy(ret, fname);
  276. _tcscat(ret, ext);
  277. }
  278. return ret;
  279. }
  280. LPTSTR utilstr::Eject()
  281. {
  282. LPTSTR str = m_str;
  283. m_str = NULL;
  284. m_len = 0;
  285. return str;
  286. }
  287. void utilstr::Empty()
  288. {
  289. if (m_str != NULL)
  290. free(m_str);
  291. m_len = 0;
  292. }
  293. bool utilstr::IsEmpty() const
  294. {
  295. return !GetLength();
  296. }
  297. int utilstr::GetLength() const
  298. {
  299. if (m_str == NULL)
  300. return 0;
  301. if (!m_len)
  302. return 0;
  303. return _tcslen(m_str);
  304. }
  305. void utilstr::Format(LPCTSTR format, ...)
  306. {
  307. static TCHAR buf[2048];
  308. va_list args;
  309. va_start(args, format);
  310. #ifdef WIN95
  311. {
  312. char *psz = NULL;
  313. char szDfs[1024]={0};
  314. strcpy(szDfs,format); // make a local copy of format string
  315. while (psz = strstr(szDfs,"%p")) // find each %p
  316. *(psz+1) = 'x'; // replace each %p with %x
  317. _vsntprintf(buf, sizeof(buf)/sizeof(TCHAR), szDfs, args); // use the local format string
  318. }
  319. #else
  320. {
  321. _vsntprintf(buf, sizeof(buf)/sizeof(TCHAR), format, args);
  322. }
  323. #endif
  324. va_end(args);
  325. equal(buf);
  326. }
  327. void utilstr::equal(LPCTSTR str)
  328. {
  329. Empty();
  330. if (str == NULL)
  331. return;
  332. m_len = _tcslen(str);
  333. m_str = (LPTSTR)malloc(sizeof(TCHAR) * (m_len + 1));
  334. if (m_str != NULL)
  335. _tcscpy(m_str, str);
  336. else
  337. m_len = 0;
  338. }
  339. void utilstr::add(LPCTSTR str)
  340. {
  341. if (str == NULL)
  342. return;
  343. if (IsEmpty())
  344. {
  345. equal(str);
  346. return;
  347. }
  348. int len = _tcslen(str);
  349. int newlen = m_len + len;
  350. LPTSTR newstr = (LPTSTR)malloc(sizeof(TCHAR) * (newlen + 1));
  351. if (newstr == NULL)
  352. return;
  353. _tcscpy(newstr, m_str);
  354. _tcscat(newstr, str);
  355. Empty();
  356. m_str = newstr;
  357. m_len = newlen;
  358. }
  359. LPTSTR AllocFlagStr(DWORD value, const AFS_FLAG flag[], int flags)
  360. {
  361. utilstr ret; // return string
  362. DWORD allknownbits = 0; // check value to see if there are any bits
  363. // set for which we don't have a define
  364. // handle each flag
  365. bool bflagfound = false;
  366. for (int i = 0; i < flags; i++)
  367. {
  368. // set bit for this flag in allknownbits
  369. allknownbits |= flag[i].value;
  370. // if this bit is set in the passed value, or the value
  371. // is zero and we're on the zero flag,
  372. // add the define for this bit/flag to the return string
  373. if (value ? value & flag[i].value : !flag[i].value)
  374. {
  375. // adding binary or operators between flags
  376. if (bflagfound)
  377. ret += _T(" | ");
  378. ret += flag[i].name;
  379. bflagfound = true;
  380. }
  381. }
  382. // now see if there are any unknown bits in passed flag
  383. DWORD unknownbits = value & ~allknownbits;
  384. if (unknownbits)
  385. {
  386. // add hex number for unknown bits
  387. utilstr unk;
  388. unk.Format(_T("0x%08X"), unknownbits);
  389. if (bflagfound)
  390. ret += _T(" | ");
  391. ret += unk;
  392. }
  393. // if value is zero (and no flags for zero) we should just set the string to "0"
  394. if (!value && !bflagfound)
  395. ret = _T("0");
  396. // now the string should definitely not be empty, in any case
  397. assert(!ret.IsEmpty());
  398. // finally, add a comment that has hex number for entire value
  399. // (for debugging)
  400. utilstr temp;
  401. temp.Format(_T(" /* 0x%08X */"), value);
  402. ret += temp;
  403. // done
  404. return ret.Eject();
  405. }
  406. void PutLinePoint(HDC hDC, POINT p)
  407. {
  408. MoveToEx(hDC, p.x, p.y, NULL);
  409. LineTo(hDC, p.x + 1, p.y);
  410. }
  411. void PolyLineArrowShadow(HDC hDC, POINT *p, int i)
  412. {
  413. PolyLineArrow(hDC, p, i, TRUE);
  414. }
  415. void PolyLineArrow(HDC hDC, POINT *rgpt, int nPoints, BOOL bDoShadow)
  416. {
  417. int i;
  418. if (rgpt == NULL || nPoints < 1)
  419. return;
  420. if (nPoints > 1)
  421. for (i = 0; i < nPoints - 1; i++)
  422. {
  423. SPOINT a = rgpt[i], b = rgpt[i + 1];
  424. if (bDoShadow)
  425. {
  426. int rise = abs(b.y - a.y), run = abs(b.x - a.x);
  427. bool vert = rise > run;
  428. int ord = vert ? 1 : 0;
  429. int nord = vert ? 0 : 1;
  430. for (int o = -1; o <= 1; o += 2)
  431. {
  432. SPOINT c(a), d(b);
  433. c.a[nord] += o;
  434. d.a[nord] += o;
  435. MoveToEx(hDC, c.x, c.y, NULL);
  436. LineTo(hDC, d.x, d.y);
  437. }
  438. bool reverse = a.a[ord] > b.a[ord];
  439. SPOINT e(reverse ? b : a), f(reverse ? a : b);
  440. e.a[ord] -= 1;
  441. f.a[ord] += 1;
  442. PutLinePoint(hDC, e);
  443. PutLinePoint(hDC, f);
  444. }
  445. else
  446. {
  447. MoveToEx(hDC, a.x, a.y, NULL);
  448. LineTo(hDC, b.x, b.y);
  449. }
  450. }
  451. POINT z = rgpt[nPoints - 1];
  452. if (bDoShadow)
  453. {
  454. POINT pt[5] = {
  455. {z.x, z.y + 2},
  456. {z.x + 2, z.y},
  457. {z.x, z.y - 2},
  458. {z.x - 2, z.y}, };
  459. pt[4] = pt[0];
  460. Polyline(hDC, pt, 5);
  461. }
  462. else
  463. {
  464. MoveToEx(hDC, z.x - 1, z.y, NULL);
  465. LineTo(hDC, z.x + 2, z.y);
  466. MoveToEx(hDC, z.x, z.y - 1, NULL);
  467. LineTo(hDC, z.x, z.y + 2);
  468. }
  469. }
  470. BOOL bEq(BOOL a, BOOL b)
  471. {
  472. bool c = !a, d = !b;
  473. return (c == d) ? TRUE : FALSE;
  474. }
  475. void DrawArrow(HDC hDC, const RECT &rect, BOOL bVert, BOOL bUpLeft)
  476. {
  477. SRECT srect = rect;
  478. srect.right--;
  479. srect.bottom--;
  480. int ord = bVert ? 1 : 0;
  481. int nord = bVert ? 0 : 1;
  482. SPOINT p(!bUpLeft ? srect.lr : srect.ul), b(!bUpLeft ? srect.ul : srect.lr);
  483. b.a[ord] += bUpLeft ? -1 : 1;
  484. SPOINT t = p;
  485. t.a[nord] = (p.a[nord] + b.a[nord]) / 2;
  486. SPOINT u;
  487. u.a[ord] = b.a[ord];
  488. u.a[nord] = p.a[nord];
  489. POINT poly[] = { {t.x, t.y}, {u.x, u.y}, {b.x, b.y} };
  490. Polygon(hDC, poly, 3);
  491. }
  492. BOOL ScreenToClient(HWND hWnd, LPRECT rect)
  493. {
  494. if (rect == NULL)
  495. return FALSE;
  496. SRECT sr = *rect;
  497. if (ScreenToClient(hWnd, &sr.ul.p) &&
  498. ScreenToClient(hWnd, &sr.lr.p))
  499. {
  500. *rect = sr;
  501. return TRUE;
  502. }
  503. return FALSE;
  504. }
  505. BOOL ClientToScreen(HWND hWnd, LPRECT rect)
  506. {
  507. if (rect == NULL)
  508. return FALSE;
  509. SRECT sr = *rect;
  510. if (ClientToScreen(hWnd, &sr.ul.p) &&
  511. ClientToScreen(hWnd, &sr.lr.p))
  512. {
  513. *rect = sr;
  514. return TRUE;
  515. }
  516. return FALSE;
  517. }
  518. #define z ((L"\0")[0])
  519. int StrLen(LPCWSTR s)
  520. {
  521. if (s == NULL)
  522. return 0;
  523. return wcslen(s);
  524. }
  525. int StrLen(LPCSTR s)
  526. {
  527. if (s == NULL)
  528. return 0;
  529. return strlen(s);
  530. }
  531. //@@BEGIN_MSINTERNAL
  532. #ifdef DDKBUILD
  533. LPCTSTR GetOpenFileName(HINSTANCE hInst, HWND hWnd, LPCTSTR title, LPCTSTR filter, LPCTSTR defext, LPCTSTR inidir)
  534. {
  535. OPENFILENAME ofn;
  536. static TCHAR tszFile[MAX_PATH + 1] = _T("");
  537. tszFile[MAX_PATH] = 0;
  538. ofn.lStructSize = sizeof(OPENFILENAME);
  539. ofn.hwndOwner = hWnd;
  540. ofn.hInstance = hInst;
  541. ofn.lpstrFilter = filter;
  542. ofn.lpstrCustomFilter = NULL;
  543. ofn.nMaxCustFilter = 0;
  544. ofn.nFilterIndex = 0;
  545. ofn.lpstrFile = tszFile;
  546. ofn.nMaxFile = MAX_PATH;
  547. ofn.lpstrFileTitle = NULL;
  548. ofn.nMaxFileTitle = 0;
  549. ofn.lpstrInitialDir = inidir;
  550. ofn.lpstrTitle = title;
  551. ofn.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST;
  552. ofn.lpstrDefExt = defext;
  553. ofn.lCustData = NULL;
  554. ofn.lpfnHook = NULL;
  555. ofn.lpTemplateName = NULL;
  556. if (!GetOpenFileName(&ofn))
  557. return NULL;
  558. return tszFile;
  559. }
  560. #endif
  561. //@@END_MSINTERNAL