|
|
///////////////////////////////////////////////////////////////////////////////
// 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 <windows.h>
#include <winuserp.h>
#include <tchar.h>
#include <stdio.h>
#include <shlwapi.h>
#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); } }
|