603 lines
21 KiB
C
603 lines
21 KiB
C
#include <windows.h>
|
|
#include <winuserp.h>
|
|
#include <tchar.H>
|
|
#include <stdio.h>
|
|
#include "shmgdefs.h"
|
|
#include <regstr.h>
|
|
|
|
// structure used to store a scheme in the registry
|
|
#define SCHEME_VERSION_16 1
|
|
#define LF_FACESIZE16 32
|
|
|
|
#pragma pack(1)
|
|
typedef struct {
|
|
SHORT lfHeight;
|
|
SHORT lfWidth;
|
|
SHORT lfEscapement;
|
|
SHORT lfOrientation;
|
|
SHORT lfWeight;
|
|
BYTE lfItalic;
|
|
BYTE lfUnderline;
|
|
BYTE lfStrikeOut;
|
|
BYTE lfCharSet;
|
|
BYTE lfOutPrecision;
|
|
BYTE lfClipPrecision;
|
|
BYTE lfQuality;
|
|
BYTE lfPitchAndFamily;
|
|
char lfFaceName[LF_FACESIZE16];
|
|
} LOGFONT16;
|
|
|
|
typedef LOGFONT16 *LPLOGFONT16;
|
|
|
|
typedef struct {
|
|
SHORT version;
|
|
NONCLIENTMETRICSA ncm;
|
|
LOGFONT16 lfIconTitle;
|
|
COLORREF rgb[COLOR_MAX];
|
|
} SCHEMEDATA16;
|
|
|
|
typedef SCHEMEDATA16 *PSCHEMEDATA16;
|
|
#pragma pack()
|
|
|
|
// structure used to store a scheme in the registry
|
|
#define SCHEME_VERSION_NT 2
|
|
|
|
typedef struct {
|
|
SHORT version;
|
|
WORD wDummy; // for alignment
|
|
NONCLIENTMETRICSW ncm;
|
|
LOGFONTW lfIconTitle;
|
|
COLORREF rgb[COLOR_MAX];
|
|
} SCHEMEDATAW;
|
|
|
|
typedef SCHEMEDATAW *PSCHEMEDATAW;
|
|
|
|
typedef TCHAR FILEPATH[MAX_PATH];
|
|
|
|
typedef struct tagSZNODE {
|
|
TCHAR *psz;
|
|
struct tagSZNODE *next;
|
|
} SZNODE;
|
|
|
|
TCHAR szApprSchemes[] = TEXT("Control Panel\\Appearance\\Schemes");
|
|
TCHAR szNTCsrSchemes[] = TEXT("Control Panel\\Cursor Schemes");
|
|
TCHAR szWinCsrSchemes[] = TEXT("Control Panel\\Cursors\\Schemes");
|
|
TCHAR szSystemRoot[] = TEXT("%SystemRoot%\\System32\\");
|
|
|
|
const TCHAR szWinCursors[] = TEXT("Control Panel\\Cursors");
|
|
const TCHAR szSchemes[] = TEXT("Schemes");
|
|
const TCHAR szDaytonaSchemes[] = REGSTR_PATH_SETUP TEXT("\\Control Panel\\Cursors\\Schemes");
|
|
|
|
#define ID_NONE_SCHEME 0 //
|
|
#define ID_USER_SCHEME 1 // These are the possible values of "Scheme Source" as define for the
|
|
#define ID_OS_SCHEME 2 // mouse pointer applet
|
|
|
|
/***********************************************************************\
|
|
*
|
|
* CONVERSION ROUTINES
|
|
*
|
|
* NOTE: Although ConvertLF16to32 appears to be identical to ConvertLFAtoW
|
|
* they are actually different once compiled: the size of the individual
|
|
* fields for a LOGFONT16 and a LOGFONTA are different.
|
|
*
|
|
\***********************************************************************/
|
|
|
|
void ConvertLF16to32( LPLOGFONTW plfwDst, UNALIGNED LOGFONT16 *plfaSrc ) {
|
|
plfwDst->lfHeight = plfaSrc->lfHeight;
|
|
plfwDst->lfWidth = plfaSrc->lfWidth;
|
|
plfwDst->lfEscapement = plfaSrc->lfEscapement;
|
|
plfwDst->lfOrientation = plfaSrc->lfOrientation;
|
|
plfwDst->lfWeight = plfaSrc->lfWeight;
|
|
plfwDst->lfItalic = plfaSrc->lfItalic;
|
|
plfwDst->lfUnderline = plfaSrc->lfUnderline;
|
|
plfwDst->lfStrikeOut = plfaSrc->lfStrikeOut;
|
|
plfwDst->lfCharSet = plfaSrc->lfCharSet;
|
|
plfwDst->lfOutPrecision = plfaSrc->lfOutPrecision;
|
|
plfwDst->lfClipPrecision = plfaSrc->lfClipPrecision;
|
|
plfwDst->lfQuality = plfaSrc->lfQuality;
|
|
plfwDst->lfPitchAndFamily = plfaSrc->lfPitchAndFamily;
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, plfaSrc->lfFaceName, -1, plfwDst->lfFaceName, ARRAYSIZE(plfwDst->lfFaceName));
|
|
}
|
|
|
|
void ConvertLFAtoW( LPLOGFONTW plfwDst, UNALIGNED LOGFONTA *plfaSrc ) {
|
|
plfwDst->lfHeight = plfaSrc->lfHeight;
|
|
plfwDst->lfWidth = plfaSrc->lfWidth;
|
|
plfwDst->lfEscapement = plfaSrc->lfEscapement;
|
|
plfwDst->lfOrientation = plfaSrc->lfOrientation;
|
|
plfwDst->lfWeight = plfaSrc->lfWeight;
|
|
plfwDst->lfItalic = plfaSrc->lfItalic;
|
|
plfwDst->lfUnderline = plfaSrc->lfUnderline;
|
|
plfwDst->lfStrikeOut = plfaSrc->lfStrikeOut;
|
|
plfwDst->lfCharSet = plfaSrc->lfCharSet;
|
|
plfwDst->lfOutPrecision = plfaSrc->lfOutPrecision;
|
|
plfwDst->lfClipPrecision = plfaSrc->lfClipPrecision;
|
|
plfwDst->lfQuality = plfaSrc->lfQuality;
|
|
plfwDst->lfPitchAndFamily = plfaSrc->lfPitchAndFamily;
|
|
|
|
MultiByteToWideChar(CP_ACP, 0, plfaSrc->lfFaceName, -1, plfwDst->lfFaceName, ARRAYSIZE(plfwDst->lfFaceName));
|
|
}
|
|
|
|
|
|
|
|
void ConvertNCMAtoW( LPNONCLIENTMETRICSW pncmwDst, UNALIGNED NONCLIENTMETRICSA *pncmaSrc ) {
|
|
pncmwDst->cbSize = sizeof(*pncmwDst);
|
|
pncmwDst->iBorderWidth = pncmaSrc->iBorderWidth;
|
|
pncmwDst->iScrollWidth = pncmaSrc->iScrollWidth;
|
|
pncmwDst->iScrollHeight = pncmaSrc->iScrollHeight;
|
|
pncmwDst->iCaptionWidth = pncmaSrc->iCaptionWidth;
|
|
pncmwDst->iCaptionHeight = pncmaSrc->iCaptionHeight;
|
|
pncmwDst->iSmCaptionWidth = pncmaSrc->iSmCaptionWidth;
|
|
pncmwDst->iSmCaptionHeight = pncmaSrc->iSmCaptionHeight;
|
|
pncmwDst->iMenuWidth = pncmaSrc->iMenuWidth;
|
|
pncmwDst->iMenuHeight = pncmaSrc->iMenuHeight;
|
|
|
|
|
|
ConvertLFAtoW( &(pncmwDst->lfCaptionFont), &(pncmaSrc->lfCaptionFont) );
|
|
ConvertLFAtoW( &(pncmwDst->lfSmCaptionFont), &(pncmaSrc->lfSmCaptionFont) );
|
|
ConvertLFAtoW( &(pncmwDst->lfMenuFont), &(pncmaSrc->lfMenuFont) );
|
|
ConvertLFAtoW( &(pncmwDst->lfStatusFont), &(pncmaSrc->lfStatusFont) );
|
|
ConvertLFAtoW( &(pncmwDst->lfMessageFont), &(pncmaSrc->lfMessageFont) );
|
|
}
|
|
|
|
void CvtDeskCPL_Win95ToSUR( void ) {
|
|
HKEY hk = NULL;
|
|
DWORD cchClass, cb, cch, cSubk, cchMaxSubk, cchMaxCls, iVal, cchMaxVName;
|
|
DWORD cbMaxVData, cbSecDes, dwType;
|
|
FILETIME pfLstWr;
|
|
TCHAR szClass[4];
|
|
LONG lRet;
|
|
PVOID pvVData = NULL;
|
|
LPTSTR pszVName = NULL;
|
|
LONG erc;
|
|
FILETIME ftLstWr;
|
|
|
|
// Open the key (Appearence\Schemes)
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, szApprSchemes, 0, KEY_READ | KEY_WRITE, &hk) != ERROR_SUCCESS)
|
|
goto ErrorExit;
|
|
|
|
|
|
cchClass = ARRAYSIZE(szClass);
|
|
erc = RegQueryInfoKey(hk, szClass, &cchClass, NULL, &cSubk, &cchMaxSubk,
|
|
&cchMaxCls, &iVal, &cchMaxVName, &cbMaxVData, &cbSecDes, &ftLstWr);
|
|
|
|
if( erc != ERROR_SUCCESS && erc != ERROR_MORE_DATA)
|
|
goto ErrorExit;
|
|
|
|
cchMaxVName += 1;
|
|
|
|
pszVName = LocalAlloc(LMEM_FIXED, cchMaxVName * SIZEOF(TCHAR));
|
|
pvVData = LocalAlloc(LMEM_FIXED, cbMaxVData);
|
|
|
|
if (pvVData == NULL || pszVName == NULL)
|
|
goto ErrorExit;
|
|
|
|
// for each value in the key
|
|
iVal = 0;
|
|
|
|
for(;;) {
|
|
PSCHEMEDATA16 psda;
|
|
SCHEMEDATAW sdw;
|
|
|
|
cch = cchMaxVName;
|
|
cb = cbMaxVData;
|
|
if( RegEnumValue(hk, iVal++, pszVName, &cch, NULL, &dwType, pvVData, &cb ) != ERROR_SUCCESS )
|
|
break;
|
|
|
|
// check if it has been converted yet
|
|
psda = pvVData;
|
|
if (psda->version != SCHEME_VERSION_16)
|
|
continue;
|
|
|
|
// if not, convert ANSI font names to UNICODE and tag the structure
|
|
// as converted
|
|
sdw.version = SCHEME_VERSION_NT;
|
|
sdw.wDummy = 0;
|
|
CopyMemory(sdw.rgb, psda->rgb, SIZEOF(sdw.rgb));
|
|
ConvertNCMAtoW( &(sdw.ncm), &(psda->ncm) );
|
|
ConvertLF16to32( &(sdw.lfIconTitle), &(psda->lfIconTitle) );
|
|
|
|
// write the new data back out
|
|
RegSetValueEx(hk, pszVName, 0L, dwType, (LPBYTE)&sdw, SIZEOF(sdw));
|
|
}
|
|
|
|
ErrorExit:
|
|
// close the key
|
|
if (hk)
|
|
RegCloseKey(hk);
|
|
|
|
if (pvVData)
|
|
LocalFree(pvVData);
|
|
|
|
if (pszVName)
|
|
LocalFree(pszVName);
|
|
|
|
}
|
|
|
|
#ifdef LATER
|
|
void CvtDeskCPL_DaytonaToSur( void ) {
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// NOTE! These enums MUST be in the same order that the names will appear in the registry string
|
|
enum { arrow,help,appstart,wait,cross,ibeam,pen,no,sizens,sizewe,sizenwse,sizenesw,move,altsel, C_CURSORS } ID_CURSORS;
|
|
|
|
FILEPATH aszCurs[C_CURSORS];
|
|
TCHAR szOut[(C_CURSORS * (MAX_PATH+1)) + 1];
|
|
|
|
void CvtCursorsCPL_DaytonaToSUR( void ) {
|
|
HKEY hkIn = NULL, hkOut = NULL;
|
|
DWORD dwTmp;
|
|
DWORD cchClass;
|
|
LONG erc;
|
|
DWORD dwType;
|
|
DWORD cSubk;
|
|
DWORD cchMaxSubk;
|
|
DWORD cchMaxCls;
|
|
DWORD iVal;
|
|
DWORD cchMaxVName;
|
|
DWORD cbMaxVData;
|
|
DWORD cbSecDes;
|
|
FILETIME ftLstWr;
|
|
DWORD cch;
|
|
DWORD cb;
|
|
TCHAR szClass[4];
|
|
PVOID pvVData = NULL;
|
|
LPTSTR pszVName = NULL;
|
|
|
|
// Open the source registry key (Cursor Schemes)
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, szNTCsrSchemes, 0, KEY_READ, &hkIn) != ERROR_SUCCESS)
|
|
goto ErrorExit;
|
|
|
|
// Open/create the dest registry key (Cursors\Schemes)
|
|
if (RegCreateKeyEx(HKEY_CURRENT_USER, szWinCsrSchemes, 0, TEXT(""), REG_OPTION_NON_VOLATILE,
|
|
KEY_READ | KEY_WRITE, NULL, &hkOut, &dwTmp) != ERROR_SUCCESS) {
|
|
goto ErrorExit;
|
|
}
|
|
|
|
// for each value in the source key
|
|
cchClass = ARRAYSIZE(szClass);
|
|
erc = RegQueryInfoKey(hkIn, szClass, &cchClass, NULL, &cSubk, &cchMaxSubk,
|
|
&cchMaxCls, &iVal, &cchMaxVName, &cbMaxVData, &cbSecDes, &ftLstWr);
|
|
|
|
if( erc != ERROR_SUCCESS && erc != ERROR_MORE_DATA)
|
|
goto ErrorExit;
|
|
|
|
cchMaxVName += 1;
|
|
|
|
pszVName = LocalAlloc(LMEM_FIXED, cchMaxVName * SIZEOF(TCHAR));
|
|
pvVData = LocalAlloc(LMEM_FIXED, cbMaxVData + sizeof(TCHAR));
|
|
|
|
if (pvVData == NULL || pszVName == NULL)
|
|
goto ErrorExit;
|
|
|
|
iVal = 0;
|
|
|
|
for(;;) {
|
|
DWORD cbData;
|
|
LPTSTR pszOut;
|
|
int i;
|
|
|
|
cch = cchMaxVName;
|
|
cb = cbMaxVData;
|
|
|
|
if( RegEnumValue(hkIn, iVal++, pszVName, &cch, NULL, &dwType, pvVData, &cb ) != ERROR_SUCCESS )
|
|
break;
|
|
|
|
// if the name already exists in the new key then skip this one
|
|
if (RegQueryValueEx(hkOut, pszVName, NULL, NULL, NULL, &cbData ) == ERROR_SUCCESS && cbData != 0)
|
|
continue;
|
|
|
|
if (dwType != REG_EXPAND_SZ && dwType != REG_SZ)
|
|
continue;
|
|
|
|
*(TCHAR *)((LPBYTE)pvVData+cb) = TEXT('\0'); // Make sure nul terminated
|
|
|
|
// convert the data to SUR format
|
|
for( i = 0; i < C_CURSORS; i++ ) {
|
|
*aszCurs[i] = TEXT('\0');
|
|
}
|
|
|
|
//arrow,wait,appstart,no,ibeam,cross,ns,ew,nwse,nesw,move
|
|
|
|
_stscanf(pvVData, TEXT("%[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,]"),
|
|
aszCurs[arrow],aszCurs[wait],aszCurs[appstart],aszCurs[no],
|
|
aszCurs[ibeam],aszCurs[cross],aszCurs[sizens],aszCurs[sizewe],
|
|
aszCurs[sizenwse],aszCurs[sizenesw],aszCurs[move]);
|
|
|
|
szOut[0] = TEXT('\0');
|
|
pszOut = szOut;
|
|
|
|
for( i = 0; i < C_CURSORS; i++ ) {
|
|
if (!HasPath(aszCurs[i]))
|
|
pszOut += mystrcpy( pszOut, szSystemRoot, TEXT('\0') );
|
|
|
|
pszOut += mystrcpy( pszOut, aszCurs[i], TEXT('\0') );
|
|
|
|
*pszOut++ = TEXT(',');
|
|
}
|
|
|
|
*(pszOut-1) = TEXT('\0');
|
|
|
|
// write the new data back out
|
|
RegSetValueEx(hkOut, pszVName, 0L, REG_EXPAND_SZ, (LPBYTE)szOut, (DWORD)(sizeof(TCHAR)*(pszOut - szOut)));
|
|
}
|
|
|
|
ErrorExit:
|
|
// close the registry keys
|
|
if (hkIn)
|
|
RegCloseKey(hkIn);
|
|
|
|
if (hkOut)
|
|
RegCloseKey(hkOut);
|
|
|
|
if (pvVData)
|
|
LocalFree(pvVData);
|
|
|
|
if (pszVName)
|
|
LocalFree(pszVName);
|
|
}
|
|
|
|
void FixupCursorSchemePaths( void ) {
|
|
HKEY hk = NULL;
|
|
DWORD cchClass, cb, cch, cSubk, cchMaxSubk, cchMaxCls, iVal, cchMaxVName;
|
|
DWORD cbMaxVData, cbSecDes, dwType;
|
|
FILETIME pfLstWr;
|
|
TCHAR szClass[4];
|
|
LONG lRet;
|
|
PVOID pvVData = NULL;
|
|
LPTSTR pszVName = NULL;
|
|
LONG erc;
|
|
FILETIME ftLstWr;
|
|
|
|
// Open the key (Appearence\Schemes)
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, szWinCsrSchemes, 0, KEY_READ | KEY_WRITE, &hk) != ERROR_SUCCESS)
|
|
goto ErrorExit;
|
|
|
|
|
|
cchClass = ARRAYSIZE(szClass);
|
|
erc = RegQueryInfoKey(hk, szClass, &cchClass, NULL, &cSubk, &cchMaxSubk,
|
|
&cchMaxCls, &iVal, &cchMaxVName, &cbMaxVData, &cbSecDes, &ftLstWr);
|
|
|
|
if( erc != ERROR_SUCCESS && erc != ERROR_MORE_DATA)
|
|
goto ErrorExit;
|
|
|
|
cchMaxVName += 1;
|
|
|
|
DPRINT(( TEXT("cchName:%d cbData:%d\n"), cchMaxVName, cbMaxVData ));
|
|
pszVName = LocalAlloc(LMEM_FIXED, cchMaxVName * SIZEOF(TCHAR));
|
|
pvVData = LocalAlloc(LMEM_FIXED, cbMaxVData + sizeof(TCHAR));
|
|
|
|
if (pvVData == NULL || pszVName == NULL)
|
|
goto ErrorExit;
|
|
|
|
// for each value in the key
|
|
iVal = 0;
|
|
|
|
for(;;) {
|
|
LPTSTR pszIn, pszOut;
|
|
BOOL fFixed;
|
|
TCHAR szTmp[MAX_PATH];
|
|
|
|
cch = cchMaxVName;
|
|
cb = cbMaxVData;
|
|
DPRINT(( TEXT("\n\n>>>>>>>>>>>>>>>>>>>Getting scheme %d "), iVal ));
|
|
if( RegEnumValue(hk, iVal++, pszVName, &cch, NULL, &dwType, pvVData, &cb ) != ERROR_SUCCESS )
|
|
break;
|
|
|
|
if (dwType != REG_EXPAND_SZ && dwType != REG_SZ)
|
|
continue;
|
|
|
|
*(TCHAR *)((LPBYTE)pvVData+cb) = TEXT('\0'); // Make sure nul terminated
|
|
|
|
// check if it has been converted yet
|
|
DPRINT(( TEXT("Scheme : %s = [%s]"), pszVName, pvVData ));
|
|
|
|
fFixed = FALSE;
|
|
pszOut = szOut;
|
|
|
|
pszIn = pvVData;
|
|
pszIn--; // prime pszIn for first comma skip
|
|
|
|
do {
|
|
pszIn++; // skip over comma separator
|
|
pszIn += mystrcpy( szTmp, pszIn, TEXT(',') ); // bump ptr by length of token
|
|
|
|
DPRINT((TEXT("\n\t%s"), szTmp));
|
|
|
|
if (!HasPath(szTmp)) {
|
|
fFixed = TRUE;
|
|
DPRINT((TEXT(" <fixed...")));
|
|
pszOut += mystrcpy( pszOut, szSystemRoot, TEXT('\0') );
|
|
DPRINT((TEXT(">")));
|
|
}
|
|
|
|
pszOut += mystrcpy( pszOut, szTmp, TEXT('\0') );
|
|
|
|
*pszOut++ = TEXT(',');
|
|
|
|
#ifdef SHMG_DBG
|
|
*pszOut = TEXT('\0');
|
|
DPRINT((TEXT("\nszOut so far: '%s'"), szOut ));
|
|
#endif
|
|
} while ( *pszIn );
|
|
|
|
*(pszOut-1) = TEXT('\0');
|
|
|
|
DPRINT((TEXT("\n\n******** Findal szOut: [%s]"), szOut ));
|
|
|
|
// write the new data back out
|
|
if (fFixed) {
|
|
DPRINT((TEXT(" (Saving back to reg)")));
|
|
RegSetValueEx(hk, pszVName, 0L, REG_EXPAND_SZ, (LPBYTE)szOut, (DWORD)(sizeof(TCHAR)*(pszOut - szOut)));
|
|
}
|
|
|
|
}
|
|
|
|
ErrorExit:
|
|
|
|
DPRINT(( TEXT("\n\n **EXITING FN()**\n" )));
|
|
|
|
// close the key
|
|
if (hk)
|
|
RegCloseKey(hk);
|
|
|
|
if (pvVData)
|
|
LocalFree(pvVData);
|
|
|
|
if (pszVName)
|
|
LocalFree(pszVName);
|
|
|
|
|
|
}
|
|
|
|
// this function will remove entries from HKCU\Control Panel\Cursors\Schemes which are identical to
|
|
// schemes found in HKLM\%Current Version%\Control Panel\Cursors\Schemes
|
|
//
|
|
// HKCU\Control Panel\Cursors
|
|
// This key contains the users currently selected cursor scheme
|
|
// HKCU\Control Panel\Cursors "Scheme Source"
|
|
// This is a new key which will be added if not present. The key indicates if the currently
|
|
// select user scheme is user defined or system defined.
|
|
// HKCU\Control Panel\Cursors\Schemes <Scheme name> <file list>
|
|
// This is the location for user defined schemes. If any of these schemes have both the same
|
|
// scheme name and the same file list as a system defined scheme then that key will be
|
|
// removed from the user list. If the currently selected cursor scheme is removed then
|
|
// "Scheme Source" will be updated to reflect the new location.
|
|
// HKLM\%Current Version%\Control Panel\Cursors\Schemes <Scheme name>
|
|
// Under the new optional component model, optional components are installed on a per-machine
|
|
// basis into this location instead of the old per-user basis. This allows floating profiles
|
|
// to use system pointer schemes on multiple machines and simplifies component installation.
|
|
void CvtCursorSchemesToMultiuser( void )
|
|
{
|
|
HKEY hkOldCursors, hkOldSchemes;
|
|
HKEY hkNewSchemes;
|
|
DWORD iSchemeLocation;
|
|
DWORD iType;
|
|
TCHAR szDefaultScheme[MAX_PATH+1];
|
|
const TCHAR szSchemeSource[] = TEXT("Scheme Source");
|
|
SZNODE *pnHead = NULL;
|
|
SZNODE *pnTail = NULL;
|
|
|
|
// open a key to the original cursors location
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, szWinCursors, 0, KEY_ALL_ACCESS, &hkOldCursors) == ERROR_SUCCESS)
|
|
{
|
|
long len = sizeof( szDefaultScheme );
|
|
if (RegQueryValue( hkOldCursors, NULL, szDefaultScheme, &len ) != ERROR_SUCCESS)
|
|
{
|
|
szDefaultScheme[0] = TEXT('\0'); // if the default key isn't set, the user has the default cursors
|
|
}
|
|
|
|
// try to read the value of "Scheme Source"
|
|
len = sizeof( iSchemeLocation );
|
|
if ( RegQueryValueEx( hkOldCursors, szSchemeSource, 0, &iType, (BYTE *)&iSchemeLocation, &len )
|
|
!= ERROR_SUCCESS )
|
|
{
|
|
iSchemeLocation = ID_USER_SCHEME; // if the value isn't there then it's a user scheme
|
|
RegSetValueEx( hkOldCursors, szSchemeSource, 0, REG_DWORD, (BYTE *)&iSchemeLocation,
|
|
sizeof( iSchemeLocation ) );
|
|
}
|
|
|
|
// now open the schemes subkey, this is what we're interested in
|
|
if (RegOpenKeyEx( hkOldCursors, szSchemes, 0, KEY_ALL_ACCESS, &hkOldSchemes ) == ERROR_SUCCESS )
|
|
{
|
|
TCHAR szOldKeyName[MAX_PATH+1];
|
|
TCHAR szOldKeyValue[C_CURSORS*(MAX_PATH+1)+1];
|
|
TCHAR szNewKeyValue[C_CURSORS*(MAX_PATH+1)+1];
|
|
long iLenName; // the length of the name of the old key
|
|
long iLenValue; // the length of the value of the old key
|
|
long iLenNewKey; // the length of the new key's value
|
|
int iIndex;
|
|
|
|
// now we are ready to enum the user defined schemes, but first lets make sure we can
|
|
// open the new location, if we can't open it then we bail out.
|
|
if (RegOpenKeyEx( HKEY_LOCAL_MACHINE, szDaytonaSchemes, 0, KEY_READ, &hkNewSchemes ) != ERROR_SUCCESS )
|
|
goto bailOut;
|
|
DPRINT(( TEXT("Opened key %s"), szDaytonaSchemes ));
|
|
|
|
// now we start reading the new schemes
|
|
for (iIndex = 0;;)
|
|
{
|
|
// read next scheme
|
|
iLenName = ARRAYSIZE(szOldKeyName); // these must be reset each time around
|
|
iLenValue = sizeof( szOldKeyValue );
|
|
if (RegEnumValue( hkOldSchemes, iIndex++, szOldKeyName, &iLenName, NULL, NULL,
|
|
(BYTE *)szOldKeyValue, &iLenValue ) != ERROR_SUCCESS )
|
|
{
|
|
// we fail if we are out of data, which means we're done
|
|
break;
|
|
}
|
|
DPRINT(( TEXT("Opened key: %s\n"), szOldKeyName ));
|
|
|
|
// now we try to find a key with the same name in the new location
|
|
iLenNewKey = sizeof( szNewKeyValue );
|
|
if (RegQueryValueEx( hkNewSchemes, szOldKeyName, 0, NULL, (BYTE *)szNewKeyValue, &iLenNewKey )
|
|
== ERROR_SUCCESS )
|
|
{
|
|
// if the new key exists, compare the values
|
|
DPRINT(( TEXT(" Key exists in HKLM.\n") ));
|
|
DPRINT(( TEXT(" Old=%s\n New=%s\n"), szOldKeyValue, szNewKeyValue ));
|
|
|
|
if ( lstrcmpi(szOldKeyValue, szNewKeyValue) == 0 )
|
|
{
|
|
// if the values are the same, see if this is the currently selected scheme
|
|
if ( lstrcmp(szOldKeyName, szDefaultScheme) == 0 )
|
|
{
|
|
// since we're going to delete the user defined scheme and the system scheme
|
|
// has the same name and value we simply change the value of "Scheme Source"
|
|
iSchemeLocation = ID_OS_SCHEME;
|
|
RegSetValueEx( hkOldCursors, szSchemeSource, 0, REG_DWORD, (unsigned char *)&iSchemeLocation,
|
|
sizeof( iSchemeLocation ) );
|
|
}
|
|
// remove the user key
|
|
DPRINT(( TEXT(" Tagging user key for removal.\n") ));
|
|
if ( pnTail == NULL )
|
|
{
|
|
pnTail = (SZNODE *)LocalAlloc( LMEM_FIXED, sizeof( SZNODE ) );
|
|
pnHead = pnTail;
|
|
if (!pnTail) // not enough memory
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
pnTail->next = (SZNODE *)LocalAlloc( LMEM_FIXED, sizeof( SZNODE ) );
|
|
pnTail = pnTail->next;
|
|
if (!pnTail) // not enough memory
|
|
break;
|
|
}
|
|
pnTail->next = NULL;
|
|
pnTail->psz = LocalAlloc( LMEM_FIXED, sizeof( szOldKeyName ) );
|
|
if (!pnTail->psz) // not enough memory
|
|
break;
|
|
lstrcpy( pnTail->psz, szOldKeyName );
|
|
}
|
|
}
|
|
}
|
|
|
|
// If we tagged any keys for deletion they will be stored in our list
|
|
while (pnHead)
|
|
{
|
|
if (pnHead->psz) // if we ran out of memory, this could be NULL
|
|
{
|
|
DPRINT(( TEXT("Deleting key %s\n"), pnHead->psz ));
|
|
RegDeleteValue( hkOldSchemes, pnHead->psz );
|
|
LocalFree( pnHead->psz ); // Clean up the list as we go
|
|
}
|
|
pnTail = pnHead;
|
|
pnHead = pnHead->next;
|
|
LocalFree( pnTail ); // Clean up as we go
|
|
}
|
|
|
|
// now we are finished removing the duplicate keys, clean up and exit
|
|
RegCloseKey( hkNewSchemes );
|
|
bailOut:
|
|
RegCloseKey( hkOldSchemes );
|
|
}
|
|
// else: no schemes are defined for current user so there's nothing to do
|
|
|
|
RegCloseKey( hkOldCursors );
|
|
}
|
|
// else: no cursor key exists for current user so there's nothing to do
|
|
}
|