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.

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