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.

1021 lines
34 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. TCHAR szValue[ARRAYSIZE(g_szRegValRGB)];
  256. DWORD cbData = sizeof(szValue);
  257. DWORD dwResult = SHRegGetValue(hkeyColors,
  258. NULL,
  259. pszName,
  260. SRRF_RT_REG_SZ | SRRF_NOEXPAND,
  261. NULL,
  262. (LPBYTE)szValue,
  263. &cbData);
  264. if (ERROR_SUCCESS == dwResult)
  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 = ERROR_INVALID_PARAMETER;
  330. TCHAR szValue[ARRAYSIZE(g_szRegValRGB)];
  331. //
  332. // Convert RGB triplet to a text string for storage in the registry.
  333. //
  334. if (SUCCEEDED(StringCchPrintf(szValue, ARRAYSIZE(szValue), TEXT("%d %d %d"), GetRValue(rgb), GetGValue(rgb), GetBValue(rgb))))
  335. {
  336. //
  337. // Save it to the registry.
  338. //
  339. dwResult = RegSetValueEx(hkeyColors,
  340. pszName,
  341. 0,
  342. REG_SZ,
  343. (CONST BYTE *)szValue,
  344. sizeof(szValue));
  345. }
  346. if (ERROR_SUCCESS != dwResult)
  347. {
  348. DPRINT((TEXT("Error %d setting color value \"%s\" to \"%s\"\n"), dwResult, pszName, szValue));
  349. }
  350. return dwResult;
  351. }
  352. DWORD
  353. UpdateElementColor(
  354. HKEY hkeyColors,
  355. const int *rgiElements,
  356. int cElements
  357. )
  358. {
  359. int i;
  360. for (i = 0; i < cElements; i++)
  361. {
  362. int iElement = rgiElements[i];
  363. UpdateColorForUser(hkeyColors,
  364. g_rgWinStdColors[iElement].pszName,
  365. g_rgWinStdColors[iElement].rgbValue);
  366. }
  367. return ERROR_SUCCESS;
  368. }
  369. //
  370. // Perform all color updates for a user's NCM colors.
  371. // These are the new "softer" grays and blues.
  372. // ChristoB provided the color values.
  373. //
  374. DWORD
  375. UpdateColorsForUser(
  376. HKEY hkeyUser
  377. )
  378. {
  379. HKEY hkeyColors;
  380. DWORD dwResult = RegOpenKeyEx(hkeyUser,
  381. g_szRegKeyColors,
  382. 0,
  383. KEY_QUERY_VALUE | KEY_SET_VALUE,
  384. &hkeyColors);
  385. if (ERROR_SUCCESS == dwResult)
  386. {
  387. //
  388. // Update these if the 3D button color is 192,192,192.
  389. //
  390. const int rgFaceChanges[] = { COLOR_BTNFACE,
  391. COLOR_SCROLLBAR,
  392. COLOR_MENU,
  393. COLOR_ACTIVEBORDER,
  394. COLOR_INACTIVEBORDER,
  395. COLOR_3DDKSHADOW,
  396. COLOR_3DLIGHT };
  397. //
  398. // Update these if the active caption color is 0,0,128
  399. //
  400. const int rgCaptionChanges[] = { COLOR_ACTIVECAPTION,
  401. COLOR_HIGHLIGHT,
  402. COLOR_GRADIENTACTIVECAPTION,
  403. COLOR_GRADIENTINACTIVECAPTION };
  404. //
  405. // Update these if the desktop is 128,128,0 (seafoam green)
  406. //
  407. const int rgDesktopChanges[] = { COLOR_BACKGROUND };
  408. struct
  409. {
  410. int iTest; // COLOR_XXXXX value.
  411. COLORREF rgbTest; // Color value that triggers upgrade.
  412. const int *prgChanges; // Array of elements to upgrade.
  413. int cChanges; // Number of elements to upgrade.
  414. } rgci [] = {{ COLOR_3DFACE, 0x00C0C0C0, rgFaceChanges, ARRAYSIZE(rgFaceChanges) },
  415. { COLOR_ACTIVECAPTION, 0x00800000, rgCaptionChanges, ARRAYSIZE(rgCaptionChanges) },
  416. { COLOR_BACKGROUND, 0x00808000, rgDesktopChanges, ARRAYSIZE(rgDesktopChanges) }};
  417. int i;
  418. COLORREF rgb;
  419. for (i = 0; i < ARRAYSIZE(rgci); i++)
  420. {
  421. int iTest = rgci[i].iTest;
  422. COLORREF rgbTest = rgci[i].rgbTest;
  423. if (ERROR_SUCCESS == GetColorForUser(hkeyColors, g_rgWinStdColors[iTest].pszName, &rgb) &&
  424. rgbTest == rgb)
  425. {
  426. UpdateElementColor(hkeyColors, rgci[i].prgChanges, rgci[i].cChanges);
  427. }
  428. }
  429. RegCloseKey(hkeyColors);
  430. }
  431. else
  432. {
  433. DPRINT((TEXT("Error %d opening reg key \"%s\" for user.\n"), dwResult, g_szRegKeyColors));
  434. }
  435. return dwResult;
  436. }
  437. //
  438. // Convert a font metric name to a member of the FontMetricIndex
  439. // enumeration. Used to index into g_rgpszFontMetrics[] and
  440. // g_rglfDefaults[].
  441. //
  442. // i.e. Returns FMI_CAPTIONFONT for "CaptionFont".
  443. //
  444. int
  445. FontMetricNameToIndex(
  446. LPCTSTR pszName
  447. )
  448. {
  449. int i;
  450. for (i = 0; i < ARRAYSIZE(g_rgpszFontMetrics); i++)
  451. {
  452. if (0 == lstrcmp(pszName, g_rgpszFontMetrics[i]))
  453. return i;
  454. }
  455. return -1;
  456. }
  457. //
  458. // When updating a font from "MS Sans Serif" to a TrueType font
  459. // we want to ensure the font point size is 8pt or greater.
  460. // So, if the current font face is "MS Sans Serif" and
  461. // (-11 < lfHeight < 0) is true, we force the lfHeight
  462. // to -11 which corresponds to 8pt. The standard windows
  463. // schemes incorrectly have the height of the icon font
  464. // specified as -8 (6pt) when it should be -11 (8pt).
  465. // The problem is that the smallest pt size supported by
  466. // MS Sans Serif is 8pt so even if the requested size is 6pt,
  467. // you see 8pt. Once we switch to Tahoma (a TrueType font),
  468. // it can produce the requested 6pt size so that's what you
  469. // see. 6pt is way too small for desktop icons.
  470. // The default icon font size used by user32.dll is 8pt.
  471. // See code in ntuser\kernel\inctlpan.c CreateFontFromWinIni().
  472. //
  473. void
  474. CorrectTooSmallFont(
  475. LOGFONT *plf
  476. )
  477. {
  478. if ((0 > (int)plf->lfHeight) && (-11 < (int)plf->lfHeight))
  479. {
  480. //
  481. // NT uses font height values.
  482. //
  483. plf->lfHeight = -11;
  484. }
  485. else if ((0 < (int)plf->lfHeight) && (8 > (int)plf->lfHeight))
  486. {
  487. //
  488. // Win9x uses font point sizes.
  489. //
  490. plf->lfHeight = 8;
  491. }
  492. }
  493. //
  494. // Replace any LOGFONT members in a LOGFONT structure and write the data
  495. // to the registry for a given nc font metric.
  496. //
  497. // If plf is NULL, a new LOGFONT with default data is written to
  498. // the registry for the metric value.
  499. // If plf is non-NULL and the LOGFONT's facename is in the list of
  500. // facenames to be updated, the required substitutions are made and
  501. // the LOGFONT data is replaced in the registry.
  502. //
  503. DWORD
  504. UpdateNcFont(
  505. HKEY hkeyMetrics,
  506. LPCTSTR pszValueName,
  507. const LOGFONT *plf
  508. )
  509. {
  510. DWORD dwResult = ERROR_SUCCESS;
  511. int iMetrics = FontMetricNameToIndex(pszValueName);
  512. LOGFONT lfCopy;
  513. if (NULL == plf)
  514. {
  515. //
  516. // Use all default values.
  517. //
  518. plf = &g_rglfDefaults[iMetrics];
  519. }
  520. else
  521. {
  522. //
  523. // First see if this face name should be updated.
  524. //
  525. if (0 == lstrcmpi(plf->lfFaceName, g_szMsSansSerif))
  526. {
  527. //
  528. // Yep. Update the face name string in the logfont.
  529. // Also make sure that the point size is 8 or greater
  530. //
  531. lfCopy = *plf;
  532. CorrectTooSmallFont(&lfCopy);
  533. ASSERT(_tcslen(g_szNewNcFont) < ARRAYSIZE(lfCopy.lfFaceName));
  534. StringCchCopy(lfCopy.lfFaceName, ARRAYSIZE(lfCopy.lfFaceName), g_szNewNcFont);
  535. plf = &lfCopy;
  536. }
  537. else
  538. {
  539. plf = NULL; // Don't update the LOGFONT.
  540. }
  541. }
  542. if (NULL != plf)
  543. {
  544. #ifdef NO_REG_CHANGES
  545. DumpLogFont(plf);
  546. #else
  547. dwResult = RegSetValueEx(hkeyMetrics,
  548. pszValueName,
  549. 0,
  550. REG_BINARY,
  551. (const LPBYTE)plf,
  552. sizeof(*plf));
  553. if (ERROR_SUCCESS != dwResult)
  554. {
  555. DPRINT((TEXT("Error %d setting NC font data for \"%s\"\n"),
  556. dwResult, pszValueName));
  557. }
  558. #endif
  559. }
  560. return dwResult;
  561. }
  562. //
  563. // Update the nc font metrics for a particular user key under HKEY_USERS.
  564. // If a particular font metric exists, the required replacements will be performed.
  565. // If a particular font metric doesn't exist, it is added with default information.
  566. // Note that not all keys under HKEY_USERS contain WindowMetric information.
  567. //
  568. DWORD
  569. UpdateWindowMetricsForUser(
  570. HKEY hkeyUser
  571. )
  572. {
  573. DWORD dwResult = ERROR_SUCCESS;
  574. HKEY hkeyMetrics;
  575. dwResult = RegOpenKeyEx(hkeyUser,
  576. g_szRegKeyMetrics,
  577. 0,
  578. KEY_QUERY_VALUE | KEY_SET_VALUE,
  579. &hkeyMetrics);
  580. if (ERROR_SUCCESS == dwResult)
  581. {
  582. DWORD cbValue;
  583. DWORD dwType;
  584. LOGFONT lf;
  585. int i;
  586. for (i = 0; i < ARRAYSIZE(g_rgpszFontMetrics); i++)
  587. {
  588. LPCTSTR pszValueName = g_rgpszFontMetrics[i];
  589. //
  590. // Start out with plf as NULL. If a LOGFONT doesn't exist
  591. // for this NC font, leaving plf as NULL will cause
  592. // UpdateNcFont to create a new default LOGFONT entry for this
  593. // NC font.
  594. //
  595. LOGFONT *plf = NULL;
  596. cbValue = sizeof(lf);
  597. dwResult = RegQueryValueEx(hkeyMetrics,
  598. pszValueName,
  599. NULL,
  600. &dwType,
  601. (LPBYTE)&lf,
  602. &cbValue);
  603. if (ERROR_SUCCESS == dwResult)
  604. {
  605. if (REG_BINARY == dwType)
  606. {
  607. if (sizeof(lf) == cbValue)
  608. {
  609. //
  610. // A LOGFONT already exists for this NC font.
  611. // Passing it's address to UpdateNcFont will
  612. // update the LOGFONT.
  613. //
  614. plf = &lf;
  615. }
  616. }
  617. }
  618. dwResult = UpdateNcFont(hkeyMetrics, pszValueName, plf);
  619. }
  620. }
  621. else if (ERROR_FILE_NOT_FOUND == dwResult)
  622. {
  623. //
  624. // Some keys under HKEY_USERS don't have WindowMetric information.
  625. // Such cases are not processed but are still considered successful.
  626. //
  627. dwResult = ERROR_SUCCESS;
  628. }
  629. else
  630. {
  631. DPRINT((TEXT("Error %d opening key \"%s\"\n"), dwResult, g_szRegKeyMetrics));
  632. }
  633. return dwResult;
  634. }
  635. //
  636. // Load a scheme's SCHEMEDATA from the registry, perform any necessary
  637. // updates and re-write the data back to the registry.
  638. //
  639. DWORD
  640. UpdateScheme(
  641. HKEY hkeySchemes,
  642. LPCTSTR pszScheme
  643. )
  644. {
  645. SCHEMEDATA sd;
  646. DWORD dwResult;
  647. DWORD dwType;
  648. DWORD cbsd = sizeof(sd);
  649. dwResult = RegQueryValueEx(hkeySchemes,
  650. pszScheme,
  651. NULL,
  652. &dwType,
  653. (LPBYTE)&sd,
  654. &cbsd);
  655. if (ERROR_SUCCESS == dwResult)
  656. {
  657. if (REG_BINARY == dwType)
  658. {
  659. int i;
  660. struct LogFontInfo
  661. {
  662. DWORD iMetrics;
  663. LOGFONT *plf;
  664. } rglfi[] = {
  665. { FMI_CAPTIONFONT, &sd.ncm.lfCaptionFont },
  666. { FMI_SMCAPTIONFONT, &sd.ncm.lfSmCaptionFont },
  667. { FMI_MENUFONT, &sd.ncm.lfMenuFont },
  668. { FMI_STATUSFONT, &sd.ncm.lfStatusFont },
  669. { FMI_MESSAGEFONT, &sd.ncm.lfMessageFont },
  670. { FMI_ICONFONT, &sd.lfIconTitle },
  671. };
  672. for (i = 0; i < ARRAYSIZE(rglfi); i++)
  673. {
  674. if (0 == lstrcmpi(rglfi[i].plf->lfFaceName, g_szMsSansSerif))
  675. {
  676. //
  677. // Ensure it's no smaller than 8pt. Anything less
  678. // than 8 pt is not readable on current displays.
  679. //
  680. CorrectTooSmallFont(rglfi[i].plf);
  681. //
  682. // Update the logfont's facename from
  683. // "MS Sans Serif" to "Microsoft Sans Serif".
  684. //
  685. ASSERT(_tcslen(g_szMicrosoftSansSerif) < ARRAYSIZE(rglfi[i].plf->lfFaceName));
  686. StringCchCopy(rglfi[i].plf->lfFaceName, ARRAYSIZE(rglfi[i].plf->lfFaceName), g_szMicrosoftSansSerif);
  687. }
  688. }
  689. if (cbsd < sizeof(sd))
  690. {
  691. //
  692. // This is an NT4 custom scheme.
  693. //
  694. // NT4->W2K custom schemes are not upgraded so they're still
  695. // in NT4 format. cbsd < sizeof(sd).
  696. //
  697. // W9x->W2K custom schemes are upgraded by the Win9x migration
  698. // process so they're already in W2K format.
  699. // cbsd == sizeof(sd)
  700. //
  701. // The scheme has no gradient colors defined. We set them here to
  702. // the same color as the corresponding non-gradient colors. This
  703. // will result in solid-color caption bars for custom schemes.
  704. // Also update the hotlight color.
  705. //
  706. sd.rgb[COLOR_GRADIENTACTIVECAPTION] = sd.rgb[COLOR_ACTIVECAPTION];
  707. sd.rgb[COLOR_GRADIENTINACTIVECAPTION] = sd.rgb[COLOR_INACTIVECAPTION];
  708. sd.rgb[COLOR_HOTLIGHT] = sd.rgb[COLOR_ACTIVECAPTION];
  709. }
  710. dwResult = RegSetValueEx(hkeySchemes,
  711. pszScheme,
  712. 0,
  713. REG_BINARY,
  714. (const LPBYTE)&sd,
  715. sizeof(sd));
  716. if (ERROR_SUCCESS != dwResult)
  717. {
  718. DPRINT((TEXT("Error %d saving new scheme \"%s\"\n"), dwResult, pszScheme));
  719. }
  720. }
  721. else
  722. {
  723. DPRINT((TEXT("Invalid data type %d for scheme \"%s\". Expected REG_BINARY.\n"),
  724. dwType, pszScheme));
  725. }
  726. }
  727. else
  728. {
  729. DPRINT((TEXT("Error %d querying scheme \"%s\"\n"), dwResult, pszScheme));
  730. }
  731. return dwResult;
  732. }
  733. //
  734. // Handles all of the "scheme" related adjustments.
  735. // 1. Converts "MS Sans Serif" to "Microsoft Sans Serif" in
  736. // all schemes. Also ensures we don't have any 6pt
  737. // Microsoft Sans Serif fonts used.
  738. //
  739. DWORD
  740. UpdateDesktopSchemesForUser(
  741. HKEY hkeyUser
  742. )
  743. {
  744. DWORD dwResult = ERROR_SUCCESS;
  745. HKEY hkeySchemes;
  746. dwResult = RegOpenKeyEx(hkeyUser,
  747. g_szRegKeySchemes,
  748. 0,
  749. KEY_QUERY_VALUE | KEY_SET_VALUE,
  750. &hkeySchemes);
  751. if (ERROR_SUCCESS == dwResult)
  752. {
  753. DWORD dwIndex = 0;
  754. TCHAR szValueName[MAX_PATH];
  755. DWORD cchValueName;
  756. DWORD type;
  757. while(ERROR_SUCCESS == dwResult)
  758. {
  759. cchValueName = ARRAYSIZE(szValueName);
  760. dwResult = RegEnumValue(hkeySchemes,
  761. dwIndex++,
  762. szValueName,
  763. &cchValueName,
  764. NULL,
  765. &type,
  766. NULL,
  767. NULL);
  768. if (ERROR_SUCCESS == dwResult)
  769. {
  770. //
  771. // Convert "MS Sans Serif" to "Microsoft Sans Serif" in ALL schemes
  772. //
  773. UpdateScheme(hkeySchemes, szValueName);
  774. }
  775. }
  776. RegCloseKey(hkeySchemes);
  777. }
  778. if (ERROR_FILE_NOT_FOUND == dwResult)
  779. {
  780. //
  781. // Not all subkeys under HKEY_USER have the
  782. // Control Panel\Appearance\Schemes subkey.
  783. //
  784. dwResult = ERROR_SUCCESS;
  785. }
  786. return dwResult;
  787. }
  788. //
  789. // Function used to upgrade schemes and non-client metrics on upgrades
  790. // from Win9x and NT to Win2000.
  791. //
  792. void
  793. UpgradeSchemesAndNcMetricsToWin2000ForUser(
  794. HKEY hkeyUser
  795. )
  796. {
  797. DWORD dwResult = ERROR_SUCCESS;
  798. DPRINT((TEXT("Updating schemes and non-client metrics.\n")));
  799. //
  800. // Update gradient colors BEFORE making any other changes.
  801. // This code is in gradient.c
  802. //
  803. FixGradientColors();
  804. dwResult = UpdateWindowMetricsForUser(hkeyUser);
  805. if (ERROR_SUCCESS != dwResult)
  806. {
  807. DPRINT((TEXT("Error %d updating non-client metrics for user\n"), dwResult));
  808. }
  809. dwResult = UpdateDesktopSchemesForUser(hkeyUser);
  810. if (ERROR_SUCCESS != dwResult)
  811. {
  812. DPRINT((TEXT("Error %d updating schemes for user\n"), dwResult));
  813. }
  814. dwResult = UpdateColorsForUser(hkeyUser);
  815. if (ERROR_SUCCESS != dwResult)
  816. {
  817. DPRINT((TEXT("Error %d updating color information for user\n"), dwResult));
  818. }
  819. DPRINT((TEXT("Update of schemes and non-client metrics completed.\n")));
  820. }
  821. //
  822. // This version is called on an upgrade from NT->Win2000.
  823. //
  824. void
  825. UpgradeSchemesAndNcMetricsToWin2000(
  826. void
  827. )
  828. {
  829. UpgradeSchemesAndNcMetricsToWin2000ForUser(HKEY_CURRENT_USER);
  830. }
  831. //
  832. // On upgrades from Win9x we are passed a string value representing the
  833. // key under which we'll find the user's Control Panel\Appearance subkey.
  834. // The string is in the form "HKCU\$$$". We first translate the root key
  835. // descriptor into a true root key then pass that root and the "$$$"
  836. // part onto RegOpenKeyEx. This function takes that string and opens
  837. // the associated hive key.
  838. //
  839. DWORD
  840. OpenUserKeyForWin9xUpgrade(
  841. char *pszUserKeyA,
  842. HKEY *phKey
  843. )
  844. {
  845. DWORD dwResult = ERROR_INVALID_PARAMETER;
  846. if (NULL != pszUserKeyA && NULL != phKey)
  847. {
  848. typedef struct {
  849. char *pszRootA;
  850. HKEY hKeyRoot;
  851. } REGISTRY_ROOTS, *PREGISTRY_ROOTS;
  852. static REGISTRY_ROOTS rgRoots[] = {
  853. { "HKLM", HKEY_LOCAL_MACHINE },
  854. { "HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE },
  855. { "HKCC", HKEY_CURRENT_CONFIG },
  856. { "HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG },
  857. { "HKU", HKEY_USERS },
  858. { "HKEY_USERS", HKEY_USERS },
  859. { "HKCU", HKEY_CURRENT_USER },
  860. { "HKEY_CURRENT_USER", HKEY_CURRENT_USER },
  861. { "HKCR", HKEY_CLASSES_ROOT },
  862. { "HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT }
  863. };
  864. char szUserKeyA[MAX_PATH]; // For a local copy.
  865. char *pszSubKeyA = szUserKeyA;
  866. //
  867. // Make a local copy that we can modify.
  868. //
  869. if (SUCCEEDED(StringCchCopyA(szUserKeyA, ARRAYSIZE(szUserKeyA), pszUserKeyA)))
  870. {
  871. //
  872. // Find the backslash.
  873. //
  874. while(*pszSubKeyA && '\\' != *pszSubKeyA)
  875. pszSubKeyA++;
  876. if ('\\' == *pszSubKeyA)
  877. {
  878. HKEY hkeyRoot = NULL;
  879. int i;
  880. //
  881. // Replace backslash with nul to separate the root key and
  882. // sub key strings in our local copy of the original argument
  883. // string.
  884. //
  885. *pszSubKeyA++ = '\0';
  886. //
  887. // Now find the true root key in rgRoots[].
  888. //
  889. for (i = 0; i < ARRAYSIZE(rgRoots); i++)
  890. {
  891. if (0 == lstrcmpiA(rgRoots[i].pszRootA, szUserKeyA))
  892. {
  893. hkeyRoot = rgRoots[i].hKeyRoot;
  894. break;
  895. }
  896. }
  897. if (NULL != hkeyRoot)
  898. {
  899. //
  900. // Open the key.
  901. //
  902. dwResult = RegOpenKeyExA(hkeyRoot,
  903. pszSubKeyA,
  904. 0,
  905. KEY_QUERY_VALUE, // this hkey is only used to open other sub-hkey's
  906. phKey);
  907. }
  908. }
  909. }
  910. }
  911. if (dwResult != ERROR_SUCCESS)
  912. {
  913. *phKey = NULL;
  914. }
  915. return dwResult;
  916. }
  917. //
  918. // This version is called on an upgrade from Win9x to Win2000.
  919. //
  920. void
  921. UpgradeSchemesAndNcMetricsFromWin9xToWin2000(
  922. char *pszUserKey
  923. )
  924. {
  925. HKEY hkeyUser;
  926. DWORD dwResult = OpenUserKeyForWin9xUpgrade(pszUserKey, &hkeyUser);
  927. if (ERROR_SUCCESS == dwResult)
  928. {
  929. UpgradeSchemesAndNcMetricsToWin2000ForUser(hkeyUser);
  930. RegCloseKey(hkeyUser);
  931. }
  932. }