/////////////////////////////////////////////////////////////////////////////// // schemnt5.c // // This component of shmgrate.exe is designed to upgrade the user's schemes // and colors to the new values required for Windows 2000. This work is // coordinated with changes to the scheme data provided by Win2000 setup // in the files hivedef.inx and hiveusd.inx. // // brianau 6/11/98 // brianau 2/18/99 - Updated for "MS Sans Serif"->"Microsoft Sans Serif" // conversion. // brianau 6/24/99 - Set gradient colors same as non-gradient colors in // NT4 custom schemes. // #include #include #include #include #include #include "shmgdefs.h" #ifndef COLOR_3DALTFACE // // This is not defined in winuser.h (looks like it should be). // The desktop applet places this color at ordinal 25 in the // order of colors. There's a "hole" in the ordinal numbers // defined in winuser.h between numbers 24 and 26 so I'm // assuming it's supposed to be COLOR_3DALTFACE. Regardless, // the number is valid for the arrays in this module. // # define COLOR_3DALTFACE 25 #endif // // This string defines the new font to be used for the // NC fonts. If you want to change the face name, this // is the only place a change is required. // #define STR_NEWNCFONT TEXT("Tahoma") // // Defining this macro prevents any registry changes from being // made. Used for development only. // // Undefine before flight. // //#define NO_REG_CHANGES 1 // // // Redefine a private version of COLOR_MAX macro (winuser.h) // This code needs to stay in sync with Windows Setup and // desk.cpl, not what is defined in winuser.h. Someone added // two new colors to winuser.h which increased COLOR_MAX by 2 // which increased the size of SCHEMEDATA by 8 bytes. This // caused us to write out 8 extra bytes to the registry so that // desk.cpl no longer recognizes these entries. Setup, desk.cpl // and shmgrate need to stay in sync with respect to the size of // SCHEMEDATA. [brianau - 4/3/00] // #define MAX_COLORS (COLOR_GRADIENTINACTIVECAPTION + 1) // // This structure was taken from shell\ext\cpls\desknt5\lookdlg.c // It's the definition the desktop applet uses for reading/writing // scheme data to/from the registry. // typedef struct { SHORT version; WORD wDummy; // For alignment. NONCLIENTMETRICS ncm; LOGFONT lfIconTitle; COLORREF rgb[MAX_COLORS]; } SCHEMEDATA; const TCHAR g_szRegKeySchemes[] = TEXT("Control Panel\\Appearance\\Schemes"); const TCHAR g_szRegKeyMetrics[] = TEXT("Control Panel\\Desktop\\WindowMetrics"); const TCHAR g_szRegKeyColors[] = TEXT("Control Panel\\Colors"); const TCHAR g_szRegValRGB[] = TEXT("255 255 255"); const TCHAR g_szMsSansSerif[] = TEXT("MS Sans Serif"); const TCHAR g_szMicrosoftSansSerif[] = TEXT("Microsoft Sans Serif"); const TCHAR g_szCaptionFont[] = TEXT("CaptionFont"); const TCHAR g_szSmCaptionFont[] = TEXT("SmCaptionFont"); const TCHAR g_szMenuFont[] = TEXT("MenuFont"); const TCHAR g_szStatusFont[] = TEXT("StatusFont"); const TCHAR g_szMessageFont[] = TEXT("MessageFont"); const TCHAR g_szIconFont[] = TEXT("IconFont"); const TCHAR g_szNewNcFont[] = STR_NEWNCFONT; // // Font Metric Item index values. This enumeration represents the // order of items in any global arrays associated with the // non-client metric font items. // These must stay in sync with the entries in g_rgpszFontMetrics[] // and g_rglfDefaults[]. // enum FontMetricIndex { FMI_CAPTIONFONT, FMI_SMCAPTIONFONT, FMI_MENUFONT, FMI_STATUSFONT, FMI_MESSAGEFONT, FMI_ICONFONT }; // // Font metric reg value name strings. // The order of these must match the order of the FontMetricIndex // enumeration. // const LPCTSTR g_rgpszFontMetrics[] = { g_szCaptionFont, g_szSmCaptionFont, g_szMenuFont, g_szStatusFont, g_szMessageFont, g_szIconFont }; // // Total number of window font metrics being considered. // #define NUM_NC_FONTS ARRAYSIZE(g_rgpszFontMetrics) // // Default LOGFONT data for NC fonts. // Used if there's no NC font data present (i.e. clean US install). // This data corresponds to the "Windows Standard" scheme on a clean // NT 5.0 installation modified with our desired changes. // These entries must be maintained in the order of the FontMetricIndex // enumeration. // // For reference, The LOGFONT structure is: // // struct LOGFONT { // LONG lfHeight; // LONG lfWidth; // LONG lfEscapement; // LONG lfOrientation; // LONG lfWeight; // BYTE lfItalic; // BYTE lfUnderline; // BYTE lfStrikeOut; // BYTE lfCharSet; // BYTE lfOutPrecision; // BYTE lfClipPrecision; // BYTE lfQuality; // BYTE lfPitchAndFamily; // TCHAR lfFaceName[LF_FACESIZE]; // LF_FACESIZE == 32. // }; // const LOGFONT g_rglfDefaults[NUM_NC_FONTS] = { { -11, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // CAPTION { -11, 0, 0, 0, 700, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // SMCAPTION { -11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // MENU { -11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // STATUS { -11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT }, // MESSAGE { -11, 0, 0, 0, 400, 0, 0, 0, 0, 0, 0, 0, 0, STR_NEWNCFONT } // ICON }; // // These are the elements represented in the "Control Panel\Colors" // reg key. The rgbValue member is the new color value we want // to assign. See UpdateElementColor() for usage. // const struct NcmColors { LPCTSTR pszName; // Value name in "Control Panel\Colors" reg key. COLORREF rgbValue; // The new color. } g_rgWinStdColors[] = { { TEXT("Scrollbar"), 0x00C8D0D4 }, // COLOR_SCROLLBAR { TEXT("Background"), 0x00A56E3A }, // COLOR_BACKGROUND { TEXT("ActiveTitle"), 0x006A240A }, // COLOR_ACTIVECAPTION { TEXT("InactiveTitle"), 0x00808080 }, // COLOR_INACTIVECAPTION { TEXT("Menu"), 0x00C8D0D4 }, // COLOR_MENU { TEXT("Window"), 0x00FFFFFF }, // COLOR_WINDOW { TEXT("WindowFrame"), 0x00000000 }, // COLOR_WINDOWFRAME { TEXT("MenuText"), 0x00000000 }, // COLOR_MENUTEXT { TEXT("WindowText"), 0x00000000 }, // COLOR_WINDOWTEXT { TEXT("TitleText"), 0x00FFFFFF }, // COLOR_CAPTIONTEXT { TEXT("ActiveBorder"), 0x00C8D0D4 }, // COLOR_ACTIVEBORDER { TEXT("InactiveBorder"), 0x00C8D0D4 }, // COLOR_INACTIVEBORDER { TEXT("AppWorkspace"), 0x00808080 }, // COLOR_APPWORKSPACE { TEXT("Hilight"), 0x006A240A }, // COLOR_HIGHLIGHT { TEXT("HilightText"), 0x00FFFFFF }, // COLOR_HIGHLIGHTTEXT { TEXT("ButtonFace"), 0x00C8D0D4 }, // COLOR_BTNFACE { TEXT("ButtonShadow"), 0x00808080 }, // COLOR_BTNSHADOW { TEXT("GrayText"), 0x00808080 }, // COLOR_GRAYTEXT { TEXT("ButtonText"), 0x00000000 }, // COLOR_BTNTEXT { TEXT("InactiveTitleText"), 0x00C8D0D4 }, // COLOR_INACTIVECAPTIONTEXT { TEXT("ButtonHilight"), 0x00FFFFFF }, // COLOR_BTNHIGHLIGHT { TEXT("ButtonDkShadow"), 0x00404040 }, // COLOR_3DDKSHADOW { TEXT("ButtonLight"), 0x00C8D0D4 }, // COLOR_3DLIGHT { TEXT("InfoText"), 0x00000000 }, // COLOR_INFOTEXT { TEXT("InfoWindow"), 0x00E1FFFF }, // COLOR_INFOBK { TEXT("ButtonAlternateFace"), 0x00B5B5B5 }, // COLOR_3DALTFACE { TEXT("HotTrackingColor"), 0x00800000 }, // COLOR_HOTLIGHT { TEXT("GradientActiveTitle"), 0x00F0CAA6 }, // COLOR_GRADIENTACTIVECAPTION { TEXT("GradientInactiveTitle"), 0x00C0C0C0 } // COLOR_GRADIENTINACTIVECAPTION }; #ifdef NO_REG_CHANGES void DumpLogFont( const LOGFONT *plf ) { DPRINT((TEXT("Dumping LOGFONT ----------------------------------\n"))); DPRINT((TEXT("\tplf->lfHeight.........: %d\n"), plf->lfHeight)); DPRINT((TEXT("\tplf->lfWidth..........: %d\n"), plf->lfWidth)); DPRINT((TEXT("\tplf->lfEscapement.....: %d\n"), plf->lfEscapement)); DPRINT((TEXT("\tplf->lfOrientation....: %d\n"), plf->lfOrientation)); DPRINT((TEXT("\tplf->lfWeight.........: %d\n"), plf->lfWeight)); DPRINT((TEXT("\tplf->lfItalic.........: %d\n"), plf->lfItalic)); DPRINT((TEXT("\tplf->lfUnderline......: %d\n"), plf->lfUnderline)); DPRINT((TEXT("\tplf->lfStrikeOut......: %d\n"), plf->lfStrikeOut)); DPRINT((TEXT("\tplf->lfCharSet........: %d\n"), plf->lfCharSet)); DPRINT((TEXT("\tplf->lfOutPrecision...: %d\n"), plf->lfOutPrecision)); DPRINT((TEXT("\tplf->lfClipPrecision..: %d\n"), plf->lfClipPrecision)); DPRINT((TEXT("\tplf->lfQuality........: %d\n"), plf->lfQuality)); DPRINT((TEXT("\tplf->lfPitchAndFamily.: %d\n"), plf->lfPitchAndFamily)); DPRINT((TEXT("\tplf->lfFaceName.......: \"%s\"\n"), plf->lfFaceName)); } void DumpSchemeStructure( const SCHEMEDATA *psd ) { int i; DPRINT((TEXT("version..............: %d\n"), psd->version)); DPRINT((TEXT("ncm.cbSize...........: %d\n"), psd->ncm.cbSize)); DPRINT((TEXT("ncm.iBorderWidth.....: %d\n"), psd->ncm.iBorderWidth)); DPRINT((TEXT("ncm.iScrollWidth.....: %d\n"), psd->ncm.iScrollWidth)); DPRINT((TEXT("ncm.iScrollHeight....: %d\n"), psd->ncm.iScrollHeight)); DPRINT((TEXT("ncm.iCaptionWidth....: %d\n"), psd->ncm.iCaptionWidth)); DPRINT((TEXT("ncm.iSmCaptionWidth..: %d\n"), psd->ncm.iSmCaptionWidth)); DPRINT((TEXT("ncm.iSmCaptionHeight.: %d\n"), psd->ncm.iSmCaptionHeight)); DPRINT((TEXT("ncm.iMenuWidth.......: %d\n"), psd->ncm.iMenuWidth)); DPRINT((TEXT("ncm.iMenuHeight......: %d\n"), psd->ncm.iMenuHeight)); DPRINT((TEXT("ncm.lfCaptionFont:\n"))); DumpLogFont(&psd->ncm.lfCaptionFont); DPRINT((TEXT("ncm.lfSmCaptionFont:\n"))); DumpLogFont(&psd->ncm.lfSmCaptionFont); DPRINT((TEXT("ncm.lfMenuFont:\n"))); DumpLogFont(&psd->ncm.lfMenuFont); DPRINT((TEXT("ncm.lfStatusFont:\n"))); DumpLogFont(&psd->ncm.lfStatusFont); DPRINT((TEXT("ncm.lfMessageFont:\n"))); DumpLogFont(&psd->ncm.lfMessageFont); DPRINT((TEXT("lfIconTitle:\n"))); DumpLogFont(&psd->lfIconTitle); for (i = 0; i < ARRAYSIZE(psd->rgb); i++) { DPRINT((TEXT("Color[%2d] (%3d,%3d,%3d)\n"), i, GetRValue(psd->rgb[i]), GetGValue(psd->rgb[i]), GetBValue(psd->rgb[i]))); } } #endif // // Retrieve a named color value for a given user. // DWORD GetColorForUser( HKEY hkeyColors, LPCTSTR pszName, COLORREF *prgb ) { TCHAR szValue[ARRAYSIZE(g_szRegValRGB)]; DWORD cbData = sizeof(szValue); DWORD dwResult = SHRegGetValue(hkeyColors, NULL, pszName, SRRF_RT_REG_SZ | SRRF_NOEXPAND, NULL, (LPBYTE)szValue, &cbData); if (ERROR_SUCCESS == dwResult) { // // Values in the registry are in REG_SZ formatted as // "RRR GGG BBB" where RRR, GGG and BBB are byte values // expressed as ASCII text. // BYTE rgbTemp[3] = {0,0,0}; LPTSTR pszTemp = szValue; LPTSTR pszColor = szValue; int i; for (i = 0; i < ARRAYSIZE(rgbTemp); i++) { // // Skip any leading spaces. // while(*pszTemp && TEXT(' ') == *pszTemp) pszTemp++; // // Remember the start of this color value. // pszColor = pszTemp; // // Find the end of the current color value. // while(*pszTemp && TEXT(' ') != *pszTemp) pszTemp++; if (2 != i && TEXT('\0') == *pszTemp) { // // Nul character encountered before 3rd member of color // triplet was read. Assume it's bogus data. // dwResult = ERROR_INVALID_DATA; DPRINT((TEXT("Invalid color data in registry \"%s\"\n"), szValue)); break; } // // Nul-terminate this color value string and conver it to a number. // *pszTemp++ = TEXT('\0'); rgbTemp[i] = (BYTE)StrToInt(pszColor); } // // Return color info as an RGB triplet. // *prgb = RGB(rgbTemp[0], rgbTemp[1], rgbTemp[2]); } else { DPRINT((TEXT("Error %d querying reg color value \"%s\"\n"), dwResult, pszName)); dwResult = ERROR_INVALID_HANDLE; } return dwResult; } // // Update a named color value for a specified user. // DWORD UpdateColorForUser( HKEY hkeyColors, LPCTSTR pszName, COLORREF rgb ) { DWORD dwResult = ERROR_INVALID_PARAMETER; TCHAR szValue[ARRAYSIZE(g_szRegValRGB)]; // // Convert RGB triplet to a text string for storage in the registry. // if (SUCCEEDED(StringCchPrintf(szValue, ARRAYSIZE(szValue), TEXT("%d %d %d"), GetRValue(rgb), GetGValue(rgb), GetBValue(rgb)))) { // // Save it to the registry. // dwResult = RegSetValueEx(hkeyColors, pszName, 0, REG_SZ, (CONST BYTE *)szValue, sizeof(szValue)); } if (ERROR_SUCCESS != dwResult) { DPRINT((TEXT("Error %d setting color value \"%s\" to \"%s\"\n"), dwResult, pszName, szValue)); } return dwResult; } DWORD UpdateElementColor( HKEY hkeyColors, const int *rgiElements, int cElements ) { int i; for (i = 0; i < cElements; i++) { int iElement = rgiElements[i]; UpdateColorForUser(hkeyColors, g_rgWinStdColors[iElement].pszName, g_rgWinStdColors[iElement].rgbValue); } return ERROR_SUCCESS; } // // Perform all color updates for a user's NCM colors. // These are the new "softer" grays and blues. // ChristoB provided the color values. // DWORD UpdateColorsForUser( HKEY hkeyUser ) { HKEY hkeyColors; DWORD dwResult = RegOpenKeyEx(hkeyUser, g_szRegKeyColors, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyColors); if (ERROR_SUCCESS == dwResult) { // // Update these if the 3D button color is 192,192,192. // const int rgFaceChanges[] = { COLOR_BTNFACE, COLOR_SCROLLBAR, COLOR_MENU, COLOR_ACTIVEBORDER, COLOR_INACTIVEBORDER, COLOR_3DDKSHADOW, COLOR_3DLIGHT }; // // Update these if the active caption color is 0,0,128 // const int rgCaptionChanges[] = { COLOR_ACTIVECAPTION, COLOR_HIGHLIGHT, COLOR_GRADIENTACTIVECAPTION, COLOR_GRADIENTINACTIVECAPTION }; // // Update these if the desktop is 128,128,0 (seafoam green) // const int rgDesktopChanges[] = { COLOR_BACKGROUND }; struct { int iTest; // COLOR_XXXXX value. COLORREF rgbTest; // Color value that triggers upgrade. const int *prgChanges; // Array of elements to upgrade. int cChanges; // Number of elements to upgrade. } rgci [] = {{ COLOR_3DFACE, 0x00C0C0C0, rgFaceChanges, ARRAYSIZE(rgFaceChanges) }, { COLOR_ACTIVECAPTION, 0x00800000, rgCaptionChanges, ARRAYSIZE(rgCaptionChanges) }, { COLOR_BACKGROUND, 0x00808000, rgDesktopChanges, ARRAYSIZE(rgDesktopChanges) }}; int i; COLORREF rgb; for (i = 0; i < ARRAYSIZE(rgci); i++) { int iTest = rgci[i].iTest; COLORREF rgbTest = rgci[i].rgbTest; if (ERROR_SUCCESS == GetColorForUser(hkeyColors, g_rgWinStdColors[iTest].pszName, &rgb) && rgbTest == rgb) { UpdateElementColor(hkeyColors, rgci[i].prgChanges, rgci[i].cChanges); } } RegCloseKey(hkeyColors); } else { DPRINT((TEXT("Error %d opening reg key \"%s\" for user.\n"), dwResult, g_szRegKeyColors)); } return dwResult; } // // Convert a font metric name to a member of the FontMetricIndex // enumeration. Used to index into g_rgpszFontMetrics[] and // g_rglfDefaults[]. // // i.e. Returns FMI_CAPTIONFONT for "CaptionFont". // int FontMetricNameToIndex( LPCTSTR pszName ) { int i; for (i = 0; i < ARRAYSIZE(g_rgpszFontMetrics); i++) { if (0 == lstrcmp(pszName, g_rgpszFontMetrics[i])) return i; } return -1; } // // When updating a font from "MS Sans Serif" to a TrueType font // we want to ensure the font point size is 8pt or greater. // So, if the current font face is "MS Sans Serif" and // (-11 < lfHeight < 0) is true, we force the lfHeight // to -11 which corresponds to 8pt. The standard windows // schemes incorrectly have the height of the icon font // specified as -8 (6pt) when it should be -11 (8pt). // The problem is that the smallest pt size supported by // MS Sans Serif is 8pt so even if the requested size is 6pt, // you see 8pt. Once we switch to Tahoma (a TrueType font), // it can produce the requested 6pt size so that's what you // see. 6pt is way too small for desktop icons. // The default icon font size used by user32.dll is 8pt. // See code in ntuser\kernel\inctlpan.c CreateFontFromWinIni(). // void CorrectTooSmallFont( LOGFONT *plf ) { if ((0 > (int)plf->lfHeight) && (-11 < (int)plf->lfHeight)) { // // NT uses font height values. // plf->lfHeight = -11; } else if ((0 < (int)plf->lfHeight) && (8 > (int)plf->lfHeight)) { // // Win9x uses font point sizes. // plf->lfHeight = 8; } } // // Replace any LOGFONT members in a LOGFONT structure and write the data // to the registry for a given nc font metric. // // If plf is NULL, a new LOGFONT with default data is written to // the registry for the metric value. // If plf is non-NULL and the LOGFONT's facename is in the list of // facenames to be updated, the required substitutions are made and // the LOGFONT data is replaced in the registry. // DWORD UpdateNcFont( HKEY hkeyMetrics, LPCTSTR pszValueName, const LOGFONT *plf ) { DWORD dwResult = ERROR_SUCCESS; int iMetrics = FontMetricNameToIndex(pszValueName); LOGFONT lfCopy; if (NULL == plf) { // // Use all default values. // plf = &g_rglfDefaults[iMetrics]; } else { // // First see if this face name should be updated. // if (0 == lstrcmpi(plf->lfFaceName, g_szMsSansSerif)) { // // Yep. Update the face name string in the logfont. // Also make sure that the point size is 8 or greater // lfCopy = *plf; CorrectTooSmallFont(&lfCopy); ASSERT(_tcslen(g_szNewNcFont) < ARRAYSIZE(lfCopy.lfFaceName)); StringCchCopy(lfCopy.lfFaceName, ARRAYSIZE(lfCopy.lfFaceName), g_szNewNcFont); plf = &lfCopy; } else { plf = NULL; // Don't update the LOGFONT. } } if (NULL != plf) { #ifdef NO_REG_CHANGES DumpLogFont(plf); #else dwResult = RegSetValueEx(hkeyMetrics, pszValueName, 0, REG_BINARY, (const LPBYTE)plf, sizeof(*plf)); if (ERROR_SUCCESS != dwResult) { DPRINT((TEXT("Error %d setting NC font data for \"%s\"\n"), dwResult, pszValueName)); } #endif } return dwResult; } // // Update the nc font metrics for a particular user key under HKEY_USERS. // If a particular font metric exists, the required replacements will be performed. // If a particular font metric doesn't exist, it is added with default information. // Note that not all keys under HKEY_USERS contain WindowMetric information. // DWORD UpdateWindowMetricsForUser( HKEY hkeyUser ) { DWORD dwResult = ERROR_SUCCESS; HKEY hkeyMetrics; dwResult = RegOpenKeyEx(hkeyUser, g_szRegKeyMetrics, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeyMetrics); if (ERROR_SUCCESS == dwResult) { DWORD cbValue; DWORD dwType; LOGFONT lf; int i; for (i = 0; i < ARRAYSIZE(g_rgpszFontMetrics); i++) { LPCTSTR pszValueName = g_rgpszFontMetrics[i]; // // Start out with plf as NULL. If a LOGFONT doesn't exist // for this NC font, leaving plf as NULL will cause // UpdateNcFont to create a new default LOGFONT entry for this // NC font. // LOGFONT *plf = NULL; cbValue = sizeof(lf); dwResult = RegQueryValueEx(hkeyMetrics, pszValueName, NULL, &dwType, (LPBYTE)&lf, &cbValue); if (ERROR_SUCCESS == dwResult) { if (REG_BINARY == dwType) { if (sizeof(lf) == cbValue) { // // A LOGFONT already exists for this NC font. // Passing it's address to UpdateNcFont will // update the LOGFONT. // plf = &lf; } } } dwResult = UpdateNcFont(hkeyMetrics, pszValueName, plf); } } else if (ERROR_FILE_NOT_FOUND == dwResult) { // // Some keys under HKEY_USERS don't have WindowMetric information. // Such cases are not processed but are still considered successful. // dwResult = ERROR_SUCCESS; } else { DPRINT((TEXT("Error %d opening key \"%s\"\n"), dwResult, g_szRegKeyMetrics)); } return dwResult; } // // Load a scheme's SCHEMEDATA from the registry, perform any necessary // updates and re-write the data back to the registry. // DWORD UpdateScheme( HKEY hkeySchemes, LPCTSTR pszScheme ) { SCHEMEDATA sd; DWORD dwResult; DWORD dwType; DWORD cbsd = sizeof(sd); dwResult = RegQueryValueEx(hkeySchemes, pszScheme, NULL, &dwType, (LPBYTE)&sd, &cbsd); if (ERROR_SUCCESS == dwResult) { if (REG_BINARY == dwType) { int i; struct LogFontInfo { DWORD iMetrics; LOGFONT *plf; } rglfi[] = { { FMI_CAPTIONFONT, &sd.ncm.lfCaptionFont }, { FMI_SMCAPTIONFONT, &sd.ncm.lfSmCaptionFont }, { FMI_MENUFONT, &sd.ncm.lfMenuFont }, { FMI_STATUSFONT, &sd.ncm.lfStatusFont }, { FMI_MESSAGEFONT, &sd.ncm.lfMessageFont }, { FMI_ICONFONT, &sd.lfIconTitle }, }; for (i = 0; i < ARRAYSIZE(rglfi); i++) { if (0 == lstrcmpi(rglfi[i].plf->lfFaceName, g_szMsSansSerif)) { // // Ensure it's no smaller than 8pt. Anything less // than 8 pt is not readable on current displays. // CorrectTooSmallFont(rglfi[i].plf); // // Update the logfont's facename from // "MS Sans Serif" to "Microsoft Sans Serif". // ASSERT(_tcslen(g_szMicrosoftSansSerif) < ARRAYSIZE(rglfi[i].plf->lfFaceName)); StringCchCopy(rglfi[i].plf->lfFaceName, ARRAYSIZE(rglfi[i].plf->lfFaceName), g_szMicrosoftSansSerif); } } if (cbsd < sizeof(sd)) { // // This is an NT4 custom scheme. // // NT4->W2K custom schemes are not upgraded so they're still // in NT4 format. cbsd < sizeof(sd). // // W9x->W2K custom schemes are upgraded by the Win9x migration // process so they're already in W2K format. // cbsd == sizeof(sd) // // The scheme has no gradient colors defined. We set them here to // the same color as the corresponding non-gradient colors. This // will result in solid-color caption bars for custom schemes. // Also update the hotlight color. // sd.rgb[COLOR_GRADIENTACTIVECAPTION] = sd.rgb[COLOR_ACTIVECAPTION]; sd.rgb[COLOR_GRADIENTINACTIVECAPTION] = sd.rgb[COLOR_INACTIVECAPTION]; sd.rgb[COLOR_HOTLIGHT] = sd.rgb[COLOR_ACTIVECAPTION]; } dwResult = RegSetValueEx(hkeySchemes, pszScheme, 0, REG_BINARY, (const LPBYTE)&sd, sizeof(sd)); if (ERROR_SUCCESS != dwResult) { DPRINT((TEXT("Error %d saving new scheme \"%s\"\n"), dwResult, pszScheme)); } } else { DPRINT((TEXT("Invalid data type %d for scheme \"%s\". Expected REG_BINARY.\n"), dwType, pszScheme)); } } else { DPRINT((TEXT("Error %d querying scheme \"%s\"\n"), dwResult, pszScheme)); } return dwResult; } // // Handles all of the "scheme" related adjustments. // 1. Converts "MS Sans Serif" to "Microsoft Sans Serif" in // all schemes. Also ensures we don't have any 6pt // Microsoft Sans Serif fonts used. // DWORD UpdateDesktopSchemesForUser( HKEY hkeyUser ) { DWORD dwResult = ERROR_SUCCESS; HKEY hkeySchemes; dwResult = RegOpenKeyEx(hkeyUser, g_szRegKeySchemes, 0, KEY_QUERY_VALUE | KEY_SET_VALUE, &hkeySchemes); if (ERROR_SUCCESS == dwResult) { DWORD dwIndex = 0; TCHAR szValueName[MAX_PATH]; DWORD cchValueName; DWORD type; while(ERROR_SUCCESS == dwResult) { cchValueName = ARRAYSIZE(szValueName); dwResult = RegEnumValue(hkeySchemes, dwIndex++, szValueName, &cchValueName, NULL, &type, NULL, NULL); if (ERROR_SUCCESS == dwResult) { // // Convert "MS Sans Serif" to "Microsoft Sans Serif" in ALL schemes // UpdateScheme(hkeySchemes, szValueName); } } RegCloseKey(hkeySchemes); } if (ERROR_FILE_NOT_FOUND == dwResult) { // // Not all subkeys under HKEY_USER have the // Control Panel\Appearance\Schemes subkey. // dwResult = ERROR_SUCCESS; } return dwResult; } // // Function used to upgrade schemes and non-client metrics on upgrades // from Win9x and NT to Win2000. // void UpgradeSchemesAndNcMetricsToWin2000ForUser( HKEY hkeyUser ) { DWORD dwResult = ERROR_SUCCESS; DPRINT((TEXT("Updating schemes and non-client metrics.\n"))); // // Update gradient colors BEFORE making any other changes. // This code is in gradient.c // FixGradientColors(); dwResult = UpdateWindowMetricsForUser(hkeyUser); if (ERROR_SUCCESS != dwResult) { DPRINT((TEXT("Error %d updating non-client metrics for user\n"), dwResult)); } dwResult = UpdateDesktopSchemesForUser(hkeyUser); if (ERROR_SUCCESS != dwResult) { DPRINT((TEXT("Error %d updating schemes for user\n"), dwResult)); } dwResult = UpdateColorsForUser(hkeyUser); if (ERROR_SUCCESS != dwResult) { DPRINT((TEXT("Error %d updating color information for user\n"), dwResult)); } DPRINT((TEXT("Update of schemes and non-client metrics completed.\n"))); } // // This version is called on an upgrade from NT->Win2000. // void UpgradeSchemesAndNcMetricsToWin2000( void ) { UpgradeSchemesAndNcMetricsToWin2000ForUser(HKEY_CURRENT_USER); } // // On upgrades from Win9x we are passed a string value representing the // key under which we'll find the user's Control Panel\Appearance subkey. // The string is in the form "HKCU\$$$". We first translate the root key // descriptor into a true root key then pass that root and the "$$$" // part onto RegOpenKeyEx. This function takes that string and opens // the associated hive key. // DWORD OpenUserKeyForWin9xUpgrade( char *pszUserKeyA, HKEY *phKey ) { DWORD dwResult = ERROR_INVALID_PARAMETER; if (NULL != pszUserKeyA && NULL != phKey) { typedef struct { char *pszRootA; HKEY hKeyRoot; } REGISTRY_ROOTS, *PREGISTRY_ROOTS; static REGISTRY_ROOTS rgRoots[] = { { "HKLM", HKEY_LOCAL_MACHINE }, { "HKEY_LOCAL_MACHINE", HKEY_LOCAL_MACHINE }, { "HKCC", HKEY_CURRENT_CONFIG }, { "HKEY_CURRENT_CONFIG", HKEY_CURRENT_CONFIG }, { "HKU", HKEY_USERS }, { "HKEY_USERS", HKEY_USERS }, { "HKCU", HKEY_CURRENT_USER }, { "HKEY_CURRENT_USER", HKEY_CURRENT_USER }, { "HKCR", HKEY_CLASSES_ROOT }, { "HKEY_CLASSES_ROOT", HKEY_CLASSES_ROOT } }; char szUserKeyA[MAX_PATH]; // For a local copy. char *pszSubKeyA = szUserKeyA; // // Make a local copy that we can modify. // if (SUCCEEDED(StringCchCopyA(szUserKeyA, ARRAYSIZE(szUserKeyA), pszUserKeyA))) { // // Find the backslash. // while(*pszSubKeyA && '\\' != *pszSubKeyA) pszSubKeyA++; if ('\\' == *pszSubKeyA) { HKEY hkeyRoot = NULL; int i; // // Replace backslash with nul to separate the root key and // sub key strings in our local copy of the original argument // string. // *pszSubKeyA++ = '\0'; // // Now find the true root key in rgRoots[]. // for (i = 0; i < ARRAYSIZE(rgRoots); i++) { if (0 == lstrcmpiA(rgRoots[i].pszRootA, szUserKeyA)) { hkeyRoot = rgRoots[i].hKeyRoot; break; } } if (NULL != hkeyRoot) { // // Open the key. // dwResult = RegOpenKeyExA(hkeyRoot, pszSubKeyA, 0, KEY_QUERY_VALUE, // this hkey is only used to open other sub-hkey's phKey); } } } } if (dwResult != ERROR_SUCCESS) { *phKey = NULL; } return dwResult; } // // This version is called on an upgrade from Win9x to Win2000. // void UpgradeSchemesAndNcMetricsFromWin9xToWin2000( char *pszUserKey ) { HKEY hkeyUser; DWORD dwResult = OpenUserKeyForWin9xUpgrade(pszUserKey, &hkeyUser); if (ERROR_SUCCESS == dwResult) { UpgradeSchemesAndNcMetricsToWin2000ForUser(hkeyUser); RegCloseKey(hkeyUser); } }