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
3426 lines
118 KiB
C
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;
|
|
}
|