windows-nt/Source/XPSP1/NT/shell/osshell/migrate/schemnt5.c
2020-09-26 16:20:57 +08:00

1009 lines
33 KiB
C

///////////////////////////////////////////////////////////////////////////////
// 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
)
{
DWORD dwType;
TCHAR szValue[ARRAYSIZE(g_szRegValRGB)];
DWORD cbData = sizeof(szValue);
DWORD dwResult = RegQueryValueEx(hkeyColors,
pszName,
NULL,
&dwType,
(LPBYTE)szValue,
&cbData);
if (ERROR_SUCCESS == dwResult && REG_SZ == dwType)
{
//
// 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;
TCHAR szValue[ARRAYSIZE(g_szRegValRGB)];
//
// Convert RGB triplet to a text string for storage in the registry.
//
wsprintf(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);
lstrcpyn(lfCopy.lfFaceName, g_szNewNcFont, ARRAYSIZE(lfCopy.lfFaceName));
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_ALL_ACCESS,
&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)
{
//
// 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".
//
lstrcpyn(rglfi[i].plf->lfFaceName,
g_szMicrosoftSansSerif,
ARRAYSIZE(rglfi[i].plf->lfFaceName));
}
}
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_ALL_ACCESS,
&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.
//
lstrcpynA(szUserKeyA, pszUserKeyA, ARRAYSIZE(szUserKeyA));
*phKey = NULL;
//
// 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_ALL_ACCESS,
phKey);
}
}
}
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);
}
}