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.

1519 lines
42 KiB

  1. //---------------------------------------------------------------------------
  2. // utils.cpp - theme code utilities (shared in "inc" directory)
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include <time.h>
  6. #include "utils.h"
  7. #include "cfile.h"
  8. #include "stringtable.h"
  9. //---------------------------------------------------------------------------
  10. HINSTANCE hinstUxCtrl = NULL; // protected by _csUtils
  11. IMAGE_DRAWPROC ImageList_DrawProc = NULL; // protected by _csUtils
  12. IMAGE_LOADPROC ImageList_LoadProc = NULL; // protected by _csUtils
  13. PFNDRAWSHADOWTEXT CCDrawShadowText = NULL;
  14. IMAGE_DESTROYPROC ImageList_DestroyProc = NULL; // protected by _csUtils
  15. int g_iScreenDpi = THEME_DPI; // only initialized
  16. //---------------------------------------------------------------------------
  17. CRITICAL_SECTION _csUtils = {0}; // unprotected (set during init)
  18. //---------------------------------------------------------------------------
  19. #define __ascii_towlower(c) ( (((c) >= L'A') && ((c) <= L'Z')) ? ((c) - L'A' + L'a') : (c) )
  20. // A string compare that explicitely only works on english characters
  21. // This avoids locale problems like Hungarian, without a performance hit.
  22. // NOTE: Intended for theme schema properties. Theme file names, colors styles and size styles
  23. // shouldn't be passed to this function, nor any display name.
  24. int AsciiStrCmpI(const WCHAR *dst, const WCHAR *src)
  25. {
  26. WCHAR f,l;
  27. if (dst == NULL)
  28. {
  29. return src == NULL ? 0 : -1;
  30. }
  31. if (src == NULL)
  32. {
  33. return 1;
  34. }
  35. do {
  36. #ifdef DEBUG
  37. if (*dst > 127 || *src > 127)
  38. {
  39. Log(LOG_ERROR, L"AsciiStrCmpI: Non-Ascii comparing %s and %s", dst, src);
  40. }
  41. #endif
  42. f = (WCHAR)__ascii_towlower(*dst);
  43. l = (WCHAR)__ascii_towlower(*src);
  44. dst++;
  45. src++;
  46. } while ( (f) && (f == l) );
  47. return (int)(f - l);
  48. }
  49. //---------------------------------------------------------------------------
  50. BOOL lstrtoken(LPWSTR psz, WCHAR wch)
  51. {
  52. ATLASSERT(psz != NULL);
  53. LPWSTR p = psz;
  54. while (*p)
  55. {
  56. if (*p == wch)
  57. {
  58. *p = 0;
  59. return TRUE;
  60. }
  61. p = CharNextW(p);
  62. }
  63. return FALSE;
  64. }
  65. //---------------------------------------------------------------------------
  66. BOOL FileExists(LPCWSTR pszFileName)
  67. {
  68. DWORD dwMask = GetFileAttributes(pszFileName);
  69. return (dwMask != 0xffffffff);
  70. }
  71. //---------------------------------------------------------------------------
  72. BOOL UtilsStartUp()
  73. {
  74. InitializeCriticalSection(&_csUtils);
  75. hinstUxCtrl = NULL;
  76. //---- set screen dpi (per session) ----
  77. HDC hdc = GetWindowDC(NULL);
  78. if (hdc)
  79. {
  80. g_iScreenDpi = GetDeviceCaps(hdc, LOGPIXELSX);
  81. ReleaseDC(NULL, hdc);
  82. }
  83. return TRUE;
  84. }
  85. //---------------------------------------------------------------------------
  86. BOOL UtilsShutDown()
  87. {
  88. DeleteCriticalSection(&_csUtils);
  89. if (hinstUxCtrl)
  90. {
  91. FreeLibrary(hinstUxCtrl);
  92. hinstUxCtrl = NULL;
  93. }
  94. return FALSE;
  95. }
  96. //---------------------------------------------------------------------------
  97. void ErrorBox(LPCSTR pszFormat, ...)
  98. {
  99. va_list args;
  100. va_start(args, pszFormat);
  101. char szMsgBuff[2048];
  102. wvsprintfA(szMsgBuff, pszFormat, args);
  103. MessageBoxA(NULL, szMsgBuff, "Error", MB_OK);
  104. va_end(args);
  105. }
  106. //---------------------------------------------------------------------------
  107. HANDLE CmdLineRun(LPCTSTR pszExeName, LPCTSTR pszParams, BOOL fHide)
  108. {
  109. STARTUPINFO si;
  110. memset(&si, 0, sizeof(si));
  111. si.cb = sizeof(STARTUPINFO);
  112. si.dwFlags = STARTF_FORCEOFFFEEDBACK; // don't mess with our cursor
  113. if (fHide)
  114. {
  115. si.dwFlags |= STARTF_USESHOWWINDOW; // hide window
  116. si.wShowWindow = SW_HIDE;
  117. }
  118. PROCESS_INFORMATION pi;
  119. TCHAR pszExeBuff[_MAX_PATH];
  120. TCHAR pszParmsBuff[_MAX_PATH];
  121. // Copy to buffers to avoid AVs
  122. if (pszParams)
  123. {
  124. pszParmsBuff[0] = L'"';
  125. // -1 for trailing NULL, -2 for quotation marks, -1 for space between EXE and args
  126. HRESULT hr = hr_lstrcpy(pszParmsBuff+1, pszExeName, ARRAYSIZE(pszParmsBuff) - 4);
  127. if (FAILED(hr))
  128. return NULL;
  129. int cchUsed = lstrlen(pszParmsBuff);
  130. pszParmsBuff[cchUsed++] = L'"'; // closing quotation mark
  131. pszParmsBuff[cchUsed++] = L' '; // We need a space before the cmd line
  132. hr = hr_lstrcpy(pszParmsBuff + cchUsed, pszParams, ARRAYSIZE(pszParmsBuff) - cchUsed - 1);
  133. if (FAILED(hr))
  134. return NULL;
  135. }
  136. LPTSTR lpFilePart;
  137. if (0 == SearchPath(NULL, pszExeName, NULL, ARRAYSIZE(pszExeBuff), pszExeBuff, &lpFilePart))
  138. return NULL;
  139. BOOL bSuccess = CreateProcess(pszExeBuff, pszParams ? pszParmsBuff : NULL, NULL, NULL,
  140. FALSE, 0, NULL, NULL, &si, &pi);
  141. if (! bSuccess)
  142. return NULL;
  143. return pi.hProcess;
  144. }
  145. //---------------------------------------------------------------------------
  146. HRESULT SyncCmdLineRun(LPCTSTR pszExeName, LPCTSTR pszParams)
  147. {
  148. HANDLE hInst;
  149. hInst = CmdLineRun(pszExeName, pszParams);
  150. if (! hInst)
  151. {
  152. Log(LOG_ALWAYS, L"CmdLineRun failed to create hInst. Cmd=%s", pszExeName);
  153. return MakeError32(E_FAIL); // could not run program
  154. }
  155. HRESULT hr = S_OK;
  156. //---- wait for packthem to terminate ----
  157. DWORD dwVal;
  158. dwVal = WaitForSingleObject(hInst, INFINITE);
  159. if (dwVal != WAIT_OBJECT_0)
  160. {
  161. Log(LOG_ERROR, L"CmdLineRun timed out. Cmd=%s", pszExeName);
  162. hr = MakeError32(E_FAIL); // timed out
  163. goto exit;
  164. }
  165. DWORD dwExitCode;
  166. if (! GetExitCodeProcess(hInst, &dwExitCode))
  167. {
  168. Log(LOG_ALWAYS, L"CmdLineRun failed to get exit code. Cmd=%s", pszExeName);
  169. hr = MakeError32(E_FAIL); // could not get exit code
  170. goto exit;
  171. }
  172. if (dwExitCode)
  173. {
  174. Log(LOG_ALWAYS, L"CmdLineRun returned error. Cmd=%s, ExitCode=%d", pszExeName, dwExitCode);
  175. hr = MakeError32(E_FAIL); // did not complete successfully
  176. goto exit;
  177. }
  178. exit:
  179. CloseHandle(hInst);
  180. return hr;
  181. }
  182. //---------------------------------------------------------------------------
  183. void ForceDesktopRepaint()
  184. {
  185. //---- keep for now (some non-subclassed controls don't repaint otherwise) ----
  186. InvalidateRect(NULL, NULL, TRUE); // all windows
  187. }
  188. //---------------------------------------------------------------------------
  189. // color conversion routines copied from comdlg\color2.c
  190. //---------------------------------------------------------------------------
  191. #define HLSMAX 240
  192. #define RGBMAX 255
  193. #define UNDEFINED (HLSMAX * 2 / 3)
  194. //---------------------------------------------------------------------------
  195. void RGBtoHLS(COLORREF rgb, WORD *pwHue, WORD *pwLum, WORD *pwSat)
  196. {
  197. WORD R, G, B; // input RGB values
  198. WORD cMax,cMin; // max and min RGB values
  199. WORD cSum,cDif;
  200. SHORT Rdelta, Gdelta, Bdelta; // intermediate value: % of spread from max
  201. WORD bHue, bLum, bSat;
  202. //
  203. // get R, G, and B out of DWORD.
  204. //
  205. R = GetRValue(rgb);
  206. G = GetGValue(rgb);
  207. B = GetBValue(rgb);
  208. //
  209. // Calculate lightness.
  210. //
  211. cMax = max(max(R, G), B);
  212. cMin = min(min(R, G), B);
  213. cSum = cMax + cMin;
  214. bLum = (WORD)(((cSum * (DWORD)HLSMAX) + RGBMAX) / (2 * RGBMAX));
  215. cDif = cMax - cMin;
  216. if (!cDif)
  217. {
  218. //
  219. // r = g = b --> Achromatic case.
  220. //
  221. bSat = 0; // saturation
  222. bHue = UNDEFINED; // hue
  223. }
  224. else
  225. {
  226. //
  227. // Chromatic case.
  228. //
  229. //
  230. // Saturation.
  231. //
  232. // Note: Division by cSum is not a problem, as cSum can only
  233. // be 0 if the RGB value is 0L, and that is achromatic.
  234. //
  235. if (bLum <= (HLSMAX / 2))
  236. {
  237. bSat = (WORD)(((cDif * (DWORD) HLSMAX) + (cSum / 2) ) / cSum);
  238. }
  239. else
  240. {
  241. bSat = (WORD)((DWORD)((cDif * (DWORD)HLSMAX) +
  242. (DWORD)((2 * RGBMAX - cSum) / 2)) /
  243. (2 * RGBMAX - cSum));
  244. }
  245. //
  246. // Hue.
  247. //
  248. Rdelta = (SHORT)((((cMax - R) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
  249. Gdelta = (SHORT)((((cMax - G) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
  250. Bdelta = (SHORT)((((cMax - B) * (DWORD)(HLSMAX / 6)) + (cDif / 2) ) / cDif);
  251. if (R == cMax)
  252. {
  253. bHue = Bdelta - Gdelta;
  254. }
  255. else if (G == cMax)
  256. {
  257. bHue = (WORD)((HLSMAX / 3) + Rdelta - Bdelta);
  258. }
  259. else // (B == cMax)
  260. {
  261. bHue = (WORD)(((2 * HLSMAX) / 3) + Gdelta - Rdelta);
  262. }
  263. if ((short)bHue < 0)
  264. {
  265. //
  266. // This can occur when R == cMax and G is > B.
  267. //
  268. bHue += HLSMAX;
  269. }
  270. if (bHue >= HLSMAX)
  271. {
  272. bHue -= HLSMAX;
  273. }
  274. }
  275. if (pwHue)
  276. *pwHue = bHue;
  277. if (pwLum)
  278. *pwLum = bLum;
  279. if (pwSat)
  280. *pwSat = bSat;
  281. }
  282. //---------------------------------------------------------------------------
  283. WORD HueToRGB(WORD n1, WORD n2, WORD hue)
  284. {
  285. if (hue >= HLSMAX)
  286. {
  287. hue -= HLSMAX;
  288. }
  289. //
  290. // Return r, g, or b value from this tridrant.
  291. //
  292. if (hue < (HLSMAX / 6))
  293. {
  294. return ((WORD)(n1 + (((n2 - n1) * hue + (HLSMAX / 12)) / (HLSMAX / 6))));
  295. }
  296. if (hue < (HLSMAX/2))
  297. {
  298. return (n2);
  299. }
  300. if (hue < ((HLSMAX*2)/3))
  301. {
  302. return ((WORD)(n1 + (((n2 - n1) * (((HLSMAX * 2) / 3) - hue) +
  303. (HLSMAX / 12)) / (HLSMAX / 6))));
  304. }
  305. else
  306. {
  307. return (n1);
  308. }
  309. }
  310. //---------------------------------------------------------------------------
  311. DWORD HLStoRGB(WORD hue, WORD lum, WORD sat)
  312. {
  313. WORD R, G, B; // RGB component values
  314. WORD Magic1, Magic2; // calculated magic numbers
  315. if (sat == 0)
  316. {
  317. //
  318. // Achromatic case.
  319. //
  320. R = G = B = (WORD)((lum * RGBMAX) / HLSMAX);
  321. }
  322. else
  323. {
  324. //
  325. // Chromatic case
  326. //
  327. //
  328. // Set up magic numbers.
  329. //
  330. if (lum <= (HLSMAX / 2))
  331. {
  332. Magic2 = (WORD)((lum * ((DWORD)HLSMAX + sat) + (HLSMAX / 2)) / HLSMAX);
  333. }
  334. else
  335. {
  336. Magic2 = lum + sat -
  337. (WORD)(((lum * sat) + (DWORD)(HLSMAX / 2)) / HLSMAX);
  338. }
  339. Magic1 = (WORD)(2 * lum - Magic2);
  340. //
  341. // Get RGB, change units from HLSMAX to RGBMAX.
  342. //
  343. R = (WORD)(((HueToRGB(Magic1, Magic2, (WORD)(hue + (HLSMAX / 3))) *
  344. (DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
  345. G = (WORD)(((HueToRGB(Magic1, Magic2, hue) *
  346. (DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
  347. B = (WORD)(((HueToRGB(Magic1, Magic2, (WORD)(hue - (HLSMAX / 3))) *
  348. (DWORD)RGBMAX + (HLSMAX / 2))) / HLSMAX);
  349. }
  350. return (RGB(R, G, B));
  351. }
  352. //---------------------------------------------------------------------------
  353. BOOL GetMyExePath(LPWSTR pszNameBuff)
  354. {
  355. //---- extract the dir that calling program is running in ----
  356. WCHAR filename[_MAX_PATH+1];
  357. GetModuleFileName(NULL, filename, ARRAYSIZE(filename));
  358. WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
  359. _wsplitpath(filename, drive, dir, fname, ext);
  360. wsprintf(pszNameBuff, L"%s%psz", drive, dir);
  361. return TRUE;
  362. }
  363. //---------------------------------------------------------------------------
  364. HRESULT SetFileExt(LPCWSTR pszOrigName, LPCWSTR pszNewExt, OUT LPWSTR pszNewNameBuff)
  365. {
  366. WCHAR drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
  367. _wsplitpath(pszOrigName, drive, dir, fname, ext);
  368. _wmakepath(pszNewNameBuff, drive, dir, fname, pszNewExt);
  369. return S_OK;
  370. }
  371. //---------------------------------------------------------------------------
  372. HRESULT GetPtrToResource(HINSTANCE hInst, LPCWSTR pszResType, LPCWSTR pszResName,
  373. OUT void **ppBytes, OPTIONAL OUT DWORD *pdwBytes)
  374. {
  375. HRSRC hRsc = FindResource(hInst, pszResName, pszResType);
  376. if (! hRsc)
  377. return MakeErrorLast();
  378. DWORD dwBytes = SizeofResource(hInst, hRsc);
  379. if (! dwBytes)
  380. return MakeErrorLast();
  381. HGLOBAL hGlobal = LoadResource(hInst, hRsc);
  382. if (! hGlobal)
  383. return MakeErrorLast();
  384. void *v = (WCHAR *)LockResource(hGlobal);
  385. if (! v)
  386. return MakeErrorLast();
  387. *ppBytes = v;
  388. if (pdwBytes)
  389. *pdwBytes = dwBytes;
  390. return S_OK;
  391. }
  392. //---------------------------------------------------------------------------
  393. HRESULT GetResString(HINSTANCE hInst, LPCWSTR pszResType, int id, LPWSTR pszBuff,
  394. DWORD dwMaxBuffChars)
  395. {
  396. WCHAR *p;
  397. HRESULT hr = GetPtrToResource(hInst, pszResType, MAKEINTRESOURCE(1), (void **)&p);
  398. if (SUCCEEDED(hr))
  399. {
  400. while ((*p) && (id))
  401. {
  402. p += (1 + lstrlen(p));
  403. id--;
  404. }
  405. if (*p)
  406. {
  407. hr = hr_lstrcpy(pszBuff, p, dwMaxBuffChars);
  408. }
  409. else
  410. {
  411. hr = MakeError32(ERROR_NOT_FOUND);
  412. }
  413. }
  414. return hr;
  415. }
  416. //---------------------------------------------------------------------------
  417. HRESULT AllocateTextResource(HINSTANCE hInst, LPCWSTR pszResName, WCHAR **ppszText)
  418. {
  419. WCHAR *p, *q;
  420. DWORD dwBytes, dwChars;
  421. HRESULT hr;
  422. //---- allocate so that we can add a NULL at the end of the file string ----
  423. hr = GetPtrToResource(hInst, L"TEXTFILE", pszResName, (void **)&p, &dwBytes);
  424. if (FAILED(hr))
  425. goto exit;
  426. dwChars = (dwBytes+1)/2;
  427. if ((dwChars) && (p[0] == 0xfeff)) // remove UNICODE hdr
  428. {
  429. dwChars--;
  430. p++;
  431. }
  432. q = new WCHAR[dwChars+1];
  433. if (!q)
  434. {
  435. hr = MakeError32(E_OUTOFMEMORY);
  436. goto exit;
  437. }
  438. memcpy(q, p, dwChars*sizeof(WCHAR));
  439. q[dwChars] = 0;
  440. *ppszText = q;
  441. exit:
  442. return hr;
  443. }
  444. //---------------------------------------------------------------------------
  445. void ReplChar(LPWSTR pszBuff, WCHAR wOldVal, WCHAR wNewVal)
  446. {
  447. WCHAR *p = pszBuff;
  448. while (*p)
  449. {
  450. if (*p == wOldVal)
  451. *p = wNewVal;
  452. p++;
  453. }
  454. }
  455. //---------------------------------------------------------------------------
  456. WCHAR *StringDup(LPCWSTR pszOrig)
  457. {
  458. int len = lstrlen(pszOrig);
  459. WCHAR *str = new WCHAR[1+len];
  460. if (str)
  461. lstrcpy(str, pszOrig);
  462. return str;
  463. }
  464. //---------------------------------------------------------------------------
  465. void ApplyStringProp(HWND hwnd, LPCWSTR pszStringVal, ATOM atom)
  466. {
  467. if (hwnd)
  468. {
  469. //---- remove previous value ----
  470. ATOM atomStringVal = (ATOM)GetProp(hwnd, (LPCTSTR)atom);
  471. if (atomStringVal)
  472. {
  473. DeleteAtom(atomStringVal); // decrement refcnt
  474. RemoveProp(hwnd, (LPCTSTR)atom);
  475. }
  476. //---- add new string as an atom ----
  477. if (pszStringVal)
  478. {
  479. //---- if string is empty, change it since AddAtom() doesn't ----
  480. //---- support empty strings (returns NULL) ----
  481. if (! *pszStringVal)
  482. pszStringVal = L"$"; // should never compare equal to a class name
  483. atomStringVal = AddAtom(pszStringVal);
  484. if (atomStringVal)
  485. SetProp(hwnd, (LPCTSTR)atom, (void *)atomStringVal);
  486. }
  487. }
  488. }
  489. //---------------------------------------------------------------------------
  490. HRESULT EnsureUxCtrlLoaded()
  491. {
  492. CAutoCS cs(&_csUtils);
  493. if (! hinstUxCtrl)
  494. {
  495. TCHAR szPath[MAX_PATH];
  496. GetModuleFileName(GetModuleHandle(TEXT("UxTheme.dll")), szPath, ARRAYSIZE(szPath));
  497. ACTCTX act = {0};
  498. act.cbSize = sizeof(act);
  499. act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
  500. act.lpResourceName = MAKEINTRESOURCE(1);
  501. act.lpSource = szPath;
  502. HANDLE hActCtx = CreateActCtx(&act);
  503. ULONG_PTR ulCookie = 0;
  504. if (hActCtx != INVALID_HANDLE_VALUE)
  505. ActivateActCtx(hActCtx, &ulCookie);
  506. hinstUxCtrl = LoadLibrary(L"comctl32.dll");
  507. if (ulCookie)
  508. DeactivateActCtx(0, ulCookie);
  509. if (hActCtx != INVALID_HANDLE_VALUE)
  510. ReleaseActCtx(hActCtx);
  511. }
  512. if ((hinstUxCtrl) && (! ImageList_DrawProc))
  513. {
  514. ImageList_DrawProc = (IMAGE_DRAWPROC)GetProcAddress(hinstUxCtrl, "ImageList_DrawIndirect");
  515. #if 1 // testing DrawThemeIcon()
  516. ImageList_LoadProc = (IMAGE_LOADPROC)GetProcAddress(hinstUxCtrl, "ImageList_LoadImage");
  517. ImageList_DestroyProc = (IMAGE_DESTROYPROC)GetProcAddress(hinstUxCtrl, "ImageList_Destroy");
  518. #endif
  519. CCDrawShadowText = (PFNDRAWSHADOWTEXT)GetProcAddress(hinstUxCtrl, "DrawShadowText");
  520. }
  521. if ((ImageList_DrawProc) && (CCDrawShadowText))
  522. return S_OK;
  523. return MakeError32(E_FAIL); // something went wrong
  524. }
  525. //---------------------------------------------------------------------------
  526. BOOL IsUnicode(LPCSTR pszBuff, int *piUnicodeStartOffset)
  527. {
  528. int iOffset = 0;
  529. BOOL fUnicode = FALSE;
  530. if ((pszBuff[0] == 0xff) && (pszBuff[1] == 0xfe)) // unicode marker
  531. {
  532. iOffset = 2;
  533. fUnicode = TRUE;
  534. }
  535. else if (! pszBuff[1])
  536. {
  537. // this check works well for .ini files because of the limited
  538. // legal chars it can start with
  539. fUnicode = TRUE;
  540. }
  541. if (piUnicodeStartOffset)
  542. *piUnicodeStartOffset = iOffset;
  543. return fUnicode;
  544. }
  545. //---------------------------------------------------------------------------
  546. HRESULT AnsiToUnicode(LPSTR pszSource, LPWSTR pszDest, DWORD dwMaxDestChars)
  547. {
  548. int len = 1 + static_cast<int>(strlen(pszSource));
  549. int retval = MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, pszSource, len,
  550. pszDest, dwMaxDestChars);
  551. if (! retval)
  552. return MakeErrorLast();
  553. return S_OK;
  554. }
  555. //---------------------------------------------------------------------------
  556. HRESULT AllocateTextFile(LPCWSTR szFileName, OUT LPWSTR *ppszFileText,
  557. OUT OPTIONAL BOOL *pfWasAnsi)
  558. {
  559. HRESULT hr;
  560. CSimpleFile infile;
  561. hr = infile.Open(szFileName);
  562. if (FAILED(hr))
  563. return hr;
  564. //---- read the file ----
  565. DWORD len = infile.GetFileSize();
  566. //---- assume ANSI; adjust if UNICODE ----
  567. DWORD dw;
  568. LPSTR pOrig = (LPSTR) LocalAlloc(0, 2+len); // space for 2-byte UNICODE NULL
  569. if (! pOrig)
  570. return MakeErrorLast();
  571. if (len)
  572. {
  573. hr = infile.Read((LPSTR)pOrig, len, &dw);
  574. if (FAILED(hr))
  575. {
  576. LocalFree(pOrig);
  577. return hr;
  578. }
  579. if (dw != len)
  580. {
  581. LocalFree(pOrig);
  582. return MakeError32(E_FAIL);
  583. }
  584. }
  585. infile.Close();
  586. //---- null terminate for both cases ----
  587. pOrig[len] = 0;
  588. pOrig[len+1] = 0;
  589. int iOffset;
  590. if (IsUnicode(pOrig, &iOffset))
  591. {
  592. if ((iOffset) && (len)) // shift away the UNICODE signature bits
  593. memmove(pOrig, pOrig+iOffset, len-iOffset);
  594. *ppszFileText = (LPWSTR)pOrig;
  595. if (pfWasAnsi)
  596. *pfWasAnsi = FALSE;
  597. return S_OK;
  598. }
  599. //---- need to translate to UNICODE ----
  600. LPWSTR pUnicode = (LPWSTR) LocalAlloc(0, sizeof(WCHAR)*(len+1));
  601. if (! pUnicode)
  602. {
  603. hr = MakeErrorLast();
  604. LocalFree(pOrig);
  605. return hr;
  606. }
  607. hr = AnsiToUnicode((LPSTR)pOrig, pUnicode, len+1);
  608. if (FAILED(hr))
  609. {
  610. LocalFree(pOrig);
  611. LocalFree(pUnicode);
  612. return hr;
  613. }
  614. LocalFree(pOrig);
  615. *ppszFileText = pUnicode;
  616. if (pfWasAnsi)
  617. *pfWasAnsi = TRUE;
  618. return S_OK;
  619. }
  620. //---------------------------------------------------------------------------
  621. HRESULT TextToFile(LPCWSTR szFileName, LPCWSTR szText)
  622. {
  623. CSimpleFile outfile;
  624. HRESULT hr = outfile.Create(szFileName);
  625. if (FAILED(hr))
  626. return hr;
  627. hr = outfile.Write((void*)szText, lstrlenW(szText)*sizeof(WCHAR));
  628. if (FAILED(hr))
  629. return hr;
  630. outfile.Close();
  631. return S_OK;
  632. }
  633. //---------------------------------------------------------------------------
  634. HRESULT AddPathIfNeeded(LPCWSTR pszFileName, LPCWSTR pszPath, LPWSTR pszFullName,
  635. DWORD dwFullChars)
  636. {
  637. HRESULT hr;
  638. if (! pszFileName)
  639. return MakeError32(E_FAIL);
  640. DWORD len = lstrlen(pszFileName);
  641. BOOL fQualified = ((*pszFileName == L'\\') || ((len > 1) && (pszFileName[1] == ':')));
  642. if (fQualified)
  643. {
  644. if (dwFullChars < len+1)
  645. return MakeError32(E_FAIL);
  646. hr = hr_lstrcpy(pszFullName, pszFileName, dwFullChars);
  647. if (FAILED(hr))
  648. return hr;
  649. }
  650. else
  651. {
  652. DWORD len2 = lstrlen(pszPath);
  653. if (dwFullChars < len+len2+2)
  654. return MakeError32(E_FAIL);
  655. if ((len2) && (pszPath[len2-1] == '\\'))
  656. wsprintf(pszFullName, L"%s%psz", pszPath, pszFileName);
  657. else
  658. wsprintf(pszFullName, L"%s\\%s", pszPath, pszFileName);
  659. }
  660. return S_OK;
  661. }
  662. //---------------------------------------------------------------------------
  663. HICON _GetWindowIcon(HWND hwnd, BOOL fPerferLargeIcon)
  664. {
  665. const WPARAM rgGetIconParam[] = { ICON_SMALL2, ICON_SMALL, ICON_BIG };
  666. const WPARAM rgGetIconParamLarge[] = { ICON_BIG, ICON_SMALL2, ICON_SMALL };
  667. const int rgClassIconParam[] = { GCLP_HICONSM, GCLP_HICON };
  668. HICON hicon = NULL;
  669. const WPARAM * pIcons = (fPerferLargeIcon ? rgGetIconParamLarge : rgGetIconParam);
  670. int i;
  671. // try WM_GETICON
  672. for( i = 0; i < ARRAYSIZE(rgGetIconParam) && NULL == hicon; i++ )
  673. {
  674. SendMessageTimeout(hwnd, WM_GETICON, pIcons[i], 0, SMTO_ABORTIFHUNG | SMTO_BLOCK,
  675. 500, (PULONG_PTR)&hicon);
  676. }
  677. // try GetClassLong
  678. for( i = 0; i < ARRAYSIZE(rgClassIconParam) && NULL == hicon; i++ )
  679. {
  680. // next we try the small class icon
  681. hicon = (HICON)GetClassLongPtr(hwnd, rgClassIconParam[i]);
  682. }
  683. return hicon;
  684. }
  685. //---------------------------------------------------------------------------
  686. HRESULT hr_lstrcpy(LPWSTR pszDest, LPCWSTR pszSrc, DWORD dwMaxDestChars)
  687. {
  688. if ((! pszDest) || (! pszSrc))
  689. return MakeError32(E_INVALIDARG);
  690. DWORD dwSrcChars = lstrlen(pszSrc);
  691. if (dwSrcChars + 1 > dwMaxDestChars)
  692. return MakeError32(E_FAIL); // buffer too small for long string
  693. lstrcpy(pszDest, pszSrc);
  694. return S_OK;
  695. }
  696. //---------------------------------------------------------------------------
  697. void lstrcpy_truncate(LPWSTR pszDest, LPCWSTR pszSrc, DWORD dwMaxDestChars)
  698. {
  699. if (! dwMaxDestChars) // nothing to do
  700. return;
  701. DWORD dwSrcChars;
  702. if (pszSrc)
  703. dwSrcChars = lstrlen(pszSrc);
  704. else
  705. dwSrcChars = 0;
  706. if (dwSrcChars > dwMaxDestChars-1) // truncate string
  707. dwSrcChars = dwMaxDestChars-1;
  708. if (dwSrcChars)
  709. memcpy(pszDest, pszSrc, dwSrcChars*sizeof(WCHAR));
  710. pszDest[dwSrcChars] = 0;
  711. }
  712. //---------------------------------------------------------------------------
  713. int string2number(LPCWSTR psz)
  714. {
  715. int temp = 0, base = 10;
  716. int nNeg = 1;
  717. if (*psz == L'-')
  718. {
  719. nNeg = -1;
  720. psz++;
  721. }
  722. else if (*psz == L'+')
  723. psz++;
  724. if (*psz == '0')
  725. {
  726. ++psz;
  727. switch(*psz)
  728. {
  729. case L'X':
  730. case L'x':
  731. ++psz;
  732. base = 16;
  733. break;
  734. }
  735. }
  736. while (*psz)
  737. {
  738. switch (*psz)
  739. {
  740. case L'0': case L'1': case L'2': case L'3': case L'4':
  741. case L'5': case L'6': case L'7': case L'8': case L'9':
  742. temp = (temp * base) + (*psz++ - L'0');
  743. break;
  744. case L'a': case L'b': case L'c': case L'd': case L'e': case L'f':
  745. if (base == 10)
  746. return (nNeg*temp);
  747. temp = (temp * base) + (*psz++ - L'a' + 10);
  748. break;
  749. case L'A': case L'B': case L'C': case L'D': case L'E': case L'F':
  750. if (base == 10)
  751. return (nNeg*temp);
  752. temp = (temp * base) + (*psz++ - L'A' + 10);
  753. break;
  754. default:
  755. return (nNeg*temp);
  756. }
  757. }
  758. return (nNeg*temp);
  759. }
  760. //---------------------------------------------------------------------------
  761. HRESULT GetDirBaseName(LPCWSTR pszDirName, LPWSTR pszBaseBuff, DWORD dwMaxBaseChars)
  762. {
  763. //---- extract last node of dir name ----
  764. LPCWSTR p = wcsrchr(pszDirName, '\\');
  765. if ((p) && (p > pszDirName) && (! p[1])) // last char - try next one to left
  766. p = wcsrchr(p-1, '//');
  767. if (p)
  768. return hr_lstrcpy(pszBaseBuff, p, dwMaxBaseChars);
  769. return hr_lstrcpy(pszBaseBuff, pszDirName, dwMaxBaseChars);
  770. }
  771. //---------------------------------------------------------------------------
  772. BOOL AsciiScanStringList(
  773. LPCWSTR pwszString,
  774. LPCWSTR* rgpwszList,
  775. int cStrings,
  776. BOOL fIgnoreCase )
  777. {
  778. int (* pfnCompare)( LPCWSTR, LPCWSTR ) =
  779. fIgnoreCase ? AsciiStrCmpI : lstrcmp;
  780. for( int i = 0; i < cStrings; i++ )
  781. {
  782. if( 0 == pfnCompare( pwszString, rgpwszList[i] ) )
  783. {
  784. return TRUE;
  785. }
  786. }
  787. return FALSE;
  788. }
  789. //---------------------------------------------------------------------------
  790. BOOL UnExpandEnvironmentString(LPCWSTR pszPath, LPCWSTR pszEnvVar, LPWSTR pszResult, UINT cbResult)
  791. {
  792. DWORD nToCmp;
  793. WCHAR szEnvVar[MAX_PATH];
  794. szEnvVar[0] = 0;
  795. ExpandEnvironmentStringsW(pszEnvVar, szEnvVar, ARRAYSIZE(szEnvVar)); // don't count the NULL
  796. nToCmp = lstrlenW(szEnvVar);
  797. if (CSTR_EQUAL == CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, szEnvVar, nToCmp, pszPath, nToCmp))
  798. {
  799. if (lstrlenW(pszPath) - (int)nToCmp + lstrlenW(pszEnvVar) < (int)cbResult)
  800. {
  801. lstrcpyW(pszResult, pszEnvVar);
  802. lstrcpyW(pszResult + lstrlenW(pszResult), pszPath + nToCmp);
  803. return TRUE;
  804. }
  805. }
  806. return FALSE;
  807. }
  808. //---------------------------------------------------------------------------
  809. HRESULT RegistryIntWrite(HKEY hKey, LPCWSTR pszValueName, int iValue)
  810. {
  811. HRESULT hr = S_OK;
  812. WCHAR valbuff[_MAX_PATH+1];
  813. wsprintf(valbuff, L"%d", iValue);
  814. int len = (1 + lstrlen(valbuff)) * sizeof(WCHAR);
  815. int code32 = RegSetValueEx(hKey, pszValueName, NULL, REG_SZ,
  816. (BYTE *)valbuff, len);
  817. if (code32 != ERROR_SUCCESS)
  818. hr = MakeError32(code32);
  819. return hr;
  820. }
  821. //---------------------------------------------------------------------------
  822. HRESULT RegistryStrWrite(HKEY hKey, LPCWSTR pszValueName, LPCWSTR pszValue)
  823. {
  824. HRESULT hr = S_OK;
  825. int len = (1 + lstrlen(pszValue)) * (sizeof(WCHAR));
  826. int code32 = RegSetValueEx(hKey, pszValueName, NULL, REG_SZ,
  827. (BYTE *)pszValue, len);
  828. if (code32 != ERROR_SUCCESS)
  829. hr = MakeError32(code32);
  830. return hr;
  831. }
  832. //---------------------------------------------------------------------------
  833. HRESULT RegistryStrWriteExpand(HKEY hKey, LPCWSTR pszValueName, LPCWSTR pszValue)
  834. {
  835. HRESULT hr = S_OK;
  836. int len;
  837. WCHAR szResult[_MAX_PATH + 1];
  838. LPCWSTR pszPath = pszValue;
  839. if (UnExpandEnvironmentString(pszValue, L"%SystemRoot%", szResult, ARRAYSIZE(szResult)))
  840. pszPath = szResult;
  841. len = (1 + lstrlen(pszPath)) * (sizeof(WCHAR));
  842. int code32 = RegSetValueEx(hKey, pszValueName, NULL, REG_EXPAND_SZ,
  843. (BYTE *)pszPath, len);
  844. if (code32 != ERROR_SUCCESS)
  845. hr = MakeError32(code32);
  846. return hr;
  847. }
  848. //---------------------------------------------------------------------------
  849. HRESULT RegistryIntRead(HKEY hKey, LPCWSTR pszValueName, int *piValue)
  850. {
  851. HRESULT hr = S_OK;
  852. DWORD dwValType;
  853. WCHAR valbuff[_MAX_PATH+1];
  854. DWORD dwByteSize = sizeof(valbuff); // bytes, not chars
  855. int code32 = RegQueryValueEx(hKey, pszValueName, NULL, &dwValType,
  856. (BYTE *)valbuff, &dwByteSize);
  857. if (code32 == ERROR_SUCCESS)
  858. {
  859. *piValue = string2number(valbuff);
  860. }
  861. else
  862. hr = MakeError32(code32);
  863. return hr;
  864. }
  865. //---------------------------------------------------------------------------
  866. HRESULT RegistryStrRead(HKEY hKey, LPCWSTR pszValueName, LPWSTR pszBuff, DWORD dwMaxChars)
  867. {
  868. HRESULT hr = S_OK;
  869. DWORD dwValType = 0;
  870. DWORD dwByteSize = dwMaxChars * sizeof(WCHAR); // in bytes
  871. int code32 = RegQueryValueEx(hKey, pszValueName, NULL, &dwValType,
  872. (BYTE *)pszBuff, &dwByteSize);
  873. if (code32 != ERROR_SUCCESS)
  874. {
  875. hr = MakeError32(code32);
  876. goto exit;
  877. }
  878. if (dwValType == REG_EXPAND_SZ || wcschr(pszBuff, L'%'))
  879. {
  880. int len = sizeof(WCHAR) * (1 + lstrlen(pszBuff));
  881. LPWSTR szTempBuff = (LPWSTR)alloca(len);
  882. if (szTempBuff)
  883. {
  884. lstrcpy(szTempBuff, pszBuff);
  885. DWORD dwChars = ExpandEnvironmentStrings(szTempBuff, pszBuff, dwMaxChars);
  886. if (dwChars > dwMaxChars) // caller's buffer too small
  887. {
  888. hr = MakeError32(ERROR_INSUFFICIENT_BUFFER);
  889. }
  890. }
  891. }
  892. exit:
  893. return hr;
  894. }
  895. //---------------------------------------------------------------------------
  896. BOOL PreMultiplyAlpha(DWORD *pPixelBuff, UINT iWidth, UINT iHeight)
  897. {
  898. BOOL fTrueAlpha = FALSE;
  899. DWORD *pdw = pPixelBuff;
  900. for (int i = iWidth * iHeight - 1; i >= 0; i--)
  901. {
  902. COLORREF cr = *pdw;
  903. int iAlpha = ALPHACHANNEL(cr);
  904. if ((iAlpha != 255) && (iAlpha != 0))
  905. fTrueAlpha = TRUE;
  906. pdw++;
  907. }
  908. pdw = pPixelBuff;
  909. if (fTrueAlpha)
  910. {
  911. for (UINT r=0; r < iHeight; r++)
  912. {
  913. for (UINT c=0; c < iWidth; c++)
  914. {
  915. COLORREF cr = *pdw;
  916. int iAlpha = ALPHACHANNEL(cr);
  917. int iRed = (RED(cr)*iAlpha)/255;
  918. int iGreen = (GREEN(cr)*iAlpha)/255;
  919. int iBlue = (BLUE(cr)*iAlpha)/255;
  920. *pdw++ = (RGB(iRed, iGreen, iBlue) | (iAlpha << 24));
  921. }
  922. }
  923. }
  924. return fTrueAlpha;
  925. }
  926. //---------------------------------------------------------------------------
  927. HRESULT MakeFlippedBitmap(HBITMAP hSrcBitmap, HBITMAP *phFlipped)
  928. {
  929. HRESULT hr = S_OK;
  930. BOOL fSucceeded = FALSE;
  931. Log(LOG_TMBITMAP, L"MakeFlippedBitmap %08X", hSrcBitmap);
  932. //---- setup SOURCE dc/bitmap ----
  933. HDC hdcSrc = CreateCompatibleDC(NULL);
  934. if (hdcSrc)
  935. {
  936. DWORD dwSrcLayout = GetLayout(hdcSrc);
  937. HBITMAP hOldSrcBitmap = (HBITMAP)SelectObject(hdcSrc, hSrcBitmap);
  938. if (hOldSrcBitmap)
  939. {
  940. //---- setup DEST dc/bitmap ----
  941. //---- MSDN doc for CreateCompatibleBitmap says that this works correctly ----
  942. //---- if a DIB is selected in the dc ----
  943. BITMAP bm;
  944. if (GetObject(hSrcBitmap, sizeof(bm), &bm))
  945. {
  946. int iWidth = bm.bmWidth;
  947. int iHeight = bm.bmHeight;
  948. HBITMAP hDestBitmap = CreateCompatibleBitmap(hdcSrc, iWidth, iHeight);
  949. if (hDestBitmap)
  950. {
  951. HDC hdcDest = CreateCompatibleDC(hdcSrc);
  952. if (hdcDest)
  953. {
  954. HBITMAP hOldDestBitmap = (HBITMAP)SelectObject(hdcDest, hDestBitmap);
  955. if (hOldDestBitmap)
  956. {
  957. //---- toggle layout ----
  958. DWORD dwOldDestLayout;
  959. if (dwSrcLayout & LAYOUT_RTL)
  960. dwOldDestLayout = SetLayout(hdcDest, 0);
  961. else
  962. dwOldDestLayout = SetLayout(hdcDest, LAYOUT_RTL);
  963. //---- mirror the bits from src to dest ----
  964. if (BitBlt(hdcDest, 0, 0, iWidth, iHeight, hdcSrc, 0, 0, SRCCOPY))
  965. {
  966. *phFlipped = hDestBitmap;
  967. fSucceeded = TRUE;
  968. }
  969. SelectObject(hdcDest, hOldDestBitmap);
  970. }
  971. DeleteDC(hdcDest);
  972. }
  973. if (! fSucceeded)
  974. DeleteObject(hDestBitmap);
  975. }
  976. }
  977. SelectObject(hdcSrc, hOldSrcBitmap);
  978. }
  979. DeleteDC(hdcSrc);
  980. }
  981. if (! fSucceeded)
  982. hr = GetLastError();
  983. return hr;
  984. }
  985. //---------------------------------------------------------------------------
  986. HRESULT FlipDIB32(DWORD *pBits, UINT iWidth, UINT iHeight)
  987. {
  988. DWORD temp;
  989. DWORD *pTemp1;
  990. DWORD *pTemp2;
  991. HRESULT hr = S_OK;
  992. if (pBits == NULL || iWidth == 0 || iHeight == 0)
  993. {
  994. Log(LOG_TMBITMAP, L"FlipDIB32 failed.");
  995. return E_INVALIDARG;
  996. }
  997. for (UINT iRow = 0; iRow < iHeight; iRow++)
  998. {
  999. for (UINT iCol = 0; iCol < iWidth / 2; iCol++)
  1000. {
  1001. pTemp1 = pBits + iRow * iWidth + iCol;
  1002. pTemp2 = pBits + (iRow + 1) * iWidth - iCol - 1;
  1003. temp = *pTemp1;
  1004. *pTemp1 = *pTemp2;
  1005. *pTemp2 = temp;
  1006. }
  1007. }
  1008. return hr;
  1009. }
  1010. //---------------------------------------------------------------------------
  1011. // IsBiDiLocalizedSystem is taken from stockthk.lib and simplified
  1012. // (it's only a wrapper for GetUserDefaultUILanguage and GetLocaleInfo)
  1013. //---------------------------------------------------------------------------
  1014. typedef struct {
  1015. LANGID LangID;
  1016. BOOL bInstalled;
  1017. } MUIINSTALLLANG, *LPMUIINSTALLLANG;
  1018. /***************************************************************************\
  1019. * ConvertHexStringToIntW
  1020. *
  1021. * Converts a hex numeric string into an integer.
  1022. *
  1023. * History:
  1024. * 14-June-1998 msadek Created
  1025. \***************************************************************************/
  1026. BOOL ConvertHexStringToIntW( WCHAR *pszHexNum , int *piNum )
  1027. {
  1028. int n=0L;
  1029. WCHAR *psz=pszHexNum;
  1030. for(n=0 ; ; psz=CharNextW(psz))
  1031. {
  1032. if( (*psz>='0') && (*psz<='9') )
  1033. n = 0x10 * n + *psz - '0';
  1034. else
  1035. {
  1036. WCHAR ch = *psz;
  1037. int n2;
  1038. if(ch >= 'a')
  1039. ch -= 'a' - 'A';
  1040. n2 = ch - 'A' + 0xA;
  1041. if (n2 >= 0xA && n2 <= 0xF)
  1042. n = 0x10 * n + n2;
  1043. else
  1044. break;
  1045. }
  1046. }
  1047. /*
  1048. * Update results
  1049. */
  1050. *piNum = n;
  1051. return (psz != pszHexNum);
  1052. }
  1053. /***************************************************************************\
  1054. * Mirror_EnumUILanguagesProc
  1055. *
  1056. * Enumerates MUI installed languages on W2k
  1057. * History:
  1058. * 14-June-1999 msadek Created
  1059. \***************************************************************************/
  1060. BOOL CALLBACK Mirror_EnumUILanguagesProc(LPTSTR lpUILanguageString, LONG_PTR lParam)
  1061. {
  1062. int langID = 0;
  1063. ConvertHexStringToIntW(lpUILanguageString, &langID);
  1064. if((LANGID)langID == ((LPMUIINSTALLLANG)lParam)->LangID)
  1065. {
  1066. ((LPMUIINSTALLLANG)lParam)->bInstalled = TRUE;
  1067. return FALSE;
  1068. }
  1069. return TRUE;
  1070. }
  1071. /***************************************************************************\
  1072. * Mirror_IsUILanguageInstalled
  1073. *
  1074. * Verifies that the User UI language is installed on W2k
  1075. *
  1076. * History:
  1077. * 14-June-1999 msadek Created
  1078. \***************************************************************************/
  1079. BOOL Mirror_IsUILanguageInstalled( LANGID langId )
  1080. {
  1081. MUIINSTALLLANG MUILangInstalled = {0};
  1082. MUILangInstalled.LangID = langId;
  1083. EnumUILanguagesW(Mirror_EnumUILanguagesProc, 0, (LONG_PTR)&MUILangInstalled);
  1084. return MUILangInstalled.bInstalled;
  1085. }
  1086. /***************************************************************************\
  1087. * IsBiDiLocalizedSystemEx
  1088. *
  1089. * returns TRUE if running on a lozalized BiDi (Arabic/Hebrew) NT5 or Memphis.
  1090. * Should be called whenever SetProcessDefaultLayout is to be called.
  1091. *
  1092. * History:
  1093. * 02-Feb-1998 samera Created
  1094. \***************************************************************************/
  1095. BOOL IsBiDiLocalizedSystemEx( LANGID *pLangID )
  1096. {
  1097. int iLCID=0L;
  1098. static BOOL bRet = (BOOL)(DWORD)-1;
  1099. static LANGID langID = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL);
  1100. if (bRet != (BOOL)(DWORD)-1)
  1101. {
  1102. if (bRet && pLangID)
  1103. {
  1104. *pLangID = langID;
  1105. }
  1106. return bRet;
  1107. }
  1108. bRet = FALSE;
  1109. /*
  1110. * Need to use NT5 detection method (Multiligual UI ID)
  1111. */
  1112. langID = GetUserDefaultUILanguage();
  1113. if( langID )
  1114. {
  1115. WCHAR wchLCIDFontSignature[16];
  1116. iLCID = MAKELCID( langID , SORT_DEFAULT );
  1117. /*
  1118. * Let's verify this is a RTL (BiDi) locale. Since reg value is a hex string, let's
  1119. * convert to decimal value and call GetLocaleInfo afterwards.
  1120. * LOCALE_FONTSIGNATURE always gives back 16 WCHARs.
  1121. */
  1122. if( GetLocaleInfoW( iLCID ,
  1123. LOCALE_FONTSIGNATURE ,
  1124. (WCHAR *) &wchLCIDFontSignature[0] ,
  1125. (sizeof(wchLCIDFontSignature)/sizeof(WCHAR))) )
  1126. {
  1127. /* Let's verify the bits we have a BiDi UI locale */
  1128. if(( wchLCIDFontSignature[7] & (WCHAR)0x0800) && Mirror_IsUILanguageInstalled(langID) )
  1129. {
  1130. bRet = TRUE;
  1131. }
  1132. }
  1133. }
  1134. if (bRet && pLangID)
  1135. {
  1136. *pLangID = langID;
  1137. }
  1138. return bRet;
  1139. }
  1140. //---------------------------------------------------------------------------
  1141. BOOL IsBiDiLocalizedSystem( void )
  1142. {
  1143. return IsBiDiLocalizedSystemEx(NULL);
  1144. }
  1145. //---------------------------------------------------------------------------
  1146. BOOL GetWindowDesktopName(HWND hwnd, LPWSTR pszName, DWORD dwMaxChars)
  1147. {
  1148. BOOL fGotName = FALSE;
  1149. DWORD dwThreadId = GetWindowThreadProcessId(hwnd, NULL);
  1150. HDESK hDesk = GetThreadDesktop(dwThreadId);
  1151. if (hDesk)
  1152. {
  1153. fGotName = GetUserObjectInformation(hDesk, UOI_NAME, pszName, dwMaxChars*sizeof(WCHAR), NULL);
  1154. }
  1155. return fGotName;
  1156. }
  1157. //---------------------------------------------------------------------------
  1158. void SafeSendMessage(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1159. {
  1160. DWORD dwFlags = SMTO_BLOCK | SMTO_ABORTIFHUNG;
  1161. DWORD dwTimeout = 250; // .25 secs
  1162. ULONG_PTR puRetVal;
  1163. if (! SendMessageTimeout(hwnd, uMsg, wParam, lParam, dwFlags, dwTimeout, &puRetVal))
  1164. {
  1165. Log(LOG_TMLOAD, L"SEND TIMEOUT: msg=0x%x being POSTED to hwnd=0x%x",
  1166. uMsg, hwnd);
  1167. PostMessage(hwnd, uMsg, wParam, lParam);
  1168. }
  1169. }
  1170. //---------------------------------------------------------------------------
  1171. int FontPointSize(int iFontHeight)
  1172. {
  1173. return -MulDiv(iFontHeight, 72, THEME_DPI);
  1174. }
  1175. //---------------------------------------------------------------------------
  1176. void ScaleFontForHdcDpi(HDC hdc, LOGFONT *plf)
  1177. {
  1178. if (plf->lfHeight < 0) // specified in points
  1179. {
  1180. if (! hdc)
  1181. {
  1182. ScaleFontForScreenDpi(plf);
  1183. }
  1184. else
  1185. {
  1186. int iDpi = GetDeviceCaps(hdc, LOGPIXELSX);
  1187. plf->lfHeight = MulDiv(plf->lfHeight, iDpi, THEME_DPI);
  1188. }
  1189. }
  1190. }
  1191. //---------------------------------------------------------------------------
  1192. int ScaleSizeForHdcDpi(HDC hdc, int iValue)
  1193. {
  1194. int iScaledValue;
  1195. if (! hdc)
  1196. {
  1197. iScaledValue = ScaleSizeForScreenDpi(iValue);
  1198. }
  1199. else
  1200. {
  1201. int iDpi = GetDeviceCaps(hdc, LOGPIXELSX);
  1202. iScaledValue = MulDiv(iValue, iDpi, THEME_DPI);
  1203. }
  1204. return iScaledValue;
  1205. }
  1206. //---------------------------------------------------------------------------
  1207. // --------------------------------------------------------------------------
  1208. // MinimumDisplayColorDepth
  1209. //
  1210. // Arguments: <none>
  1211. //
  1212. // Returns: DWORD
  1213. //
  1214. // Purpose: Iterates all monitors attached to the system and finds those
  1215. // that are active. Returns the lowest bit depth availabe. This
  1216. // is the lowest common denominator.
  1217. //
  1218. // History: 2001-04-11 lmouton moved from services.cpp
  1219. // 2000-11-11 vtan created (rewritten from themeldr.cpp)
  1220. // --------------------------------------------------------------------------
  1221. DWORD MinimumDisplayColorDepth (void)
  1222. {
  1223. DWORD dwMinimumDepth, dwIndex;
  1224. bool fContinue;
  1225. DISPLAY_DEVICE displayDevice;
  1226. dwMinimumDepth = 0;
  1227. ZeroMemory(&displayDevice, sizeof(displayDevice));
  1228. dwIndex = 0;
  1229. do
  1230. {
  1231. displayDevice.cb = sizeof(displayDevice);
  1232. fContinue = (EnumDisplayDevices(NULL, dwIndex++, &displayDevice, 0) != FALSE);
  1233. if (fContinue)
  1234. {
  1235. if ((displayDevice.StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) != 0)
  1236. {
  1237. DEVMODE devMode;
  1238. ZeroMemory(&devMode, sizeof(devMode));
  1239. devMode.dmSize = sizeof(devMode);
  1240. devMode.dmDriverExtra = 0;
  1241. if (EnumDisplaySettings(displayDevice.DeviceName, ENUM_CURRENT_SETTINGS, &devMode) != FALSE)
  1242. {
  1243. if ((dwMinimumDepth == 0) || (dwMinimumDepth > devMode.dmBitsPerPel))
  1244. {
  1245. dwMinimumDepth = devMode.dmBitsPerPel;
  1246. }
  1247. }
  1248. }
  1249. }
  1250. } while (fContinue);
  1251. // Note: We can fail here (return 0) because when a session is disconnected, the desktop is attached to
  1252. // a hidden display. OK to fail silently then.
  1253. return(dwMinimumDepth);
  1254. }
  1255. // --------------------------------------------------------------------------
  1256. // CheckMinColorDepth
  1257. //
  1258. // Arguments: hInst msstyle module handle
  1259. // dwCurMinDepth current minimum active screen resolution
  1260. // iIndex index to the color/size combo to test, or
  1261. // -1 to enumerate them all
  1262. //
  1263. // Returns: bool true if at least a color/size combo supports
  1264. // the current screen resolution
  1265. //
  1266. // History: 2001-04-11 lmouton created
  1267. // --------------------------------------------------------------------------
  1268. bool CheckMinColorDepth(HINSTANCE hInst, DWORD dwCurMinDepth, int iIndex)
  1269. {
  1270. BYTE *pBytes = NULL;
  1271. DWORD dwBytes = 0;
  1272. bool bMatch = true; // OK if the resource doesn't exist
  1273. if (SUCCEEDED(GetPtrToResource(hInst, L"MINDEPTH", MAKEINTRESOURCE(1), (void**) &pBytes, &dwBytes)) && dwBytes > 0)
  1274. {
  1275. bMatch = false;
  1276. if (iIndex != -1)
  1277. {
  1278. if (*((WORD*) pBytes + iIndex) <= dwCurMinDepth)
  1279. bMatch = true;
  1280. }
  1281. else
  1282. {
  1283. WORD wDepth = *((WORD*) pBytes);
  1284. while (wDepth != 0)
  1285. {
  1286. if (wDepth <= (WORD) dwCurMinDepth)
  1287. {
  1288. bMatch = true;
  1289. break;
  1290. }
  1291. pBytes += sizeof(WORD);
  1292. wDepth = *((WORD*) pBytes);
  1293. }
  1294. }
  1295. }
  1296. return bMatch;
  1297. }