mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2699 lines
81 KiB
2699 lines
81 KiB
/** FILE: cache.c ********** Module Header ********************************
|
|
*
|
|
* Control Panel caching functions and procedures.
|
|
*
|
|
* History:
|
|
* 21 Sept 1993 -by- Steve Cathcart [stevecat]
|
|
* Added Caching of Control Panel modules
|
|
*
|
|
*
|
|
* Copyright (C) 1990-1993 Microsoft Corporation
|
|
*
|
|
*************************************************************************/
|
|
//==========================================================================
|
|
// Include files
|
|
//==========================================================================
|
|
// Windows SDK
|
|
#include <windows.h>
|
|
#include <shellapi.h>
|
|
|
|
// Application specific
|
|
#include "cpl.h"
|
|
#include "cpl_defs.h"
|
|
#include "uniconv.h"
|
|
|
|
//==========================================================================
|
|
// Local Definitions
|
|
//==========================================================================
|
|
#define BMPSIZE 4096
|
|
|
|
//==========================================================================
|
|
// External Declarations
|
|
//==========================================================================
|
|
// External functions
|
|
|
|
// External data
|
|
|
|
//==========================================================================
|
|
// Local Data Declarations
|
|
//==========================================================================
|
|
TCHAR szAA[] = TEXT("aaaaaa");
|
|
|
|
// Control Panel registry cache entry key
|
|
TCHAR *pszCplCache = TEXT("Control Panel\\Cache\\%s");
|
|
TCHAR *pszRegCache = TEXT("Control Panel\\Cache");
|
|
|
|
// Control Panel cache - validation flag key
|
|
TCHAR *pszCacheValid = TEXT("Cache Valid");
|
|
TCHAR *pszDisplayType = TEXT("Display Type");
|
|
|
|
// Control Panel cache - display flag keys
|
|
TCHAR *pszBitspixel = TEXT("Bits/Pixel");
|
|
TCHAR *pszColorres = TEXT("ColorRes");
|
|
TCHAR *pszPlanes = TEXT("Planes");
|
|
TCHAR *pszAveCharWidth = TEXT("tmAveCharWidth");
|
|
TCHAR *pszHeight = TEXT("tmHeight");
|
|
TCHAR *pszWeight = TEXT("tmWeight");
|
|
|
|
//
|
|
// Global flag to indicate that an applet is active
|
|
//
|
|
|
|
BOOL bAppletActive = FALSE;
|
|
|
|
//
|
|
// Global flag to indicate that the cache is invalid and needs to be
|
|
// rebuilt.
|
|
//
|
|
|
|
BOOL bRebuildCache = FALSE;
|
|
|
|
// Global flag to indicate all 2nd thread validation of modules is done
|
|
// Initial state is TRUE, because 2nd thread will control its state
|
|
// but it may never be invoked.
|
|
|
|
BOOL bValidationDone = TRUE;
|
|
|
|
// Control Panel cache module data value keys
|
|
TCHAR *pszFileSize = TEXT("File Size");
|
|
TCHAR *pszFileTimeHigh = TEXT("High File Time");
|
|
TCHAR *pszFileTimeLow = TEXT("Low File Time");
|
|
TCHAR *pszModulePath = TEXT("Module Path");
|
|
TCHAR *pszNumApplets = TEXT("Number Applets");
|
|
|
|
// Control Panel cache module applet data value keys
|
|
TCHAR *pszAppletIconC = TEXT("Icon Color");
|
|
TCHAR *pszAppletIconM = TEXT("Icon Mask");
|
|
TCHAR *pszAppletIconX = TEXT("IconX");
|
|
TCHAR *pszAppletIconY = TEXT("IconY");
|
|
TCHAR *pszAppletInfoC = TEXT("Color Info");
|
|
TCHAR *pszAppletInfoM = TEXT("Mask Info");
|
|
TCHAR *pszAppletFull = TEXT("Applet Full Name");
|
|
TCHAR *pszAppletName = TEXT("Applet Name");
|
|
TCHAR *pszAppletInfo = TEXT("Description");
|
|
TCHAR *pszAppletHelp = TEXT("Help File");
|
|
TCHAR *pszAppletCntx = TEXT("Help Context");
|
|
TCHAR *pszAppletData = TEXT("Applet Data");
|
|
|
|
|
|
//==========================================================================
|
|
// Local Function Prototypes
|
|
//==========================================================================
|
|
|
|
|
|
//==========================================================================
|
|
// Functions
|
|
//==========================================================================
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Replace "\" chars in path with "/" chars because MUTEX objects do not
|
|
// like it but we want to maintain the uniqueness of mutex object names
|
|
// based on modules full pathname.
|
|
//
|
|
// Also, since MUTEX objects are in global, flat name space, make the
|
|
// name unique by prepending User's name to it.
|
|
//
|
|
// Assumes pszMutex string is at least same size as pszPathname string
|
|
// plus MAX_PATH to hold User's logon name and pszPathname.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CreateMutexNameFromPath (LPTSTR pszPathname, LPTSTR pszMutex)
|
|
{
|
|
TCHAR szMutexName[MAX_PATH * 2];
|
|
LPTSTR pszTemp;
|
|
int iLen2 = MAX_PATH / 2;
|
|
int iLen4 = MAX_PATH / 4;
|
|
int iLen8 = MAX_PATH / 8;
|
|
|
|
lstrcpy (szMutexName, szUsername);
|
|
lstrcat (szMutexName, pszPathname);
|
|
|
|
if (lstrlen (szMutexName) > MAX_PATH - 1)
|
|
{
|
|
// Name is too long, just use parts of it
|
|
|
|
// Use first and last MAX_PATH / 8 (approx. 30) chars of Username
|
|
|
|
if (lstrlen (szUsername) > iLen4 + 3)
|
|
{
|
|
_tcsncpy (szMutexName, szUsername, iLen8);
|
|
lstrcat (szMutexName, TEXT("..."));
|
|
pszTemp = szUsername + (lstrlen (szUsername) - iLen8) * sizeof(TCHAR);
|
|
lstrcat (szMutexName, pszTemp);
|
|
}
|
|
else
|
|
{
|
|
lstrcpy (szMutexName, szUsername);
|
|
}
|
|
|
|
// Fill in rest with (parts of) pathname
|
|
|
|
if (lstrlen (pszPathname) > iLen2 + 3)
|
|
{
|
|
_tcsncat (szMutexName, pszPathname, iLen4);
|
|
lstrcat (szMutexName, TEXT("..."));
|
|
pszTemp = pszPathname + (lstrlen (pszPathname) - iLen4) * sizeof(TCHAR);
|
|
lstrcat (szMutexName, pszTemp);
|
|
}
|
|
else
|
|
{
|
|
lstrcpy (szMutexName, pszPathname);
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
if (lstrlen (szMutexName) > MAX_PATH - 1)
|
|
RIP(TEXT("CreateMutexNameFromPath - MUTEX name too long."));
|
|
#endif // DBG
|
|
|
|
lstrcpy (pszMutex, szMutexName);
|
|
_tcsupr (pszMutex);
|
|
|
|
while (pszTemp = _tcschr(pszMutex, TEXT('\\')))
|
|
*pszTemp = TEXT('/');
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Load module into memory and pass initial messages to it, fill in
|
|
// necessary fields of PCPLMODULE struct
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL LoadCachedModule (PCPLMODULE pCPlMod)
|
|
{
|
|
TCHAR szLoadingName[64+ CharSizeOf(szLoading)];
|
|
int numApplets;
|
|
BOOL bLoaded=FALSE;
|
|
|
|
|
|
if (pCPlMod && !pCPlMod->bLoaded)
|
|
{
|
|
if (hCPlWnd)
|
|
{
|
|
/* update feedback on what applet library is currently loading */
|
|
#ifdef JAPAN /* V-KeijiY July.6.7 */
|
|
lstrcpy(szLoadingName, pCPlMod->szPathname);
|
|
lstrcat(szLoadingName, szLoading);
|
|
#else
|
|
lstrcpy(szLoadingName, szLoading);
|
|
lstrcat(szLoadingName, pCPlMod->szPathname);
|
|
#endif
|
|
SetWindowText(hCPlTB, szLoadingName);
|
|
UpdateWindow(hCPlWnd);
|
|
}
|
|
|
|
if (pCPlMod->hLibrary = LoadLibrary(pCPlMod->szPathname))
|
|
{
|
|
if ((pCPlMod->lpfnCPlApplet =
|
|
(APPLET_PROC)GetProcAddress(pCPlMod->hLibrary, szCPlApplet)) &&
|
|
(*pCPlMod->lpfnCPlApplet)(hCPlWnd, CPL_INIT, 0L, 0L))
|
|
{
|
|
|
|
numApplets = (int)(*pCPlMod->lpfnCPlApplet)(hCPlWnd, CPL_GETCOUNT, 0L, 0L);
|
|
|
|
bLoaded = TRUE;
|
|
|
|
ASSERT(pCPlMod->numApplets == numApplets);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Error after library loaded, so free it and force a
|
|
// rebuild of applet cache.
|
|
//
|
|
|
|
FreeLibrary (pCPlMod->hLibrary);
|
|
pCPlMod->hLibrary = NULL;
|
|
pCPlMod->lpfnCPlApplet = NULL;
|
|
goto SetFaultCondition;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetFaultCondition:
|
|
//
|
|
// Failure to load an applet that we thought was valid.
|
|
// Set global to force CACHE rebuild on LoadLibrary failure.
|
|
//
|
|
|
|
bRebuildCache = TRUE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return (pCPlMod->bLoaded);
|
|
}
|
|
|
|
return bLoaded;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Create a unique key value for this pathname.
|
|
//
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CreateCacheKey (LPTSTR szReturn, LPTSTR szPathname, int iUnique)
|
|
{
|
|
LPTSTR pszTemp;
|
|
TCHAR szUnq[10];
|
|
|
|
// Find last backslash and copy from there
|
|
pszTemp = _tcsrchr (szPathname, TEXT('\\'));
|
|
|
|
// Increment past "\" char
|
|
pszTemp++;
|
|
|
|
// If this is "MAIN.CPL" make a special key for it so it will
|
|
// always be first in the registry. This will insure that it
|
|
// is always loaded first from the cache area.
|
|
|
|
if (!_tcsicmp (pszTemp, szMAINCPL))
|
|
{
|
|
lstrcpy (szReturn, szAA);
|
|
}
|
|
else
|
|
{
|
|
lstrcpy (szReturn, pszTemp);
|
|
}
|
|
|
|
if (iUnique != 0)
|
|
{
|
|
MyItoa (iUnique, szUnq, 10);
|
|
lstrcat (szReturn, szUnq);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Free the .CPL module and load it in later, only when asked for again
|
|
// by User. This will help to significantly decrease the Control Panel's
|
|
// working set and memory allocation.
|
|
//
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void FreeCachedModule (PCPLMODULE pCPlMod)
|
|
{
|
|
if (pCPlMod && pCPlMod->bLoaded && pCPlMod->hLibrary)
|
|
{
|
|
// no longer in need of your services
|
|
if (*pCPlMod->lpfnCPlApplet)
|
|
(*pCPlMod->lpfnCPlApplet) (hCPlWnd, CPL_EXIT, 0L, 0L);
|
|
|
|
if (FreeLibrary (pCPlMod->hLibrary))
|
|
pCPlMod->hLibrary = NULL;
|
|
|
|
pCPlMod->lpfnCPlApplet = NULL;
|
|
pCPlMod->bLoaded = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Clear "Cache Valid" flag in registry
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void ClearCacheValid()
|
|
{
|
|
int j;
|
|
HKEY hkeyRCache = NULL;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Clear "Cache Valid" flag
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, pszRegCache, 0L, KEY_ALL_ACCESS,
|
|
&hkeyRCache) == ERROR_SUCCESS)
|
|
{
|
|
j = 0;
|
|
if ((RegSetValueEx (hkeyRCache, pszCacheValid, 0L, REG_DWORD,
|
|
(LPBYTE) &j, sizeof(DWORD)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
}
|
|
|
|
RegCloseKey (hkeyRCache);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Set "Cache Valid" flag in registry
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetCacheValid()
|
|
{
|
|
int j;
|
|
HKEY hkeyRCache;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Indicate "Cache Valid"
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, pszRegCache, 0L, KEY_ALL_ACCESS,
|
|
&hkeyRCache) == ERROR_SUCCESS)
|
|
{
|
|
j = 1;
|
|
if ((RegSetValueEx (hkeyRCache, pszCacheValid, 0L, REG_DWORD,
|
|
(LPBYTE) &j, sizeof(DWORD)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
}
|
|
|
|
RegCloseKey (hkeyRCache);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Return state of "Cache Valid" flag in registry
|
|
//
|
|
// Note: This routine will create the "Control Panel\Cache" key if it
|
|
// does not exist.
|
|
//
|
|
// Returns:
|
|
// TRUE - if CacheValid flag is TRUE
|
|
// FALSE - if CacheValid flag is FALSE
|
|
// cache should be updated, some items do not match
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL IsCacheValid()
|
|
{
|
|
HKEY hkeyRCache = NULL;
|
|
DWORD j = 0;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
DWORD dwDisposition;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Check "Cache Valid" flag
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (RegCreateKeyEx (HKEY_CURRENT_USER, // Root key
|
|
pszRegCache, // Subkey to open/create
|
|
0L, // Reserved
|
|
NULL, // Class string
|
|
0L, // Options
|
|
KEY_ALL_ACCESS, // SAM
|
|
NULL, // ptr to Security struct
|
|
&hkeyRCache, // return handle
|
|
&dwDisposition) // return disposition
|
|
== ERROR_SUCCESS)
|
|
{
|
|
dwSize = sizeof(DWORD);
|
|
|
|
RegQueryValueEx (hkeyRCache,
|
|
pszCacheValid,
|
|
0L,
|
|
&dwType,
|
|
(LPBYTE) &j,
|
|
&dwSize);
|
|
|
|
RegCloseKey (hkeyRCache);
|
|
}
|
|
|
|
return (j != 0);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Return DWORD value of "pszCacheEntry" registry value under the "Cache"
|
|
// key in registry.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
DWORD GetCachedValue (LPTSTR pszCacheEntry)
|
|
{
|
|
HKEY hkeyRCache = NULL;
|
|
DWORD j = 0;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
DWORD dwDisposition;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Check "Cache Valid" flag
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (RegCreateKeyEx (HKEY_CURRENT_USER, // Root key
|
|
pszRegCache, // Subkey to open/create
|
|
0L, // Reserved
|
|
NULL, // Class string
|
|
0L, // Options
|
|
KEY_ALL_ACCESS, // SAM
|
|
NULL, // ptr to Security struct
|
|
&hkeyRCache, // return handle
|
|
&dwDisposition) // return disposition
|
|
== ERROR_SUCCESS)
|
|
{
|
|
dwSize = sizeof(DWORD);
|
|
|
|
RegQueryValueEx (hkeyRCache,
|
|
pszCacheEntry,
|
|
0L,
|
|
&dwType,
|
|
(LPBYTE) &j,
|
|
&dwSize);
|
|
|
|
RegCloseKey (hkeyRCache);
|
|
}
|
|
|
|
return j;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Write DWORD value of "pszCacheEntry" under the "Cache" key in registry.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void SetCachedValue (LPTSTR pszCacheEntry, DWORD dwValue)
|
|
{
|
|
HKEY hkeyRCache;
|
|
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, pszRegCache, 0L, KEY_ALL_ACCESS,
|
|
&hkeyRCache) == ERROR_SUCCESS)
|
|
{
|
|
if ((RegSetValueEx (hkeyRCache, pszCacheEntry, 0L, REG_DWORD,
|
|
(LPBYTE) &dwValue, sizeof(DWORD)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
}
|
|
|
|
RegCloseKey (hkeyRCache);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Free all memory allocated for linked list of all CPL Module keys.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL FreeModuleKeyList (REGKEY *prkFirst)
|
|
{
|
|
REGKEY *prkRegKey;
|
|
|
|
|
|
// Traverse the list, freeing list memory
|
|
|
|
prkRegKey = prkFirst;
|
|
|
|
while (prkRegKey)
|
|
{
|
|
prkFirst = prkRegKey;
|
|
prkRegKey = prkRegKey->prkNext;
|
|
|
|
if (LocalFree ((HLOCAL) prkFirst->pszKeyName))
|
|
{
|
|
RIPMEM();
|
|
return FALSE;
|
|
}
|
|
|
|
if (LocalFree ((HLOCAL) prkFirst))
|
|
{
|
|
RIPMEM();
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Return a linked list of all CPL Module keys listed in the registry
|
|
// under the "Cache" key.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
REGKEY *GetModuleKeyList (HKEY hkeyRCache)
|
|
{
|
|
int i;
|
|
DWORD dwBufz;
|
|
REGKEY *prkFirst = NULL;
|
|
REGKEY *prkRegKey = NULL;
|
|
TCHAR szModKey[MAX_PATH];
|
|
|
|
|
|
i = 0;
|
|
dwBufz = CharSizeOf(szModKey);
|
|
|
|
// Create a linked list of all "Module keys"
|
|
|
|
while (RegEnumKeyEx (hkeyRCache, i, szModKey, &dwBufz, 0L,
|
|
NULL, NULL, NULL) != ERROR_NO_MORE_ITEMS)
|
|
{
|
|
if (prkFirst)
|
|
{
|
|
prkRegKey->prkNext = (REGKEY *) LocalAlloc (LPTR, sizeof(REGKEY));
|
|
prkRegKey = prkRegKey->prkNext;
|
|
}
|
|
else // First time thru
|
|
{
|
|
prkFirst =
|
|
prkRegKey = (REGKEY *) LocalAlloc (LPTR, sizeof(REGKEY));
|
|
}
|
|
|
|
if (prkRegKey)
|
|
prkRegKey->prkNext = NULL;
|
|
else
|
|
{
|
|
RIPMEM();
|
|
goto ErrorExit;
|
|
}
|
|
|
|
if (prkRegKey->pszKeyName = (LPTSTR) LocalAlloc (LPTR,
|
|
ByteCountOf(lstrlen((LPTSTR)szModKey)+1)))
|
|
{
|
|
lstrcpy(prkRegKey->pszKeyName, (LPTSTR)szModKey);
|
|
}
|
|
else
|
|
{
|
|
RIPMEM();
|
|
goto ErrorExit;
|
|
}
|
|
|
|
// Get next Key name
|
|
i++;
|
|
dwBufz = CharSizeOf(szModKey);
|
|
}
|
|
|
|
return (prkFirst);
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine error handling
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
ErrorExit:
|
|
|
|
FreeModuleKeyList (prkFirst);
|
|
return NULL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Find (but do not load) all of the .CPL modules that would be found
|
|
// during the normal filesystem search. This routine uses the same
|
|
// algorithm to find modules as LoadApplets().
|
|
//
|
|
// Get the keynames under [MMCPL] in CONTROL.INI and cycle
|
|
// through all such keys to create cpl file structs for each.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int CheckFindModules (CPLFILES *pcfCPlFiles)
|
|
{
|
|
LPTSTR pstr;
|
|
int numMods = 0;
|
|
TCHAR szKeys[256]; // array size = 256 is assumed by GetSysDir()!
|
|
TCHAR szName[64];
|
|
HANDLE hFile = NULL;
|
|
BOOL b;
|
|
|
|
WIN32_FIND_DATA FindFileData;
|
|
|
|
BY_HANDLE_FILE_INFORMATION bhfiMod;
|
|
|
|
|
|
// Find the modules specified in CONTROL.INI under [MMCPL]
|
|
|
|
// First, enumerate all keys under szMMCPL
|
|
GetPrivateProfileString(szMMCPL, NULL, szNULL, szKeys, CharSizeOf(szKeys), aszControlIniPath);
|
|
|
|
for (pstr = szKeys; *pstr && (numMods < CPL_MAXMODS-1); pstr += lstrlen(pstr) + 1)
|
|
{
|
|
//
|
|
// For each key, get its data
|
|
//
|
|
|
|
GetPrivateProfileString(szMMCPL, pstr, szNULL, szName, 64, aszControlIniPath);
|
|
|
|
//
|
|
// If pstr NOT EQUAL to our known values under szMMCPL,
|
|
// we have found a module to be added to our list
|
|
//
|
|
|
|
if (_tcsicmp(pstr, szNumApps) && _tcsicmp(pstr, szMaxWidth) &&
|
|
!((*(pstr+1) == (TCHAR) 0) && // skip over Wnd size keynames
|
|
((*pstr == *szWndDim[0]) || (*pstr == *szWndDim[1]) ||
|
|
(*pstr == *szWndDim[2]) || (*pstr == *szWndDim[3])) ))
|
|
{
|
|
// We have found a potential module to load - get file info
|
|
|
|
lstrcpy(pcfCPlFiles->szPathname, szName);
|
|
|
|
// Open File and get info on it
|
|
if ((hFile = CreateFile (pcfCPlFiles->szPathname,
|
|
0,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
RIPGEN();
|
|
//
|
|
// Ignore errors - file may not exist (i.e. it may just be
|
|
// a bad entry under [MMCPL] key). This is not a reason to
|
|
// to force cache invalid.
|
|
//
|
|
continue;
|
|
}
|
|
|
|
if (!GetFileInformationByHandle (hFile, &bhfiMod))
|
|
{
|
|
RIPGEN();
|
|
//
|
|
// Same as above.
|
|
//
|
|
|
|
if (hFile != NULL)
|
|
CloseHandle (hFile);
|
|
|
|
continue;
|
|
}
|
|
|
|
CloseHandle (hFile);
|
|
|
|
hFile = NULL;
|
|
|
|
pcfCPlFiles->dwSize = bhfiMod.nFileSizeLow;
|
|
|
|
pcfCPlFiles->ftModule = bhfiMod.ftLastWriteTime;
|
|
|
|
pcfCPlFiles->numApplets = 0;
|
|
|
|
pcfCPlFiles->bAlreadyMatched = FALSE;
|
|
|
|
numMods++; // Increment module count
|
|
pcfCPlFiles++;
|
|
}
|
|
}
|
|
|
|
// Find applets in the system directory (this will include MAIN.CPL)
|
|
|
|
MakeSysPath (szKeys, szCPL);
|
|
|
|
if ((hFile = FindFirstFile(szKeys, &FindFileData)) != INVALID_HANDLE_VALUE)
|
|
{
|
|
b = TRUE;
|
|
|
|
while (b && (numMods < CPL_MAXMODS - 1))
|
|
{
|
|
CatPath(szKeys, FindFileData.cFileName, lstrlen(szKeys));
|
|
|
|
lstrcpy(pcfCPlFiles->szPathname, szKeys);
|
|
|
|
pcfCPlFiles->dwSize = FindFileData.nFileSizeLow;
|
|
|
|
pcfCPlFiles->ftModule = FindFileData.ftLastWriteTime;
|
|
|
|
pcfCPlFiles->numApplets = 0;
|
|
|
|
pcfCPlFiles->bAlreadyMatched = FALSE;
|
|
|
|
numMods++;
|
|
pcfCPlFiles++;
|
|
|
|
b = FindNextFile(hFile, &FindFileData);
|
|
}
|
|
FindClose(hFile);
|
|
}
|
|
|
|
return (numMods);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Get a list of all of the Cached .CPL modules from registry
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
int CheckGetCacheMods (CPLFILES *pcfCPlFiles)
|
|
{
|
|
int numMods = 0;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
|
|
HKEY hkeyCache = NULL;
|
|
HKEY hkeyRCache = NULL;
|
|
|
|
REGKEY *prkFirst = NULL;
|
|
REGKEY *prkRegKey = NULL;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Open Cache
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, pszRegCache, 0L, KEY_ALL_ACCESS,
|
|
&hkeyRCache)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Get linked list of all "Module keys" for use below
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (!(prkFirst = GetModuleKeyList (hkeyRCache)))
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Now go thru module key list and fill-in cpl file structs
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
prkRegKey = prkFirst;
|
|
|
|
while (prkRegKey)
|
|
{
|
|
// Open cache of module applets
|
|
if (RegOpenKeyEx (hkeyRCache, // Root key
|
|
prkRegKey->pszKeyName, // Subkey to open/create
|
|
0L, // Reserved
|
|
KEY_ALL_ACCESS, // SAM
|
|
&hkeyCache) // return handle
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Get cached Module info
|
|
|
|
// Number of applets
|
|
pcfCPlFiles->numApplets = 0;
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if (RegQueryValueEx (hkeyCache, pszNumApplets, 0L, &dwType,
|
|
(LPBYTE) &pcfCPlFiles->numApplets, &dwSize)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Module pathname
|
|
dwSize = sizeof(pcfCPlFiles->szPathname);
|
|
|
|
if ((RegQueryValueEx (hkeyCache, pszModulePath, 0L, &dwType,
|
|
(LPBYTE) pcfCPlFiles->szPathname, &dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Module size
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if ((RegQueryValueEx (hkeyCache, pszFileSize, 0L, &dwType,
|
|
(LPBYTE) &pcfCPlFiles->dwSize, &dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Module filetime low
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if ((RegQueryValueEx (hkeyCache, pszFileTimeLow, 0L, &dwType,
|
|
(LPBYTE) &pcfCPlFiles->ftModule.dwLowDateTime,
|
|
&dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Module filetime high
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if ((RegQueryValueEx (hkeyCache, pszFileTimeHigh, 0L, &dwType,
|
|
(LPBYTE) &pcfCPlFiles->ftModule.dwHighDateTime,
|
|
&dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
pcfCPlFiles->bAlreadyMatched = FALSE;
|
|
|
|
pcfCPlFiles++;
|
|
|
|
RegCloseKey (hkeyCache);
|
|
hkeyCache = NULL;
|
|
|
|
// Next key name in list
|
|
prkRegKey = prkRegKey->prkNext;
|
|
|
|
// Keep a count of modules for return to caller
|
|
numMods++;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Clean up and leave
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Free list
|
|
|
|
if (!FreeModuleKeyList (prkFirst))
|
|
goto MemoryError;
|
|
|
|
if (hkeyRCache != NULL)
|
|
RegCloseKey (hkeyRCache);
|
|
|
|
return numMods;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine error handling
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
RegistryError:
|
|
MemoryError:
|
|
|
|
if (hkeyRCache != NULL)
|
|
RegCloseKey (hkeyRCache);
|
|
|
|
if (hkeyCache != NULL)
|
|
RegCloseKey (hkeyCache);
|
|
|
|
FreeModuleKeyList (prkFirst);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Validate Control Panel module (i.e. *.CPL) cache entries. Check all of
|
|
// the modules found during filesystem search against the date, time, size
|
|
// and number of applets of those stored in registry cache entries.
|
|
//
|
|
// Also, check the display type and resolution to see if we need to force
|
|
// a cache rebuild due to ICON size/type change.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL CheckCache()
|
|
{
|
|
DWORD i, j;
|
|
DWORD numFiles = 0;
|
|
DWORD numCache = 0;
|
|
BOOL bRet = TRUE;
|
|
HDC hdc;
|
|
|
|
CPLFILES *cfCPlFiles;
|
|
CPLFILES *cfCPlCache;
|
|
|
|
TEXTMETRIC tm;
|
|
|
|
|
|
cfCPlFiles = cfCPlCache = NULL;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Check "Cache Valid" flag
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (!IsCacheValid())
|
|
return FALSE;
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Check "Display Type" flags against current display type
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
hdc = GetDC (NULL);
|
|
|
|
GetTextMetrics (hdc, &tm);
|
|
|
|
if ((GetDeviceCaps (hdc, BITSPIXEL) != (int) GetCachedValue (pszBitspixel))
|
|
|| (GetDeviceCaps (hdc, COLORRES) != (int) GetCachedValue (pszColorres))
|
|
|| (GetDeviceCaps (hdc, PLANES) != (int) GetCachedValue (pszPlanes))
|
|
|| (tm.tmAveCharWidth != (LONG) GetCachedValue (pszAveCharWidth))
|
|
|| (tm.tmHeight != (LONG) GetCachedValue (pszHeight))
|
|
|| (tm.tmWeight != (LONG) GetCachedValue (pszWeight)))
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
ReleaseDC (NULL, hdc);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Check Filesystem .CPL modules against Cached Modules
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Get some storage for modules
|
|
cfCPlFiles = (CPLFILES *) LocalAlloc (LPTR, sizeof(CPLFILES)*CPL_MAXMODS);
|
|
|
|
cfCPlCache = (CPLFILES *) LocalAlloc (LPTR, sizeof(CPLFILES)*CPL_MAXMODS);
|
|
|
|
if (!cfCPlFiles || !cfCPlCache)
|
|
{
|
|
RIPMEM();
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
// Now get info on CPl files and Cached modules
|
|
if ((numFiles = CheckFindModules (cfCPlFiles)) == 0)
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
if ((numCache = CheckGetCacheMods (cfCPlCache)) == 0)
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
// Compare until everything matches up, if error invalid cache
|
|
|
|
// Check for quick exits
|
|
|
|
if (numFiles != numCache)
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Now match up and compare cached and filesystem modules
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
for (i = 0; i < numFiles; i++)
|
|
{
|
|
// if (cfCPlFiles[i].bAlreadyMatched)
|
|
// continue;
|
|
|
|
for (j = 0; j < numCache; j++)
|
|
{
|
|
if (cfCPlCache[j].bAlreadyMatched)
|
|
continue;
|
|
|
|
if (!_tcsicmp (cfCPlCache[j].szPathname, cfCPlFiles[i].szPathname))
|
|
{
|
|
// We found a name match
|
|
cfCPlCache[j].bAlreadyMatched = TRUE;
|
|
cfCPlFiles[i].bAlreadyMatched = TRUE;
|
|
|
|
// Check size and then filetimes
|
|
if (cfCPlCache[j].dwSize != cfCPlFiles[i].dwSize)
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
if (CompareFileTime (&cfCPlCache[j].ftModule,
|
|
&cfCPlFiles[i].ftModule))
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Are there any unmatched files?
|
|
|
|
for (i = 0; i < numFiles; i++)
|
|
{
|
|
if (!cfCPlFiles[i].bAlreadyMatched)
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < numCache; i++)
|
|
{
|
|
if (!cfCPlCache[i].bAlreadyMatched)
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Common exit code
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
CommonExit:
|
|
|
|
if (cfCPlFiles)
|
|
LocalFree ((HLOCAL) cfCPlFiles);
|
|
|
|
if (cfCPlCache)
|
|
LocalFree ((HLOCAL) cfCPlCache);
|
|
|
|
if (!bRet)
|
|
ClearCacheValid ();
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Init the icon handle, and ptrs to the strings.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CacheSetAppItems(PCPLMODULE pCPlMod, PCPLAPPLET pCPlApp, int iIndex)
|
|
{
|
|
HMENU hMenu;
|
|
HDC hDC;
|
|
HFONT hFont;
|
|
TCHAR szBuffer[128];
|
|
LPNTCPL lpNtCPl;
|
|
|
|
if (!hCPlWnd) // don't add the LB stuff if we aren't showing
|
|
return; // the main window
|
|
|
|
hDC = GetDC (NULL);
|
|
hFont = SelectObject (hDC, hCPlFont);
|
|
|
|
lstrcpy(szBuffer, pCPlApp->pszFullName);
|
|
|
|
// longest name determines column width
|
|
|
|
// Get the name length without '&' and adjust the longest name
|
|
// Also add & before the first char if there is none
|
|
|
|
if ( (pCPlApp->iNameW = GetNameExtent(hDC, szBuffer)) > iWidth)
|
|
iWidth = pCPlApp->iNameW;
|
|
|
|
SelectObject (hDC, hFont);
|
|
ReleaseDC (NULL, hDC);
|
|
|
|
ScanName (szBuffer); // adds '&'
|
|
|
|
// Append a new menu item to the Settings pop-up menu
|
|
lstrcat (szBuffer, szDots);
|
|
hMenu = GetMenu (hCPlWnd);
|
|
hMenu = GetSubMenu (hMenu, 0);
|
|
InsertMenu (hMenu, numApps,
|
|
(!numApps || (numApps & 0x0F)) ?
|
|
MF_STRING|MF_BYPOSITION : MF_STRING|MF_MENUBARBREAK|MF_BYPOSITION,
|
|
numApps+MENU_SETTINGS, szBuffer);
|
|
|
|
numApps++;
|
|
|
|
lpNtCPl = (LPNTCPL) LocalAlloc (LPTR, sizeof(NTCPL));
|
|
|
|
if (lpNtCPl)
|
|
{
|
|
lpNtCPl->pCPlMod = pCPlMod;
|
|
lpNtCPl->iApplet = iIndex;
|
|
SendMessage (hCPlLB, LB_ADDSTRING, 0, (LONG)lpNtCPl);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Load cached Control Panel items from registry keys
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
BOOL LoadFromCache()
|
|
{
|
|
int i, j;
|
|
DWORD nApplets;
|
|
DWORD dwBits;
|
|
DWORD dwSize;
|
|
DWORD dwType;
|
|
|
|
HKEY hkey = NULL;
|
|
HKEY hkeyCache = NULL;
|
|
HKEY hkeyRCache = NULL;
|
|
HANDLE hMod = NULL;
|
|
HANDLE hFile = NULL;
|
|
HLOCAL lhndBits = NULL;
|
|
LPBYTE lpBits = NULL;
|
|
|
|
PCPLMODULE pCPlMod;
|
|
PCPLAPPLET pCPlApp;
|
|
ICONINFO iconinfo;
|
|
BITMAP bmInfo;
|
|
REGKEY *prkFirst = NULL;
|
|
REGKEY *prkRegKey = NULL;
|
|
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Open cache of modules and applets, create local modules
|
|
//
|
|
// Enumerate each "Module" key under "Cache" and then
|
|
// enumerate each "Applet" key under "Module" key and
|
|
// build linked list of Modules and Applets from this
|
|
// instead of from searching file system.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, pszRegCache, 0L, KEY_ALL_ACCESS,
|
|
&hkeyRCache)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
if (lhndBits = LocalAlloc (LMEM_FIXED, BMPSIZE))
|
|
lpBits = LocalLock (lhndBits);
|
|
else
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
// Get linked list of all "Module keys" for use below
|
|
if (!(prkFirst = GetModuleKeyList (hkeyRCache)))
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Now go thru list of modules
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
prkRegKey = prkFirst;
|
|
i = 0;
|
|
|
|
while (prkRegKey)
|
|
{
|
|
// Open cache of module applets
|
|
if (RegOpenKeyEx (hkeyRCache, // Root key
|
|
prkRegKey->pszKeyName, // Subkey to open/create
|
|
0L, // Reserved
|
|
KEY_ALL_ACCESS, // SAM
|
|
&hkeyCache) // return handle
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Get useful Module info - like number of applets
|
|
|
|
nApplets = 0;
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if (RegQueryValueEx (hkeyCache, pszNumApplets, 0L, &dwType,
|
|
(LPBYTE) &nApplets, &dwSize)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////
|
|
// If numApplets == 0 - this is a Cache entry for an invalid
|
|
// or bad .CPL file/module - just ignore it and continue
|
|
//////////////////////////////////////////////////////////////////
|
|
|
|
if (nApplets == 0)
|
|
goto GetNextCacheEntry;
|
|
|
|
if (!(pCPlMod = (PCPLMODULE)LocalAlloc (LPTR, sizeof(CPLMODULE))))
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
pCPlMod->hLibrary = NULL;
|
|
pCPlMod->bLoaded = FALSE;
|
|
|
|
pCPlMod->lpfnCPlApplet = NULL;
|
|
pCPlMod->pCPlApps = NULL;
|
|
|
|
CPlMods[i] = pCPlMod;
|
|
|
|
// Module pathname
|
|
dwSize = sizeof(pCPlMod->szPathname);
|
|
|
|
if ((RegQueryValueEx (hkeyCache, pszModulePath, 0L, &dwType,
|
|
(LPBYTE) pCPlMod->szPathname, &dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Get some space for this module's applets
|
|
|
|
pCPlMod->numApplets = nApplets;
|
|
|
|
if (!(pCPlMod->pCPlApps = (PCPLAPPLET)LocalAlloc(LPTR,
|
|
nApplets*sizeof(CPLAPPLET))))
|
|
{
|
|
RIPGEN();
|
|
goto GeneralError;
|
|
}
|
|
|
|
// Open each applet subkey and get info, create icon, etc.
|
|
|
|
for (j = 0, pCPlApp = pCPlMod->pCPlApps; j < (int) nApplets; j++, pCPlApp++)
|
|
{
|
|
wsprintf (szTemp, TEXT("%d"), j);
|
|
|
|
if (RegOpenKey (hkeyCache, szTemp, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
// Get all applet info into pCPlApp struct and create
|
|
// ICON from binary data
|
|
|
|
// Get icon info
|
|
|
|
iconinfo.fIcon = TRUE;
|
|
|
|
// IconX
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if ((RegQueryValueEx (hkey, pszAppletIconX, 0L,
|
|
&dwType,
|
|
(LPBYTE) &iconinfo.xHotspot,
|
|
&dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// IconY
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if ((RegQueryValueEx (hkey,
|
|
pszAppletIconY,
|
|
0L,
|
|
&dwType,
|
|
(LPBYTE) &iconinfo.yHotspot,
|
|
&dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Create Mask bitmap
|
|
dwSize = sizeof(BITMAP);
|
|
|
|
if ((RegQueryValueEx (hkey,
|
|
pszAppletInfoM,
|
|
0L,
|
|
&dwType,
|
|
(LPBYTE) &bmInfo,
|
|
&dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
dwBits = BMPSIZE;
|
|
if ((RegQueryValueEx (hkey,
|
|
pszAppletIconM,
|
|
0L,
|
|
&dwType,
|
|
(LPBYTE) lpBits,
|
|
&dwBits))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
bmInfo.bmBits = lpBits;
|
|
|
|
if (!(iconinfo.hbmMask = CreateBitmapIndirect (&bmInfo)))
|
|
{
|
|
RIPGEN();
|
|
goto BitmapError;
|
|
}
|
|
|
|
// Create Color bitmap
|
|
dwSize = sizeof(BITMAP);
|
|
|
|
if ((RegQueryValueEx (hkey,
|
|
pszAppletInfoC,
|
|
0L,
|
|
&dwType,
|
|
(LPBYTE) &bmInfo,
|
|
&dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
dwBits = BMPSIZE;
|
|
if ((RegQueryValueEx (hkey,
|
|
pszAppletIconC,
|
|
0L,
|
|
&dwType,
|
|
(LPBYTE) lpBits,
|
|
&dwBits))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
bmInfo.bmBits = lpBits;
|
|
|
|
if (!(iconinfo.hbmColor = CreateBitmapIndirect (&bmInfo)))
|
|
{
|
|
RIPGEN();
|
|
goto BitmapError;
|
|
}
|
|
|
|
pCPlApp->hIcon = CreateIconIndirect (&iconinfo);
|
|
|
|
// Now cleanup and get rid of our old bitmaps
|
|
|
|
DeleteObject (iconinfo.hbmMask);
|
|
DeleteObject (iconinfo.hbmColor);
|
|
|
|
// Get other applet string and help info
|
|
|
|
// Name
|
|
dwSize = BMPSIZE;
|
|
|
|
if ((RegQueryValueEx (hkey, pszAppletName, 0L, &dwType,
|
|
(LPBYTE) lpBits, &dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
if (pCPlApp->pszName = (LPTSTR) LocalAlloc (LPTR,
|
|
ByteCountOf(lstrlen((LPTSTR)lpBits)+1)))
|
|
{
|
|
lstrcpy(pCPlApp->pszName, (LPTSTR)lpBits);
|
|
}
|
|
else
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
// Full Namewith '&' char
|
|
dwSize = BMPSIZE;
|
|
|
|
if ((RegQueryValueEx (hkey, pszAppletFull, 0L, &dwType,
|
|
(LPBYTE) lpBits, &dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
if (pCPlApp->pszFullName = (LPTSTR) LocalAlloc (LPTR,
|
|
ByteCountOf(lstrlen((LPTSTR)lpBits)+1)))
|
|
{
|
|
lstrcpy(pCPlApp->pszFullName, (LPTSTR)lpBits);
|
|
}
|
|
else
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
// Info
|
|
dwSize = BMPSIZE;
|
|
|
|
if ((RegQueryValueEx (hkey, pszAppletInfo, 0L, &dwType,
|
|
(LPBYTE) lpBits, &dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
if (pCPlApp->pszInfo = (LPTSTR) LocalAlloc (LPTR,
|
|
ByteCountOf(lstrlen((LPTSTR)lpBits)+1)))
|
|
{
|
|
lstrcpy(pCPlApp->pszInfo, (LPTSTR)lpBits);
|
|
}
|
|
else
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
// Helpfile name
|
|
//
|
|
// NOTE: This is an optional value, it is not an ERROR to
|
|
// not read this value, just set ptr to NULL
|
|
//
|
|
dwSize = BMPSIZE;
|
|
|
|
if ((RegQueryValueEx (hkey, pszAppletHelp, 0L, &dwType,
|
|
(LPBYTE) lpBits, &dwSize))
|
|
== ERROR_SUCCESS)
|
|
{
|
|
if (pCPlApp->pszHelpFile = (LPTSTR) LocalAlloc (LPTR,
|
|
ByteCountOf(lstrlen((LPTSTR)lpBits)+1)))
|
|
{
|
|
lstrcpy(pCPlApp->pszHelpFile, (LPTSTR)lpBits);
|
|
}
|
|
else
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pCPlApp->pszHelpFile = NULL;
|
|
}
|
|
|
|
// Help context
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if ((RegQueryValueEx (hkey, pszAppletCntx, 0L, &dwType,
|
|
(LPBYTE) &pCPlApp->dwContext, &dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// lData value
|
|
dwSize = sizeof(DWORD);
|
|
|
|
if ((RegQueryValueEx (hkey, pszAppletData, 0L, &dwType,
|
|
(LPBYTE) &pCPlApp->lData, &dwSize))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Set all application items for Listbox control and drawing
|
|
CacheSetAppItems(pCPlMod, pCPlApp, j);
|
|
|
|
RegCloseKey (hkey);
|
|
hkey = NULL;
|
|
}
|
|
|
|
i++;
|
|
|
|
GetNextCacheEntry:
|
|
|
|
RegCloseKey (hkeyCache);
|
|
hkeyCache = NULL;
|
|
|
|
// Next key name in list
|
|
prkRegKey = prkRegKey->prkNext;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Clean up and leave
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Free list
|
|
|
|
if (!FreeModuleKeyList (prkFirst))
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
if (lhndBits != NULL)
|
|
{
|
|
LocalUnlock (lhndBits);
|
|
if (LocalFree (lhndBits))
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
}
|
|
|
|
if (hkeyRCache != NULL)
|
|
RegCloseKey (hkeyRCache);
|
|
|
|
return TRUE;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine error handling
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
BitmapError:
|
|
GeneralError:
|
|
MemoryError:
|
|
RegistryError:
|
|
|
|
if (hkeyRCache != NULL)
|
|
RegCloseKey (hkeyRCache);
|
|
|
|
if (hkey != NULL)
|
|
RegCloseKey (hkey);
|
|
|
|
if (hkeyCache != NULL)
|
|
RegCloseKey (hkeyCache);
|
|
|
|
if (lhndBits != NULL)
|
|
{
|
|
LocalUnlock (lhndBits);
|
|
LocalFree (lhndBits);
|
|
}
|
|
|
|
FreeModuleKeyList (prkFirst);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Clear all registry Module Cache entries under "Control Panel\Cache"
|
|
// key. Also, delete their associated Applet cache entries.
|
|
//
|
|
// This routine returns no errors because there is the possibility of an
|
|
// empty cache and; hence, nothing for it to do. (i.e. Initial run)
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void FlushCache()
|
|
{
|
|
int i;
|
|
DWORD dwRes;
|
|
DWORD dwBufz;
|
|
TCHAR szTemp[MAX_PATH];
|
|
|
|
HKEY hkeyCache = NULL;
|
|
HKEY hkeyRCache = NULL;
|
|
|
|
REGKEY *prkFirst = NULL;
|
|
REGKEY *prkRegKey = NULL;
|
|
FILETIME ftReg;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Open cache of modules and applets
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (RegOpenKeyEx (HKEY_CURRENT_USER, pszRegCache, 0L, KEY_ALL_ACCESS,
|
|
&hkeyRCache)
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Get linked list of all "Module keys" for use below
|
|
prkFirst = GetModuleKeyList (hkeyRCache);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Now go thru list of modules
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
prkRegKey = prkFirst;
|
|
|
|
while (prkRegKey)
|
|
{
|
|
// Open cache of module applets
|
|
if (RegOpenKeyEx (hkeyRCache, // Root key
|
|
prkRegKey->pszKeyName, // Subkey to open/create
|
|
0L, // Reserved
|
|
KEY_ALL_ACCESS, // SAM
|
|
&hkeyCache) // return handle
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
dwRes = 0;
|
|
dwBufz = CharSizeOf(szTemp);
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// Delete each applet subkey under the Module key
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
// Get number of subkeys
|
|
if (RegQueryInfoKey (hkeyCache, // handle of key to query
|
|
szTemp, // ptr class string
|
|
&dwBufz, // ptr size class string buffer
|
|
NULL, // reserved
|
|
&dwRes, // ptr number of subkeys
|
|
&dwBufz, // ptr longest subkey name length
|
|
&dwBufz, // ptr longest class string length
|
|
&dwBufz, // ptr number of value entries
|
|
&dwBufz, // ptr longest value name length
|
|
&dwBufz, // ptr longest value data length
|
|
&dwBufz, // ptr security descriptor length
|
|
&ftReg) // ptr last write time
|
|
== ERROR_SUCCESS)
|
|
{
|
|
// Now, since we have a count on the number of
|
|
// keys, delete them
|
|
|
|
for (i = 0; i < (int) dwRes; i++)
|
|
{
|
|
wsprintf (szTemp, TEXT("%d"), i);
|
|
RegDeleteKey (hkeyCache, szTemp);
|
|
}
|
|
}
|
|
|
|
RegCloseKey (hkeyCache);
|
|
hkeyCache = NULL;
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// Now delete this Module key
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
RegDeleteKey (hkeyRCache, prkRegKey->pszKeyName);
|
|
|
|
// Get next key name in list
|
|
prkRegKey = prkRegKey->prkNext;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Clean up and leave
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Free list
|
|
FreeModuleKeyList (prkFirst);
|
|
|
|
ASSERT(hkeyCache == NULL);
|
|
|
|
if (hkeyRCache != NULL)
|
|
RegCloseKey (hkeyRCache);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Force a complete rebuild of registry cache by setting cache invalid
|
|
// and reloading in all modules from scratch.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void RebuildCache()
|
|
{
|
|
HMENU hMenu;
|
|
int i, iApps;
|
|
|
|
|
|
//
|
|
// If an applet is currently displayed, just set global
|
|
// flag to force CACHE rebuild after if goes away.
|
|
//
|
|
|
|
if (bAppletActive)
|
|
{
|
|
bRebuildCache = TRUE;
|
|
return;
|
|
}
|
|
|
|
// Make a copy becaue LB_RESETCONTENT causes it decrement to 0
|
|
iApps = numApps;
|
|
|
|
// Clear current list box contents
|
|
SendMessage (hCPlLB, LB_RESETCONTENT, 0, 0L);
|
|
|
|
UpdateWindow (hCPlLB);
|
|
|
|
// Delete current menu items
|
|
|
|
hMenu = GetMenu (hCPlWnd);
|
|
hMenu = GetSubMenu (hMenu, 0);
|
|
|
|
for (i = 0; i < iApps; i++)
|
|
DeleteMenu (hMenu, MENU_SETTINGS+i, MF_BYCOMMAND);
|
|
|
|
// Dirty the cache
|
|
ClearCacheValid ();
|
|
|
|
// Re-init control panel module structs and refresh cache
|
|
if (!LoadAndSizeApplets())
|
|
{
|
|
if (hCPlWnd)
|
|
MessageBox (hCPlWnd, szErrNoApps, szAppName,
|
|
MB_OK | MB_ICONEXCLAMATION | MB_SYSTEMMODAL);
|
|
}
|
|
|
|
bRebuildCache = FALSE;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Update Control Panel module/applet cache in registry. Delete any
|
|
// existing cache entries and create new keys based on module chain
|
|
// created during initial search and loading of modules/applets.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void UpdateCache()
|
|
{
|
|
int i, j, k, nApplets;
|
|
DWORD dwDisposition;
|
|
DWORD dwBits;
|
|
DWORD numFiles = 0;
|
|
DWORD numCache = 0;
|
|
|
|
HDC hdc;
|
|
HKEY hkey = NULL;
|
|
HKEY hkeyCache = NULL;
|
|
HANDLE hFile = NULL;
|
|
HLOCAL lhndBits = NULL;
|
|
LPBYTE lpBits = NULL;
|
|
|
|
PCPLMODULE pCPlMod;
|
|
PCPLAPPLET pCPlApp;
|
|
ICONINFO iconinfo;
|
|
BITMAP bmInfo;
|
|
|
|
BY_HANDLE_FILE_INFORMATION bhfiMod;
|
|
|
|
TCHAR szTemp[MAX_PATH];
|
|
TCHAR szCacheKey[MAX_PATH];
|
|
|
|
CPLFILES *cfCPlFiles;
|
|
CPLFILES *cfCPlCache;
|
|
|
|
TEXTMETRIC tm;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Clear "Cache Valid" flag
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
cfCPlFiles = cfCPlCache = NULL;
|
|
|
|
ClearCacheValid ();
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// First thing to do is flush cache of all existing cache entries
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
FlushCache ();
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Create cache of modules and applets
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (lhndBits = LocalAlloc (LMEM_FIXED, BMPSIZE))
|
|
lpBits = LocalLock (lhndBits);
|
|
else
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
i = 0;
|
|
|
|
while (CPlMods[i] != NULL)
|
|
{
|
|
pCPlMod = CPlMods[i];
|
|
|
|
k = 0;
|
|
|
|
CreateKeyAgain:
|
|
|
|
CreateCacheKey (szTemp, pCPlMod->szPathname, k);
|
|
|
|
hkeyCache = NULL;
|
|
wsprintf (szCacheKey, pszCplCache, szTemp);
|
|
|
|
if (RegCreateKeyEx (HKEY_CURRENT_USER, // Root key
|
|
szCacheKey, // Subkey to open/create
|
|
0L, // Reserved
|
|
NULL, // Class string
|
|
0L, // Options
|
|
KEY_ALL_ACCESS, // SAM
|
|
NULL, // ptr to Security struct
|
|
&hkeyCache, // return handle
|
|
&dwDisposition) // return disposition
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
// Try it with next value until we get a unique key
|
|
if (++k > 5)
|
|
{
|
|
// If key creation fails 5 times we have a serious problem
|
|
// because it is unlikely that we will try to load 5 modules
|
|
// with the same name.
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
else
|
|
goto CreateKeyAgain;
|
|
}
|
|
else
|
|
{
|
|
// All existing subkeys should have been deleted
|
|
ASSERT(dwDisposition != REG_OPENED_EXISTING_KEY);
|
|
|
|
// Open File and get info on it
|
|
if ((hFile = CreateFile (pCPlMod->szPathname,
|
|
0,
|
|
FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL,
|
|
NULL)) == INVALID_HANDLE_VALUE)
|
|
{
|
|
RIPGEN();
|
|
goto GeneralError;
|
|
}
|
|
|
|
// Put some data values into the cache
|
|
// Get File size, time, num applets, full pathname
|
|
|
|
if (!GetFileInformationByHandle (hFile, &bhfiMod))
|
|
{
|
|
RIPGEN();
|
|
goto GeneralError;
|
|
}
|
|
|
|
CloseHandle (hFile);
|
|
|
|
// Set "Module Path" value
|
|
if ((RegSetValueEx (hkeyCache, pszModulePath, 0L, REG_SZ,
|
|
(LPBYTE) pCPlMod->szPathname,
|
|
ByteCountOf(lstrlen(pCPlMod->szPathname)+1)))
|
|
|| // Set "Low File Time" value
|
|
(RegSetValueEx (hkeyCache, pszFileTimeLow, 0L, REG_DWORD,
|
|
(LPBYTE) &bhfiMod.ftLastWriteTime.dwLowDateTime,
|
|
sizeof(DWORD)))
|
|
|| // Set "High File Time" value
|
|
(RegSetValueEx (hkeyCache, pszFileTimeHigh, 0L, REG_DWORD,
|
|
(LPBYTE) &bhfiMod.ftLastWriteTime.dwHighDateTime,
|
|
sizeof(DWORD)))
|
|
|| // Set "File Size" value
|
|
(RegSetValueEx (hkeyCache, pszFileSize, 0L, REG_DWORD,
|
|
(LPBYTE) &bhfiMod.nFileSizeLow, sizeof(DWORD)))
|
|
|| // Set "Number Applets" value
|
|
(RegSetValueEx (hkeyCache, pszNumApplets, 0L, REG_DWORD,
|
|
(LPBYTE) &pCPlMod->numApplets, sizeof(DWORD)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
nApplets = pCPlMod->numApplets;
|
|
|
|
// Create subkey for each applet (use # for speed)
|
|
|
|
for (j = 0, pCPlApp = pCPlMod->pCPlApps; j < nApplets; j++, pCPlApp++)
|
|
{
|
|
wsprintf (szTemp, TEXT("%d"), j);
|
|
|
|
if (RegCreateKey (hkeyCache, szTemp, &hkey) == ERROR_SUCCESS)
|
|
{
|
|
// Save applet items
|
|
|
|
#ifdef ICONID
|
|
DWORD dwRes;
|
|
|
|
// Copy, duplicate, save icon and store something in registry
|
|
// NOTE: This is the preferred way to save an icon from the resources
|
|
// that were used to create it initially. This is both faster
|
|
// and has the benefit of saving all of the icon information.
|
|
// When we would go to create the icon during LoadFromCache()
|
|
// USER would automatically choose the best icon for this display.
|
|
//++++ NEED iICON value from ICON Handle (pCPlApp->hIcon)
|
|
|
|
iIcon = ResIdfromHandle (pCPlMod->hLibrary, pCPlApp->hIcon);
|
|
|
|
hIconRes = FindResource (pCPlMod->hLibrary, MAKEINTRESOURCE(iIcon), MAKEINTRESOURCE(RT_ICON))
|
|
|
|
dwRes = SizeofResource (pCPlMod->hLibrary, hIconRes);
|
|
hIconRes = LoadResource (pCPlMod->hLibrary, hIconRes);
|
|
lpIconRes = LockResource (hIconRes);
|
|
|
|
// Icon
|
|
if ((RegSetValueEx (hkey, pszAppletIcon, 0L, REG_BINARY,
|
|
(LPBYTE) lpIconRes, dwRes))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
dwRes = SizeofResource (pCPlMod->hLibrary, pCPlApp->hIcon);
|
|
// dwIconId = ExtractIcon (pCPlMod->hLibrary, pCPlApp->hIcon);
|
|
#endif // ICONID
|
|
|
|
// Save all icon info
|
|
if (GetIconInfo (pCPlApp->hIcon, &iconinfo))
|
|
{
|
|
// IconX
|
|
if ((RegSetValueEx (hkey, pszAppletIconX, 0L,
|
|
REG_DWORD,
|
|
(LPBYTE) &iconinfo.xHotspot,
|
|
sizeof(DWORD)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
// IconY
|
|
if ((RegSetValueEx (hkey,
|
|
pszAppletIconY,
|
|
0L,
|
|
REG_DWORD,
|
|
(LPBYTE) &iconinfo.yHotspot,
|
|
sizeof(DWORD)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
if (iconinfo.hbmMask)
|
|
{
|
|
if (dwBits = GetObject (iconinfo.hbmMask,
|
|
sizeof(BITMAP), (LPTSTR) &bmInfo))
|
|
{
|
|
if ((RegSetValueEx (hkey,
|
|
pszAppletInfoM,
|
|
0L,
|
|
REG_BINARY,
|
|
(LPBYTE) &bmInfo,
|
|
dwBits))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
}
|
|
|
|
dwBits = GetBitmapBits (iconinfo.hbmMask,
|
|
BMPSIZE,
|
|
(LPVOID) lpBits);
|
|
|
|
if ((RegSetValueEx (hkey,
|
|
pszAppletIconM,
|
|
0L,
|
|
REG_BINARY,
|
|
(LPBYTE) lpBits,
|
|
dwBits))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
DeleteObject (iconinfo.hbmMask);
|
|
}
|
|
|
|
if (iconinfo.hbmColor)
|
|
{
|
|
if (dwBits = GetObject (iconinfo.hbmColor,
|
|
sizeof(BITMAP), (LPTSTR) &bmInfo))
|
|
{
|
|
if ((RegSetValueEx (hkey,
|
|
pszAppletInfoC,
|
|
0L,
|
|
REG_BINARY,
|
|
(LPBYTE) &bmInfo,
|
|
dwBits))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
}
|
|
|
|
dwBits = GetBitmapBits (iconinfo.hbmColor,
|
|
BMPSIZE,
|
|
(LPVOID) lpBits);
|
|
|
|
if ((RegSetValueEx (hkey,
|
|
pszAppletIconC,
|
|
0L,
|
|
REG_BINARY,
|
|
(LPBYTE) lpBits,
|
|
dwBits))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
DeleteObject (iconinfo.hbmColor);
|
|
}
|
|
}
|
|
// Name
|
|
if ((RegSetValueEx (hkey, pszAppletName, 0L, REG_SZ,
|
|
(LPBYTE) pCPlApp->pszName,
|
|
ByteCountOf(lstrlen (pCPlApp->pszName)+1)))
|
|
|| // Full Name includes '&' char
|
|
(RegSetValueEx (hkey, pszAppletFull, 0L, REG_SZ,
|
|
(LPBYTE) pCPlApp->pszFullName,
|
|
ByteCountOf(lstrlen (pCPlApp->pszFullName)+1)))
|
|
|| // Info
|
|
(RegSetValueEx (hkey, pszAppletInfo, 0L, REG_SZ,
|
|
(LPBYTE) pCPlApp->pszInfo,
|
|
ByteCountOf(lstrlen (pCPlApp->pszInfo)+1)))
|
|
|| // Help context
|
|
(RegSetValueEx (hkey, pszAppletCntx, 0L, REG_DWORD,
|
|
(LPBYTE) &pCPlApp->dwContext, sizeof(DWORD)))
|
|
|| // lData value
|
|
(RegSetValueEx (hkey, pszAppletData, 0L, REG_DWORD,
|
|
(LPBYTE) &pCPlApp->lData, sizeof(DWORD)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
// Helpfile name - Optional
|
|
if (pCPlApp->pszHelpFile != NULL)
|
|
{
|
|
if ((RegSetValueEx (hkey, pszAppletHelp, 0L, REG_SZ,
|
|
(LPBYTE) pCPlApp->pszHelpFile,
|
|
ByteCountOf(lstrlen (pCPlApp->pszHelpFile)+1)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
|
|
RegCloseKey (hkey);
|
|
hkey = NULL;
|
|
}
|
|
}
|
|
|
|
RegCloseKey (hkeyCache);
|
|
hkeyCache = NULL;
|
|
i++;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Now create a cache entry for any .CPL modules found that either
|
|
// did not load or are not valid modules
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Check Filesystem .CPL modules against Cached Modules
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// Get some storage for modules
|
|
cfCPlFiles = (CPLFILES *) LocalAlloc (LPTR, sizeof(CPLFILES)*CPL_MAXMODS);
|
|
|
|
cfCPlCache = (CPLFILES *) LocalAlloc (LPTR, sizeof(CPLFILES)*CPL_MAXMODS);
|
|
|
|
if (!cfCPlFiles || !cfCPlCache)
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
// Now get info on CPl files and Cached modules
|
|
if ((numFiles = CheckFindModules (cfCPlFiles)) == 0)
|
|
{
|
|
RIPGEN();
|
|
goto GeneralError;
|
|
}
|
|
|
|
if ((numCache = CheckGetCacheMods (cfCPlCache)) == 0)
|
|
{
|
|
RIPGEN();
|
|
goto GeneralError;
|
|
}
|
|
|
|
// Check for quick exits
|
|
|
|
if (numFiles == numCache)
|
|
goto CleanExit;
|
|
|
|
ASSERT(numCache <= numFiles);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// At this point we have an extra module found during the filesystem
|
|
// search. Identify it and create a cache entry for it.
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
for (i = 0; i < (int) numFiles; i++)
|
|
{
|
|
if (cfCPlFiles[i].bAlreadyMatched)
|
|
continue;
|
|
|
|
for (j = 0; j < (int) numCache; j++)
|
|
{
|
|
if (cfCPlCache[j].bAlreadyMatched)
|
|
continue;
|
|
|
|
if (!_tcsicmp (cfCPlCache[j].szPathname, cfCPlFiles[i].szPathname))
|
|
{
|
|
// We found a name match
|
|
cfCPlCache[j].bAlreadyMatched = TRUE;
|
|
cfCPlFiles[i].bAlreadyMatched = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Find the extra .CPL files/modules
|
|
|
|
for (i = 0; i < (int) numFiles; i++)
|
|
{
|
|
if (!cfCPlFiles[i].bAlreadyMatched)
|
|
{
|
|
// Create a cache entry for this unmatched file/module
|
|
k = 0;
|
|
|
|
TryCreateKeyAgain:
|
|
|
|
CreateCacheKey (szTemp, cfCPlFiles[i].szPathname, k);
|
|
|
|
hkeyCache = NULL;
|
|
wsprintf (szCacheKey, pszCplCache, szTemp);
|
|
|
|
if (RegCreateKeyEx (HKEY_CURRENT_USER, // Root key
|
|
szCacheKey, // Subkey to open/create
|
|
0L, // Reserved
|
|
NULL, // Class string
|
|
0L, // Options
|
|
KEY_ALL_ACCESS, // SAM
|
|
NULL, // ptr to Security struct
|
|
&hkeyCache, // return handle
|
|
&dwDisposition) // return disposition
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
// Try it with next value until we get a unique key
|
|
if (++k > 5)
|
|
{
|
|
// If key creation fails 5 times we have a serious problem
|
|
// because it is unlikely that we will try to load 5 modules
|
|
// with the same name.
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
else
|
|
goto TryCreateKeyAgain;
|
|
}
|
|
else
|
|
{
|
|
// This condition would be a serious problem
|
|
ASSERT(dwDisposition != REG_OPENED_EXISTING_KEY);
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// SPECIAL NOTE: Here we set the cache entries for the
|
|
// invalid module. We know it is invalid because the
|
|
// numApplets ("Number Applets") field is 0. This is
|
|
// the default set by CheckFindModules().
|
|
////////////////////////////////////////////////////////////
|
|
|
|
// Set "Module Path" value
|
|
if ((RegSetValueEx (hkeyCache, pszModulePath, 0L, REG_SZ,
|
|
(LPBYTE) cfCPlFiles[i].szPathname,
|
|
ByteCountOf(lstrlen(cfCPlFiles[i].szPathname)+1)))
|
|
|| // Set "Low File Time" value
|
|
(RegSetValueEx (hkeyCache, pszFileTimeLow, 0L, REG_DWORD,
|
|
(LPBYTE) &cfCPlFiles[i].ftModule.dwLowDateTime,
|
|
sizeof(DWORD)))
|
|
|| // Set "High File Time" value
|
|
(RegSetValueEx (hkeyCache, pszFileTimeHigh, 0L, REG_DWORD,
|
|
(LPBYTE) &cfCPlFiles[i].ftModule.dwHighDateTime,
|
|
sizeof(DWORD)))
|
|
|| // Set "File Size" value
|
|
(RegSetValueEx (hkeyCache, pszFileSize, 0L, REG_DWORD,
|
|
(LPBYTE) &cfCPlFiles[i].dwSize, sizeof(DWORD)))
|
|
|| // Set "Number Applets" value
|
|
(RegSetValueEx (hkeyCache, pszNumApplets, 0L, REG_DWORD,
|
|
(LPBYTE) &cfCPlFiles[i].numApplets, sizeof(DWORD)))
|
|
!= ERROR_SUCCESS)
|
|
{
|
|
RIPREG();
|
|
goto RegistryError;
|
|
}
|
|
}
|
|
|
|
RegCloseKey (hkeyCache);
|
|
hkeyCache = NULL;
|
|
}
|
|
}
|
|
|
|
#if DBG
|
|
// NOTE: This should only be in the debug or "checked" build
|
|
//
|
|
// We should never have this condition
|
|
|
|
for (i = 0; i < (int) numCache; i++)
|
|
{
|
|
if (!cfCPlCache[i].bAlreadyMatched)
|
|
{
|
|
RIPGEN();
|
|
goto GeneralError;
|
|
}
|
|
}
|
|
#endif // DBG
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Indicate "Cache Valid"
|
|
//////////////////////////////////////////////////////////////////////
|
|
CleanExit:
|
|
|
|
// Set "Display Type" flags for current display type
|
|
|
|
hdc = GetDC (NULL);
|
|
|
|
SetCachedValue (pszBitspixel, GetDeviceCaps (hdc, BITSPIXEL));
|
|
SetCachedValue (pszColorres, GetDeviceCaps (hdc, COLORRES));
|
|
SetCachedValue (pszPlanes, GetDeviceCaps (hdc, PLANES));
|
|
|
|
GetTextMetrics (hdc, &tm);
|
|
|
|
SetCachedValue (pszAveCharWidth, tm.tmAveCharWidth);
|
|
SetCachedValue (pszHeight, tm.tmHeight);
|
|
SetCachedValue (pszWeight, tm.tmWeight);
|
|
|
|
ReleaseDC (NULL, hdc);
|
|
|
|
SetCacheValid ();
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Cleanup and leave
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
ASSERT(lhndBits != NULL)
|
|
|
|
LocalUnlock (lhndBits);
|
|
LocalFree (lhndBits);
|
|
|
|
if (cfCPlFiles)
|
|
if (LocalFree ((HLOCAL) cfCPlFiles))
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
if (cfCPlCache)
|
|
if (LocalFree ((HLOCAL) cfCPlCache))
|
|
{
|
|
RIPMEM();
|
|
goto MemoryError;
|
|
}
|
|
|
|
return;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Routine error handling
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
GeneralError:
|
|
MemoryError:
|
|
RegistryError:
|
|
|
|
if (hkey != NULL)
|
|
RegCloseKey (hkey);
|
|
|
|
if (hkeyCache != NULL)
|
|
RegCloseKey (hkeyCache);
|
|
|
|
if (lhndBits != NULL)
|
|
{
|
|
LocalUnlock (lhndBits);
|
|
LocalFree (lhndBits);
|
|
}
|
|
|
|
if (cfCPlFiles)
|
|
LocalFree ((HLOCAL) cfCPlFiles);
|
|
|
|
if (cfCPlCache)
|
|
LocalFree ((HLOCAL) cfCPlCache);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Pass initial messages to the indicated module, and match its' responses
|
|
// against what we know about it from our cache entry for it.
|
|
//
|
|
// NOTE: We cannot even get to this routine unless we have already verified
|
|
// that this module exists in the file system, and that we already
|
|
// have a cache entry for it. What we are doing in this routine is
|
|
// verifying that it matches what we know about it.
|
|
//
|
|
// Arguments:
|
|
// name - the name of the .CPL module to verify
|
|
// pcfCPlCache - ptr to a struct containing cache entry info that
|
|
// matches the name of the module
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// This value is a special value only sent out in LPARAM2 of the
|
|
// CPL_INIT, CPL_GETCOUNT and CPL_EXIT messages only during the
|
|
// Control Panels Validation thread to let certain CPL applets
|
|
// know that they are in the validation portion of the Control
|
|
// Panel. This will allow them to respond quicker and not start-
|
|
// up unnecessary services, timers, etc.
|
|
//
|
|
|
|
#define VALIDATE_PARAM ((LPARAM)(-1))
|
|
|
|
BOOL ValidateAskModule (LPTSTR name, CPLFILES *pcfCPlCache)
|
|
{
|
|
int numApplets = 0;
|
|
BOOL bValid=FALSE;
|
|
HANDLE hCpl;
|
|
APPLET_PROC lpfnCPlApplet;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Load module, initialize it and get applet count to test against
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
if (hCpl = LoadLibrary(name))
|
|
{
|
|
if ((lpfnCPlApplet = (APPLET_PROC)GetProcAddress(hCpl, szCPlApplet))
|
|
&& (*lpfnCPlApplet)(hCPlWnd, CPL_INIT, 0L, VALIDATE_PARAM))
|
|
{
|
|
numApplets = (int)(*lpfnCPlApplet)(hCPlWnd, CPL_GETCOUNT, 0L, VALIDATE_PARAM);
|
|
|
|
// If the module loads and the number of applets are
|
|
// the same as my Cached module, then everything is OK.
|
|
|
|
if (pcfCPlCache->numApplets == numApplets)
|
|
bValid = TRUE;
|
|
|
|
// Send exit message before freeing the module
|
|
(*lpfnCPlApplet) (hCPlWnd, CPL_EXIT, 0L, VALIDATE_PARAM);
|
|
}
|
|
|
|
FreeLibrary(hCpl);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Check for the case where we already know about a module and have
|
|
// marked it with 0 applets. If this module fails to load, it's OK.
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
if (!bValid && (pcfCPlCache->numApplets == 0) && numApplets == 0)
|
|
bValid = TRUE;
|
|
|
|
return bValid;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Load all modules found during Filesystem search and check them against
|
|
// what we loaded from cache to be "Absolutely" certain that what we think
|
|
// is a complete set of applet icons is indeed what would load if had done
|
|
// a simple startup.
|
|
//
|
|
// NOTE: This routine runs on a separate thread to allow the User to
|
|
// start applets while this check is being done.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void AbsoluteValidation ()
|
|
{
|
|
DWORD i, j;
|
|
DWORD numFiles = 0;
|
|
DWORD numCache = 0;
|
|
BOOL bRet = TRUE;
|
|
TCHAR szMutex[MAX_PATH];
|
|
HANDLE hmutex;
|
|
UINT uError;
|
|
|
|
CPLFILES *cfCPlFiles;
|
|
CPLFILES *cfCPlCache;
|
|
|
|
//
|
|
// Disable WIN32 Error Popup Message box on attempt to load bad
|
|
// images.
|
|
//
|
|
// Note: Since the ErrorMode state is maintained on a per process
|
|
// basis, this call is placed at the start of this thread to
|
|
// avoid collisions, race conditions, or any sort of foul-up
|
|
// between the Error Mode state of a running CPL applet and
|
|
// whatever may happen to the Error Mode during this background
|
|
// check.
|
|
//
|
|
|
|
uError = SetErrorMode (SEM_FAILCRITICALERRORS);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Check Filesystem .CPL modules against Cached Modules
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_IDLE);
|
|
|
|
cfCPlFiles = cfCPlCache = NULL;
|
|
|
|
// Get some storage for modules
|
|
cfCPlFiles = (CPLFILES *) LocalAlloc (LPTR, sizeof(CPLFILES)*CPL_MAXMODS);
|
|
|
|
cfCPlCache = (CPLFILES *) LocalAlloc (LPTR, sizeof(CPLFILES)*CPL_MAXMODS);
|
|
|
|
if (!cfCPlFiles || !cfCPlCache)
|
|
{
|
|
RIPMEM();
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
// Now get info on CPl files and Cached modules
|
|
if ((numFiles = CheckFindModules (cfCPlFiles)) == 0)
|
|
{
|
|
RIP(TEXT("CheckFindModules failed"));
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
if ((numCache = CheckGetCacheMods (cfCPlCache)) == 0)
|
|
{
|
|
RIP(TEXT("CheckGetCacheMods failed"));
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
|
|
for (i = 0; i < numFiles; i++)
|
|
{
|
|
for (j = 0; j < numCache; j++)
|
|
{
|
|
if (cfCPlCache[j].bAlreadyMatched)
|
|
continue;
|
|
|
|
if (!_tcsicmp (cfCPlCache[j].szPathname, cfCPlFiles[i].szPathname))
|
|
{
|
|
// We found a name match
|
|
cfCPlCache[j].bAlreadyMatched = TRUE;
|
|
cfCPlFiles[i].bAlreadyMatched = TRUE;
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// Before loading this module, make sure that it is not
|
|
// in use by the Main thread.
|
|
//////////////////////////////////////////////////////////////
|
|
|
|
CreateMutexNameFromPath (cfCPlCache[j].szPathname, szMutex);
|
|
hmutex = CreateMutex (NULL, FALSE, szMutex);
|
|
|
|
WaitForSingleObject (hmutex, INFINITE);
|
|
|
|
if (!ValidateAskModule (cfCPlFiles[i].szPathname, &cfCPlCache[j]))
|
|
bRet = FALSE;
|
|
|
|
ReleaseMutex (hmutex);
|
|
CloseHandle (hmutex);
|
|
|
|
if (!bRet)
|
|
goto CommonExit;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Are there any unmatched files?
|
|
|
|
for (i = 0; i < numFiles; i++)
|
|
{
|
|
if (!cfCPlFiles[i].bAlreadyMatched)
|
|
{
|
|
bRet = FALSE;
|
|
goto CommonExit;
|
|
}
|
|
}
|
|
|
|
|
|
CommonExit:
|
|
|
|
if (cfCPlFiles)
|
|
LocalFree ((HLOCAL) cfCPlFiles);
|
|
|
|
if (cfCPlCache)
|
|
LocalFree ((HLOCAL) cfCPlCache);
|
|
|
|
//
|
|
// Restore prior error mode
|
|
//
|
|
|
|
SetErrorMode (uError);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// For FALSE return - force system to re-load all modules and cache
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
if (!bRet)
|
|
PostMessage (hCPlWnd, WM_COMMAND, MENU_CACHE, 0);
|
|
|
|
bValidationDone = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Build the Control Panel Cache in the registry without a window.
|
|
//
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
void BuildCache ()
|
|
{
|
|
DWORD i;
|
|
DWORD numFiles = 0;
|
|
int numMods = 0;
|
|
|
|
CPLFILES *cfCPlFiles = NULL;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Check and Update cache as necessary
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
if (IsCacheValid())
|
|
goto CommonExit;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Check Filesystem .CPL modules
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Get some storage for modules
|
|
cfCPlFiles = (CPLFILES *) LocalAlloc (LPTR, sizeof(CPLFILES)*CPL_MAXMODS);
|
|
|
|
if (!cfCPlFiles)
|
|
{
|
|
RIPMEM();
|
|
goto CommonExit;
|
|
}
|
|
|
|
// Now get info on CPl files and Cached modules
|
|
if ((numFiles = CheckFindModules (cfCPlFiles)) == 0)
|
|
{
|
|
RIP(TEXT("CheckFindModules failed"));
|
|
goto CommonExit;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Create global CPlMods[] array
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
numMods = 0;
|
|
|
|
for (i = 0; i < numFiles; i++)
|
|
{
|
|
if (AskModule (cfCPlFiles[i].szPathname, numMods))
|
|
numMods += 1;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Now build the cache
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
UpdateCache();
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Free all of the modules
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
FreeApps ();
|
|
|
|
CommonExit:
|
|
|
|
if (cfCPlFiles)
|
|
LocalFree ((HLOCAL) cfCPlFiles);
|
|
|
|
return;
|
|
}
|
|
|