Files
admin
base
com
developer
drivers
ds
enduser
inetcore
inetsrv
loc
mergedcomponents
multimedia
net
printscan
public
published
sdktools
shell
applets
browseinfo
browseui
comctl32
comdlg32
cpls
ddk
docs
drts
evtmon
explorer
ext
iecontrols
iexplore
inc
lcinf
lib
osshell
accesory
accessib
control
convgrp
cpls
dskquota
encrypt
ep
fontfldr
games
grptoreg
inc
lmui
migrate
pifmgr
progman
regedit.nt4
regwiz
rundll32
runonce
security
shcompui
shole
snapins
taskman
themes
cpl
inc
themesw
win98
winnt
adutil.cpp
adutil.h
bkgd.c
bkgd.h
bkgdutil.c
cb.c
dirs
dither.c
dither.h
etcdlg.c
fakewin.c
fakewin.h
frost.c
frost.def
frost.h
frost.rc
global.h
halftone.c
halftone.h
htmlprev.cpp
htmlprev.h
icons.c
init.c
keys.h
loadimag.c
loadimag.h
nc.c
nc.h
play.bmp
question.bmp
regutils.c
savedlg.c
schedule.cpp
schedule.h
sound.ico
sources.inc
themes.ico
themes.rcv
utils.c
dirs
tools
version
winver
dirs
policies
published
samplemusic
samplemypicts
services
shdocvw
shell32
shelldrt
shlwapi
sld
themes
thunk
tools
typebin
types
wallpaper
ccshell.ini
common.inc
common.mk
dirs
dummy.txt
gnumakefile
makefile.inc
project.mk
termsrv
tools
windows
dirs
makefil0
2025-04-27 07:49:33 -04:00

3426 lines
118 KiB
C

/* REGUTILS.C
Resident Code Segment // Tweak: make non-resident?
Routines for reading and writing to the system registry and our .THM files.
GatherThemeToFile()
ApplyThemeFile()
Frosting: Master Theme Selector for Windows '95
Copyright (c) 1994-1999 Microsoft Corporation. All rights reserved.
*/
// ---------------------------------------------
// Brief file history:
// Alpha:
// Beta:
// Bug fixes
// ---------
//
// ---------------------------------------------
//
// Critique 2/1/95 jdk at dvw
//
// The design intends to have everything work transparently from
// the KEYS.H file. The tables there specify all of the fields
// in the registry that we want to save to a theme file and to set
// from a theme file, along with flags for how to treat each field,
// etc. It works in nice abstract loops that just save/set what
// you tell it. You can add and change elements that you care to
// have in the theme by adjusting the KEYS.H file, without touching
// your code. Clean.
//
// Unfortunately, once you've set everything in the registry, you
// still need to hand-code how you make many of the elements take
// effect in the system in the current user session. This involves
// wildly divergent APIs/parameters. This blows the abstraction noted
// above. Everytime you change something in the KEYS.H file, you have
// to hand-code changes here, too.
//
// I've isolated the non-abstract, item-specific code in HandPumpSystem()
// below. Looking back on it now, there is some redundancy here. If
// we started by doing everything by hand, then we could do the registry
// and system settings together. Now you may end up reading, writing,
// and later rereading the same string -- with attendant Reg open/closes
// as well.
#include "windows.h"
#include "frost.h"
#include "global.h"
#include "keys.h" // only this files refers to list of keys
#include "shlobj.h" // for SHChangeNotify() and flag
#include "loadimag.h"
#include "Bkgd.h"
#include "adutil.h"
#include "schedule.h"
#include "mmsystem.h"
// Stuff in bkgd.c
extern void GetPlusBitmapName(LPTSTR szPlus);
extern HBITMAP LoadWallpaper(LPTSTR szWallpaper, LPTSTR szTheme, BOOL fPreview);
// Externs in NC.C
extern BOOL FAR GatherIconMetricsByHand();
extern BOOL FAR GatherNonClientMetricsByHand();
extern VOID FAR SetIconMetricsByHand(BOOL, BOOL);
extern VOID FAR SetNonClientMetricsByHand(BOOL, BOOL);
// Local Routines
BOOL GatherSubkeys(HKEY, FROST_SUBKEY *, int, LPTSTR);
BOOL DatumRegisterToFile(HKEY, FROST_VALUE, LPTSTR, LPTSTR);
BOOL FAR WriteBytesToFile(LPTSTR, LPTSTR, BYTE *, int, LPTSTR);
BOOL ApplySubkeys(HKEY, FROST_SUBKEY *, int, LPTSTR, BOOL);
BOOL DatumFileToRegister(HKEY, FROST_VALUE, LPTSTR, LPTSTR, BOOL);
BOOL WriteBytesToRegister(HKEY, LPTSTR, int, LPTSTR);
int FAR WriteBytesToBuffer(LPTSTR);
BOOL IsTrashFull();
BOOL ApplyCurrentTrash(BOOL, LPTSTR);
BOOL HandPumpSystem();
BOOL GatherSysColorsByHand(LPTSTR);
BOOL SetSysColorsByHand();
BOOL GatherWallpaperBitsByHand(LPTSTR);
VOID AbstractPath(LPTSTR, int);
BOOL GatherICONS(LPCTSTR);
BOOL ApplyWebView(LPCTSTR);
BOOL GatherWebView(LPCTSTR);
BOOL ExtractWVResource(LPCTSTR, LPCTSTR);
VOID ExpandSZ(LPTSTR);
extern TCHAR szCursors[];
#define DEF_SCREENSAVETIMEOUT 15 * 60 // default time to screen saver in seconds
//
// Local Globals
//
TCHAR pValue[MAX_VALUELEN+1]; // multi-use buffer: char, hex string, etc.
BOOL bReadOK, bWroteOK; // Save: read from reg/sys, write to file
// Apply: not implemented since ignoring results anyway
// strings for grody screen saver case
TCHAR szSS_Section[] = TEXT("boot");
TCHAR szSS_Key[] = TEXT("SCRNSAVE.EXE");
TCHAR szSS_File[] = TEXT("SYSTEM.INI"); // this worked in disp cpl code with no path....
TCHAR szCP_Clr[] = TEXT("Control Panel\\Colors");
TCHAR szCP_Appearance[] = TEXT("Control Panel\\Appearance");
TCHAR szCP_SoundSchemes[] = TEXT("AppEvents\\Schemes");
extern TCHAR szCP_DT[];
TCHAR szSS_Active[] = TEXT("ScreenSaveActive");
TCHAR szCurrent[] = TEXT("Current");
extern TCHAR szTileWP[];
TCHAR szWPStyle[] = TEXT("WallpaperStyle");
//
// For DoSysColors() and GetThemeColors() and others
//
// Important that these two arrays are the same length, and that they
// are kept in the same order together during any change.
//
// SYNCHRONIZATION ALERT! -- Keep INDEX_* defines in FROST.H in
// sync with this array. Keep NUM_COLORS define in FAKEWIN.H
// in sync with this array.
TCHAR *pRegColors[] = {
TEXT("ActiveTitle"),
TEXT("Background"),
TEXT("Hilight"),
TEXT("HilightText"),
TEXT("TitleText"),
TEXT("Window"),
TEXT("WindowText"),
TEXT("Scrollbar"),
TEXT("InactiveTitle"),
TEXT("Menu"),
TEXT("WindowFrame"),
TEXT("MenuText"),
TEXT("ActiveBorder"),
TEXT("InactiveBorder"),
TEXT("AppWorkspace"),
TEXT("ButtonFace"),
TEXT("ButtonShadow"),
TEXT("GrayText"),
TEXT("ButtonText"),
TEXT("InactiveTitleText"),
TEXT("ButtonHilight"),
TEXT("ButtonDkShadow"),
TEXT("ButtonLight"),
TEXT("InfoText"),
TEXT("InfoWindow"),
// These next two are bogus -- just here to pad the array. They
// should be something like the "ButtonAlternateFace" (not sure
// about that one) and "HotTrackingColor".
TEXT("GradientActiveTitle"),
TEXT("GradientInactiveTitle"),
// These next two are the real deal for the gradient title bars
TEXT("GradientActiveTitle"),
TEXT("GradientInactiveTitle")
};
int iSysColorIndices[] = {
COLOR_ACTIVECAPTION,
COLOR_DESKTOP,
COLOR_HIGHLIGHT,
COLOR_HIGHLIGHTTEXT,
COLOR_CAPTIONTEXT,
COLOR_WINDOW,
COLOR_WINDOWTEXT,
COLOR_SCROLLBAR,
COLOR_INACTIVECAPTION,
COLOR_MENU,
COLOR_WINDOWFRAME,
COLOR_MENUTEXT,
COLOR_ACTIVEBORDER,
COLOR_INACTIVEBORDER,
COLOR_APPWORKSPACE,
COLOR_3DFACE,
COLOR_3DSHADOW,
COLOR_GRAYTEXT,
COLOR_BTNTEXT,
COLOR_INACTIVECAPTIONTEXT,
COLOR_3DHILIGHT,
COLOR_3DDKSHADOW,
COLOR_3DLIGHT,
COLOR_INFOTEXT,
COLOR_INFOBK,
// These next two are bogus -- just here to pad the array. They
// should be something like the "COLOR_3DFACE" (not sure about
// that one) and "COLOR_HOTLIGHT".
COLOR_GRADIENTACTIVECAPTION,
COLOR_GRADIENTINACTIVECAPTION,
// These next two are the real deal for the gradient title bars
COLOR_GRADIENTACTIVECAPTION,
COLOR_GRADIENTINACTIVECAPTION
};
__inline int _atoi(char *sz)
{
int i=0;
while (*sz && *sz >= '0' && *sz <= '9')
i = i*10 + *sz++ -'0';
return i;
}
//
// GetRegString
//
void GetRegString(HKEY hkey, LPCTSTR szKey, LPCTSTR szValue, LPCTSTR szDefault, LPTSTR szBuffer, UINT cbBuffer)
{
if (szDefault)
lstrcpy(szBuffer, szDefault);
else
szBuffer[0] = 0;
if (RegOpenKey(hkey, szKey, &hkey) == 0)
{
RegQueryValueEx(hkey, szValue, NULL, NULL, (LPBYTE)szBuffer, &cbBuffer);
RegCloseKey(hkey);
}
}
//
// GetRegInt
//
int GetRegInt(HKEY hkey, LPCTSTR szKey, LPCTSTR szValue, int def)
{
TCHAR ach[40];
#ifdef UNICODE
CHAR szTempA[40];
#endif
GetRegString(hkey, szKey, szValue, NULL, ach, sizeof(ach));
if (ach[0])
#ifdef UNICODE
// Need to do conversion to ANSI for _atoi to work.
{
wcstombs(szTempA, (wchar_t *)ach, sizeof(szTempA));
return _atoi(szTempA);
}
#else // !UNICODE
return _atoi(ach);
#endif
else
return def;
}
//
// GatherThemeToFile
//
// This is one of the workhorse routines of the package.
// For the whole list of theme items that we care about, go check the
// cur Windows system settings in the registry. Copy those settings to
// a new file with the given full pathname.
//
// Oh, and umh then: for the two sets of things we do by hand --
// rather than by reading (and later writing) directly from (to)
// the registry -- go off and do the special case code for them.
// That is, Icon metrics and Nonclient metrics.
//
// Uses: global szCurDir to get theme directory
// resets szCurThemeFile if successful writing to file
//
// Returns: BOOL success writing to file
//
BOOL FAR GatherThemeToFile(LPTSTR lpszFullPath)
{
int imaxkey;
BOOL bRet, bOK = TRUE;
//
// init global error flags
bReadOK = bWroteOK = TRUE;
//
// first do the ICON subkeys
// OLD Plus95 code for gathering icon information has been replaced
// by GatherICONS() function below.
//imaxkey = sizeof(fsRoot)/sizeof(FROST_SUBKEY);
//bOK = GatherSubkeys(HKEY_CLASSES_ROOT, fsRoot, imaxkey, lpszFullPath);
bOK = GatherICONS(lpszFullPath);
//
// then do the CURRENT_USER subkeys
imaxkey = sizeof(fsCurUser)/sizeof(FROST_SUBKEY);
bRet = GatherSubkeys(HKEY_CURRENT_USER, fsCurUser, imaxkey, lpszFullPath);
bOK = bOK && bRet;
//
// Now do the special cases
bRet = GatherIconMetricsByHand(lpszFullPath);
bOK = bOK && bRet;
bRet = GatherNonClientMetricsByHand(lpszFullPath);
bOK = bOK && bRet;
bRet = GatherSysColorsByHand(lpszFullPath);
bOK = bOK && bRet;
bRet = GatherWallpaperBitsByHand(lpszFullPath);
bOK = bOK && bRet;
//
// then do the Screen Saver setting, off in its own world
// get cur
GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szSS_File);
// abstract out variable path if appropriate
AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
// and save it to the theme
bRet = WritePrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)pValue, lpszFullPath);
bOK = bOK && bRet;
if (!bRet) bWroteOK = FALSE;
// Collect the WebView settings -- don't think we really care
// if this fails...
GatherWebView(lpszFullPath);
//
// then write magic number for file verification
bRet = WritePrivateProfileString((LPTSTR)szFrostSection,
(LPTSTR)szMagic,
(LPTSTR)szVerify,
lpszFullPath);
bOK = bOK && bRet;
if (!bRet) bWroteOK = FALSE;
//
// cleanup
Assert(bOK, TEXT("didn't gather theme to file successfully\n"));
return (bOK);
}
//
// GatherSubkeys
//
// OK, read this carefully.
//
// This routine takes a handle to a currently open Registry key.
// Then it takes a pointer to an array of FROST_SUBKEYs that identifies
// subkey name strings of the open key. Then for those subkey names
// each FROST_SUBKEY also points to another array of value names. This
// is the final leaf of the Registry scheme. With a key, a subkey and a
// specific value name, you can get an actual value. The actual query and
// writing to a file happens in the DatumRegisterToFile() routine below.
//
// So here's the scheme:
// for each subkey
// open the subkey to get a key handle
// for each value of this subkey that we care about
// pass all the info to DatumRegisterToFile() to write one value
//
// Returns: BOOL success writing to file
//
BOOL GatherSubkeys(HKEY hKeyRoot, FROST_SUBKEY *fsEnum, int iMaxKey, LPTSTR lpszFile)
{
HKEY hKey; // cur open key
int ikey, ival;
LONG lret;
BOOL bRet, bOK = TRUE;
// loop through each subkey
for (ikey = 0; ikey < iMaxKey; ikey++) {
// open this subkey
lret = RegOpenKeyEx( hKeyRoot, (LPTSTR)fsEnum[ikey].szSubKey,
(DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKey );
// check that you got a good key here
if (lret != ERROR_SUCCESS) {
Assert(FALSE, TEXT("problem on RegOpenKey (read) of subkey "));
Assert(FALSE, fsEnum[ikey].szSubKey);
Assert(FALSE, TEXT("\n"));
// OK, you couldn't open the key to even look at the values.
// *****************************************************************
// based on the sketchy documentation we have for this Reg* and Error
// stuff, we're guessing that you've ended up here because this
// totally standard, Windows-defined subkey name just doesn't happen
// to be defined for the current user.
// *****************************************************************
// SO: just write empty strings to the THM file for each valuename
// you have for this subkey. You have then faithfully recorded that
// there was nothing there.
// still successful so long as all the empty strings are written out
// with the value names to the THM file. also do default string if
// appropriate.
// (null loop if default string only)
for (ival = 0; ival < fsEnum[ikey].iNumVals; ival++) {
bRet = WritePrivateProfileString(
fsEnum[ikey].szSubKey,
(LPTSTR)fsEnum[ikey].fvVals[ival].szValName,
(LPTSTR)szNULL, lpszFile
);
Assert(bRet, TEXT("couldn't write empty value string to THM file\n"));
bOK = bOK && bRet;
if (!bRet) bWroteOK = FALSE;
}
if (fsEnum[ikey].fValues != FV_LIST) { // either def or list+def
bRet = WritePrivateProfileString(
fsEnum[ikey].szSubKey,
(LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL, lpszFile
);
Assert(bRet, TEXT("couldn't write empty default string to THM file\n"));
bOK = bOK && bRet;
if (!bRet) bWroteOK = FALSE;
}
continue; // Open (read) subkey problem EXIT
}
// treat depending on type of values for this subkey
switch (fsEnum[ikey].fValues) {
case FV_LIST:
case FV_LISTPLUSDEFAULT:
// loop through each value in the list for this subkey
for (ival = 0; ival < fsEnum[ikey].iNumVals; ival++) {
bRet = DatumRegisterToFile(hKey, fsEnum[ikey].fvVals[ival],
lpszFile,
(LPTSTR)(fsEnum[ikey].szSubKey) );
bOK = bOK && bRet;
}
// check if just list or list plus default
if (FV_LIST == fsEnum[ikey].fValues)
break; // normal EXIT
// else fall through and do default, too
case FV_DEFAULT:
//
// Default string: There are no "valuenames" to search for under
// this key. Like the old INI file routines, it's just
//
// get default string:
// this is a little messy to include here and get it right
{ // variable scope
DWORD dwSize;
DWORD dwType;
LONG lret;
BOOL bDefault = TRUE;
// first do paranoid check of data size
lret = RegQueryValueEx(hKey, (LPTSTR)szNULL, // null str to get default
(LPDWORD)NULL,
(LPDWORD)&dwType,
(LPBYTE)NULL,
(LPDWORD)&dwSize );
if (ERROR_SUCCESS == lret) { // saw something there
// here's the size check before getting the data
if (dwSize > (DWORD)(MAX_VALUELEN * sizeof(TCHAR))) {
Assert(FALSE, TEXT("Humongous default entry string in registry...\n"));
bDefault = FALSE; // can't read, so very bad news
bReadOK = FALSE;
}
else { // size is acceptable
// now really get the value
lret = RegQueryValueEx(hKey, (LPTSTR)szNULL,// null str to get default
(LPDWORD)NULL,
(LPDWORD)&dwType,
(LPBYTE)pValue, // getting actual def value
(LPDWORD)&dwSize);
// If the value is an EXPAND_SZ we need to expand it...
if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
Assert(lret == ERROR_SUCCESS, TEXT("bad return on default entry string\n"));
Assert(((dwType == (DWORD)REG_SZ) || (dwType == (DWORD)REG_EXPAND_SZ)), TEXT("unexpected default entry type\n"));
if (ERROR_SUCCESS != lret)
// couldn't read somehow, so use null string
*pValue = 0;
}
}
else
// couldn't even find the default string, so use null string
*pValue = 0;
// be sure to remember if couldn't get a value as above
bOK = bOK && bDefault;
} // end variable scope
//
// OK, if this is a path/filename, see about xlating to relative path
if (fsEnum[ikey].bDefRelPath)
AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
//
// Phew, finally:write single default value
//
bRet = WritePrivateProfileString((LPTSTR)(fsEnum[ikey].szSubKey),
(LPTSTR)FROST_DEFSTR,
(LPTSTR)pValue, lpszFile);
Assert(bRet, TEXT("couldn't write default string to THM file.\n"));
bOK = bOK && bRet;
if (!bRet) bWroteOK = FALSE;
break;
default:
Assert(FALSE, TEXT("Unlisted .fValues value in Gather!\n"));
break;
}
// close this key
RegCloseKey(hKey);
}
// CLEANUP
Assert(bOK, TEXT("didn't GatherSubkeys well\n"));
return (bOK);
}
//
// DatumRegisterToFile
//
// This is the atomic operation: a single datum from the registry to the file.
// The technique varies a little by type of datum.
//
// Returns: BOOL success writing to file
// Note that sucess doesn't depend on reading value from registry;
// could be a value that's not set. Only reason to fail is: value
// was too big to read, or the write itself failed.
//
BOOL DatumRegisterToFile(
HKEY hQueryKey,
FROST_VALUE fvQuery,
LPTSTR lpszFile, // full pathname for output file
LPTSTR lpszKeyname )
{
DWORD dwSize;
DWORD dwType;
LONG lret;
BOOL bOK = TRUE;
BOOL bSkipReadingWP = FALSE;
// First off, if this is the Wallpaper and ActiveDesktop is on we
// need to read the current wallpaper setting from the IActiveDesktop
// interface instead of from the registry.
bSkipReadingWP = FALSE;
if ((lstrcmpi(fvQuery.szValName,TEXT("Wallpaper")) == 0) && IsActiveDesktopOn()) {
if (GetADWallpaper(pValue)) {
bSkipReadingWP = TRUE;
dwType = REG_SZ; // Set dwType as if we read a SZ from the reg
lret = ERROR_SUCCESS;
}
// Couldn't read the wallpaper from IActiveDesktop so go ahead and
// try reading it from the registry.
}
// Else, if this is the Wallpaper Pattern and ActiveDesktop is on we
// need to read the current Pattern setting from the IActiveDesktop
// interface instead of from the registry.
else if ((lstrcmpi(fvQuery.szValName,TEXT("Pattern")) == 0) &&
IsActiveDesktopOn()) {
if (GetADWPPattern(pValue)) {
bSkipReadingWP = TRUE;
dwType = REG_SZ; // Set dwType as if we read a SZ from the reg
lret = ERROR_SUCCESS;
}
// Couldn't read the Pattern from IActiveDesktop so go ahead and
// try reading it from the registry.
}
if (!bSkipReadingWP) {
// first do paranoid check of data size
lret = RegQueryValueEx(hQueryKey, fvQuery.szValName, (LPDWORD)NULL,
(LPDWORD)&dwType, (LPBYTE)NULL, (LPDWORD)&dwSize);
if (ERROR_SUCCESS == lret) {
// here's the size check before getting the data
if (dwSize > (DWORD)(MAX_VALUELEN*sizeof(TCHAR))) {
Assert(FALSE, TEXT("Humongous entry in registry...\n"));
bReadOK = FALSE;
return (FALSE); // incredibly unlikely mammoth entry EXIT
}
//
// now really get the value
//
lret = RegQueryValueEx(hQueryKey, fvQuery.szValName, (LPDWORD)NULL,
(LPDWORD)&dwType, (LPBYTE)pValue, (LPDWORD)&dwSize);
// If EXPAND_SZ type we need to expand it
if (REG_EXPAND_SZ == dwType)
{
ExpandSZ(pValue);
dwType = REG_SZ; // Fudge this to make that assert happy
}
Assert(lret == ERROR_SUCCESS, TEXT("bad return on datum retrieval\n"));
Assert(dwType == (DWORD)fvQuery.iValType, TEXT("unexpected datum type\n"));
}
}
//
// if you got something, go ahead and write it
if (ERROR_SUCCESS == lret) {
// switch on value type to get how to write it
switch ((int)dwType) {
case REG_SZ:
case REG_EXPAND_SZ:
// before writing, if this is a path/filename,
// see about xlating to relative path
//
// even before that, see if it is a bitmap
// and find out what compressed file it came from --
// that is if it's not an HTM/HTML wallpaper.
if ((lstrcmpi(fvQuery.szValName, TEXT("Wallpaper")) == 0) &&
(lstrcmpi(FindExtension(pValue), TEXT(".htm")) != 0) &&
(lstrcmpi(FindExtension(pValue), TEXT(".html")) !=0)) {
GetImageTitle(pValue, pValue, sizeof(pValue));
}
if (fvQuery.bValRelPath)
AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
bOK = WritePrivateProfileString(lpszKeyname,
(LPTSTR)fvQuery.szValName,
(LPTSTR)pValue, lpszFile);
Assert(bOK, TEXT("couldn't write value string to THM file.\n"));
if (!bOK) bWroteOK = FALSE;
break;
//
// these two cases are both just treated as binary output
case REG_DWORD:
case REG_BINARY:
bOK = WriteBytesToFile(lpszKeyname, (LPTSTR)fvQuery.szValName,
(BYTE *)pValue, (int)dwSize, lpszFile);
Assert(bOK, TEXT("couldn't write value bytes to THM file.\n"));
if (!bOK) bWroteOK = FALSE; // pretty unitary write function
break;
default:
Assert(FALSE, TEXT("unexpected REG_* data type read from registry\n"));
break;
}
}
// EITHER: couldn't query size OR couldn't retrieve value
else {
// *****************************************************************
// based on the sketchy documentation we have for this Reg* and Error
// stuff, we're guessing that you've ended up here because this
// totally legitimate, successfully opened key and this totally
// standard, Windows-defined value name just doesn't happen to have
// a value assigned to it for the current user.
// *****************************************************************
// So: just write an empty string to the THM file. Still successful
// so long as the key actually is written to the THM file.
bOK = WritePrivateProfileString(lpszKeyname,
(LPTSTR)fvQuery.szValName,
(LPTSTR)szNULL, lpszFile);
Assert(bOK, TEXT("couldn't write empty string to THM file.\n"));
if (!bOK) bWroteOK = FALSE;
}
// cleanup
Assert(bOK, TEXT("missed a datum from register to file\n"));
return (bOK);
}
//
// WriteBytesToFile
//
// Writes binary data out to the THM file.
// Converts the data byte by byte to ASCII numbers, appends
// them to one long string, writes string to profile.
//
// Returns: success of write to theme file
//
BOOL FAR WriteBytesToFile(LPTSTR lpszProfileSection, LPTSTR lpszProfileKey,
BYTE *pData, int iBytes, LPTSTR lpszProfile)
{
HLOCAL hXlat;
TCHAR *psz;
BOOL bWrote = TRUE;
int iter;
#ifdef UNICODE
char szNumberA[10]; // byte value converted to ANSI
#endif
//
// inits
// alloc and lock memory for translation
hXlat = LocalAlloc(LPTR, 5*sizeof(TCHAR)*iBytes+2);
if (!hXlat) { // couldn't create buffer!!
NoMemMsg(STR_TO_SAVE); // post low mem message!
return (FALSE); // bad news couldn't write EXIT
}
//
// do the translation to a string
psz = (TCHAR *)hXlat; // start at beginning of string buffer
// loop through the bytes
for (iter = 0; iter < iBytes; iter++) {
// translate one byte into our string buffer
#ifdef UNICODE
// With UNICODE we need to use a temporary ANSI buffer
// for the litoa conversion, then convert that string to
// UNICODE when putting it into our main string buffer.
litoa( (int)(pData[iter]), (LPSTR)szNumberA);
mbstowcs((wchar_t *)psz, szNumberA, sizeof(szNumberA));
#else // !UNICODE
litoa( (int)(pData[iter]), (LPSTR)psz);
#endif
// add a space
lstrcat((LPTSTR)psz, TEXT(" "));
// bump pointer up to end of string for next byte
psz = psz + lstrlen((LPTSTR)psz);
}
//
// do the write to the THM file
bWrote = WritePrivateProfileString(lpszProfileSection,
lpszProfileKey,
(LPTSTR)hXlat,
lpszProfile);
//
// cleanup
// free up memory allocated
LocalFree(hXlat);
return (bWrote);
}
//
// ApplyThemeFile
//
// The inverse of GatherThemeToFile(), this routine takes a theme
// file and sets system registry values from the file. It also then
// calls individual APIs to make some of the settings take immediate
// effect.
//
// Goes through the list of theme values and if the controlling checkbox
// is checked, sets the value from the file to the registry. This is
// a nice clean loop using the tables in KEYS.H to match checkboxes to
// registry keys/valuenames.
//
// Then for each checkbox, do the current system settings by hand as
// necessary.
//
// lpszFilename == full pathname
BOOL FAR ApplyThemeFile(LPTSTR lpszFilename)
{
BOOL bRet, bOK = TRUE;
int imaxkey;
BOOL bFullTrash;
extern TCHAR szPlus_CurTheme[];
//
// first apply the ROOT subkeys to the registry: these are the icons
// but first first go check cur registry to see if trash can full or empty
bFullTrash = IsTrashFull();
// OK now apply the root subkeys -- this is where Win95 checks for
// the icons
//imaxkey = sizeof(fsRoot)/sizeof(FROST_SUBKEY);
//bOK = ApplySubkeys(HKEY_CLASSES_ROOT, fsRoot, imaxkey, lpszFilename,
// FALSE); // don't apply null theme entries for icons!
// Now apply the Win98/current user icon keys
imaxkey = sizeof(fsCUIcons)/sizeof(FROST_SUBKEY);
bOK = ApplySubkeys(HKEY_CURRENT_USER, fsCUIcons, imaxkey, lpszFilename,
FALSE); // don't apply null theme entries for icons!
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// now apply the right current trash icon from theme
bRet = ApplyCurrentTrash(bFullTrash, lpszFilename);
bOK = bOK && bRet;
//
// then apply the CURRENT_USER subkeys to the registry
imaxkey = sizeof(fsCurUser)/sizeof(FROST_SUBKEY);
bRet = ApplySubkeys(HKEY_CURRENT_USER, fsCurUser, imaxkey, lpszFilename, TRUE);
bOK = bOK && bRet;
// have to keep setting cursor to wait because someone resets it
WaitCursor();
ApplyWebView(lpszFilename);
WaitCursor();
// just a random place to check this:
Assert(NUM_CURSORS == (sizeof(fvCursors)/sizeof(FROST_VALUE)),
TEXT("DANGER: mismatched number of cursors in fvCursors and NUM_CURSORS constant!\n"));
//
// now try to make everything apply to the system currently
bRet = HandPumpSystem();
// *** DEBUG *** need specific error message here
bOK = bOK && bRet;
//
// cleanup
// save this theme file in the registry as the last one applied
// if you messed with stored CB values for color problem filter
if (bLowColorProblem && (fLowBPPFilter == APPLY_NONE))
SaveCheckboxes(); // then reset from the actual buttons
Assert(bOK, TEXT("didn't apply theme successfully\n"));
return (bOK);
}
//
// ApplySubkeys
//
// This is parallel to the GatherSubkeys() function above, copying
// values instead _from_ the theme file _to_ the Registry. It uses
// the same loop structure, see the comments to GatherSubkeys().
//
// The one change is that on applying values, we check first the
// FC_* flag in the fValCheckbox or fDefCheckbox fields to identify
// the controlling checkbox for that valuename. If the checkbox is
// unchecked, the value is not set. (We already got the checkbox states
// into bCBStates[] in ApplyThemeFile() above.
//
// Returns: success writing to Registry, should be always TRUE.
//
BOOL ApplySubkeys(HKEY hKeyRoot, FROST_SUBKEY *fsEnum, int iMaxKey, LPTSTR lpszFile, BOOL bApplyNull)
{
HKEY hKey; // cur open key
int ikey, ival, iret;
LONG lret;
BOOL bRet, bOK = TRUE;
TCHAR szNTReg[MAX_PATH];
// loop through each subkey
for (ikey = 0; ikey < iMaxKey; ikey++) {
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// If this is NT and the key is for the icons we need to touch
// up the reg pathing
if (IsPlatformNT() && (ikey < MAX_ICON) &&
((lstrcmpi(fsEnum[ikey].szSubKey, fsCUIcons[ikey].szSubKey) == 0) ||
(lstrcmpi(fsEnum[ikey].szSubKey, fsRoot[ikey].szSubKey) == 0)))
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, fsRoot[ikey].szSubKey);
// open this subkey
lret = RegOpenKeyEx( hKeyRoot, (LPTSTR)szNTReg,
(DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
}
else
{
// open this subkey
lret = RegOpenKeyEx( hKeyRoot, (LPTSTR)fsEnum[ikey].szSubKey,
(DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
}
// check that you got a good key here
if (lret != ERROR_SUCCESS) {
DWORD dwDisposition;
Assert(FALSE, TEXT("problem on RegOpenKey (write) of subkey "));
Assert(FALSE, fsEnum[ikey].szSubKey);
Assert(FALSE, TEXT("\n"));
// OK, you couldn't even open the key !!!
// *****************************************************************
// based on the sketchy documentation we have for this Reg* and Error
// stuff, we're guessing that you've ended up here because this
// totally standard, Windows-defined subkey name just doesn't happen
// to be defined for the current user.
// *****************************************************************
// SO: Just create this subkey for this user, and maybe it will get
// used after you create and set it.
// still successful so long as can create new subkey to write to
if (IsPlatformNT() && (ikey < MAX_ICON) &&
((lstrcmpi(fsEnum[ikey].szSubKey, fsCUIcons[ikey].szSubKey) == 0) ||
(lstrcmpi(fsEnum[ikey].szSubKey, fsRoot[ikey].szSubKey) == 0)))
{
lret = RegCreateKeyEx( hKeyRoot, (LPTSTR)szNTReg,
(DWORD)0, (LPTSTR)szNULL, REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE, (LPSECURITY_ATTRIBUTES)NULL,
(PHKEY)&hKey, (LPDWORD)&dwDisposition );
}
else
{
lret = RegCreateKeyEx( hKeyRoot, (LPTSTR)fsEnum[ikey].szSubKey,
(DWORD)0, (LPTSTR)szNULL, REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE, (LPSECURITY_ATTRIBUTES)NULL,
(PHKEY)&hKey, (LPDWORD)&dwDisposition );
}
if (lret != ERROR_SUCCESS) {
Assert(FALSE, TEXT("problem even with RegCreateKeyEx (write) of subkey "));
Assert(FALSE, fsEnum[ikey].szSubKey);
Assert(FALSE, TEXT("\n"));
// we are not happy campers
bOK = FALSE;
// but we'll keep on truckin'
continue; // bad subkey EXIT
}
}
// treat depending on type of values for this subkey
switch (fsEnum[ikey].fValues) {
case FV_LIST:
case FV_LISTPLUSDEFAULT:
// loop through each value in the list for this subkey
for (ival = 0; ival < fsEnum[ikey].iNumVals; ival++) {
// if the checkbox that controls this value is checked
if ( bCBStates[ fsEnum[ikey].fvVals[ival].fValCheckbox ] ) {
// then read from theme file and write to registry
bRet = DatumFileToRegister(hKey, fsEnum[ikey].fvVals[ival],
lpszFile,
(LPTSTR)(fsEnum[ikey].szSubKey),
bApplyNull);
bOK = bOK && bRet;
}
}
// check if just list or list plus default
if (FV_LIST == fsEnum[ikey].fValues)
break; // normal EXIT
// else fall through and do default, too
case FV_DEFAULT:
//
// if this subkey's default value's checkbox is checked
if (bCBStates[fsEnum[ikey].fDefCheckbox]) {
//
// Default string: There are no "valuenames" to set under
// this key. Like the old INI file routines, it's just one value.
//
//
// Get default value string
iret = GetPrivateProfileString((LPTSTR)(fsEnum[ikey].szSubKey),
(LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN, lpszFile);
// no error case; legit null string value is indistinguishable from
// error case...
// If we're reading the ICON strings and we got a NULL return
// then we should try using the "old" Win95 reg keys in case
// this is an old .Theme file
if ((!*pValue) && (ikey < MAX_ICON) &&
(lstrcmpi(fsEnum[ikey].szSubKey, fsCUIcons[ikey].szSubKey) == 0))
{
iret = GetPrivateProfileString((LPTSTR)(fsRoot[ikey].szSubKey),
(LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL,
(LPTSTR)pValue,
MAX_VALUELEN,
lpszFile);
// PLUS98 bug 1042
// If this is the MyDocs icon and there is no setting for
// it in the Theme file then we need to default to the
// szMyDocsDefault icon.
if ((MYDOC_INDEX == ikey) && (!*pValue)) {
lstrcpy(pValue, MYDOC_DEFSTR);
}
}
// if this value is a relative path filename string,
// first see about making abstract path into current instance
if (fsEnum[ikey].bDefRelPath) {
InstantiatePath((LPTSTR)pValue, MAX_VALUELEN);
// look for and confirm finding the file, with replacement
if (ConfirmFile((LPTSTR)pValue, TRUE) == CF_NOTFOUND) {
*pValue = 0; // if not found, just null out filename
bOK = FALSE; // couldn't apply this file
}
}
//
// sometimes don't want to set a null string to the Registry
if (*pValue || bApplyNull) { // either non-null or OK to set null
// now set the value in the registry
lret = RegSetValueEx(hKey, (LPTSTR)szNULL,// null str to set default value
0,
(DWORD)REG_SZ,
(LPBYTE)pValue, // getting actual def value
(DWORD)(SZSIZEINBYTES(pValue)));
Assert(lret == ERROR_SUCCESS, TEXT("couldn't write a default entry string!\n"));
bOK = bOK && (lret == ERROR_SUCCESS);
}
} // end if controlling checkbox checked
break;
default:
Assert(FALSE, TEXT("Unlisted .fValues value in Apply!\n"));
break;
}
// close this key
RegCloseKey(hKey);
}
// CLEANUP
Assert(bOK, TEXT("didn't ApplySubkeys well\n"));
return (bOK);
}
//
// DatumFileToRegister
//
// Like DatumRegisterToFile(), this is an atomic operation; in this
// case, move a single datum from theme file to the registry.
// Here, too, technique differs slightly between strings and numbers.
//
// Returns: BOOL success writing to registry
//
BOOL DatumFileToRegister(
HKEY hSetKey,
FROST_VALUE fvSet,
LPTSTR lpszFile, // full pathname for theme file
LPTSTR lpszKeyname,
BOOL bOKtoApplyNull)
{
LONG lret;
int iret;
BOOL bOK = TRUE;
//
// get the saved string from the theme file
iret = GetPrivateProfileString(lpszKeyname,
(LPTSTR)fvSet.szValName,
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN, lpszFile);
// no error case: can't tell difference between legit null string and default
// If we're reading the TRASH ICON strings and we got a NULL return
// then we should try using the "old" Win95 reg keys in case
// this is an old .Theme file
if ((!*pValue) &&
(lstrcmpi(lpszKeyname, fsCUIcons[TRASH_INDEX].szSubKey) == 0)) {
iret = GetPrivateProfileString((LPTSTR)(fsRoot[TRASH_INDEX].szSubKey),
(LPTSTR)fvSet.szValName,
(LPTSTR)szNULL,
(LPTSTR)pValue,
MAX_VALUELEN,
lpszFile);
}
// not always OK to set null value to registry
if (!bOKtoApplyNull && !(*pValue))
return(TRUE); // no work to do EXIT
// switch on value type to get how to write it
switch (fvSet.iValType) {
case REG_SZ:
// if this value is a relative path filename string,
// first see about making abstract path into current instance
if (fvSet.bValRelPath) {
InstantiatePath((LPTSTR)pValue, MAX_VALUELEN);
// look for and confirm finding the file, with replacement
if (ConfirmFile((LPTSTR)pValue, TRUE) == CF_NOTFOUND) {
*pValue = 0; // if not found, just null out filename
bOK = FALSE; // couldn't apply this file!
}
}
// If this is the Wallpaper setting and it's an .htm or .html
// wallpaper we need to apply this via IActiveDesktop
//
if (lstrcmpi(fvSet.szValName, TEXT("Wallpaper")) == 0 && pValue && *pValue &&
(lstrcmpi(FindExtension(pValue),TEXT(".htm")) == 0 ||
lstrcmpi(FindExtension(pValue),TEXT(".html")) == 0)) {
// First, clear the existing registry wallpaper setting.
// Don't really care if this fails.
lret = RegSetValueEx(hSetKey, fvSet.szValName,
0,
(DWORD)REG_SZ,
(LPBYTE)TEXT("\0"),
(DWORD)sizeof(TCHAR));
// Now try applying the new wallpaper via ActiveDesktop SetWP.
if (SetADWallpaper(pValue, TRUE /* Force AD on */)) {
bOK = TRUE;
*pValue = 0;
bOKtoApplyNull = FALSE; // Don't want to set Wallpaper string to
// NULL later on because it causes AD to
// forget about the HTML wallpaper!!
}
else {
// Setting the HTML wallpaper failed!
bOK = FALSE;
*pValue = 0;
}
}
//
// if we are applying a compressed image, lets decompress it first
//
// NOTE we can handle the out 'o disk case a little better
//
if (lstrcmpi(fvSet.szValName, TEXT("Wallpaper")) == 0 && pValue && *pValue &&
lstrcmpi(FindExtension(pValue),TEXT(".bmp")) != 0 &&
lstrcmpi(FindExtension(pValue),TEXT(".dib")) != 0 &&
lstrcmpi(FindExtension(pValue),TEXT(".rle")) != 0 ) {
TCHAR plus_bmp[MAX_PATH];
if (g_hbmWall)
{
CacheDeleteBitmap(g_hbmWall);
g_hbmWall = NULL;
}
g_hbmWall = LoadWallpaper(pValue, lpszFile, FALSE);
Assert(g_hbmWall, TEXT("LoadWallpaper failed!\n"));
if (g_hbmWall) {
GetPlusBitmapName(plus_bmp);
bOK = bOK && SaveImageToFile(g_hbmWall, plus_bmp, pValue);
Assert(bOK, TEXT("unable to save wallpaper to plus!.bmp\n"));
}
else {
bOK = FALSE;
}
if (bOK)
lstrcpy(pValue, plus_bmp);
else
*pValue = 0; // if not found, just null out filename
}
// not always OK to set null value to registry
if (!bOKtoApplyNull && !(*pValue))
return(TRUE); // no work to do EXIT
// just write the string to the registry
lret = RegSetValueEx(hSetKey, fvSet.szValName,
0,
(DWORD)REG_SZ,
(LPBYTE)pValue,
(DWORD)SZSIZEINBYTES(pValue));
bOK = bOK && (lret == ERROR_SUCCESS);
// One last thing -- if this is the Wallpaper and
// ActiveDesktop is on we need to use the ActiveDesktop
// interface to set the wallpaper. We do this because
// we want this wallpaper setting in BOTH the registry
// and the ActiveDesktop. If you set a BMP wallpaper
// via the registry w/out also doing it via the AD
// interface it's possible for the AD/Non-AD desktops
// to be out of sync on their wallpaper.
//
// Note this is the case where the wallpaper is not html.
// Html wallpapers are set via the ActiveDesktop interface
// above.
if ((lstrcmpi(fvSet.szValName, TEXT("Wallpaper")) == 0) &&
IsActiveDesktopOn()) {
bOK = SetADWallpaper(pValue, FALSE);
}
Assert(bOK, TEXT("couldn't write a string value to registry!\n"));
break;
//
// these two cases are both just treated as binary output
case REG_DWORD:
case REG_BINARY:
bOK = WriteBytesToRegister(hSetKey, (LPTSTR)fvSet.szValName,
fvSet.iValType,
(LPTSTR)pValue);
Assert(bOK, TEXT("couldn't write value bytes to registry.\n"));
break;
default:
Assert(FALSE, TEXT("unexpected REG_* data type from our own tables!\n"));
break;
}
// cleanup
Assert(bOK, TEXT("missed a datum from register to file\n"));
return (bOK);
}
//
// WriteBytesToRegister
//
// Parallel to WriteBytesToFile() function. This function takes an ASCII
// string of space-separated 0-255 numbers, translates them into byte
// number values packed into an output buffer, and then assigns that
// binary data to the given key/valuename in the registry -- as the data
// type given.
//
// Note that lpByteStr points to the same pValue that we are using as
// an output buffer. This depends on the numbers compressing as they
// are translated from ASCII to binary. Uses an itermediary variable so
// the first translation isn't messed up.
//
// ********************************************************************
// ASSUMPTIONS: You assume that noone has mucked with this theme file
// manually! In particular, this function depends on no leading blank
// and exactly one blank between each number in the string, and one
// trailing blank at the end followed by a null terminator.
// WHOOPS! BAD ASSUMPTION: trailing blank is stripped by Write/Get
// PrivateProfileString() functions! So need to watch for end manually.
// ********************************************************************
//
// Uses: writes binary data to global pValue[]
//
// Returns: success of write to register
BOOL WriteBytesToRegister(HKEY hKeySet, LPTSTR lpszValName,
int iType, LPTSTR lpszByteStr)
{
BOOL bOK = TRUE;
int iBytes;
LONG lret;
iBytes = WriteBytesToBuffer(lpszByteStr);
// set binary data in register file with the right data type
lret = RegSetValueEx(hKeySet, lpszValName,
0,
(DWORD)iType,
(LPBYTE)pValue,
(DWORD)iBytes);
bOK = (lret == ERROR_SUCCESS);
Assert(bOK, TEXT("couldn't write a string value to registry!\n"));
//
// cleanup
return (bOK);
}
//
// Utility routine for above; takes ASCII string to binary in
// global pValue[] buffer.
//
// Since the values this guy is manipulating is purely ASCII
// numerics we should be able to get away with this char pointer
// arithmetic. If they were not simple ASCII numerics I think
// we could get into trouble with some DBCS chars
//
// Uses: writes binary data to global pValue[]
//
int FAR WriteBytesToBuffer(LPTSTR lpszInput)
{
LPTSTR lpszCur, lpszNext, lpszEnd;
BYTE *pbCur;
int iTemp, iBytes;
#ifdef UNICODE
CHAR szTempA[10];
#endif
//
// inits
lpszNext = lpszInput;
pbCur = (BYTE *)&pValue;
iBytes = 0;
lpszEnd = lpszInput + lstrlen(lpszInput); // points to null term
//
// translating loop
while (*lpszNext && (lpszNext < lpszEnd)) {
//
// update str pointers
// hold onto your starting place
lpszCur = lpszNext;
// advance pointer to next and null terminate cur
while ((TEXT(' ') != *lpszNext) && *lpszNext) { lpszNext++; }
*lpszNext = 0; lpszNext++;
// on last number, this leaves lpszNext pointing past lpszEnd
// translate this string-number into binary number and place in
// output buffer.
#ifdef UNICODE
wcstombs(szTempA, lpszCur, sizeof(szTempA));
iTemp = latoi(szTempA);
#else // !UNICODE
iTemp = latoi(lpszCur);
#endif
*pbCur = (BYTE)iTemp;
pbCur++; // incr byte loc in output buffer
// keep track of your bytes
iBytes++;
}
//
// cleanup
return (iBytes);
}
//
// Trash functions
//
// The registry holds three icons for the trash: full, empty, and default.
// In theory default is always one of the full or empty, and it is the current
// state of the actual trash.
//
// These functions are to query the trash state:
//
// IsTrashFull returns BOOL on full state
//
// and to apply the correct-state trash icon from
// the theme file to the default/cur:
//
// ApplyCurrentTrash
//
#define szCUTrashKey (fsCUIcons[TRASH_INDEX].szSubKey)
#define szRTrashKey (fsRoot[TRASH_INDEX].szSubKey)
#define szEmptyTrashVal TEXT("empty")
#define szFullTrashVal TEXT("full")
BOOL IsTrashFull()
{
TCHAR szEmpty[MAX_PATHLEN+1];
TCHAR szDefault[MAX_PATHLEN+1];
TCHAR szNTReg[MAX_PATH];
// Get the two strings
// First try the CURRENT_USER branch
// Then try the CLASSES_ROOT branch
if (IsPlatformNT())
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, szRTrashKey);
szEmpty[0] = TEXT('\0');
HandGet(HKEY_CURRENT_USER, szNTReg, szEmptyTrashVal, (LPTSTR)szEmpty);
if (!*szEmpty) {
// Didn't get a valid string from CURRENT_USER so try CLASSES_ROOT
HandGet(HKEY_CLASSES_ROOT, szRTrashKey, szEmptyTrashVal, (LPTSTR)szEmpty);
}
szDefault[0] = TEXT('\0');
HandGet(HKEY_CURRENT_USER, szNTReg, szNULL, (LPTSTR)szDefault);
if (!*szDefault) {
// Didn't get a valid string from CURRENT_USER so try CLASSES_ROOT
HandGet(HKEY_CLASSES_ROOT, szRTrashKey, szNULL, (LPTSTR)szDefault);
}
}
else // Not NT
{
szEmpty[0] = TEXT('\0');
HandGet(HKEY_CURRENT_USER, szCUTrashKey, szEmptyTrashVal, (LPTSTR)szEmpty);
if (!*szEmpty) {
// Didn't get a valid string from CURRENT_USER so try CLASSES_ROOT
HandGet(HKEY_CLASSES_ROOT, szRTrashKey, szEmptyTrashVal, (LPTSTR)szEmpty);
}
szDefault[0] = TEXT('\0');
HandGet(HKEY_CURRENT_USER, szCUTrashKey, szNULL, (LPTSTR)szDefault);
if (!*szDefault) {
// Didn't get a valid string from CURRENT_USER so try CLASSES_ROOT
HandGet(HKEY_CLASSES_ROOT, szRTrashKey, szNULL, (LPTSTR)szDefault);
}
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// compare strings and return
return(lstrcmpi((LPTSTR)szEmpty, (LPTSTR)szDefault));
// lstrcmpi rets 0 for equal strings; equal to empty means FALSE to full
}
BOOL ApplyCurrentTrash(BOOL bTrashFull, LPTSTR lpszFile)
{
LONG lret;
HKEY hKey; // cur open key
TCHAR szNTReg[MAX_PATH];
//
// check first that we are even touching the icons
if (!bCBStates[FC_ICONS])
return (TRUE); // no trash to apply EXIT
// have to keep setting cursor to wait because someone resets it
WaitCursor();
//
// inits
//lret = RegOpenKeyEx( HKEY_CLASSES_ROOT, (LPTSTR)szRTrashKey,
// (DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
if (IsPlatformNT())
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, szRTrashKey);
lret = RegOpenKeyEx( HKEY_CURRENT_USER, (LPTSTR)szNTReg,
(DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
}
else // NOT NT
{
lret = RegOpenKeyEx( HKEY_CURRENT_USER, (LPTSTR)szCUTrashKey,
(DWORD)0, KEY_SET_VALUE, (PHKEY)&hKey );
}
if (lret != ERROR_SUCCESS) {
Assert(FALSE, TEXT("problem on RegOpenKey CURRENT_USER in ApplyCurrentTrash\n"));
return (FALSE); // nothing else to do EXIT
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// get the right trash icon file
GetPrivateProfileString((LPTSTR)szCUTrashKey,
(LPTSTR)(bTrashFull ? szFullTrashVal : szEmptyTrashVal),
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
lpszFile);
// If we didn't get the value it could be that we've got an old
// Win95/Plus95 .Theme file. Let's try reading the Theme file
// using the Win95 reg key:
if (!*pValue) {
GetPrivateProfileString((LPTSTR)szRTrashKey,
(LPTSTR)(bTrashFull ? szFullTrashVal : szEmptyTrashVal),
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
lpszFile);
}
InstantiatePath((LPTSTR)pValue, MAX_VALUELEN);
// look for and confirm finding the file, with replacement
if (ConfirmFile((LPTSTR)pValue, TRUE) == CF_NOTFOUND) {
*pValue = 0; // if not found, just null out filename --> ret FALSE
}
if (!(*pValue)) {
Assert(FALSE, TEXT("ApplyCurrentTrash came up with no file\n"));
RegCloseKey(hKey); // mini-cleanup
return (FALSE); // no usable icon file, so just EXIT and leave cur
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// Do the deed
lret = RegSetValueEx(hKey, (LPTSTR)szNULL, // sets default value
0,
(DWORD)REG_SZ,
(LPBYTE)pValue,
(DWORD)SZSIZEINBYTES(pValue));
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// cleanup and return
RegCloseKey(hKey);
Assert(lret == ERROR_SUCCESS, TEXT("bad return setting current trash\n"));
return (ERROR_SUCCESS == lret);
}
//
// HandPumpSystem
//
// OK. You've applied all of the theme file settings to the registry.
// Congratulations. Now reboot! HA HA HA! No seriously, most of the
// settings don't take effect in the current system just by writing
// them to the registry. You have to make each system change happen
// by hand. Hand pump it.
//
// So here we try to get things actually changing in front of the
// astonished user's eyes.
// Of course, assuming the checkbox to request it is checked.
//
// First, to be robustly certain that we are setting what is in the
// registry, actually read the value from the registry. Then use the
// random API for this element to set it.
//
// This is long and messy, the way it has to be. See design critique
// note at head of file.
//
// NOTE that SetSysColors() in SetSysColorsByHand() sends a
// WM_SYSCOLORCHANGE message. We also need to send a WM_SYSCOLORCHANGE
// message if we change any of the metrics - since Excel and other apps
// saw color/metric changes as unitary in 3.1 and would look for color.
// The extra BOOLs watching color and sys changes are to avoid sending
// two WM_SYSCOLORCHANGE messages.
//
// Uses: global bCBStates[] for checkbox states
// global szCurThemeFile[], non-encapsulated uncool
// but this is the grody routine anyway
//
BOOL HandPumpSystem()
{
BOOL bret, bOK = TRUE, bChangedSettings = FALSE;
TCHAR szWinMetrics[] = TEXT("WindowMetrics");
BOOL fClearAppearance = FALSE;
BOOL bSaverIsNull = FALSE;
HKEY hKey;
LONG lret;
DWORD dwDisposition;
int screenSaverTimeout = 0; // Screen saver timeout
BOOL bSkipWP = FALSE; // ActiveDesktop/HTML WP so skip HP WP
TCHAR szADWP[MAX_PATH]; // Current/ActiveDesktop wallpaper setting
// FC_SCRSVR
if (bCBStates[FC_SCRSVR]) {
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// Take a peek at the current SS setting. If it's null we want to
// force the timeout to 15 minutes iff current timeout is 1 minute
// per Plus98 bug 1075. The reason for doing this is because Win98
// sets the timeout to 1 min by default -- so the first time a
// SS is applied the timeout is very short. Too short in some
// people's opinion. So we try to detect this one scenario and
// make the timeout a little bit longer.
GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szSS_File);
if (!*pValue) bSaverIsNull = TRUE;
//
// This one is different: Screen Saver is saved in SYSTEM.INI.
#ifdef GENTLER
// get the current value from SYSTEM.INI
GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)szNULL,
(LPTSTR)szTemp, MAX_VALUELEN,
(LPTSTR)szSS_File);
// now, with cur value as default, get value from theme file
GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)szTemp, // cur value is default
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szCurThemeFile);
#endif
// get scr saver from theme
GetPrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)szNULL, // NULL is default
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szCurThemeFile);
// next, translate path variable if necessary
InstantiatePath((LPTSTR)pValue, MAX_VALUELEN);
// look for and confirm finding the file, with replacement
if (ConfirmFile((LPTSTR)pValue, TRUE) == CF_NOTFOUND) {
*pValue = 0; // if not found, just null out filename
bOK = FALSE; // couldn't apply this file!
}
else { // file's OK, so continue
// now, MAKE SURE that you only write short filenames to old-fashioned system
if (FilenameToShort((LPTSTR)pValue, (LPTSTR)szMsg))
lstrcpy(FileFromPath((LPTSTR)pValue), (LPTSTR)szMsg);
}
// and finally, apply value from theme file (or NULL if not in theme)
WritePrivateProfileString((LPTSTR)szSS_Section, (LPTSTR)szSS_Key,
(LPTSTR)pValue, (LPTSTR)szSS_File);
// and make it live in the system
SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,
// set depending on whether scr saver in theme
// pValue still has scr saver name
(*pValue ? 1 : 0),
NULL, SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
// Set screen saver timeout value
if (!SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &screenSaverTimeout, 0))
{
screenSaverTimeout = 0;
}
// Plus 98 bug 1075 -- if current screensaver setting is NULL and
// the timeout is 1 minute, then force timeout to default (15 mins).
if (bSaverIsNull && (60 == screenSaverTimeout)) screenSaverTimeout = 0;
if (*pValue && !screenSaverTimeout)
{
// There must be a screen saver timeout value, otherwise the system
// assumes that there is no screen saver selected.
SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, DEF_SCREENSAVETIMEOUT, NULL,
SPIF_SENDCHANGE | SPIF_UPDATEINIFILE);
}
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// FC_SOUND
// already in effect just by setting registry settings
if (bCBStates[FC_SOUND]) {
// but need to flush buffer and ensure new sounds used for next events
sndPlaySound((LPTSTR)NULL, SND_ASYNC | SND_NODEFAULT);
//
// Clear the current pointer scheme string from the registry so that Mouse
// cpl doesn't display a bogus name. Don't care if this fails.
RegSetValue(HKEY_CURRENT_USER, (LPTSTR) szCP_SoundSchemes, REG_SZ,
TEXT(".current"), 0);
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// FC_PTRS
if (bCBStates[FC_PTRS]) {
SystemParametersInfo( SPI_SETCURSORS, 0, 0, SPIF_SENDCHANGE);
//
// Clear the current pointer scheme string from the registry so that Mouse
// cpl doesn't display a bogus name. Don't care if this fails.
RegSetValue(HKEY_CURRENT_USER, (LPTSTR) szCP_Appearance, REG_SZ, szNULL, sizeof(TCHAR));
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// FC_WALL
// If ActiveDesktop is on and we're using an html wallpaper
// we don't want to do this hand pump stuff for the various
// wallpaper settings
bSkipWP = FALSE;
if (IsActiveDesktopOn()) {
if (GetADWallpaper(szADWP)) {
if (lstrcmpi(FindExtension(szADWP), TEXT(".htm")) == 0 ||
lstrcmpi(FindExtension(szADWP), TEXT(".html")) == 0 ) {
bSkipWP = TRUE;
}
}
}
if ((bCBStates[FC_WALL]) && !bSkipWP) {
//
// TileWallpaper and WallpaperStyle done by hand here
//
lret = RegCreateKeyEx( HKEY_CURRENT_USER, (LPTSTR)szCP_DT,
(DWORD)0, (LPTSTR)szNULL, REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE, (LPSECURITY_ATTRIBUTES)NULL,
(PHKEY)&hKey, (LPDWORD)&dwDisposition );
if (lret != ERROR_SUCCESS) {
Assert(FALSE, TEXT("problem on RegCreateKeyEx for CP Desktop in HandPump!\n"));
bOK = FALSE; // we are not happy campers
}
if (ERROR_SUCCESS == lret) { // got an open key; set the two values
// do TileWallpaper
GetPrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szTileWP,
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szCurThemeFile);
if (*pValue) { // if in theme, set; else leave reg alone!
lret = RegSetValueEx(hKey,
(LPTSTR)szTileWP,
0,
(DWORD)REG_SZ,
(LPBYTE)pValue,
(DWORD)SZSIZEINBYTES(pValue));
Assert(lret == ERROR_SUCCESS, TEXT("bad return setting szTileWP in HandPump!\n"));
if (ERROR_SUCCESS != lret)
bOK = FALSE;
}
// do WallpaperStyle
GetPrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szWPStyle,
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szCurThemeFile);
if (*pValue) { // if in theme, set; else leave reg alone!
lret = RegSetValueEx(hKey,
(LPTSTR)szWPStyle,
0,
(DWORD)REG_SZ,
(LPBYTE)pValue,
(DWORD)SZSIZEINBYTES(pValue));
Assert(lret == ERROR_SUCCESS, TEXT("bad return setting WPStyle in HandPump!\n"));
if (ERROR_SUCCESS != lret)
bOK = FALSE;
}
RegCloseKey(hKey); // mini-cleanup
}
//
// Wallpaper and Pattern are set in reg in ApplySubkeys.
// Just make them live here
//
// get the Wallpaper reset in system
bret = HandGet(HKEY_CURRENT_USER,
TEXT("Control Panel\\Desktop"),
TEXT("Wallpaper"),
(LPTSTR)pValue);
SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, pValue,
SPIF_SENDCHANGE);
// get the Pattern reset in system
bret = HandGet(HKEY_CURRENT_USER,
TEXT("Control Panel\\Desktop"),
TEXT("Pattern"),
(LPTSTR)pValue);
SystemParametersInfo(SPI_SETDESKPATTERN, 0, pValue,
SPIF_SENDCHANGE);
// PLUS! 98 Bug 896 -- when switching from an HTML wallpaper
// to a BMP wallpaper the shell didn't update the WP if the
// ICONS setting was not checked -- user had to press F5 to
// refresh the desktop. This fixes that problem.
SHChangeNotify(SHCNE_ASSOCCHANGED, 0, NULL, NULL);
// the rest of the wallpaper items seem to be read from registry as needed
// "TileWallpaper"
// NIX: "WallpaperStyle"
// "WallPaperOriginX"
// "WallPaperOriginY"
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// FC_ICONS
// already done
// FC_ICONSIZE and FC_FONTS are NO LONGER intertwined
// if (bCBStates[FC_FONTS] || bCBStates[FC_ICONSIZE]) {
// for icons, this is just for the spacing; size already done
// FC_FONTS
if (bCBStates[FC_FONTS]) {
// for fonts, this is the icon fonts
SetIconMetricsByHand(FALSE, bCBStates[FC_FONTS]);
fClearAppearance = TRUE;
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// FC_FONTS and FC_BORDERS are intertwined
if (bCBStates[FC_FONTS] || bCBStates[FC_BORDERS]) {
SetNonClientMetricsByHand(bCBStates[FC_FONTS], bCBStates[FC_BORDERS]);
bChangedSettings = TRUE;
fClearAppearance = TRUE;
}
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// FC_COLORS
if (bCBStates[FC_COLORS]) {
bret = SetSysColorsByHand();
//
// THIS SENT A WM_SYSCOLORCHANGE MESSAGE
//
bOK = bOK && bret;
fClearAppearance = TRUE;
}
else if (bChangedSettings) // may need to send color msg anyway
// for Win3.1 app compatibility, need to say COLOR changed if any metrics changed
PostMessage(HWND_BROADCAST, WM_SYSCOLORCHANGE, 0, 0);
// Changed SendMessage to PostMessage to get around Plus! Setup bug
//
// cleanup
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// let the world know you've mucked with it all
if (bChangedSettings)
SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE,
SPI_SETNONCLIENTMETRICS, (LPARAM)(LPTSTR)szWinMetrics);
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// if (bCBStates[FC_ICONS] || bCBStates[FC_ICONSIZE]) {
if (bCBStates[FC_ICONS]) {
SHChangeNotify(SHCNE_ASSOCCHANGED, 0, NULL, NULL); // should do the trick!
SendMessage(HWND_BROADCAST, WM_SETTINGCHANGE,
SPI_SETICONMETRICS, (LPARAM)(LPTSTR)szWinMetrics);
}
if (fClearAppearance) {
//
// Clear the current appearance string from the registry so that Display cpl
// doesn't display a bogus name. Don't care if this fails.
if (RegOpenKeyEx(HKEY_CURRENT_USER, (LPTSTR)szCP_Appearance, (DWORD)0,
KEY_SET_VALUE, (PHKEY)&hKey ) == ERROR_SUCCESS) {
RegDeleteValue(hKey, szCurrent);
RegCloseKey(hKey);
}
}
return (bOK);
}
//
// HandGet
//
// Just a little helper routine, gets an individual string value from the
// registry and returns it to the caller. Takes care of registry headaches,
// including a paranoid length check before getting the string.
//
// NOTE that this function thinks it's getting a string value. If it's
// another kind, this function will do OK: but the caller may be surprised
// if expecting a string.
//
// Returns: success of string retrieval
//
BOOL FAR HandGet(HKEY hKeyRoot, LPTSTR lpszSubKey, LPTSTR lpszValName, LPTSTR lpszRet)
{
LONG lret;
HKEY hKey; // cur open key
BOOL bOK = TRUE;
DWORD dwSize;
DWORD dwType;
//
// inits
// get subkey
lret = RegOpenKeyEx( hKeyRoot, lpszSubKey,
(DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKey );
if (lret != ERROR_SUCCESS) {
Assert(FALSE, TEXT("problem on RegOpenKey in HandGet\n"));
return (FALSE);
}
// now do our paranoid check of data size
lret = RegQueryValueEx(hKey, lpszValName,
(LPDWORD)NULL,
(LPDWORD)&dwType,
(LPBYTE)NULL, // null for size info only
(LPDWORD)&dwSize );
if (ERROR_SUCCESS == lret) { // saw something there
// here's the size check before getting the data
if (dwSize > (DWORD)(MAX_VALUELEN * sizeof(TCHAR))) { // if string too big
Assert(FALSE, TEXT("Humongous registry string; can't HandGet...\n"));
bOK = FALSE; // can't read, so very bad news
bReadOK = FALSE;
}
else { // size is OK to continue
// now really get the value
lret = RegQueryValueEx(hKey, lpszValName,
(LPDWORD)NULL,
(LPDWORD)&dwType,
(LPBYTE)lpszRet, // getting actual value
(LPDWORD)&dwSize);
// If this is an EXPAND_SZ we need to expand it...
if (REG_EXPAND_SZ == dwType) ExpandSZ(lpszRet);
Assert(lret == ERROR_SUCCESS, TEXT("bad return HandGet query\n"));
Assert(((dwType == (DWORD)REG_SZ) || (dwType == (DWORD)REG_EXPAND_SZ)), TEXT("non-string type in HandGet!\n"));
if (ERROR_SUCCESS != lret) bOK = FALSE;
}
}
else bOK = FALSE;
//
// cleanup
// close subkey
RegCloseKey(hKey);
return (bOK);
}
//
// Gather/SetSysColorsByHand
//
// Colors would seem to be the prototypical setting, that we could just
// read and write directly in the registry. But noooooooo.....
// A. On initial install, somehow the color settings all remain blank.
// B. Need to use SetSysColor() anyway to broadcast message.
//
// So on both read and write, need to use Get/SetSysColor. On write, still
// also need to write directly to registry.
//
//
// Uses GetSysColor() rather than reading directly from the Registry.
// Writes to theme file.
//
BOOL GatherSysColorsByHand(LPTSTR lpszTheme)
{
int iColor;
COLORREF crRGB;
BOOL bRet, bOK = TRUE;
BOOL bGrad = FALSE; // Are gradient titles enabled?
// init bGrad
SystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, (LPVOID)&bGrad, 0);
//
// inits
Assert ((sizeof(iSysColorIndices)/sizeof(int)) == (sizeof(pRegColors)/sizeof(TCHAR *)),
TEXT("mismatched color arrays in GatherSysColorsByHand\n"));
//
// main process
// go through each color in your array
for (iColor = 0; iColor < (sizeof(pRegColors)/sizeof(TCHAR *)); iColor ++) {
// If this is the Gradient Caption setting and the system does
// not currently show gradient captions then don't write them out
// to the theme file.
//
// bGrad == Are gradient captions currently enabled?
// g_bGradient == Enough colors to show gradients?
if (((COLOR_GRADIENTACTIVECAPTION == iSysColorIndices[iColor]) ||
(COLOR_GRADIENTINACTIVECAPTION == iSysColorIndices[iColor])) &&
(!(bGrad && g_bGradient))) continue;
// get the system color
crRGB = GetSysColor(iSysColorIndices[iColor]);
// ASSUME THAT YOU NEVER GET A BOGUS VALUE FROM THIS FUNCTION!!
// translate to a string
ColorToRGBString((LPTSTR)szMsg, crRGB);
// write to theme file
bRet = WritePrivateProfileString((LPTSTR)szCP_Clr, (LPTSTR)(pRegColors[iColor]),
(LPTSTR)szMsg, lpszTheme);
if (!bRet) bOK = FALSE;
}
// cleanup
if (!bOK) bWroteOK = FALSE;
return (bOK);
}
//
// Reads from the theme and writes to the Registry.
// At the same time, does the grody SetSysColor thing:
// creates an array to set up the call. Makes the call.
//
BOOL SetSysColorsByHand()
{
LONG lret;
HKEY hKey; // cur open key
BOOL bOK = TRUE;
COLORREF crSet[(sizeof(iSysColorIndices)/sizeof(int))];
int iColor;
DWORD dwDisposition;
//
// inits
Assert ((sizeof(iSysColorIndices)/sizeof(int)) == (sizeof(pRegColors)/sizeof(TCHAR *)),
TEXT("mismatched color arrays in SetSysColorsByHand\n"));
// have to keep setting cursor to wait because someone resets it
WaitCursor();
// Open the color key if it exists, otherwise create it.
lret = RegCreateKeyEx( HKEY_CURRENT_USER, (LPTSTR)szCP_Clr,
(DWORD)0, (LPTSTR)szNULL, REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE, NULL, (PHKEY)&hKey, (LPDWORD)&dwDisposition );
if (lret != ERROR_SUCCESS) {
Assert(FALSE, TEXT("problem on RegOpenKey in SetSysColorsByHand\n"));
return (FALSE);
}
//
// main process
// go through each color valuename in your array
for (iColor = 0; iColor < (sizeof(pRegColors)/sizeof(TCHAR *)); iColor ++) {
// get color string from theme file
GetPrivateProfileString((LPTSTR)szCP_Clr, (LPTSTR)(pRegColors[iColor]),
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szCurThemeFile);
// If this is one of the Gradient Title bar settings and the setting
// doesn't exist in the Theme file, read the non-gradient title setting
// instead.
if ((iColor == INDEX_GRADIENTACTIVE) && !*pValue) {
GetPrivateProfileString((LPTSTR)szCP_Clr,
(LPTSTR)(pRegColors[INDEX_ACTIVE]),
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szCurThemeFile);
}
if ((iColor == INDEX_GRADIENTINACTIVE) && !*pValue) {
GetPrivateProfileString((LPTSTR)szCP_Clr,
(LPTSTR)(pRegColors[INDEX_INACTIVE]),
(LPTSTR)szNULL,
(LPTSTR)pValue, MAX_VALUELEN,
(LPTSTR)szCurThemeFile);
}
if (!(*pValue)) {
// if nothing in theme, use cur sys colors
crSet[iColor] = GetSysColor(iSysColorIndices[iColor]);
continue; // null color value CONTINUE
}
// set color to Registry
lret = RegSetValueEx(hKey, (LPTSTR)(pRegColors[iColor]),
0,
(DWORD)REG_SZ,
(LPBYTE)pValue,
(DWORD)SZSIZEINBYTES(pValue));
Assert(lret == ERROR_SUCCESS, TEXT("bad return SetSysColorsByHand query\n"));
if (ERROR_SUCCESS != lret)
bOK = FALSE;
// OK, you've got a str version of a COLOR.
// Translate string and add to COLORREF array.
crSet[iColor] = RGBStringToColor((LPTSTR)pValue);
}
//
// There. You've finally got an array of color RGB values. Apply liberally.
SystemParametersInfo(SPI_SETGRADIENTCAPTIONS, 0, IntToPtr(g_bGradient), SPIF_UPDATEINIFILE);
SetSysColors((sizeof(iSysColorIndices)/sizeof(int)), iSysColorIndices, crSet);
//
// Cleanup
RegCloseKey(hKey);
return (bOK);
}
//
// RGB to String to RGB utilities.
//
COLORREF FAR RGBStringToColor(LPTSTR lpszRGB)
{
LPTSTR lpszCur, lpszNext;
BYTE bRed, bGreen, bBlue;
#ifdef UNICODE
CHAR szTempA[10];
#endif
// inits
lpszNext = lpszRGB;
// set up R for translation
lpszCur = lpszNext;
while ((TEXT(' ') != *lpszNext) && *lpszNext) { lpszNext++; }
*lpszNext = 0; lpszNext++;
// get Red
#ifdef UNICODE
wcstombs(szTempA, (wchar_t *)lpszCur, sizeof(szTempA));
bRed = (BYTE)latoi(szTempA);
#else // !UNICODE
bRed = (BYTE)latoi(lpszCur);
#endif
// set up G for translation
lpszCur = lpszNext;
while ((TEXT(' ') != *lpszNext) && *lpszNext) { lpszNext++; }
*lpszNext = 0; lpszNext++;
// get Green
#ifdef UNICODE
wcstombs(szTempA, (wchar_t *)lpszCur, sizeof(szTempA));
bGreen = (BYTE)latoi(szTempA);
#else // !UNICODE
bGreen = (BYTE)latoi(lpszCur);
#endif
// set up B for translation
lpszCur = lpszNext;
while ((TEXT(' ') != *lpszNext) && *lpszNext) { lpszNext++; }
*lpszNext = 0; lpszNext++;
// get Blue
#ifdef UNICODE
wcstombs(szTempA, (wchar_t *)lpszCur, sizeof(szTempA));
bBlue = (BYTE)latoi(szTempA);
#else // !UNICODE
bBlue = (BYTE)latoi(lpszCur);
#endif
// OK, now combine them all for the big finish.....!
return(RGB(bRed, bGreen, bBlue));
}
void FAR ColorToRGBString(LPTSTR lpszRet, COLORREF crColor)
{
int iTemp;
TCHAR szTemp[12];
#ifdef UNICODE
CHAR szTempA[10];
#endif
// first do R value
iTemp = (int) GetRValue(crColor);
#ifdef UNICODE
litoa(iTemp, szTempA);
mbstowcs(lpszRet, szTempA, sizeof(szTempA));
#else // !UNICODE
litoa(iTemp, lpszRet);
#endif
// add on G value
lstrcat(lpszRet, TEXT(" "));
iTemp = (int) GetGValue(crColor);
#ifdef UNICODE
litoa(iTemp, szTempA);
mbstowcs(szTemp, szTempA, sizeof(szTempA));
#else // !UNICODE
litoa(iTemp, szTemp);
#endif
lstrcat(lpszRet, (LPTSTR)szTemp);
// add on B value
lstrcat(lpszRet, TEXT(" "));
iTemp = (int) GetBValue(crColor);
#ifdef UNICODE
litoa(iTemp, szTempA);
mbstowcs(szTemp, szTempA, sizeof(szTempA));
#else // !UNICODE
litoa(iTemp, szTemp);
#endif
lstrcat(lpszRet, (LPTSTR)szTemp);
// OK, you're done now
}
BOOL GatherWallpaperBitsByHand(LPTSTR lpszTheme)
{
BOOL bret, bOK = TRUE;
// save TileWallpaper
bret = HandGet(HKEY_CURRENT_USER, (LPTSTR)szCP_DT, (LPTSTR)szTileWP,(LPTSTR)pValue);
Assert(bret, TEXT("couldn't get WallpaperStyle from Registry!\n"));
bOK = bOK && bret;
bret = WritePrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szTileWP,
// only store if got something, else null
(LPTSTR)(bret ? pValue : szNULL),
lpszTheme);
bOK = bOK && bret;
if (!bret) bWroteOK = FALSE;
// save Wallpaper Style
bret = HandGet(HKEY_CURRENT_USER, (LPTSTR)szCP_DT, (LPTSTR)szWPStyle, (LPTSTR)pValue);
Assert(bret, TEXT("couldn't get WallpaperStyle from Registry!\n"));
bOK = bOK && bret;
bret = WritePrivateProfileString((LPTSTR)szCP_DT, (LPTSTR)szWPStyle,
// only store if got something, else null
(LPTSTR)(bret ? pValue : szNULL),
lpszTheme);
bOK = bOK && bret;
if (!bret) bWroteOK = FALSE;
return (bOK);
}
//
// *Path
//
// These routines help to make themes transportable between computers.
// The problem is that the registry keeps filenames for the various
// theme elements and, of course, these are hard-coded paths that vary
// from machine to machine.
//
// The way we work around this problem is by storing filenames in the
// theme file as _relative_ paths: relative to the theme file directory
// or the Windows directory. (Actually, these routines are set up to
// be relative to any number of directories.) When saving a filename to
// a theme, we check to see if any relative paths can be abstracted out.
// When retrieving a filename from a theme, we take the abstract placeholder
// and replace it with the current sessions instances.
// these must parallel each other. abstract strs must start with %
TCHAR *szAbstractDirs[] = {szThemeDir, szWinDir, szWinDir};
TCHAR *szAbstractStrs[] = {TEXT("%ThemeDir%"), TEXT("%WinDir%"), TEXT("%SystemRoot%")};
// AbstractPath (see header above)
//
// Takes actual full path/filename and takes out a leading substring
// that matches any of the paths to abstract, if any.
//
// lpszPath both input and output; assumes it's huge
//
VOID AbstractPath(LPTSTR lpszPath, int imax)
{
int iter, iAbstrDirLen;
TCHAR szTemp[MAX_PATHLEN+1];
// check easy out first
if (!lpszPath[0])
return; // easy out, nothing to change EXIT
// paranoid init
szTemp[MAX_PATHLEN] = 0;
// look for each of the path prefixes we care about in the given string
for (iter = 0; iter < (sizeof(szAbstractDirs)/sizeof(TCHAR *)); iter++ ) {
// inits
iAbstrDirLen = lstrlen((LPTSTR)(szAbstractDirs[iter]));
// get beginning of passed path string
lstrcpyn((LPTSTR)szTemp, lpszPath,
// ********************************
// LSTRCPYN issue: doc says that N specifies number of chars, not
// including the terminating null char. Behavior seems to include
// the null char, so I add one here. If the Win libs are modified
// to match their doc, then this will become a bug.
// ********************************
iAbstrDirLen + 1);
// compare to path prefix to abstract
if (!lstrcmpi((LPTSTR)szTemp, (LPTSTR)(szAbstractDirs[iter]))) {
//
// GOT A MATCH: now do the substitution
lstrcpy((LPTSTR)szTemp,
(LPTSTR)(szAbstractStrs[iter])); // start w/ abstract key
lstrcat((LPTSTR)szTemp,
(LPTSTR)(lpszPath + iAbstrDirLen)); // rest of path
lstrcpy(lpszPath, (LPTSTR)szTemp); // copy the result to ret str
// now get out
return; // got yer result now EXIT
}
}
// if you didn't get a match, then you're just returning the same path str
}
// InstantiatePath (see header above)
//
// Takes theme file's version of path/filename and looks for leading abstraction
// string that matches any of the known abstractions, replacing it with
// current system's equivalent if found.
//
// lpszPath both input and output; assumes it's huge
//
VOID FAR InstantiatePath(LPTSTR lpszPath, int imax)
{
int iter, iAbstrStrLen;
TCHAR szTemp[MAX_PATHLEN+1];
// easy outs
if ((TEXT('%') != lpszPath[0]) || !lpszPath[0])
return; // easy out, nothing to change EXIT
// paranoid init
szTemp[MAX_PATHLEN] = 0;
// look for each of the possible abstraction prefixes in the given string
for (iter = 0; iter < (sizeof(szAbstractStrs)/sizeof(TCHAR *)); iter++ ) {
// inits
iAbstrStrLen = lstrlen((LPTSTR)(szAbstractStrs[iter]));
// get beginning of passed path string
lstrcpyn((LPTSTR)szTemp, lpszPath,
// ********************************
// LSTRCPYN issue: doc says that N specifies number of chars, not
// including the terminating null char. Behavior seems to include
// the null char, so I add one here. If the Win libs are modified
// to match their doc, then this will become a bug.
// ********************************
iAbstrStrLen + 1);
// compare to this abstraction key string
if (!lstrcmpi((LPTSTR)szTemp, (LPTSTR)(szAbstractStrs[iter]))) {
//
// GOT A MATCH: now do the substitution
lstrcpy((LPTSTR)szTemp,
(LPTSTR)(szAbstractDirs[iter])); // actual path prefix
// Avoid the double backslash problem
if (lpszPath[iAbstrStrLen] == TEXT('\\')) iAbstrStrLen++;
lstrcat((LPTSTR)szTemp,
(LPTSTR)(lpszPath + iAbstrStrLen)); // rest of path
lstrcpy(lpszPath, (LPTSTR)szTemp); // copy the result to ret str
// now get out
return; // got yer result now EXIT
}
}
// On NT there is one more abstraction we need to worry about but
// we can't add it to the array of abstraction strings -- doing
// so would cause us to write it out to Theme files which would
// make the theme files not backward compatible.
//
// %SystemDrive%
//
if (IsPlatformNT())
{
// inits
iAbstrStrLen = lstrlen((LPTSTR)(TEXT("%SystemDrive%")));
// get beginning of passed path string
lstrcpyn((LPTSTR)szTemp, lpszPath,
// ********************************
// LSTRCPYN issue: doc says that N specifies number of chars, not
// including the terminating null char. Behavior seems to include
// the null char, so I add one here. If the Win libs are modified
// to match their doc, then this will become a bug.
// ********************************
iAbstrStrLen + 1);
// compare to this abstraction key string
if (!lstrcmpi((LPTSTR)szTemp, (LPTSTR)(TEXT("%SystemDrive%")))) {
//
// GOT A MATCH: now do the substitution
szTemp[0] = szWinDir[0]; // drive letter 'C'
szTemp[1] = szWinDir[1]; // colon ':'
szTemp[2] = TEXT('\0'); // null
lstrcat((LPTSTR)szTemp,
(LPTSTR)(lpszPath + iAbstrStrLen)); // rest of path
lstrcpy(lpszPath, (LPTSTR)szTemp); // copy the result to ret str
// now get out
return; // got yer result now EXIT
}
}
// if you didn't get a match, then you're just returning the same path str
}
//
// ConfirmFile
//
// This function does the "smart" file searching that's supposed to be
// built into each resource file reference in applying themes.
//
// First see if the full pathname + file given actually exists.
// If it does not, then try looking for the same filename (stripped from path)
// in other standard directories, in this order:
// Current Theme file directory
// Theme switcher THEMES subdirectory
// Windows directory
// Windows/MEDIA directory
// Windows/CURSORS directory
// Windows/SYSTEM directory
//
// Input: LPTSTR lpszPath full pathname
// BOOL bUpdate whether to alter the filename string with found file
// Returns: int flag telling if and how file has been confirmed
// CF_EXISTS pathname passed in was actual file
// CF_FOUND file did not exist, but found same filename elsewhere
// CF_NOTFOUND file did not exist, could not find elsewhere
//
int FAR ConfirmFile(LPTSTR lpszPath, BOOL bUpdate)
{
TCHAR szWork[MAX_PATHLEN+1];
TCHAR szTest[MAX_PATHLEN+1];
int iret = CF_NOTFOUND; // default value
LPTSTR lpFile;
LPTSTR lpNumber;
HANDLE hTest;
// special case easy return: if it's null, then trivially satisfied.
if (!*lpszPath) return (CF_EXISTS); // NO WORK EXIT
//
// Inits
// copy pathname to a work string for the function
lstrcpy((LPTSTR)szWork, lpszPath);
// input can be of the form foo.dll,13. need to strip off that comma,#
// but hold onto it to put back at the end if we change the pathname
lpNumber = FindChar(szWork, TEXT(','));
if (*lpNumber) { // if there is a comma
lpFile = lpNumber; // temp
lpNumber = CharNext(lpNumber);// hold onto number
*lpFile = 0;
}
//
// Do the checks
// *** first check if the given file just exists as is
hTest = CreateFile(szWork, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTest != INVALID_HANDLE_VALUE) { // success
iret = CF_EXISTS; // assign ret value
// don't need to worry about bUpdate: found with input string
}
// otherwise, let's go searching for the same filename in other dirs
else {
Assert(FALSE, TEXT("had to go looking for "));
Assert(FALSE, szWork);
Assert(FALSE, TEXT("....\n"));
// get ptr to the filename separated from the path
lpFile = FileFromPath(szWork);
// *** try the cur theme file dir
lstrcpy((LPTSTR)szTest, (LPTSTR)szCurDir);
lstrcat((LPTSTR)szTest, lpFile);
hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTest != INVALID_HANDLE_VALUE) { // success
iret = CF_FOUND; // assign ret value
Assert(FALSE, TEXT(" OK, found it in cur theme file dir\n"));
}
// *** otherwise try the Theme switcher THEMES subdirectory
else {
lstrcpy((LPTSTR)szTest, (LPTSTR)szThemeDir);
lstrcat((LPTSTR)szTest, lpFile);
hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTest != INVALID_HANDLE_VALUE) { // success
iret = CF_FOUND; // assign ret value
Assert(FALSE, TEXT(" OK, found it in themes directory\n"));
}
// *** otherwise try the win dir
else {
lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
lstrcat((LPTSTR)szTest, lpFile);
hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTest != INVALID_HANDLE_VALUE) { // success
iret = CF_FOUND; // assign ret value
Assert(FALSE, TEXT(" OK, found it in windows directory\n"));
}
// *** otherwise try the win/media dir
else {
// can get this one directly from Registry
HandGet(HKEY_LOCAL_MACHINE,
TEXT("SOFTWARE\\Microsoft\\Windows\\CurrentVersion"),
TEXT("MediaPath"), (LPTSTR)szTest);
#ifdef THEYREMOVEREGSETTING
lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
lstrcat((LPTSTR)szTest, TEXT("Media\\"));
#endif
lstrcat((LPTSTR)szTest, TEXT("\\"));
lstrcat((LPTSTR)szTest, lpFile);
hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTest != INVALID_HANDLE_VALUE) { // success
iret = CF_FOUND; // assign ret value
Assert(FALSE, TEXT(" OK, found it in windows media directory\n"));
}
// *** otherwise try the win/cursors dir
else {
lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
lstrcat((LPTSTR)szTest, TEXT("CURSORS\\"));
lstrcat((LPTSTR)szTest, lpFile);
hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTest != INVALID_HANDLE_VALUE) { // success
iret = CF_FOUND; // assign ret value
Assert(FALSE, TEXT(" OK, found it in windows cursors directory\n"));
}
// *** otherwise try the win/system dir
else {
lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
lstrcat((LPTSTR)szTest, TEXT("SYSTEM\\"));
lstrcat((LPTSTR)szTest, lpFile);
hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTest != INVALID_HANDLE_VALUE) { // success
iret = CF_FOUND; // assign ret value
Assert(FALSE, TEXT(" OK, found it in windows system directory\n"));
}
// *** otherwise try the win/system32 dir
else {
lstrcpy((LPTSTR)szTest, (LPTSTR)szWinDir);
lstrcat((LPTSTR)szTest, TEXT("SYSTEM32\\"));
lstrcat((LPTSTR)szTest, lpFile);
hTest = CreateFile((LPTSTR)szTest, GENERIC_READ, FILE_SHARE_READ,
(LPSECURITY_ATTRIBUTES)NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
if (hTest != INVALID_HANDLE_VALUE) { // success
iret = CF_FOUND; // assign ret value
Assert(FALSE, TEXT(" OK, found it in windows system32 directory\n"));
}
}
}
}
}
}
}
// if found anywhere other than orig, copy found path/str as requested
if ((iret == CF_FOUND) && bUpdate) {
lstrcpy(lpszPath, (LPTSTR)szTest);
// if we stripped off a number, let's add it back on
if (*lpNumber) {
lstrcat(lpszPath, TEXT(","));
lstrcat(lpszPath, lpNumber);
}
} // endif found file by searching
}
// cleanup
Assert(iret != CF_NOTFOUND, TEXT(" But never found it!\n"));
if (iret != CF_NOTFOUND)
CloseHandle(hTest); // close file if opened
return (iret);
}
#ifdef ACTUALLY_DOING_THIS
//
// SetCheckboxesFromThemeFile
//
// After a new theme is selected from the listbox, you have to update
// the checkboxes in the main dlg window:
// uncheck and disable those that are not used in the theme
// check and enable those that are used in the theme
//
// Some of the checkboxes will always be enabled.
// Some of the checkboxes require a check of a sequence of settings
// (e.g. the sound events) and enabling iff any of them are used.
//
void FAR SetCheckboxesFromThemeFile(LPTSTR lpszFilename)
{
}
//
// SetCheckboxesFromRegistry
//
// Similar to SetCheckboxesFromThemeFile(), but for the case of
// "Current Windows settings" there is no file -- you just query
// the cur registry to get all the same values.
//
void FAR SetCheckboxesFromRegistry()
{
}
#endif
//
// CheckSpace
//
// Checks if there is enough space on drive to apply theme file.
//
BOOL FAR CheckSpace (HWND hWnd, BOOL fComplain)
{
//
// Step 1. Calculate Worst case Space needed
//
// 4 48 x 48 hicolor icons (10K each worst case) + (10K theme file) + padding
// Multiple by 2 for Prev and Curr Themes
#define FUDGE_SIZE (2L << 16)
HDC hdc;
ULONG cHorz;
ULONG cVert;
ULONG cPlanes;
ULONG cBPP;
ULONG fFlags;
ULONG cbNeeded;
ULONG cPalSize;
ULONG cColorDepth;
TCHAR szTemp[MAX_MSGLEN+1];
TCHAR szMsg[MAX_MSGLEN+1];
HANDLE hFile;
WIN32_FIND_DATA fd;
TCHAR chDrive;
TCHAR szDrive[4];
ULONG ckNeeded;
ULONG cbAvail;
DWORD csCluster;
DWORD cbSector;
DWORD ccFree;
DWORD ccTotal;
hdc = GetDC (HWND_DESKTOP);
cHorz = GetDeviceCaps (hdc, HORZRES);
cVert = GetDeviceCaps (hdc, VERTRES);
cPlanes = GetDeviceCaps (hdc, PLANES);
cBPP = GetDeviceCaps (hdc, BITSPIXEL);
fFlags = GetDeviceCaps (hdc, RASTERCAPS);
cPalSize = 3L;
cColorDepth = cPlanes * cBPP;
if ((fFlags & RC_PALETTE) == RC_PALETTE)
{
cPalSize = GetDeviceCaps (hdc, SIZEPALETTE);
}
ReleaseDC (HWND_DESKTOP, hdc);
// Get Worst case size of Plus! bitmap
cbNeeded = (cHorz * cVert * cColorDepth)/8L;
// Add in Bitmap File Header
cbNeeded += sizeof (BITMAPFILEHEADER);
// Add in Bitmap Info Header
cbNeeded += sizeof (BITMAPINFOHEADER);
// Add in worst case palette size
cbNeeded += sizeof (RGBQUAD) * cPalSize;
// Add in Fudge factor
cbNeeded += FUDGE_SIZE;
//
// Step 2. Is there a current Plus! bitmap ?!?
// Subtract it's size from our requirements
//
GetPlusBitmapName (szTemp);
hFile = FindFirstFile(szTemp, &fd);
if (hFile != INVALID_HANDLE_VALUE)
{
// Make sure it isn't larger than we know what to do with
if (!fd.nFileSizeHigh)
{
if (cbNeeded > fd.nFileSizeLow)
cbNeeded -= fd.nFileSizeLow;
else
{
// Just to be safe we need some space
cbNeeded = FUDGE_SIZE;
}
}
FindClose (hFile);
}
//
// Step 3. Get Space available on drive
//
chDrive = szTemp[0];
szDrive[0] = chDrive;
szDrive[1] = TEXT(':');
szDrive[2] = TEXT('\\');
szDrive[3] = 0;
if (! GetDiskFreeSpace (szDrive, &csCluster, &cbSector, &ccFree, &ccTotal))
return FALSE;
cbAvail = ccFree * csCluster * cbSector;
//
// Step 3. Is there a problem ?!?
//
if (cbAvail < cbNeeded)
{
// Inform User ?!?
if (fComplain)
{
// Let user know about space problem
ckNeeded = cbNeeded/1024L;
LoadString (hInstApp, STR_ERRNEEDSPACE, (LPTSTR)szTemp, MAX_MSGLEN);
wsprintf ((LPTSTR)szMsg, (LPTSTR)szTemp, chDrive, ckNeeded, chDrive);
MessageBox((HWND)hWnd, (LPTSTR)szMsg, (LPTSTR)szAppName,
MB_OK | MB_ICONERROR | MB_APPLMODAL);
}
// Don't bother to do any work
return FALSE;
}
return TRUE;
}
// GatherICONS
//
BOOL GatherICONS(LPCTSTR lpszThemefile)
{
DWORD ikey; // index for FROST_SUBKEY arrary
DWORD dwMaxKey; // number of FROST_SUBKEY's in array
int ival; // index for FROST_VALUE array
DWORD dwType; // type of reg key
DWORD dwSize; // size of reg key
HKEY hKeyCU; // handle to CURRENT_USER key
HKEY hKeyR; // handle to CLASSES_ROOT key
BOOL bGotCU; // Do we have a good CU handle?
BOOL bGotR; // Do we have a good ROOT handle?
BOOL bGotValCU; // We got the value from the CU key
BOOL bGotValR; // We got the value from the R key
BOOL bRet; // Return from bool function
BOOL bOK = TRUE; // cumulative return code for this function
LONG lret; // function result
TCHAR szNTReg[MAX_PATH]; // Reg path to use for NT
dwMaxKey = sizeof(fsCUIcons)/sizeof(FROST_SUBKEY);
// loop through each subkey in the fsCUIcons() enumeration
for (ikey = 0; ikey < dwMaxKey; ikey++) {
// The icon information is typically kept in the CURRENT_USER
// branch, but if we don't find it there we need to check the
// CLASSES_ROOT branch as well.
//
// On the NT Platform we check the c_szSoftwareClassesFmt reg
// path first (instead of CURRENT_USER/fsCUIcons) then try the
// CLASSES_ROOT branch.
// Try to open the appropriate CURRENT_USER subkey for this platform
if (IsPlatformNT())
{
lstrcpy(szNTReg, c_szSoftwareClassesFmt);
lstrcat(szNTReg, fsRoot[ikey].szSubKey);
lret = RegOpenKeyEx(HKEY_CURRENT_USER, szNTReg,
(DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKeyCU);
}
else // Not NT so don't use the touched-up current_user path
{
lret = RegOpenKeyEx(HKEY_CURRENT_USER, (LPTSTR)fsCUIcons[ikey].szSubKey,
(DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKeyCU);
}
if (lret != ERROR_SUCCESS) bGotCU = FALSE;
else bGotCU = TRUE;
// Try to open the CLASSES_ROOT subkey
lret = RegOpenKeyEx(HKEY_CLASSES_ROOT, (LPTSTR)fsRoot[ikey].szSubKey,
(DWORD)0, KEY_QUERY_VALUE, (PHKEY)&hKeyR);
if (lret != ERROR_SUCCESS) bGotR = FALSE;
else bGotR = TRUE;
// If we couldn't open a key in either the CU or R branch then
// we should write a null value to the Theme file.
if (!bGotCU && !bGotR) {
// (null loop if default string only)
for (ival = 0; ival < fsCUIcons[ikey].iNumVals; ival++) {
bRet = WritePrivateProfileString(
fsCUIcons[ikey].szSubKey,
(LPTSTR)fsCUIcons[ikey].fvVals[ival].szValName,
(LPTSTR)szNULL, lpszThemefile);
bOK = bOK && bRet;
}
if (fsCUIcons[ikey].fValues != FV_LIST) { // either def or list+def
bRet = WritePrivateProfileString(
fsCUIcons[ikey].szSubKey,
(LPTSTR)FROST_DEFSTR,
(LPTSTR)szNULL, lpszThemefile);
bOK = bOK && bRet;
}
continue; // Failed to OPEN reg key so continue on to next ikey
}
// Assume that we successfully opened either the CU or R subkey
// treat depending on type of values for this subkey
switch (fsCUIcons[ikey].fValues) {
case FV_LIST:
case FV_LISTPLUSDEFAULT:
// loop through each value in the list for this subkey
for (ival = 0; ival < fsCUIcons[ikey].iNumVals; ival++) {
bGotValCU = FALSE;
if (bGotCU) {
dwSize = (DWORD)(MAX_VALUELEN * sizeof(TCHAR));
lret = RegQueryValueEx(
hKeyCU,
fsCUIcons[ikey].fvVals[ival].szValName,
(LPDWORD)NULL,
(LPDWORD)&dwType,
(LPBYTE)pValue,
(LPDWORD)&dwSize);
if (lret == ERROR_SUCCESS)
{
bGotValCU = TRUE;
if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
}
}
// If we have a CLASSES_ROOT handle AND:
//
// * We failed to read from CU OR
// * We got a NULL string from CU
//
// Try reading from the CR branch instead:
bGotValR = FALSE;
if ((bGotR) && (!bGotValCU || !*pValue)) {
dwSize = (DWORD)(MAX_VALUELEN * sizeof(TCHAR));
lret = RegQueryValueEx(
hKeyR,
fsRoot[ikey].fvVals[ival].szValName,
(LPDWORD)NULL,
(LPDWORD)&dwType,
(LPBYTE)pValue,
(LPDWORD)&dwSize);
if (lret == ERROR_SUCCESS)
{
bGotValR = TRUE;
if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
}
}
if (!bGotValCU && !bGotValR) {
// Failed to get value from either CU or R so write
// a null string to the Theme file
bRet = WritePrivateProfileString(
fsCUIcons[ikey].szSubKey,
(LPTSTR)fsCUIcons[ikey].fvVals[ival].szValName,
(LPTSTR)szNULL, lpszThemefile);
bOK = bOK && bRet;
continue; // Next ival
}
// Assume we got the value from either the CU or R key
// Regardless of which one we *got* it from we'll write it
// out to the Theme file as if it came from the CURRENT USER
// branch
if (fsCUIcons[ikey].fvVals[ival].bValRelPath)
AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
bRet = WritePrivateProfileString(
fsCUIcons[ikey].szSubKey,
(LPTSTR)fsCUIcons[ikey].fvVals[ival].szValName,
(LPTSTR)pValue, lpszThemefile);
bOK = bOK && bRet;
} // End for ival loop
// check if just list or list plus default
if (FV_LIST == fsCUIcons[ikey].fValues)
break; // normal EXIT
// else fall through and do default, too
case FV_DEFAULT:
//
// Default string: There are no "valuenames" to search for under
// this key.
//
// First try getting the default string from the CU key
bGotValCU = FALSE;
if (bGotCU) {
dwSize = (DWORD)(MAX_VALUELEN * sizeof(TCHAR));
lret = RegQueryValueEx(hKeyCU,
(LPTSTR)szNULL,// null str to get default
(LPDWORD)NULL,
(LPDWORD)&dwType,
(LPBYTE)pValue, // getting actual def value
(LPDWORD)&dwSize);
if (ERROR_SUCCESS == lret)
{
bGotValCU = TRUE;
if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
}
}
// If we have a CLASSES_ROOT handle AND:
//
// * We failed to read from CU OR
// * We got a NULL string from CU
//
// Try reading from the CR branch instead:
bGotValR = FALSE;
if ((bGotR) && (!bGotValCU || !*pValue)) {
dwSize = (DWORD)(MAX_VALUELEN * sizeof(TCHAR));
lret = RegQueryValueEx(hKeyR,
(LPTSTR)szNULL,// null str to get default
(LPDWORD)NULL,
(LPDWORD)&dwType,
(LPBYTE)pValue, // getting actual def value
(LPDWORD)&dwSize);
if (ERROR_SUCCESS == lret)
{
bGotValR = TRUE;
if (REG_EXPAND_SZ == dwType) ExpandSZ(pValue);
}
}
if (!bGotValCU && !bGotValR) {
// Failed to get the default value from either the CU or R key
*pValue = TEXT('\0'); // Set pValue to null string
}
// OK, if this is a path/filename, see about xlating to relative path
if (fsCUIcons[ikey].bDefRelPath)
AbstractPath((LPTSTR)pValue, MAX_VALUELEN);
//
// Phew, finally. Write single default value
//
bRet = WritePrivateProfileString((LPTSTR)(fsCUIcons[ikey].szSubKey),
(LPTSTR)FROST_DEFSTR,
(LPTSTR)pValue, lpszThemefile);
bOK = bOK && bRet;
break;
default:
Assert(FALSE, TEXT("Unlisted .fValues value in GatherICONS!\n"));
break;
} // End switch
// close the keys if appropriate
if (bGotR) RegCloseKey(hKeyR);
if (bGotCU) RegCloseKey(hKeyCU);
} // End for ikey
return bOK;
}
// ApplyWebView
//
// For each setting in the [WebView] portion of the *.Theme
// file copy the specified file into the \windir\web directory.
//
// If there is no setting, extract the resource from the WEBVW.DLL.
//
// [WebView]
//
// WVLEFT.BMP = filename.bmp // Webview top left "watermark"
// WVLINE.GIF = filename.gif // Webview line in top left corner
// WVLOGO.GIF = filename.gif // Webview gears & win98 logo
//
// Params: Full path to *.Theme file.
//
// Returns: FALSE if major catastrophe
// TRUE if things (sort of) went OK
//
BOOL ApplyWebView(LPCTSTR szThemefile)
{
DWORD dwI = 0; // Index into szWVNames array
DWORD dwResult = 0; // Result of function call
TCHAR szWinDirWeb[MAX_PATH]; // Path to \windir\web
TCHAR szWinDirWebFile[MAX_PATH]; // Full path to WebView art file
TCHAR szBuffer[MAX_PATH]; // Read from *.Theme file
TCHAR szTempPath[MAX_PATH]; // Path to temp directory
TCHAR szTempFile[MAX_PATH]; // Full path to temporary file
// Initialize the path to the \windir\web directory where we'll
// put the WebView artwork files
if (!GetWindowsDirectory(szWinDirWeb, MAX_PATH)) {
// This is bad -- we can't find the windows directory?! Abandon ship.
return FALSE;
}
lstrcat(szWinDirWeb, TEXT("\\Web\0"));
// Get a temp filename where we can store the resource we extract
// out of WEBVW.DLL (if we need to).
// First the path to temp dir
if (!GetTempPath(MAX_PATH, szTempPath)) {
// This is bad -- we can't find the temp directory?! Abandon ship.
return FALSE;
}
// Now a temp filename
if (!GetTempFileName(szTempPath, TEXT("THM"), 0, szTempFile)) {
// Couldn't get a temp file? Not likely but if so bail out...
return FALSE;
}
// For each potential [WebView] setting in the Theme file do
// this stuff...
for (dwI = 0; dwI < MAX_WVNAMES; dwI++)
{
// Get the current setting from the *.Theme file if the setting
// exists
GetPrivateProfileString(TEXT("WebView"),
szWVNames[dwI],
TEXT("\0"),
szBuffer,
MAX_PATH,
szThemefile);
// Instantiate the path
InstantiatePath(szBuffer, MAX_PATH);
// Now check to see if this file even exists
dwResult = GetFileAttributes(szBuffer);
// If GFA failed we need to extract this file from webvw.dll
if (0xFFFFFFFF == dwResult) {
if (ExtractWVResource(szWVNames[dwI], szTempFile)) {
// We successfully extracted the resource into TempFile.
// Now copy it to the ultimate destination.
// Create a path to the \windir\web\file
lstrcpy(szWinDirWebFile, szWinDirWeb);
lstrcat(szWinDirWebFile, TEXT("\\"));
lstrcat(szWinDirWebFile, szWVNames[dwI]);
// Copy the file
DeleteFile(szWinDirWebFile);
CopyFile(szTempFile, szWinDirWebFile, FALSE);
// Delete the temporary file
DeleteFile(szTempFile);
}
} // End if GFA failed
else {
// The .Theme file exists so we need to copy it to the Web dir
// Create a path to the \windir\web\file
lstrcpy(szWinDirWebFile, szWinDirWeb);
lstrcat(szWinDirWebFile, TEXT("\\"));
lstrcat(szWinDirWebFile, szWVNames[dwI]);
DeleteFile(szWinDirWebFile);
CopyFile(szBuffer, szWinDirWebFile, FALSE);
}
} // End for dwI loop
// Cleanup the temp file
DeleteFile(szTempFile);
return TRUE; // this isn't very meaningful...
}
// GatherWebView
//
// Collect the current WebView artwork files, store them in the
// theme dir under the appropriate name, and save the settings
// in the *.Theme file under the appropriate setting.
//
// [WebView]
//
// WVLEFT.BMP = Theme name WVLEFT.BMP // Webview top left "watermark"
// WVLINE.GIF = Theme name WVLINE.GIF // Webview line in top left corner
// WVLOGO.GIF = Theme name WVLOGO.GIF // Webview gears & win98 logo
//
// Params: Full path to *.Theme file.
//
// Returns: FALSE if major catastrophe
// TRUE if things sort of went OK
//
BOOL GatherWebView(LPCTSTR szThemefile)
{
DWORD dwI = 0; // Index into szWVNames array
TCHAR szWinDirWeb[MAX_PATH]; // Path to \windir\web
TCHAR szWinDirWebFile[MAX_PATH]; // Full path to WebView art file
TCHAR szSaveFile[MAX_PATH]; // Full path to destination file
// Initialize the path to the \windir\web directory where we'll
// get the WebView artwork files
if (!GetWindowsDirectory(szWinDirWeb, MAX_PATH)) {
// This is bad -- we can't find the windows directory?! Abandon ship.
return FALSE;
}
lstrcat(szWinDirWeb, TEXT("\\Web\0"));
// For each potential [WebView] setting in the Theme file do
// this stuff...
for (dwI = 0; dwI < MAX_WVNAMES; dwI++)
{
// Verify that we have a file for the current setting
lstrcpy(szWinDirWebFile, szWinDirWeb);
lstrcat(szWinDirWebFile, TEXT("\\"));
lstrcat(szWinDirWebFile, szWVNames[dwI]);
if (GetFileAttributes(szWinDirWebFile)) {
// We've got a file so let's save it to the theme dir
// under a unique name
if (GetWVFilename(szThemefile, szWVNames[dwI], szSaveFile)) {
if (CopyFile(szWinDirWebFile, szSaveFile, FALSE)) {
SetFileAttributes(szSaveFile, FILE_ATTRIBUTE_ARCHIVE);
AbstractPath(szSaveFile, MAX_PATH);
WritePrivateProfileString(TEXT("WebView"),
szWVNames[dwI],
szSaveFile,
szThemefile);
}
}
}
}
return TRUE;
}
// ExtractWVResource
//
// Extracts the specified custom resource from the windir\system\webvw.dll
// file and stores it in the specified destination file.
//
// If the destination file exists it is overwritten.
//
// Params: lpszResource -- Resource name to extract (i.e. WVLEFT.BMP)
// lpszDestination -- File to save resource to
//
// Returns: True if successful, False if not.
//
BOOL ExtractWVResource(LPCTSTR lpszResource, LPCTSTR lpszDestination)
{
HINSTANCE hInstWVDLL = NULL; // Instance handle for WEBVW.DLL
HRSRC hRsrc = NULL; // Handle to resource in WEBVW.DLL
HGLOBAL hGlobal = NULL; // Global handle to loaded resource
LPVOID lpResource = NULL; // Memory pointer to locked resource
DWORD dwRSize = 0; // Size of resource
DWORD dwBytesW = 0; // Number of bytes written to dest file
HANDLE hFile = NULL; // Handle to destination file
TCHAR szWebVWDLL[MAX_PATH]; // Full path to \windir\system\webvw.dll
DWORD dwResult; // Result of function call
// Build full path to \windir\system\webvw.dll
if (!GetWindowsDirectory(szWebVWDLL, MAX_PATH)) {
// This is bad -- we can't find the windows directory?! Abandon ship.
return FALSE;
}
if (IsPlatformNT()) {
lstrcat(szWebVWDLL, TEXT("\\SYSTEM32\\WEBVW.DLL\0"));
}
else {
lstrcat(szWebVWDLL, TEXT("\\SYSTEM\\WEBVW.DLL\0"));
}
// Load WEBVW.DLL
hInstWVDLL = NULL;
hInstWVDLL = LoadLibrary(szWebVWDLL);
if (!hInstWVDLL) {
return FALSE;
}
// Find the desired resource in WEBVW.DLL
hRsrc = NULL;
hRsrc = FindResource(hInstWVDLL, lpszResource, TEXT("#23") /*Resource Type*/);
if (!hRsrc) {
FreeLibrary(hInstWVDLL);
return FALSE;
}
// Load the resource into memory
hGlobal = NULL;
hGlobal = LoadResource(hInstWVDLL, hRsrc);
if (!hGlobal) {
FreeLibrary(hInstWVDLL);
return FALSE;
}
// Figure out how big the resource is.
dwRSize = 0;
dwRSize = SizeofResource(hInstWVDLL, hRsrc);
if (!dwRSize) {
FreeLibrary(hInstWVDLL);
return FALSE;
}
// Get a memory pointer to and lock the resource
lpResource = NULL;
lpResource = LockResource(hGlobal);
if (!lpResource) {
FreeLibrary(hInstWVDLL);
return FALSE;
}
// Get a handle to the destination file
hFile = CreateFile(lpszDestination,
GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_ARCHIVE,
NULL);
if (INVALID_HANDLE_VALUE == hFile) {
FreeLibrary(hInstWVDLL);
return FALSE;
}
// Write the full resource into the destination file
dwBytesW = 0;
dwResult = 0;
dwResult = WriteFile(hFile, lpResource, dwRSize, &dwBytesW, NULL);
// Problems writing the resource?
if ((!dwResult) || (dwRSize != dwBytesW)) {
CloseHandle(hFile);
DeleteFile(lpszDestination);
FreeLibrary(hInstWVDLL);
return FALSE;
}
// Cleanup and hit the road
CloseHandle(hFile);
FreeLibrary(hInstWVDLL);
return TRUE;
}
// GetWVFilename
//
// Given a Themefile (with path info), a WebView file name (i.e. WVLEFT.BMP),
// and a pointer to a string buffer, build a name for the Theme WebView file.
//
// For example:
//
// lpszThemefile = C:\Program Files\Plus!\Themes\Sports.Theme
// lpszWVName = WVLOGO.GIF
//
// Result:
//
// lpszWVFile = "C:\Program Files\Plus!\Themes\Sports WVLOGO.GIF"
//
// NOTE: lpszWVFile does not have the double quotes in it -- I put
// them in this comment for clarity.
//
// Params:
//
// lpszThemefile -- path/name of theme file
// lpszWVName -- name of WebView artwork file
// lpszWVFile -- destination buffer to hold final file name
//
// Returns: TRUE if lpszWVFile is valid name, else FALSE
BOOL GetWVFilename(LPCTSTR lpszThemefile, LPCTSTR lpszWVName, LPTSTR lpszWVFile)
{
LPTSTR lpszThemeName = NULL; // Pointer to Theme filename in path
LPTSTR Begin;
LPTSTR Current;
LPTSTR End;
// Take the easy out if we got bogus params
if (!lpszThemefile || !*lpszThemefile || !lpszWVName || !*lpszWVName ||
!lpszWVFile) {
return FALSE;
}
if (GetFullPathName(lpszThemefile, MAX_PATH, lpszWVFile, &lpszThemeName)) {
// Remove the extension from the Theme name -- go to the
// end of the string then back up to the first ".".
Current = lpszWVFile;
while (*Current) Current = CharNext(Current);
End = Current;
// Current now points to the end of lpszWVFile -- back up to the
// first '.' (the extension marker).
Begin = lpszWVFile;
Current = CharPrev(Begin, Current);
while ((Current > Begin) && (*Current != TEXT('.'))) Current = CharPrev(Begin, Current);
if (Current >= Begin) *Current = TEXT('\0');
// Append a space followed by the WebView file name
lstrcat(lpszWVFile, TEXT(" "));
lstrcat(lpszWVFile, lpszWVName);
}
return TRUE;
}
VOID ExpandSZ(LPTSTR pszSrc)
{
LPTSTR pszTmp;
Assert(FALSE, TEXT("GOT EXPAND_SZ -- Before: "));
Assert(FALSE, pszSrc);
Assert(FALSE, TEXT("\n"));
pszTmp = (LPTSTR)GlobalAlloc(GPTR, (MAX_PATH * sizeof(TCHAR)));
Assert(pszTmp, TEXT("THEMES: Error allocating memory in ExpandSZ()\n"));
if (pszTmp)
{
if (ExpandEnvironmentStrings(pszSrc, pszTmp, MAX_PATH))
{
lstrcpy(pszSrc, pszTmp);
}
GlobalFree(pszTmp);
}
Assert(FALSE, TEXT("GOT EXPAND_SZ -- After: "));
Assert(FALSE, pszSrc);
Assert(FALSE, TEXT("\n"));
return;
}