2029 lines
41 KiB
C
2029 lines
41 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1996 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
userdiff.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains routines for updating the userdifr hive.
|
|||
|
|
|||
|
In the following, the list of changes to be applied when a user
|
|||
|
logs on after an upgrade will be called UserRun. UserRun is
|
|||
|
developed from three sources:
|
|||
|
|
|||
|
1) The UserRun generated on the last upgrade. This forms the
|
|||
|
basis for this upgrade's UserRun.
|
|||
|
|
|||
|
2) The list of changes shipped with the system. Call this
|
|||
|
UserShip. The changes from all build numbers that are
|
|||
|
present in UserShip but not in UserRun are copied into
|
|||
|
UserRun. (Note that if a build number is already present
|
|||
|
in UserRun, we don't copy the UserShip changes. This
|
|||
|
means that changes cannot be made retroactively in UserShip.)
|
|||
|
|
|||
|
3) Changes made during the current upgrade. These changes are
|
|||
|
detected at run time (see watch.c). All changes detected
|
|||
|
during the upgrade are added to UserRun.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Chuck Lenzmeier (chuckl)
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "setupp.h"
|
|||
|
#pragma hdrstop
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Debugging aids.
|
|||
|
//
|
|||
|
|
|||
|
#if USERDIFF_DEBUG
|
|||
|
|
|||
|
DWORD UserdiffDebugLevel = 0;
|
|||
|
#define dprintf(_lvl_,_x_) if ((_lvl_) <= UserdiffDebugLevel) DbgPrint _x_
|
|||
|
|
|||
|
#else
|
|||
|
|
|||
|
#define dprintf(_lvl_,_x_)
|
|||
|
|
|||
|
#endif
|
|||
|
|
|||
|
//
|
|||
|
// Macro to calculate length of string including terminator.
|
|||
|
//
|
|||
|
|
|||
|
#define SZLEN(_wcs) ((wcslen(_wcs) + 1) * sizeof(WCHAR))
|
|||
|
|
|||
|
//
|
|||
|
// Context record used in this module to track registry state.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _USERRUN_CONTEXT {
|
|||
|
BOOL UserRunLoaded;
|
|||
|
HKEY UserRunKey;
|
|||
|
HKEY BuildKey;
|
|||
|
HKEY FilesKey;
|
|||
|
HKEY HiveKey;
|
|||
|
ULONG FilesIndex;
|
|||
|
ULONG HiveIndex;
|
|||
|
HKEY UserShipKey;
|
|||
|
} USERRUN_CONTEXT, *PUSERRUN_CONTEXT;
|
|||
|
|
|||
|
//
|
|||
|
// Context record used in MakeUserRunEnumRoutine.
|
|||
|
//
|
|||
|
|
|||
|
typedef struct _KEY_ENUM_CONTEXT {
|
|||
|
PUSERRUN_CONTEXT UserRunContext;
|
|||
|
PWCH CurrentPath;
|
|||
|
} KEY_ENUM_CONTEXT, *PKEY_ENUM_CONTEXT;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Forward declaration of local subroutines.
|
|||
|
//
|
|||
|
|
|||
|
DWORD
|
|||
|
LoadUserRun (
|
|||
|
OUT PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH UserRunPath
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MergeUserShipIntoUserRun (
|
|||
|
IN OUT PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH UserShipPath
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
CreateAndLoadUserRun (
|
|||
|
OUT PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH UserRunPath
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
OpenUserRunKeys (
|
|||
|
IN OUT PUSERRUN_CONTEXT Context
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
UnloadUserRun (
|
|||
|
IN OUT PUSERRUN_CONTEXT Context
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
CheckUserShipKey (
|
|||
|
IN PVOID Context,
|
|||
|
IN DWORD KeyNameLength,
|
|||
|
IN PWCH KeyName
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeUserRunEnumRoutine (
|
|||
|
IN PVOID Context,
|
|||
|
IN PWATCH_ENTRY Entry
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeAddDirectory (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeAddValue (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeDeleteValue (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeAddKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeDeleteKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
AddDirectory (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH FullPath,
|
|||
|
IN PWCH Path
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
AddKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Path
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
AddValueDuringAddKey (
|
|||
|
IN PVOID Context,
|
|||
|
IN DWORD ValueNameLength,
|
|||
|
IN PWCH ValueName,
|
|||
|
IN DWORD ValueType,
|
|||
|
IN PVOID ValueData,
|
|||
|
IN DWORD ValueDataLength
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
AddKeyDuringAddKey (
|
|||
|
IN PVOID Context,
|
|||
|
IN DWORD KeyNameLength,
|
|||
|
IN PWCH KeyName
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
AddValue (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH KeyName OPTIONAL,
|
|||
|
IN PWCH ValueName,
|
|||
|
IN DWORD ValueType,
|
|||
|
IN PVOID ValueData,
|
|||
|
IN DWORD ValueDataLength
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
CreateUserRunSimpleFileKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN DWORD Action,
|
|||
|
IN PWCH Name
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
CreateUserRunKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN BOOL IsFileKey,
|
|||
|
OUT PHKEY NewKeyHandle
|
|||
|
);
|
|||
|
|
|||
|
DWORD
|
|||
|
QueryValue (
|
|||
|
IN PWCH KeyName OPTIONAL,
|
|||
|
IN PWCH ValueName,
|
|||
|
OUT PDWORD ValueType,
|
|||
|
OUT PVOID *ValueData,
|
|||
|
OUT PDWORD ValueDataLength
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
SzToMultiSz (
|
|||
|
IN PWCH Sz,
|
|||
|
OUT PWCH *MultiSz,
|
|||
|
OUT PDWORD MultiSzLength
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeUserdifr (
|
|||
|
IN PVOID WatchHandle
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Creates the UserRun hive based on the changes made to the current user's
|
|||
|
profile directory and the HKEY_CURRENT_USER key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
WatchHandle - supplies the handle returned by WatchStart.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY userrunKey;
|
|||
|
USERRUN_CONTEXT context;
|
|||
|
DWORD error;
|
|||
|
DWORD disposition;
|
|||
|
WCHAR userRunPath[MAX_PATH + 1];
|
|||
|
WCHAR userShipPath[MAX_PATH + 1];
|
|||
|
|
|||
|
//
|
|||
|
// Merge UserShip with UserRun.
|
|||
|
//
|
|||
|
// If both UserRun and UserShip exist, merge into UserRun those build
|
|||
|
// keys from UserShip that do no exist in UserRun.
|
|||
|
//
|
|||
|
// If the UserRun hive file doesn't exist, this means that no
|
|||
|
// upgrade has ever been run on this machine. Copy the UserShip
|
|||
|
// hive file into place as UserRun. This effectively does the
|
|||
|
// registry merge by using a file copy.
|
|||
|
//
|
|||
|
// In the unlikely event that neither UserRun nor UserShip exists,
|
|||
|
// create an empty UserRun.
|
|||
|
//
|
|||
|
|
|||
|
//
|
|||
|
// Initialize the context record.
|
|||
|
//
|
|||
|
|
|||
|
context.UserRunLoaded = FALSE;
|
|||
|
context.UserRunKey = NULL;
|
|||
|
context.BuildKey = NULL;
|
|||
|
context.FilesKey = NULL;
|
|||
|
context.HiveKey = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// Enable SeBackupPrivilege and SeRestorePrivilege.
|
|||
|
//
|
|||
|
|
|||
|
pSetupEnablePrivilege( SE_BACKUP_NAME, TRUE );
|
|||
|
pSetupEnablePrivilege( SE_RESTORE_NAME, TRUE );
|
|||
|
|
|||
|
//
|
|||
|
// Check to see whether UserRun exists.
|
|||
|
//
|
|||
|
|
|||
|
error = GetWindowsDirectory( userRunPath, MAX_PATH );
|
|||
|
if( error == 0) {
|
|||
|
MYASSERT(FALSE);
|
|||
|
return ERROR_PATH_NOT_FOUND;
|
|||
|
}
|
|||
|
wcscat( userRunPath, TEXT("\\") );
|
|||
|
wcscpy( userShipPath, userRunPath );
|
|||
|
wcscat( userRunPath, USERRUN_PATH );
|
|||
|
wcscat( userShipPath, USERSHIP_PATH );
|
|||
|
|
|||
|
if ( FileExists( userRunPath, NULL ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// UserRun exists. Load it into the registry. Check to see whether
|
|||
|
// UserShip exists.
|
|||
|
//
|
|||
|
|
|||
|
error = LoadUserRun( &context, userRunPath );
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
if ( FileExists( userShipPath, NULL ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// UserShip also exists. Merge UserShip into UserRun.
|
|||
|
//
|
|||
|
|
|||
|
error = MergeUserShipIntoUserRun( &context, userShipPath );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// UserShip doesn't exist. Just use the existing UserRun.
|
|||
|
//
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// UserRun doesn't exist. If UserShip exists, just copy the UserShip
|
|||
|
// hive file into place as UserRun. If neither one exists, create
|
|||
|
// an empty UserRun.
|
|||
|
//
|
|||
|
|
|||
|
if ( FileExists( userShipPath, NULL ) ) {
|
|||
|
|
|||
|
//
|
|||
|
// UserShip exists. Copy UserShip into UserRun.
|
|||
|
//
|
|||
|
|
|||
|
if ( !CopyFile( userShipPath, userRunPath, TRUE ) ) {
|
|||
|
error = GetLastError();
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Load the new UserRun.
|
|||
|
//
|
|||
|
|
|||
|
error = LoadUserRun( &context, userRunPath );
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// UserShip doesn't exist. Create an empty UserRun.
|
|||
|
//
|
|||
|
|
|||
|
error = CreateAndLoadUserRun( &context, userRunPath );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add changes from this upgrade to UserRun.
|
|||
|
//
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
error = OpenUserRunKeys( &context );
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = WatchEnum( WatchHandle, &context, MakeUserRunEnumRoutine );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Unload the UserRun hive.
|
|||
|
//
|
|||
|
|
|||
|
UnloadUserRun( &context );
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // MakeUserdifr
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
LoadUserRun (
|
|||
|
OUT PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH UserRunPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Loads the UserRun hive into the registry and opens the root key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
UserRunPath - supplies the path to the UserRun hive file.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD error;
|
|||
|
|
|||
|
//
|
|||
|
// Load the UserRun hive into the registry.
|
|||
|
//
|
|||
|
|
|||
|
error = RegLoadKey( HKEY_USERS, USERRUN_KEY, UserRunPath );
|
|||
|
if ( error != NO_ERROR ) {
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
Context->UserRunLoaded = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// Open the UserRun root.
|
|||
|
//
|
|||
|
|
|||
|
error = RegOpenKeyEx( HKEY_USERS,
|
|||
|
USERRUN_KEY,
|
|||
|
0,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&Context->UserRunKey );
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // LoadUserRun
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MergeUserShipIntoUserRun (
|
|||
|
IN OUT PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH UserShipPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Merges the UserShip hive into the UserRun hive.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
UserShipPath - supplies the path to the UserShip file.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD error;
|
|||
|
DWORD disposition;
|
|||
|
|
|||
|
//
|
|||
|
// Load the UserShip hive into the registry.
|
|||
|
//
|
|||
|
|
|||
|
error = RegLoadKey( HKEY_USERS, USERSHIP_KEY, UserShipPath );
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// Open the UserShip root.
|
|||
|
//
|
|||
|
|
|||
|
error = RegOpenKeyEx( HKEY_USERS,
|
|||
|
USERSHIP_KEY,
|
|||
|
0,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
&Context->UserShipKey );
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate the build number keys in UserShip, looking for
|
|||
|
// builds that aren't represented in UserRun.
|
|||
|
//
|
|||
|
|
|||
|
error = EnumerateKey( Context->UserShipKey,
|
|||
|
Context,
|
|||
|
NULL, // don't enumerate values
|
|||
|
CheckUserShipKey );
|
|||
|
|
|||
|
//
|
|||
|
// Close the UserShip root.
|
|||
|
//
|
|||
|
|
|||
|
RegCloseKey( Context->UserShipKey );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Unload the UserShip hive.
|
|||
|
//
|
|||
|
|
|||
|
RegUnLoadKey( HKEY_USERS, USERSHIP_KEY );
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // MergeUserShipIntoUserRun
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
CreateAndLoadUserRun (
|
|||
|
OUT PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH UserRunPath
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Create a new UserRun hive and load it into the registry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
UserRunPath - supplies the path to the UserRun file.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD error;
|
|||
|
DWORD disposition;
|
|||
|
HKEY userRunKey;
|
|||
|
|
|||
|
//
|
|||
|
// Create the UserRun key under HKEY_CURRENT_USER.
|
|||
|
//
|
|||
|
// NOTE: Trying to create this under HKEY_USERS doesn't work.
|
|||
|
//
|
|||
|
|
|||
|
error = RegCreateKeyEx( HKEY_CURRENT_USER,
|
|||
|
USERRUN_KEY,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
NULL,
|
|||
|
&userRunKey,
|
|||
|
&disposition );
|
|||
|
if ( error != NO_ERROR ) {
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Save the newly created UserRun key to a hive file.
|
|||
|
//
|
|||
|
|
|||
|
error = RegSaveKey( userRunKey,
|
|||
|
UserRunPath,
|
|||
|
NULL );
|
|||
|
|
|||
|
//
|
|||
|
// Close and delete the UserRun key.
|
|||
|
//
|
|||
|
|
|||
|
RegCloseKey( userRunKey );
|
|||
|
|
|||
|
RegDeleteKey( HKEY_CURRENT_USER, USERRUN_KEY );
|
|||
|
|
|||
|
//
|
|||
|
// Now load UserRun back into the registry.
|
|||
|
//
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = LoadUserRun( Context, UserRunPath );
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // CreateAndLoadUserRun
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
OpenUserRunKeys (
|
|||
|
IN OUT PUSERRUN_CONTEXT Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Opens the core keys in the UserRun hive.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD error;
|
|||
|
DWORD disposition;
|
|||
|
OSVERSIONINFO versionInfo;
|
|||
|
WCHAR buildNumber[6];
|
|||
|
|
|||
|
//
|
|||
|
// Get the current build number.
|
|||
|
//
|
|||
|
|
|||
|
versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
|||
|
|
|||
|
if ( !GetVersionEx( &versionInfo ) ) {
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
|
|||
|
wsprintf( buildNumber, TEXT("%d"), LOWORD(versionInfo.dwBuildNumber) );
|
|||
|
|
|||
|
//
|
|||
|
// Open/create a subkey for the current build.
|
|||
|
//
|
|||
|
|
|||
|
error = RegCreateKeyEx( Context->UserRunKey,
|
|||
|
buildNumber,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
NULL,
|
|||
|
&Context->BuildKey,
|
|||
|
&disposition );
|
|||
|
if ( error != NO_ERROR ) {
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Create a Files subkey.
|
|||
|
//
|
|||
|
|
|||
|
error = RegCreateKeyEx( Context->BuildKey,
|
|||
|
FILES_KEY,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
NULL,
|
|||
|
&Context->FilesKey,
|
|||
|
&disposition );
|
|||
|
if ( error != NO_ERROR ) {
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Create a Hive subkey.
|
|||
|
//
|
|||
|
|
|||
|
error = RegCreateKeyEx( Context->BuildKey,
|
|||
|
HIVE_KEY,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
NULL,
|
|||
|
&Context->HiveKey,
|
|||
|
&disposition );
|
|||
|
if ( error != NO_ERROR ) {
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set the FilesIndex and HiveIndex so that we append to whatever
|
|||
|
// information already exists for the current build.
|
|||
|
//
|
|||
|
|
|||
|
error = RegQueryInfoKey( Context->FilesKey,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&Context->FilesIndex,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL );
|
|||
|
if ( error != NO_ERROR ) {
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
error = RegQueryInfoKey( Context->HiveKey,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
&Context->HiveIndex,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL,
|
|||
|
NULL );
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // OpenUserRunKeys
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
UnloadUserRun (
|
|||
|
IN OUT PUSERRUN_CONTEXT Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Unloads the UserRun hive from the registry.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
//
|
|||
|
// Close the core keys, if they are open.
|
|||
|
//
|
|||
|
|
|||
|
if ( Context->HiveKey != NULL ) {
|
|||
|
RegCloseKey( Context->HiveKey );
|
|||
|
}
|
|||
|
if ( Context->FilesKey != NULL ) {
|
|||
|
RegCloseKey( Context->FilesKey );
|
|||
|
}
|
|||
|
if ( Context->BuildKey != NULL ) {
|
|||
|
RegCloseKey( Context->BuildKey );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Close the root key, if it is open.
|
|||
|
//
|
|||
|
|
|||
|
if ( Context->UserRunKey != NULL ) {
|
|||
|
RegCloseKey( Context->UserRunKey );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Unload the hive, if it has been loaded.
|
|||
|
//
|
|||
|
|
|||
|
if ( Context->UserRunLoaded ) {
|
|||
|
RegUnLoadKey( HKEY_USERS, USERRUN_KEY );
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // UnloadUserRun
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
CheckUserShipKey (
|
|||
|
IN PVOID Context,
|
|||
|
IN DWORD KeyNameLength,
|
|||
|
IN PWCH KeyName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Checks an enumerated key in the UserShip hive to see if a corresponding
|
|||
|
key is present in the UserRun hive. If not, copies the key from UserShip
|
|||
|
into UserRun.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
KeyNameLength - length in characters of key name.
|
|||
|
|
|||
|
KeyName - pointer to name of key.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUSERRUN_CONTEXT context = Context;
|
|||
|
|
|||
|
DWORD error;
|
|||
|
DWORD disposition;
|
|||
|
HKEY userRunBuildKey;
|
|||
|
HKEY userShipBuildKey;
|
|||
|
WCHAR path[MAX_PATH + 1];
|
|||
|
|
|||
|
//
|
|||
|
// We have the name of a key in UserShip. Try to open the
|
|||
|
// corresponding key in UserRun.
|
|||
|
//
|
|||
|
|
|||
|
error = RegCreateKeyEx( context->UserRunKey,
|
|||
|
KeyName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_READ | KEY_WRITE,
|
|||
|
NULL,
|
|||
|
&userRunBuildKey,
|
|||
|
&disposition );
|
|||
|
if ( error != NO_ERROR ) {
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// No error occurred. The key was either opened or created.
|
|||
|
//
|
|||
|
|
|||
|
if ( disposition == REG_OPENED_EXISTING_KEY ) {
|
|||
|
|
|||
|
//
|
|||
|
// The key already existed in UserRun. We assume that it already
|
|||
|
// contains the information that is in UserShip.
|
|||
|
//
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// The key didn't exist in UserRun. Copy the key from UserShip
|
|||
|
// into UserRun. This is done by saving the UserShip key to
|
|||
|
// a file, then restoring the file back under the UserRun key.
|
|||
|
//
|
|||
|
// Note that the copy operation will fail if the file already
|
|||
|
// exists.
|
|||
|
//
|
|||
|
|
|||
|
error = RegOpenKeyEx( context->UserShipKey,
|
|||
|
KeyName,
|
|||
|
0,
|
|||
|
KEY_READ,
|
|||
|
&userShipBuildKey );
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
GetWindowsDirectory( path, MAX_PATH );
|
|||
|
wcscat( path, TEXT("\\") );
|
|||
|
wcscat( path, USERTMP_PATH );
|
|||
|
|
|||
|
error = RegSaveKey( userShipBuildKey,
|
|||
|
path,
|
|||
|
NULL );
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
error = RegRestoreKey( userRunBuildKey,
|
|||
|
path,
|
|||
|
0 );
|
|||
|
|
|||
|
DeleteFile( path );
|
|||
|
}
|
|||
|
|
|||
|
RegCloseKey( userShipBuildKey );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Close the UserRun key.
|
|||
|
//
|
|||
|
|
|||
|
RegCloseKey( userRunBuildKey );
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // CheckUserShipKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeUserRunEnumRoutine (
|
|||
|
IN PVOID Context,
|
|||
|
IN PWATCH_ENTRY Entry
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
EnumRoutine for the MakeUserdifr operation. Calls the appropriate
|
|||
|
processing routine based on the entry type (file/directory/key/value)
|
|||
|
and the change type (changed, new, deleted).
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to WatchEnum.
|
|||
|
|
|||
|
Entry - description of the changed entry.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PUSERRUN_CONTEXT context = Context;
|
|||
|
DWORD index;
|
|||
|
HKEY newKey;
|
|||
|
DWORD error;
|
|||
|
DWORD dword;
|
|||
|
|
|||
|
//
|
|||
|
// Call the appropriate processing routine.
|
|||
|
//
|
|||
|
|
|||
|
switch ( Entry->EntryType ) {
|
|||
|
|
|||
|
case WATCH_DIRECTORY:
|
|||
|
|
|||
|
switch ( Entry->ChangeType ) {
|
|||
|
|
|||
|
case WATCH_NEW:
|
|||
|
dprintf( 1, ("New directory %ws\n", Entry->Name) );
|
|||
|
error = MakeAddDirectory( Context, Entry->Name );
|
|||
|
break;
|
|||
|
|
|||
|
case WATCH_DELETED:
|
|||
|
dprintf( 1, ("Deleted directory %ws\n", Entry->Name) );
|
|||
|
error = CreateUserRunSimpleFileKey( Context, 2, Entry->Name );
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
error = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case WATCH_FILE:
|
|||
|
|
|||
|
switch ( Entry->ChangeType ) {
|
|||
|
|
|||
|
case WATCH_NEW:
|
|||
|
case WATCH_CHANGED:
|
|||
|
dprintf( 1, ("New or changed file %ws\n", Entry->Name) );
|
|||
|
error = CreateUserRunSimpleFileKey( Context, 3, Entry->Name );
|
|||
|
break;
|
|||
|
|
|||
|
case WATCH_DELETED:
|
|||
|
dprintf( 1, ("Deleted file %ws\n", Entry->Name) );
|
|||
|
error = CreateUserRunSimpleFileKey( Context, 4, Entry->Name );
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
error = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case WATCH_KEY:
|
|||
|
switch ( Entry->ChangeType ) {
|
|||
|
|
|||
|
case WATCH_NEW:
|
|||
|
dprintf( 1, ("New key %ws\n", Entry->Name) );
|
|||
|
error = MakeAddKey( Context, Entry->Name );
|
|||
|
break;
|
|||
|
|
|||
|
case WATCH_DELETED:
|
|||
|
dprintf( 1, ("Deleted key %ws\n", Entry->Name) );
|
|||
|
error = MakeDeleteKey( Context, Entry->Name );
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
error = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
case WATCH_VALUE:
|
|||
|
|
|||
|
switch ( Entry->ChangeType ) {
|
|||
|
|
|||
|
case WATCH_NEW:
|
|||
|
case WATCH_CHANGED:
|
|||
|
dprintf( 1, ("New or changed value %ws\n", Entry->Name) );
|
|||
|
error = MakeAddValue( Context, Entry->Name );
|
|||
|
break;
|
|||
|
|
|||
|
case WATCH_DELETED:
|
|||
|
dprintf( 1, ("Deleted value %ws\n", Entry->Name) );
|
|||
|
error = MakeDeleteValue( Context, Entry->Name );
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
error = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
|
|||
|
error = ERROR_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // MakeUserRunEnumRoutine
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeAddDirectory (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds entries to the UserRun hive for a new directory.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to WatchEnum.
|
|||
|
|
|||
|
Name - name of new directory (relative to root of watched tree).
|
|||
|
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
WCHAR fullpath[MAX_PATH + 1];
|
|||
|
PWCH path;
|
|||
|
BOOL ok;
|
|||
|
|
|||
|
//
|
|||
|
// Get the full path to the new directory. "fullpath" is the full path;
|
|||
|
// "path" is just this directory.
|
|||
|
//
|
|||
|
|
|||
|
ok = GetSpecialFolderPath ( CSIDL_PROGRAMS, fullpath );
|
|||
|
if ( !ok ) {
|
|||
|
return GetLastError();
|
|||
|
}
|
|||
|
wcscat( fullpath, TEXT("\\") );
|
|||
|
path = fullpath + wcslen(fullpath);
|
|||
|
wcscpy( path, Name );
|
|||
|
|
|||
|
//
|
|||
|
// Call AddDirectory to do the recursive work.
|
|||
|
//
|
|||
|
|
|||
|
return AddDirectory( Context, fullpath, path );
|
|||
|
|
|||
|
} // MakeAddDirectory
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeAddValue (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds an entry to the UserRun hive for a new value.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to WatchEnum.
|
|||
|
|
|||
|
Name - name of new value (relative to HKEY_CURRENT_USER).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY newKey;
|
|||
|
PWCH keyName;
|
|||
|
PWCH valueName;
|
|||
|
PWCH splitPoint;
|
|||
|
DWORD valueType;
|
|||
|
PVOID valueData;
|
|||
|
DWORD valueDataLength;
|
|||
|
DWORD error;
|
|||
|
DWORD dword;
|
|||
|
|
|||
|
//
|
|||
|
// Split the name into key and value portions.
|
|||
|
//
|
|||
|
|
|||
|
splitPoint = wcsrchr( Name, TEXT('\\') );
|
|||
|
if ( splitPoint != NULL ) {
|
|||
|
keyName = Name;
|
|||
|
valueName = splitPoint + 1;
|
|||
|
*splitPoint = 0;
|
|||
|
} else {
|
|||
|
keyName = NULL;
|
|||
|
valueName = Name;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query the value data.
|
|||
|
//
|
|||
|
|
|||
|
valueData = NULL;
|
|||
|
error = QueryValue( keyName, valueName, &valueType, &valueData, &valueDataLength );
|
|||
|
|
|||
|
//
|
|||
|
// Add an entry for the value.
|
|||
|
//
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = AddValue( Context, keyName, valueName, valueType, valueData, valueDataLength );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the value data buffer allocated by QueryValue.
|
|||
|
//
|
|||
|
|
|||
|
if ( valueData != NULL ) {
|
|||
|
MyFree( valueData );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Restore the input value name string.
|
|||
|
//
|
|||
|
|
|||
|
if ( splitPoint != NULL ) {
|
|||
|
*splitPoint = TEXT('\\');
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // MakeAddValue
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeDeleteValue (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds an entry to the UserRun hive for a deleted value.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to WatchEnum.
|
|||
|
|
|||
|
Name - name of deleted value (relative to HKEY_CURRENT_USER).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY newKey;
|
|||
|
PWCH keyName;
|
|||
|
PWCH valueName;
|
|||
|
PWCH valueNames;
|
|||
|
PWCH splitPoint;
|
|||
|
DWORD valueNamesLength;
|
|||
|
DWORD error;
|
|||
|
DWORD dword;
|
|||
|
|
|||
|
error = NO_ERROR;
|
|||
|
|
|||
|
//
|
|||
|
// Split the name into key and value portions. Create a MULTI_SZ
|
|||
|
// version of the deleted name (to match userdiff format).
|
|||
|
//
|
|||
|
|
|||
|
splitPoint = wcsrchr( Name, TEXT('\\') );
|
|||
|
if ( splitPoint != NULL ) {
|
|||
|
keyName = Name;
|
|||
|
valueName = splitPoint + 1;
|
|||
|
*splitPoint = 0;
|
|||
|
} else {
|
|||
|
keyName = NULL;
|
|||
|
valueName = Name;
|
|||
|
}
|
|||
|
|
|||
|
SzToMultiSz( valueName, &valueNames, &valueNamesLength );
|
|||
|
if ( valueNames == NULL ) {
|
|||
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Create an entry key and popuplate it.
|
|||
|
//
|
|||
|
|
|||
|
newKey = NULL;
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = CreateUserRunKey( Context, FALSE, &newKey );
|
|||
|
}
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
dword = 4;
|
|||
|
error = RegSetValueEx( newKey, ACTION_VALUE, 0, REG_DWORD, (PBYTE)&dword, sizeof(DWORD) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, KEYNAME_VALUE, 0, REG_SZ, (PBYTE)keyName, SZLEN(keyName) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, VALUENAMES_VALUE, 0, REG_MULTI_SZ, (PBYTE)valueNames, valueNamesLength );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
if ( *valueNames == 0 ) {
|
|||
|
dword = 1;
|
|||
|
error = RegSetValueEx( newKey, FLAGS_VALUE, 0, REG_DWORD, (PBYTE)&dword, sizeof(DWORD) );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( newKey != NULL ) {
|
|||
|
RegCloseKey( newKey );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the buffer allocated by SzToMultiSz.
|
|||
|
//
|
|||
|
|
|||
|
if ( valueNames != NULL ) {
|
|||
|
MyFree( valueNames );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Restore the input value name string.
|
|||
|
//
|
|||
|
|
|||
|
if ( splitPoint != NULL ) {
|
|||
|
*splitPoint = TEXT('\\');
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // MakeDeleteValue
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeAddKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds entries to the UserRun hive for a new key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to WatchEnum.
|
|||
|
|
|||
|
Name - name of new key (relative to HKEY_CURRENT_USER).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
WCHAR path[MAX_PATH + 1];
|
|||
|
|
|||
|
//
|
|||
|
// Copy the key name into a large buffer and call AddKey to do the
|
|||
|
// recursive work.
|
|||
|
//
|
|||
|
|
|||
|
wcscpy( path, Name );
|
|||
|
return AddKey( Context, path );
|
|||
|
|
|||
|
} // MakeAddKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
MakeDeleteKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Name
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds an entry to the UserRun hive for a deleted key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to WatchEnum.
|
|||
|
|
|||
|
Name - name of deleted key (relative to HKEY_CURRENT_USER).
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY newKey;
|
|||
|
DWORD error;
|
|||
|
DWORD dword;
|
|||
|
|
|||
|
//
|
|||
|
// Create an entry key and popuplate it.
|
|||
|
//
|
|||
|
|
|||
|
newKey = NULL;
|
|||
|
error = CreateUserRunKey( Context, FALSE, &newKey );
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
dword = 2;
|
|||
|
error = RegSetValueEx( newKey, ACTION_VALUE, 0, REG_DWORD, (PBYTE)&dword, sizeof(DWORD) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, KEYNAME_VALUE, 0, REG_SZ, (PBYTE)Name, SZLEN(Name) );
|
|||
|
}
|
|||
|
|
|||
|
if ( newKey != NULL ) {
|
|||
|
RegCloseKey( newKey );
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // MakeDeleteKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
AddDirectory (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH FullPath,
|
|||
|
IN PWCH Path
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Recursively adds entries to the UserRun hive for a new directory
|
|||
|
and its subtree.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to WatchEnum.
|
|||
|
|
|||
|
FullPath - full path to directory.
|
|||
|
|
|||
|
Path - path to directory relative to root of watched directory.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY newKey;
|
|||
|
DWORD error;
|
|||
|
DWORD dword;
|
|||
|
HANDLE findHandle;
|
|||
|
WIN32_FIND_DATA fileData;
|
|||
|
BOOL ok;
|
|||
|
|
|||
|
//
|
|||
|
// Create an entry key for the directory and popuplate it.
|
|||
|
//
|
|||
|
|
|||
|
newKey = NULL;
|
|||
|
error = CreateUserRunKey( Context, TRUE, &newKey );
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
dword = 1;
|
|||
|
error = RegSetValueEx( newKey, ACTION_VALUE, 0, REG_DWORD, (PBYTE)&dword, sizeof(DWORD) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, ITEM_VALUE, 0, REG_SZ, (PBYTE)Path, SZLEN(Path) );
|
|||
|
}
|
|||
|
|
|||
|
if ( newKey != NULL ) {
|
|||
|
RegCloseKey( newKey );
|
|||
|
}
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// Search the directory and add file and directory entries.
|
|||
|
//
|
|||
|
|
|||
|
wcscat( Path, TEXT("\\*") );
|
|||
|
findHandle = FindFirstFile( FullPath, &fileData );
|
|||
|
Path[wcslen(Path) - 2] = 0;
|
|||
|
|
|||
|
if ( findHandle != INVALID_HANDLE_VALUE ) {
|
|||
|
|
|||
|
do {
|
|||
|
|
|||
|
//
|
|||
|
// Append the name of the current directory entry to the path.
|
|||
|
//
|
|||
|
|
|||
|
wcscat( Path, TEXT("\\") );
|
|||
|
wcscat( Path, fileData.cFileName );
|
|||
|
|
|||
|
//
|
|||
|
// If the current entry is a file, add an entry in UserRun
|
|||
|
// for it. If the current entry is a directory, call
|
|||
|
// AddDirectory recursively to process it.
|
|||
|
//
|
|||
|
|
|||
|
if ( FlagOff(fileData.dwFileAttributes, FILE_ATTRIBUTE_DIRECTORY) ) {
|
|||
|
error = CreateUserRunSimpleFileKey( Context, 3, Path );
|
|||
|
} else if ((wcscmp(fileData.cFileName,TEXT(".")) != 0) &&
|
|||
|
(wcscmp(fileData.cFileName,TEXT("..")) != 0)) {
|
|||
|
error = AddDirectory( Context, FullPath, Path );
|
|||
|
}
|
|||
|
|
|||
|
*wcsrchr( Path, TEXT('\\') ) = 0;
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
ok = FindNextFile( findHandle, &fileData );
|
|||
|
}
|
|||
|
|
|||
|
} while ( (error == NO_ERROR) && ok );
|
|||
|
|
|||
|
FindClose( findHandle );
|
|||
|
|
|||
|
} // findHandle != INVALID_HANDLE_VALUE
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // AddDirectory
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
AddKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH Path
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Recursively adds entries to the UserRun hive for a new key
|
|||
|
and its subtree.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to WatchEnum.
|
|||
|
|
|||
|
Path - path to key relative to HKEY_CURRENT_USER.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY newKey;
|
|||
|
DWORD error;
|
|||
|
DWORD dword;
|
|||
|
HKEY findHandle;
|
|||
|
KEY_ENUM_CONTEXT enumContext;
|
|||
|
|
|||
|
//
|
|||
|
// Create an entry key for the key and popuplate it.
|
|||
|
//
|
|||
|
|
|||
|
newKey = NULL;
|
|||
|
error = CreateUserRunKey( Context, FALSE, &newKey );
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
dword = 1;
|
|||
|
error = RegSetValueEx( newKey, ACTION_VALUE, 0, REG_DWORD, (PBYTE)&dword, sizeof(DWORD) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, KEYNAME_VALUE, 0, REG_SZ, (PBYTE)Path, SZLEN(Path) );
|
|||
|
}
|
|||
|
|
|||
|
if ( newKey != NULL ) {
|
|||
|
RegCloseKey( newKey );
|
|||
|
}
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// Search the key and add value and key entries.
|
|||
|
//
|
|||
|
|
|||
|
findHandle = NULL;
|
|||
|
|
|||
|
error = RegOpenKeyEx( HKEY_CURRENT_USER,
|
|||
|
Path,
|
|||
|
0,
|
|||
|
KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
|
|||
|
&findHandle );
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
|
|||
|
//
|
|||
|
// Enumerate the values and subkeys of the key, adding entries
|
|||
|
// to the UserRun hive for each one.
|
|||
|
//
|
|||
|
|
|||
|
enumContext.UserRunContext = Context;
|
|||
|
enumContext.CurrentPath = Path;
|
|||
|
error = EnumerateKey( findHandle,
|
|||
|
&enumContext,
|
|||
|
AddValueDuringAddKey,
|
|||
|
AddKeyDuringAddKey );
|
|||
|
|
|||
|
RegCloseKey( findHandle );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // AddKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
AddValueDuringAddKey (
|
|||
|
IN PVOID Context,
|
|||
|
IN DWORD ValueNameLength,
|
|||
|
IN PWCH ValueName,
|
|||
|
IN DWORD ValueType,
|
|||
|
IN PVOID ValueData,
|
|||
|
IN DWORD ValueDataLength
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds a value entry to UserRun during AddKey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to EnumerateKey.
|
|||
|
|
|||
|
ValueNameLength - length in characters of ValueName.
|
|||
|
|
|||
|
ValueName - pointer to name of the value.
|
|||
|
|
|||
|
ValueType - type of the value data.
|
|||
|
|
|||
|
ValueData - pointer to value data.
|
|||
|
|
|||
|
ValueDataLength - length in bytes of ValueData.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PKEY_ENUM_CONTEXT context = Context;
|
|||
|
|
|||
|
//
|
|||
|
// Add the value entry to UserRun.
|
|||
|
//
|
|||
|
|
|||
|
return AddValue( context->UserRunContext,
|
|||
|
context->CurrentPath,
|
|||
|
ValueName,
|
|||
|
ValueType,
|
|||
|
ValueData,
|
|||
|
ValueDataLength );
|
|||
|
|
|||
|
} // AddValueDuringAddKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
AddKeyDuringAddKey (
|
|||
|
IN PVOID Context,
|
|||
|
IN DWORD KeyNameLength,
|
|||
|
IN PWCH KeyName
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds a key entry to UserRun during AddKey.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - context value passed to EnumerateKey.
|
|||
|
|
|||
|
KeyNameLength - length in characters of KeyName.
|
|||
|
|
|||
|
KeyName - pointer to name of the key.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PKEY_ENUM_CONTEXT context = Context;
|
|||
|
DWORD error;
|
|||
|
|
|||
|
//
|
|||
|
// Append the key name to the path and call AddKey to do the
|
|||
|
// recursive work.
|
|||
|
//
|
|||
|
|
|||
|
wcscat( context->CurrentPath, TEXT("\\") );
|
|||
|
wcscat( context->CurrentPath, KeyName );
|
|||
|
error = AddKey( context->UserRunContext, context->CurrentPath );
|
|||
|
|
|||
|
//
|
|||
|
// Remove the key name from the path.
|
|||
|
//
|
|||
|
|
|||
|
*wcsrchr( context->CurrentPath, TEXT('\\') ) = 0;
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // AddKeyDuringAddKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
AddValue (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN PWCH KeyName OPTIONAL,
|
|||
|
IN PWCH ValueName,
|
|||
|
IN DWORD ValueType,
|
|||
|
IN PVOID ValueData,
|
|||
|
IN DWORD ValueDataLength
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Adds an entry for a new value to UserRun.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
KeyName - pointer to name of the key containing the value.
|
|||
|
|
|||
|
ValueName - pointer to name of the value.
|
|||
|
|
|||
|
ValueType - type of the value data.
|
|||
|
|
|||
|
ValueData - pointer to value data.
|
|||
|
|
|||
|
ValueDataLength - length in bytes of ValueData.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY newKey;
|
|||
|
DWORD error;
|
|||
|
DWORD dword;
|
|||
|
|
|||
|
//
|
|||
|
// Create an entry key for the value and popuplate it.
|
|||
|
//
|
|||
|
|
|||
|
newKey = NULL;
|
|||
|
error = CreateUserRunKey( Context, FALSE, &newKey );
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
dword = 3;
|
|||
|
error = RegSetValueEx( newKey, ACTION_VALUE, 0, REG_DWORD, (PBYTE)&dword, sizeof(DWORD) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, KEYNAME_VALUE, 0, REG_SZ, (PBYTE)KeyName, SZLEN(KeyName) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, VALUENAME_VALUE, 0, REG_SZ, (PBYTE)ValueName, SZLEN(ValueName) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, VALUE_VALUE, 0, ValueType, (PBYTE)ValueData, ValueDataLength );
|
|||
|
}
|
|||
|
|
|||
|
if ( newKey != NULL ) {
|
|||
|
RegCloseKey( newKey );
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // AddValue
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
CreateUserRunSimpleFileKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN DWORD Action,
|
|||
|
IN PWCH Name
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Creates an entry under the Files key for the "simple" cases -- delete
|
|||
|
directory, add file, delete file.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
Action - value to store in Action value of entry.
|
|||
|
|
|||
|
Name - pointer to name of the file or directory.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY newKey;
|
|||
|
DWORD error;
|
|||
|
|
|||
|
//
|
|||
|
// Create an entry key and popuplate it.
|
|||
|
//
|
|||
|
|
|||
|
newKey = NULL;
|
|||
|
error = CreateUserRunKey( Context, TRUE, &newKey );
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, ACTION_VALUE, 0, REG_DWORD, (PBYTE)&Action, sizeof(DWORD) );
|
|||
|
}
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegSetValueEx( newKey, ITEM_VALUE, 0, REG_SZ, (PBYTE)Name, SZLEN(Name) );
|
|||
|
}
|
|||
|
|
|||
|
if ( newKey != NULL ) {
|
|||
|
RegCloseKey( newKey );
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
|
|||
|
} // CreateUserRunSimpleFileKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
CreateUserRunKey (
|
|||
|
IN PUSERRUN_CONTEXT Context,
|
|||
|
IN BOOL IsFileKey,
|
|||
|
OUT PHKEY NewKeyHandle
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Creates an indexed key in UserRun, under either the Files key or the
|
|||
|
Hive key.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - pointer to context record.
|
|||
|
|
|||
|
IsFileKey - indicates whether to create the key under Files or Hive.
|
|||
|
|
|||
|
NewKeyHandle - returns the handle to the new key.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY parentKeyHandle;
|
|||
|
DWORD index;
|
|||
|
WCHAR keyName[11];
|
|||
|
DWORD disposition;
|
|||
|
|
|||
|
//
|
|||
|
// Get the handle to the parent key and the index for this entry.
|
|||
|
//
|
|||
|
|
|||
|
if ( IsFileKey ) {
|
|||
|
parentKeyHandle = Context->FilesKey;
|
|||
|
index = ++Context->FilesIndex;
|
|||
|
} else {
|
|||
|
parentKeyHandle = Context->HiveKey;
|
|||
|
index = ++Context->HiveIndex;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Convert the index number into a string.
|
|||
|
//
|
|||
|
|
|||
|
wsprintf( keyName, TEXT("%d"), index );
|
|||
|
|
|||
|
//
|
|||
|
// Create the entry key.
|
|||
|
//
|
|||
|
|
|||
|
return RegCreateKeyEx( parentKeyHandle,
|
|||
|
keyName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
NULL,
|
|||
|
NewKeyHandle,
|
|||
|
&disposition );
|
|||
|
|
|||
|
} // CreateUserRunKey
|
|||
|
|
|||
|
|
|||
|
DWORD
|
|||
|
QueryValue (
|
|||
|
IN PWCH KeyName OPTIONAL,
|
|||
|
IN PWCH ValueName,
|
|||
|
OUT PDWORD ValueType,
|
|||
|
OUT PVOID *ValueData,
|
|||
|
OUT PDWORD ValueDataLength
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Queries the data for a value.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
KeyName - pointer to name of the key containing the value.
|
|||
|
|
|||
|
ValueName - pointer to name of the value.
|
|||
|
|
|||
|
ValueType - returns the type of the value data.
|
|||
|
|
|||
|
ValueData - returns a pointer to value data. This buffer must be
|
|||
|
freed by the caller using MyFree.
|
|||
|
|
|||
|
ValueDataLength - length in bytes of ValueData.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
DWORD - Win32 status of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
HKEY hkey;
|
|||
|
DWORD disposition;
|
|||
|
DWORD error;
|
|||
|
|
|||
|
//
|
|||
|
// Open the parent key.
|
|||
|
//
|
|||
|
|
|||
|
if ( (KeyName == NULL) || (wcslen(KeyName) == 0) ) {
|
|||
|
hkey = HKEY_CURRENT_USER;
|
|||
|
} else {
|
|||
|
error = RegCreateKeyEx( HKEY_CURRENT_USER,
|
|||
|
KeyName,
|
|||
|
0,
|
|||
|
NULL,
|
|||
|
REG_OPTION_NON_VOLATILE,
|
|||
|
KEY_ALL_ACCESS,
|
|||
|
NULL,
|
|||
|
&hkey,
|
|||
|
&disposition );
|
|||
|
if ( error != ERROR_SUCCESS ) {
|
|||
|
return error;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query the value to get the length of its data.
|
|||
|
//
|
|||
|
|
|||
|
*ValueDataLength = 0;
|
|||
|
*ValueData = NULL;
|
|||
|
error = RegQueryValueEx( hkey,
|
|||
|
ValueName,
|
|||
|
NULL,
|
|||
|
ValueType,
|
|||
|
NULL,
|
|||
|
ValueDataLength );
|
|||
|
|
|||
|
//
|
|||
|
// Allocate a buffer to hold the value data.
|
|||
|
//
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
*ValueData = MyMalloc( *ValueDataLength );
|
|||
|
if ( *ValueData == NULL ) {
|
|||
|
error = ERROR_NOT_ENOUGH_MEMORY;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Query the value again, this time retrieving the data.
|
|||
|
//
|
|||
|
|
|||
|
if ( error == NO_ERROR ) {
|
|||
|
error = RegQueryValueEx( hkey,
|
|||
|
ValueName,
|
|||
|
NULL,
|
|||
|
ValueType,
|
|||
|
*ValueData,
|
|||
|
ValueDataLength );
|
|||
|
if ( error != NO_ERROR ) {
|
|||
|
MyFree( *ValueData );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Close the parent key.
|
|||
|
//
|
|||
|
|
|||
|
if ( hkey != HKEY_CURRENT_USER ) {
|
|||
|
RegCloseKey( hkey );
|
|||
|
}
|
|||
|
|
|||
|
return error;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
SzToMultiSz (
|
|||
|
IN PWCH Sz,
|
|||
|
OUT PWCH *MultiSz,
|
|||
|
OUT PDWORD MultiSzLength
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Creates a MULTI_SZ version of a null-terminated string. Allocates
|
|||
|
a buffer, copies the string to the buffer, and appends an additional
|
|||
|
null terminator.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Sz - pointer to the string that is to be copied.
|
|||
|
|
|||
|
MultiSz - returns a pointer to the MULTI_SZ version of Sz. The caller
|
|||
|
must free this buffer using MyFree. If the allocation fails,
|
|||
|
MultiSz will be NULL.
|
|||
|
|
|||
|
MultiSzLength - returns the length in bytes of MultiSz, including the
|
|||
|
null terminators.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
DWORD szlen;
|
|||
|
|
|||
|
//
|
|||
|
// Get the length of the input string and calculate the MULTI_SZ length.
|
|||
|
//
|
|||
|
|
|||
|
szlen = wcslen(Sz);
|
|||
|
*MultiSzLength = (szlen + 1 + 1) * sizeof(WCHAR);
|
|||
|
|
|||
|
//
|
|||
|
// Allocate the MULTI_SZ buffer, copy the input string, and append
|
|||
|
// an additional null.
|
|||
|
//
|
|||
|
|
|||
|
*MultiSz = MyMalloc( *MultiSzLength );
|
|||
|
if ( *MultiSz != NULL ) {
|
|||
|
wcscpy( *MultiSz, Sz );
|
|||
|
(*MultiSz)[szlen+1] = 0;
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|