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.

1008 lines
33 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. // schemnt5.c
  3. //
  4. // This component of shmgrate.exe is designed to upgrade the user's schemes
  5. // and colors to the new values required for Windows 2000. This work is
  6. // coordinated with changes to the scheme data provided by Win2000 setup
  7. // in the files hivedef.inx and hiveusd.inx.
  8. //
  9. // brianau 6/11/98
  10. // brianau 2/18/99 - Updated for "MS Sans Serif"->"Microsoft Sans Serif"
  11. // conversion.
  12. // brianau 6/24/99 - Set gradient colors same as non-gradient colors in
  13. // NT4 custom schemes.
  14. //
  15. #include <windows.h>
  16. #include <winuserp.h>
  17. #include <tchar.h>
  18. #include <stdio.h>
  19. #include <shlwapi.h>
  20. #include "shmgdefs.h"
  21. #ifndef COLOR_3DALTFACE
  22. //
  23. // This is not defined in winuser.h (looks like it should be).
  24. // The desktop applet places this color at ordinal 25 in the
  25. // order of colors. There's a "hole" in the ordinal numbers
  26. // defined in winuser.h between numbers 24 and 26 so I'm
  27. // assuming it's supposed to be COLOR_3DALTFACE. Regardless,
  28. // the number is valid for the arrays in this module.
  29. //
  30. # define COLOR_3DALTFACE 25
  31. #endif
  32. //
  33. // This string defines the new font to be used for the
  34. // NC fonts. If you want to change the face name, this
  35. // is the only place a change is required.
  36. //
  37. #define STR_NEWNCFONT TEXT("Tahoma")
  38. //
  39. // Defining this macro prevents any registry changes from being
  40. // made. Used for development only.
  41. //
  42. // Undefine before flight.
  43. //
  44. //#define NO_REG_CHANGES 1
  45. //
  46. //
  47. // Redefine a private version of COLOR_MAX macro (winuser.h)
  48. // This code needs to stay in sync with Windows Setup and
  49. // desk.cpl, not what is defined in winuser.h. Someone added
  50. // two new colors to winuser.h which increased COLOR_MAX by 2
  51. // which increased the size of SCHEMEDATA by 8 bytes. This
  52. // caused us to write out 8 extra bytes to the registry so that
  53. // desk.cpl no longer recognizes these entries. Setup, desk.cpl
  54. // and shmgrate need to stay in sync with respect to the size of
  55. // SCHEMEDATA. [brianau - 4/3/00]
  56. //
  57. #define MAX_COLORS (COLOR_GRADIENTINACTIVECAPTION + 1)
  58. //
  59. // This structure was taken from shell\ext\cpls\desknt5\lookdlg.c
  60. // It's the definition the desktop applet uses for reading/writing
  61. // scheme data to/from the registry.
  62. //
  63. typedef struct {
  64. SHORT version;
  65. WORD wDummy; // For alignment.
  66. NONCLIENTMETRICS ncm;
  67. LOGFONT lfIconTitle;
  68. COLORREF rgb[MAX_COLORS];
  69. } SCHEMEDATA;
  70. const TCHAR g_szRegKeySchemes[] = TEXT("Control Panel\\Appearance\\Schemes");
  71. const TCHAR g_szRegKeyMetrics[] = TEXT("Control Panel\\Desktop\\WindowMetrics");
  72. const TCHAR g_szRegKeyColors[] = TEXT("Control Panel\\Colors");
  73. const TCHAR g_szRegValRGB[] = TEXT("255 255 255");
  74. const TCHAR g_szMsSansSerif[] = TEXT("MS Sans Serif");
  75. const TCHAR g_szMicrosoftSansSerif[] = TEXT("Microsoft Sans Serif");
  76. const TCHAR g_szCaptionFont[] = TEXT("CaptionFont");
  77. const TCHAR g_szSmCaptionFont[] = TEXT("SmCaptionFont");
  78. const TCHAR g_szMenuFont[] = TEXT("MenuFont");
  79. const TCHAR g_szStatusFont[] = TEXT("StatusFont");
  80. const TCHAR g_szMessageFont[] = TEXT("MessageFont");
  81. const TCHAR g_szIconFont[] = TEXT("IconFont");
  82. const TCHAR g_szNewNcFont[] = STR_NEWNCFONT;
  83. //
  84. // Font Metric Item index values. This enumeration represents the
  85. // order of items in any global arrays associated with the
  86. // non-client metric font items.
  87. // These must stay in sync with the entries in g_rgpszFontMetrics[]
  88. // and g_rglfDefaults[].
  89. //
  90. enum FontMetricIndex { FMI_CAPTIONFONT,
  91. FMI_SMCAPTIONFONT,
  92. FMI_MENUFONT,
  93. FMI_STATUSFONT,
  94. FMI_MESSAGEFONT,
  95. FMI_ICONFONT };
  96. //
  97. // Font metric reg value name strings.
  98. // The order of these must match the order of the FontMetricIndex
  99. // enumeration.
  100. //
  101. const LPCTSTR g_rgpszFontMetrics[] = { g_szCaptionFont,
  102. g_szSmCaptionFont,
  103. g_szMenuFont,
  104. g_szStatusFont,
  105. g_szMessageFont,
  106. g_szIconFont
  107. };
  108. //
  109. // Total number of window font metrics being considered.
  110. //
  111. #define NUM_NC_FONTS ARRAYSIZE(g_rgpszFontMetrics)
  112. //
  113. // Default LOGFONT data for NC fonts.
  114. // Used if there's no NC font data present (i.e. clean US install).
  115. // This data corresponds to the "Windows Standard" scheme on a clean
  116. // NT 5.0 installation modified with our desired changes.
  117. // These entries must be maintained in the order of the FontMetricIndex
  118. // enumeration.
  119. //
  120. // For reference, The LOGFONT structure is:
  121. //
  122. // struct LOGFONT {
  123. // LONG lfHeight;
  124. // LONG lfWidth;
  125. // LONG lfEscapement;
  126. // LONG lfOrientation;
  127. // LONG lfWeight;
  128. // BYTE lfItalic;
  129. // BYTE lfUnderline;
  130. // BYTE lfStrikeOut;
  131. // BYTE lfCharSet;
  132. // BYTE lfOutPrecision;
  133. // BYTE lfClipPrecision;
  134. // BYTE lfQuality;
  135. // BYTE lfPitchAndFamily;
  136. // TCHAR lfFaceName[LF_FACESIZE]; // LF_FACESIZE == 32.
  137. // };
  138. //
  139. const LOGFONT g_rglfDefaults[NUM_NC_FONTS] = {
  140. { -11, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // CAPTION
  141. { -11, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // SMCAPTION
  142. { -11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // MENU
  143. { -11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // STATUS
  144. { -11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // MESSAGE
  145. { -11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT } // ICON
  146. };
  147. //
  148. // These are the elements represented in the "Control Panel\Colors"
  149. // reg key. The rgbValue member is the new color value we want
  150. // to assign. See UpdateElementColor() for usage.
  151. //
  152. const struct NcmColors
  153. {
  154. LPCTSTR pszName; // Value name in "Control Panel\Colors" reg key.
  155. COLORREF rgbValue; // The new color.
  156. } g_rgWinStdColors[] = {
  157. { TEXT("Scrollbar"), 0x00C8D0D4 }, // COLOR_SCROLLBAR
  158. { TEXT("Background"), 0x00A56E3A }, // COLOR_BACKGROUND
  159. { TEXT("ActiveTitle"), 0x006A240A }, // COLOR_ACTIVECAPTION
  160. { TEXT("InactiveTitle"), 0x00808080 }, // COLOR_INACTIVECAPTION
  161. { TEXT("Menu"), 0x00C8D0D4 }, // COLOR_MENU
  162. { TEXT("Window"), 0x00FFFFFF }, // COLOR_WINDOW
  163. { TEXT("WindowFrame"), 0x00000000 }, // COLOR_WINDOWFRAME
  164. { TEXT("MenuText"), 0x00000000 }, // COLOR_MENUTEXT
  165. { TEXT("WindowText"), 0x00000000 }, // COLOR_WINDOWTEXT
  166. { TEXT("TitleText"), 0x00FFFFFF }, // COLOR_CAPTIONTEXT
  167. { TEXT("ActiveBorder"), 0x00C8D0D4 }, // COLOR_ACTIVEBORDER
  168. { TEXT("InactiveBorder"), 0x00C8D0D4 }, // COLOR_INACTIVEBORDER
  169. { TEXT("AppWorkspace"), 0x00808080 }, // COLOR_APPWORKSPACE
  170. { TEXT("Hilight"), 0x006A240A }, // COLOR_HIGHLIGHT
  171. { TEXT("HilightText"), 0x00FFFFFF }, // COLOR_HIGHLIGHTTEXT
  172. { TEXT("ButtonFace"), 0x00C8D0D4 }, // COLOR_BTNFACE
  173. { TEXT("ButtonShadow"), 0x00808080 }, // COLOR_BTNSHADOW
  174. { TEXT("GrayText"), 0x00808080 }, // COLOR_GRAYTEXT
  175. { TEXT("ButtonText"), 0x00000000 }, // COLOR_BTNTEXT
  176. { TEXT("InactiveTitleText"), 0x00C8D0D4 }, // COLOR_INACTIVECAPTIONTEXT
  177. { TEXT("ButtonHilight"), 0x00FFFFFF }, // COLOR_BTNHIGHLIGHT
  178. { TEXT("ButtonDkShadow"), 0x00404040 }, // COLOR_3DDKSHADOW
  179. { TEXT("ButtonLight"), 0x00C8D0D4 }, // COLOR_3DLIGHT
  180. { TEXT("InfoText"), 0x00000000 }, // COLOR_INFOTEXT
  181. { TEXT("InfoWindow"), 0x00E1FFFF }, // COLOR_INFOBK
  182. { TEXT("ButtonAlternateFace"), 0x00B5B5B5 }, // COLOR_3DALTFACE
  183. { TEXT("HotTrackingColor"), 0x00800000 }, // COLOR_HOTLIGHT
  184. { TEXT("GradientActiveTitle"), 0x00F0CAA6 }, // COLOR_GRADIENTACTIVECAPTION
  185. { TEXT("GradientInactiveTitle"), 0x00C0C0C0 } // COLOR_GRADIENTINACTIVECAPTION
  186. };
  187. #ifdef NO_REG_CHANGES
  188. void DumpLogFont(
  189. const LOGFONT *plf
  190. )
  191. {
  192. DPRINT((TEXT("Dumping LOGFONT ----------------------------------\n")));
  193. DPRINT((TEXT("\tplf->lfHeight.........: %d\n"), plf->lfHeight));
  194. DPRINT((TEXT("\tplf->lfWidth..........: %d\n"), plf->lfWidth));
  195. DPRINT((TEXT("\tplf->lfEscapement.....: %d\n"), plf->lfEscapement));
  196. DPRINT((TEXT("\tplf->lfOrientation....: %d\n"), plf->lfOrientation));
  197. DPRINT((TEXT("\tplf->lfWeight.........: %d\n"), plf->lfWeight));
  198. DPRINT((TEXT("\tplf->lfItalic.........: %d\n"), plf->lfItalic));
  199. DPRINT((TEXT("\tplf->lfUnderline......: %d\n"), plf->lfUnderline));
  200. DPRINT((TEXT("\tplf->lfStrikeOut......: %d\n"), plf->lfStrikeOut));
  201. DPRINT((TEXT("\tplf->lfCharSet........: %d\n"), plf->lfCharSet));
  202. DPRINT((TEXT("\tplf->lfOutPrecision...: %d\n"), plf->lfOutPrecision));
  203. DPRINT((TEXT("\tplf->lfClipPrecision..: %d\n"), plf->lfClipPrecision));
  204. DPRINT((TEXT("\tplf->lfQuality........: %d\n"), plf->lfQuality));
  205. DPRINT((TEXT("\tplf->lfPitchAndFamily.: %d\n"), plf->lfPitchAndFamily));
  206. DPRINT((TEXT("\tplf->lfFaceName.......: \"%s\"\n"), plf->lfFaceName));
  207. }
  208. void DumpSchemeStructure(
  209. const SCHEMEDATA *psd
  210. )
  211. {
  212. int i;
  213. DPRINT((TEXT("version..............: %d\n"), psd->version));
  214. DPRINT((TEXT("ncm.cbSize...........: %d\n"), psd->ncm.cbSize));
  215. DPRINT((TEXT("ncm.iBorderWidth.....: %d\n"), psd->ncm.iBorderWidth));
  216. DPRINT((TEXT("ncm.iScrollWidth.....: %d\n"), psd->ncm.iScrollWidth));
  217. DPRINT((TEXT("ncm.iScrollHeight....: %d\n"), psd->ncm.iScrollHeight));
  218. DPRINT((TEXT("ncm.iCaptionWidth....: %d\n"), psd->ncm.iCaptionWidth));
  219. DPRINT((TEXT("ncm.iSmCaptionWidth..: %d\n"), psd->ncm.iSmCaptionWidth));
  220. DPRINT((TEXT("ncm.iSmCaptionHeight.: %d\n"), psd->ncm.iSmCaptionHeight));
  221. DPRINT((TEXT("ncm.iMenuWidth.......: %d\n"), psd->ncm.iMenuWidth));
  222. DPRINT((TEXT("ncm.iMenuHeight......: %d\n"), psd->ncm.iMenuHeight));
  223. DPRINT((TEXT("ncm.lfCaptionFont:\n")));
  224. DumpLogFont(&psd->ncm.lfCaptionFont);
  225. DPRINT((TEXT("ncm.lfSmCaptionFont:\n")));
  226. DumpLogFont(&psd->ncm.lfSmCaptionFont);
  227. DPRINT((TEXT("ncm.lfMenuFont:\n")));
  228. DumpLogFont(&psd->ncm.lfMenuFont);
  229. DPRINT((TEXT("ncm.lfStatusFont:\n")));
  230. DumpLogFont(&psd->ncm.lfStatusFont);
  231. DPRINT((TEXT("ncm.lfMessageFont:\n")));
  232. DumpLogFont(&psd->ncm.lfMessageFont);
  233. DPRINT((TEXT("lfIconTitle:\n")));
  234. DumpLogFont(&psd->lfIconTitle);
  235. for (i = 0; i < ARRAYSIZE(psd->rgb); i++)
  236. {
  237. DPRINT((TEXT("Color[%2d] (%3d,%3d,%3d)\n"),
  238. i,
  239. GetRValue(psd->rgb[i]),
  240. GetGValue(psd->rgb[i]),
  241. GetBValue(psd->rgb[i])));
  242. }
  243. }
  244. #endif
  245. //
  246. // Retrieve a named color value for a given user.
  247. //
  248. DWORD
  249. GetColorForUser(
  250. HKEY hkeyColors,
  251. LPCTSTR pszName,
  252. COLORREF *prgb
  253. )
  254. {
  255. DWORD dwType;
  256. TCHAR szValue[ARRAYSIZE(g_szRegValRGB)];
  257. DWORD cbData = sizeof(szValue);
  258. DWORD dwResult = RegQueryValueEx(hkeyColors,
  259. pszName,
  260. NULL,
  261. &dwType,
  262. (LPBYTE)szValue,
  263. &cbData);
  264. if (ERROR_SUCCESS == dwResult && REG_SZ == dwType)
  265. {
  266. //
  267. // Values in the registry are in REG_SZ formatted as
  268. // "RRR GGG BBB" where RRR, GGG and BBB are byte values
  269. // expressed as ASCII text.
  270. //
  271. BYTE rgbTemp[3] = {0,0,0};
  272. LPTSTR pszTemp = szValue;
  273. LPTSTR pszColor = szValue;
  274. int i;
  275. for (i = 0; i < ARRAYSIZE(rgbTemp); i++)
  276. {
  277. //
  278. // Skip any leading spaces.
  279. //
  280. while(*pszTemp && TEXT(' ') == *pszTemp)
  281. pszTemp++;
  282. //
  283. // Remember the start of this color value.
  284. //
  285. pszColor = pszTemp;
  286. //
  287. // Find the end of the current color value.
  288. //
  289. while(*pszTemp && TEXT(' ') != *pszTemp)
  290. pszTemp++;
  291. if (2 != i && TEXT('\0') == *pszTemp)
  292. {
  293. //
  294. // Nul character encountered before 3rd member of color
  295. // triplet was read. Assume it's bogus data.
  296. //
  297. dwResult = ERROR_INVALID_DATA;
  298. DPRINT((TEXT("Invalid color data in registry \"%s\"\n"), szValue));
  299. break;
  300. }
  301. //
  302. // Nul-terminate this color value string and conver it to a number.
  303. //
  304. *pszTemp++ = TEXT('\0');
  305. rgbTemp[i] = (BYTE)StrToInt(pszColor);
  306. }
  307. //
  308. // Return color info as an RGB triplet.
  309. //
  310. *prgb = RGB(rgbTemp[0], rgbTemp[1], rgbTemp[2]);
  311. }
  312. else
  313. {
  314. DPRINT((TEXT("Error %d querying reg color value \"%s\"\n"), dwResult, pszName));
  315. dwResult = ERROR_INVALID_HANDLE;
  316. }
  317. return dwResult;
  318. }
  319. //
  320. // Update a named color value for a specified user.
  321. //
  322. DWORD
  323. UpdateColorForUser(
  324. HKEY hkeyColors,
  325. LPCTSTR pszName,
  326. COLORREF rgb
  327. )
  328. {
  329. DWORD dwResult;
  330. TCHAR szValue[ARRAYSIZE(g_szRegValRGB)];
  331. //
  332. // Convert RGB triplet to a text string for storage in the registry.
  333. //
  334. wsprintf(szValue, TEXT("%d %d %d"), GetRValue(rgb), GetGValue(rgb), GetBValue(rgb));
  335. //
  336. // Save it to the registry.
  337. //
  338. dwResult = RegSetValueEx(hkeyColors,
  339. pszName,
  340. 0,
  341. REG_SZ,
  342. (CONST BYTE *)szValue,
  343. sizeof(szValue));
  344. if (ERROR_SUCCESS != dwResult)
  345. {
  346. DPRINT((TEXT("Error %d setting color value \"%s\" to \"%s\"\n"), dwResult, pszName, szValue));
  347. }
  348. return dwResult;
  349. }
  350. DWORD
  351. UpdateElementColor(
  352. HKEY hkeyColors,
  353. const int *rgiElements,
  354. int cElements
  355. )
  356. {
  357. int i;
  358. for (i = 0; i < cElements; i++)
  359. {
  360. int iElement = rgiElements[i];
  361. UpdateColorForUser(hkeyColors,
  362. g_rgWinStdColors[iElement].pszName,
  363. g_rgWinStdColors[iElement].rgbValue);
  364. }
  365. return ERROR_SUCCESS;
  366. }
  367. //
  368. // Perform all color updates for a user's NCM colors.
  369. // These are the new "softer" grays and blues.
  370. // ChristoB provided the color values.
  371. //
  372. DWORD
  373. UpdateColorsForUser(
  374. HKEY hkeyUser
  375. )
  376. {
  377. HKEY hkeyColors;
  378. DWORD dwResult = RegOpenKeyEx(hkeyUser,
  379. g_szRegKeyColors,
  380. 0,
  381. KEY_QUERY_VALUE | KEY_SET_VALUE,
  382. &hkeyColors);
  383. if (ERROR_SUCCESS == dwResult)
  384. {
  385. //
  386. // Update these if the 3D button color is 192,192,192.
  387. //
  388. const int rgFaceChanges[] = { COLOR_BTNFACE,
  389. COLOR_SCROLLBAR,
  390. COLOR_MENU,
  391. COLOR_ACTIVEBORDER,
  392. COLOR_INACTIVEBORDER,
  393. COLOR_3DDKSHADOW,
  394. COLOR_3DLIGHT };
  395. //
  396. // Update these if the active caption color is 0,0,128
  397. //
  398. const int rgCaptionChanges[] = { COLOR_ACTIVECAPTION,
  399. COLOR_HIGHLIGHT,
  400. COLOR_GRADIENTACTIVECAPTION,
  401. COLOR_GRADIENTINACTIVECAPTION };
  402. //
  403. // Update these if the desktop is 128,128,0 (seafoam green)
  404. //
  405. const int rgDesktopChanges[] = { COLOR_BACKGROUND };
  406. struct
  407. {
  408. int iTest; // COLOR_XXXXX value.
  409. COLORREF rgbTest; // Color value that triggers upgrade.
  410. const int *prgChanges; // Array of elements to upgrade.
  411. int cChanges; // Number of elements to upgrade.
  412. } rgci [] = {{ COLOR_3DFACE, 0x00C0C0C0, rgFaceChanges, ARRAYSIZE(rgFaceChanges) },
  413. { COLOR_ACTIVECAPTION, 0x00800000, rgCaptionChanges, ARRAYSIZE(rgCaptionChanges) },
  414. { COLOR_BACKGROUND, 0x00808000, rgDesktopChanges, ARRAYSIZE(rgDesktopChanges) }};
  415. int i;
  416. COLORREF rgb;
  417. for (i = 0; i < ARRAYSIZE(rgci); i++)
  418. {
  419. int iTest = rgci[i].iTest;
  420. COLORREF rgbTest = rgci[i].rgbTest;
  421. if (ERROR_SUCCESS == GetColorForUser(hkeyColors, g_rgWinStdColors[iTest].pszName, &rgb) &&
  422. rgbTest == rgb)
  423. {
  424. UpdateElementColor(hkeyColors, rgci[i].prgChanges, rgci[i].cChanges);
  425. }
  426. }
  427. RegCloseKey(hkeyColors);
  428. }
  429. else
  430. {
  431. DPRINT((TEXT("Error %d opening reg key \"%s\" for user.\n"), dwResult, g_szRegKeyColors));
  432. }
  433. return dwResult;
  434. }
  435. //
  436. // Convert a font metric name to a member of the FontMetricIndex
  437. // enumeration. Used to index into g_rgpszFontMetrics[] and
  438. // g_rglfDefaults[].
  439. //
  440. // i.e. Returns FMI_CAPTIONFONT for "CaptionFont".
  441. //
  442. int
  443. FontMetricNameToIndex(
  444. LPCTSTR pszName
  445. )
  446. {
  447. int i;
  448. for (i = 0; i < ARRAYSIZE(g_rgpszFontMetrics); i++)
  449. {
  450. if (0 == lstrcmp(pszName, g_rgpszFontMetrics[i]))
  451. return i;
  452. }
  453. return -1;
  454. }
  455. //
  456. // When updating a font from "MS Sans Serif" to a TrueType font
  457. // we want to ensure the font point size is 8pt or greater.
  458. // So, if the current font face is "MS Sans Serif" and
  459. // (-11 < lfHeight < 0) is true, we force the lfHeight
  460. // to -11 which corresponds to 8pt. The standard windows
  461. // schemes incorrectly have the height of the icon font
  462. // specified as -8 (6pt) when it should be -11 (8pt).
  463. // The problem is that the smallest pt size supported by
  464. // MS Sans Serif is 8pt so even if the requested size is 6pt,
  465. // you see 8pt. Once we switch to Tahoma (a TrueType font),
  466. // it can produce the requested 6pt size so that's what you
  467. // see. 6pt is way too small for desktop icons.
  468. // The default icon font size used by user32.dll is 8pt.
  469. // See code in ntuser\kernel\inctlpan.c CreateFontFromWinIni().
  470. //
  471. void
  472. CorrectTooSmallFont(
  473. LOGFONT *plf
  474. )
  475. {
  476. if ((0 > (int)plf->lfHeight) && (-11 < (int)plf->lfHeight))
  477. {
  478. //
  479. // NT uses font height values.
  480. //
  481. plf->lfHeight = -11;
  482. }
  483. else if ((0 < (int)plf->lfHeight) && (8 > (int)plf->lfHeight))
  484. {
  485. //
  486. // Win9x uses font point sizes.
  487. //
  488. plf->lfHeight = 8;
  489. }
  490. }
  491. //
  492. // Replace any LOGFONT members in a LOGFONT structure and write the data
  493. // to the registry for a given nc font metric.
  494. //
  495. // If plf is NULL, a new LOGFONT with default data is written to
  496. // the registry for the metric value.
  497. // If plf is non-NULL and the LOGFONT's facename is in the list of
  498. // facenames to be updated, the required substitutions are made and
  499. // the LOGFONT data is replaced in the registry.
  500. //
  501. DWORD
  502. UpdateNcFont(
  503. HKEY hkeyMetrics,
  504. LPCTSTR pszValueName,
  505. const LOGFONT *plf
  506. )
  507. {
  508. DWORD dwResult = ERROR_SUCCESS;
  509. int iMetrics = FontMetricNameToIndex(pszValueName);
  510. LOGFONT lfCopy;
  511. if (NULL == plf)
  512. {
  513. //
  514. // Use all default values.
  515. //
  516. plf = &g_rglfDefaults[iMetrics];
  517. }
  518. else
  519. {
  520. //
  521. // First see if this face name should be updated.
  522. //
  523. if (0 == lstrcmpi(plf->lfFaceName, g_szMsSansSerif))
  524. {
  525. //
  526. // Yep. Update the face name string in the logfont.
  527. // Also make sure that the point size is 8 or greater
  528. //
  529. lfCopy = *plf;
  530. CorrectTooSmallFont(&lfCopy);
  531. lstrcpyn(lfCopy.lfFaceName, g_szNewNcFont, ARRAYSIZE(lfCopy.lfFaceName));
  532. plf = &lfCopy;
  533. }
  534. else
  535. {
  536. plf = NULL; // Don't update the LOGFONT.
  537. }
  538. }
  539. if (NULL != plf)
  540. {
  541. #ifdef NO_REG_CHANGES
  542. DumpLogFont(plf);
  543. #else
  544. dwResult = RegSetValueEx(hkeyMetrics,
  545. pszValueName,
  546. 0,
  547. REG_BINARY,
  548. (const LPBYTE)plf,
  549. sizeof(*plf));
  550. if (ERROR_SUCCESS != dwResult)
  551. {
  552. DPRINT((TEXT("Error %d setting NC font data for \"%s\"\n"),
  553. dwResult, pszValueName));
  554. }
  555. #endif
  556. }
  557. return dwResult;
  558. }
  559. //
  560. // Update the nc font metrics for a particular user key under HKEY_USERS.
  561. // If a particular font metric exists, the required replacements will be performed.
  562. // If a particular font metric doesn't exist, it is added with default information.
  563. // Note that not all keys under HKEY_USERS contain WindowMetric information.
  564. //
  565. DWORD
  566. UpdateWindowMetricsForUser(
  567. HKEY hkeyUser
  568. )
  569. {
  570. DWORD dwResult = ERROR_SUCCESS;
  571. HKEY hkeyMetrics;
  572. dwResult = RegOpenKeyEx(hkeyUser,
  573. g_szRegKeyMetrics,
  574. 0,
  575. KEY_ALL_ACCESS,
  576. &hkeyMetrics);
  577. if (ERROR_SUCCESS == dwResult)
  578. {
  579. DWORD cbValue;
  580. DWORD dwType;
  581. LOGFONT lf;
  582. int i;
  583. for (i = 0; i < ARRAYSIZE(g_rgpszFontMetrics); i++)
  584. {
  585. LPCTSTR pszValueName = g_rgpszFontMetrics[i];
  586. //
  587. // Start out with plf as NULL. If a LOGFONT doesn't exist
  588. // for this NC font, leaving plf as NULL will cause
  589. // UpdateNcFont to create a new default LOGFONT entry for this
  590. // NC font.
  591. //
  592. LOGFONT *plf = NULL;
  593. cbValue = sizeof(lf);
  594. dwResult = RegQueryValueEx(hkeyMetrics,
  595. pszValueName,
  596. NULL,
  597. &dwType,
  598. (LPBYTE)&lf,
  599. &cbValue);
  600. if (ERROR_SUCCESS == dwResult)
  601. {
  602. if (REG_BINARY == dwType)
  603. {
  604. //
  605. // A LOGFONT already exists for this NC font.
  606. // Passing it's address to UpdateNcFont will
  607. // update the LOGFONT.
  608. //
  609. plf = &lf;
  610. }
  611. }
  612. dwResult = UpdateNcFont(hkeyMetrics, pszValueName, plf);
  613. }
  614. }
  615. else if (ERROR_FILE_NOT_FOUND == dwResult)
  616. {
  617. //
  618. // Some keys under HKEY_USERS don't have WindowMetric information.
  619. // Such cases are not processed but are still considered successful.
  620. //
  621. dwResult = ERROR_SUCCESS;
  622. }
  623. else
  624. {
  625. DPRINT((TEXT("Error %d opening key \"%s\"\n"), dwResult, g_szRegKeyMetrics));
  626. }
  627. return dwResult;
  628. }
  629. //
  630. // Load a scheme's SCHEMEDATA from the registry, perform any necessary
  631. // updates and re-write the data back to the registry.
  632. //
  633. DWORD
  634. UpdateScheme(
  635. HKEY hkeySchemes,
  636. LPCTSTR pszScheme
  637. )
  638. {
  639. SCHEMEDATA sd;
  640. DWORD dwResult;
  641. DWORD dwType;
  642. DWORD cbsd = sizeof(sd);
  643. dwResult = RegQueryValueEx(hkeySchemes,
  644. pszScheme,
  645. NULL,
  646. &dwType,
  647. (LPBYTE)&sd,
  648. &cbsd);
  649. if (ERROR_SUCCESS == dwResult)
  650. {
  651. if (REG_BINARY == dwType)
  652. {
  653. int i;
  654. struct LogFontInfo
  655. {
  656. DWORD iMetrics;
  657. LOGFONT *plf;
  658. } rglfi[] = {
  659. { FMI_CAPTIONFONT, &sd.ncm.lfCaptionFont },
  660. { FMI_SMCAPTIONFONT, &sd.ncm.lfSmCaptionFont },
  661. { FMI_MENUFONT, &sd.ncm.lfMenuFont },
  662. { FMI_STATUSFONT, &sd.ncm.lfStatusFont },
  663. { FMI_MESSAGEFONT, &sd.ncm.lfMessageFont },
  664. { FMI_ICONFONT, &sd.lfIconTitle },
  665. };
  666. for (i = 0; i < ARRAYSIZE(rglfi); i++)
  667. {
  668. if (0 == lstrcmpi(rglfi[i].plf->lfFaceName, g_szMsSansSerif))
  669. {
  670. //
  671. // Ensure it's no smaller than 8pt. Anything less
  672. // than 8 pt is not readable on current displays.
  673. //
  674. CorrectTooSmallFont(rglfi[i].plf);
  675. //
  676. // Update the logfont's facename from
  677. // "MS Sans Serif" to "Microsoft Sans Serif".
  678. //
  679. lstrcpyn(rglfi[i].plf->lfFaceName,
  680. g_szMicrosoftSansSerif,
  681. ARRAYSIZE(rglfi[i].plf->lfFaceName));
  682. }
  683. }
  684. if (cbsd < sizeof(sd))
  685. {
  686. //
  687. // This is an NT4 custom scheme.
  688. //
  689. // NT4->W2K custom schemes are not upgraded so they're still
  690. // in NT4 format. cbsd < sizeof(sd).
  691. //
  692. // W9x->W2K custom schemes are upgraded by the Win9x migration
  693. // process so they're already in W2K format.
  694. // cbsd == sizeof(sd)
  695. //
  696. // The scheme has no gradient colors defined. We set them here to
  697. // the same color as the corresponding non-gradient colors. This
  698. // will result in solid-color caption bars for custom schemes.
  699. // Also update the hotlight color.
  700. //
  701. sd.rgb[COLOR_GRADIENTACTIVECAPTION] = sd.rgb[COLOR_ACTIVECAPTION];
  702. sd.rgb[COLOR_GRADIENTINACTIVECAPTION] = sd.rgb[COLOR_INACTIVECAPTION];
  703. sd.rgb[COLOR_HOTLIGHT] = sd.rgb[COLOR_ACTIVECAPTION];
  704. }
  705. dwResult = RegSetValueEx(hkeySchemes,
  706. pszScheme,
  707. 0,
  708. REG_BINARY,
  709. (const LPBYTE)&sd,
  710. sizeof(sd));
  711. if (ERROR_SUCCESS != dwResult)
  712. {
  713. DPRINT((TEXT("Error %d saving new scheme \"%s\"\n"), dwResult, pszScheme));
  714. }
  715. }
  716. else
  717. {
  718. DPRINT((TEXT("Invalid data type %d for scheme \"%s\". Expected REG_BINARY.\n"),
  719. dwType, pszScheme));
  720. }
  721. }
  722. else
  723. {
  724. DPRINT((TEXT("Error %d querying scheme \"%s\"\n"), dwResult, pszScheme));
  725. }
  726. return dwResult;
  727. }
  728. //
  729. // Handles all of the "scheme" related adjustments.
  730. // 1. Converts "MS Sans Serif" to "Microsoft Sans Serif" in
  731. // all schemes. Also ensures we don't have any 6pt
  732. // Microsoft Sans Serif fonts used.
  733. //
  734. DWORD
  735. UpdateDesktopSchemesForUser(
  736. HKEY hkeyUser
  737. )
  738. {
  739. DWORD dwResult = ERROR_SUCCESS;
  740. HKEY hkeySchemes;
  741. dwResult = RegOpenKeyEx(hkeyUser,
  742. g_szRegKeySchemes,
  743. 0,
  744. KEY_ALL_ACCESS,
  745. &hkeySchemes);
  746. if (ERROR_SUCCESS == dwResult)
  747. {
  748. DWORD dwIndex = 0;
  749. TCHAR szValueName[MAX_PATH];
  750. DWORD cchValueName;
  751. DWORD type;
  752. while(ERROR_SUCCESS == dwResult)
  753. {
  754. cchValueName = ARRAYSIZE(szValueName);
  755. dwResult = RegEnumValue(hkeySchemes,
  756. dwIndex++,
  757. szValueName,
  758. &cchValueName,
  759. NULL,
  760. &type,
  761. NULL,
  762. NULL);
  763. if (ERROR_SUCCESS == dwResult)
  764. {
  765. //
  766. // Convert "MS Sans Serif" to "Microsoft Sans Serif" in ALL schemes
  767. //
  768. UpdateScheme(hkeySchemes, szValueName);
  769. }
  770. }
  771. RegCloseKey(hkeySchemes);
  772. }
  773. if (ERROR_FILE_NOT_FOUND == dwResult)
  774. {
  775. //
  776. // Not all subkeys under HKEY_USER have the
  777. // Control Panel\Appearance\Schemes subkey.
  778. //
  779. dwResult = ERROR_SUCCESS;
  780. }
  781. return dwResult;
  782. }
  783. //
  784. // Function used to upgrade schemes and non-client metrics on upgrades
  785. // from Win9x and NT to Win2000.
  786. //
  787. void
  788. UpgradeSchemesAndNcMetricsToWin2000ForUser(
  789. HKEY hkeyUser
  790. )
  791. {
  792. DWORD dwResult = ERROR_SUCCESS;
  793. DPRINT((TEXT("Updating schemes and non-client metrics.\n")));
  794. //
  795. // Update gradient colors BEFORE making any other changes.
  796. // This code is in gradient.c
  797. //
  798. FixGradientColors();
  799. dwResult = UpdateWindowMetricsForUser(hkeyUser);
  800. if (ERROR_SUCCESS != dwResult)
  801. {
  802. DPRINT((TEXT("Error %d updating non-client metrics for user\n"), dwResult));
  803. }
  804. dwResult = UpdateDesktopSchemesForUser(hkeyUser);
  805. if (ERROR_SUCCESS != dwResult)
  806. {
  807. DPRINT((TEXT("Error %d updating schemes for user\n"), dwResult));
  808. }
  809. dwResult = UpdateColorsForUser(hkeyUser);
  810. if (ERROR_SUCCESS != dwResult)
  811. {
  812. DPRINT((TEXT("Error %d updating color information for user\n"), dwResult));
  813. }
  814. DPRINT((TEXT("Update of schemes and non-client metrics completed.\n")));
  815. }
  816. //
  817. // This version is called on an upgrade from NT->Win2000.
  818. //
  819. void
  820. UpgradeSchemesAndNcMetricsToWin2000(
  821. void
  822. )
  823. {
  824. UpgradeSchemesAndNcMetricsToWin2000ForUser(HKEY_CURRENT_USER);
  825. }
  826. //
  827. // On upgrades from Win9x we are passed a string value representing the
  828. // key under which we'll find the user's Control Panel\Appearance subkey.
  829. // The string is in the form "HKCU\$$$". We first translate the root key
  830. // descriptor into a true root key then pass that root and the "$$$"
  831. // part onto RegOpenKeyEx. This function takes that string and opens
  832. // the associated hive key.
  833. //
  834. DWORD
  835. OpenUserKeyForWin9xUpgrade(
  836. char *pszUserKeyA,
  837. HKEY *phKey
  838. )
  839. {
  840. DWORD dwResult = ERROR_INVALID_PARAMETER;
  841. if (NULL != pszUserKeyA && NULL != phKey)
  842. {
  843. typedef struct {
  844. char *pszRootA;
  845. HKEY hKeyRoot;
  846. } REGISTRY_ROOTS, *PREGISTRY_ROOTS;
  847. static REGISTRY_ROOTS rgRoots[] = {
  848. { "HKLM", HKEY_LOCAL_MACHINE },
  849. { "HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE },
  850. { "HKCC", HKEY_CURRENT_CONFIG },
  851. { "HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG },
  852. { "HKU", HKEY_USERS },
  853. { "HKEY_USERS", HKEY_USERS },
  854. { "HKCU", HKEY_CURRENT_USER },
  855. { "HKEY_CURRENT_USER", HKEY_CURRENT_USER },
  856. { "HKCR", HKEY_CLASSES_ROOT },
  857. { "HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT }
  858. };
  859. char szUserKeyA[MAX_PATH]; // For a local copy.
  860. char *pszSubKeyA = szUserKeyA;
  861. //
  862. // Make a local copy that we can modify.
  863. //
  864. lstrcpynA(szUserKeyA, pszUserKeyA, ARRAYSIZE(szUserKeyA));
  865. *phKey = NULL;
  866. //
  867. // Find the backslash.
  868. //
  869. while(*pszSubKeyA && '\\' != *pszSubKeyA)
  870. pszSubKeyA++;
  871. if ('\\' == *pszSubKeyA)
  872. {
  873. HKEY hkeyRoot = NULL;
  874. int i;
  875. //
  876. // Replace backslash with nul to separate the root key and
  877. // sub key strings in our local copy of the original argument
  878. // string.
  879. //
  880. *pszSubKeyA++ = '\0';
  881. //
  882. // Now find the true root key in rgRoots[].
  883. //
  884. for (i = 0; i < ARRAYSIZE(rgRoots); i++)
  885. {
  886. if (0 == lstrcmpiA(rgRoots[i].pszRootA, szUserKeyA))
  887. {
  888. hkeyRoot = rgRoots[i].hKeyRoot;
  889. break;
  890. }
  891. }
  892. if (NULL != hkeyRoot)
  893. {
  894. //
  895. // Open the key.
  896. //
  897. dwResult = RegOpenKeyExA(hkeyRoot,
  898. pszSubKeyA,
  899. 0,
  900. KEY_ALL_ACCESS,
  901. phKey);
  902. }
  903. }
  904. }
  905. return dwResult;
  906. }
  907. //
  908. // This version is called on an upgrade from Win9x to Win2000.
  909. //
  910. void
  911. UpgradeSchemesAndNcMetricsFromWin9xToWin2000(
  912. char *pszUserKey
  913. )
  914. {
  915. HKEY hkeyUser;
  916. DWORD dwResult = OpenUserKeyForWin9xUpgrade(pszUserKey, &hkeyUser);
  917. if (ERROR_SUCCESS == dwResult)
  918. {
  919. UpgradeSchemesAndNcMetricsToWin2000ForUser(hkeyUser);
  920. RegCloseKey(hkeyUser);
  921. }
  922. }