summaryrefslogtreecommitdiffstats
path: root/private/windows/gina/userenv/userdiff.c
diff options
context:
space:
mode:
Diffstat (limited to 'private/windows/gina/userenv/userdiff.c')
-rw-r--r--private/windows/gina/userenv/userdiff.c1392
1 files changed, 1392 insertions, 0 deletions
diff --git a/private/windows/gina/userenv/userdiff.c b/private/windows/gina/userenv/userdiff.c
new file mode 100644
index 000000000..967b8e6d6
--- /dev/null
+++ b/private/windows/gina/userenv/userdiff.c
@@ -0,0 +1,1392 @@
+//*************************************************************
+//
+// Userdiff.c
+//
+// Microsoft Confidential
+// Copyright (c) Microsoft Corporation 1995
+// All rights reserved
+//
+//*************************************************************
+
+#include "uenv.h"
+
+#define MAX_KEY_NAME MAX_PATH
+
+BOOL AddUDNode (LPUDNODE *lpList, LPTSTR lpBuildNumber);
+BOOL FreeUDList (LPUDNODE lpList);
+BOOL ProcessBuild(LPPROFILE lpProfile, LPUDNODE lpItem);
+BOOL ProcessHive(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey);
+BOOL ProcessFiles(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey);
+BOOL ProcessPrograms(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey);
+BOOL OkToProcessItem(DWORD dwProductType);
+
+//*************************************************************
+//
+// ProcessUserDiff()
+//
+// Purpose: Processes the userdiff hive
+//
+// Parameters: lpProfile - Profile information
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments:
+//
+// History: Date Author Comment
+// 10/2/95 ericflo Created
+//
+//*************************************************************
+
+BOOL ProcessUserDiff (LPPROFILE lpProfile, DWORD dwBuildNumber)
+{
+ TCHAR szUserDiff[MAX_PATH];
+ TCHAR szName[MAX_KEY_NAME];
+ HANDLE hFile;
+ WIN32_FIND_DATA fd;
+ LPUDNODE lpList = NULL, lpItem;
+ LONG lResult;
+ HKEY hKeyUserDiff;
+ UINT Index = 0;
+ DWORD dwSize;
+ FILETIME ftWrite;
+
+
+ //
+ // Verbose output
+ //
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Entering.")));
+
+
+ //
+ // Determine which platform we are running on.
+ //
+
+ InitializeProductType();
+
+
+ //
+ // Test if the hive exists, first look for USERDIFR
+ //
+
+ ExpandEnvironmentStrings(USERDIFR_LOCATION, szUserDiff, MAX_PATH);
+ hFile = FindFirstFile (szUserDiff, &fd);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: userdifr hive doesn't exist. Trying userdiff.")));
+
+ ExpandEnvironmentStrings(USERDIFF_LOCATION, szUserDiff, MAX_PATH);
+ hFile = FindFirstFile (szUserDiff, &fd);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: userdiff hive doesn't exist. Leaving.")));
+ return TRUE;
+ }
+ }
+
+ FindClose (hFile);
+
+
+ //
+ // Load the hive
+ //
+
+ if (MyRegLoadKey(lpProfile, HKEY_USERS, USERDIFF, szUserDiff) != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: Failed to load userdiff.")));
+ return FALSE;
+ }
+
+
+ //
+ // Open the key
+ //
+
+ lResult = RegOpenKeyEx(HKEY_USERS, USERDIFF, 0, KEY_READ, &hKeyUserDiff);
+
+ if (lResult != ERROR_SUCCESS) {
+ MyRegUnLoadKey(HKEY_USERS, USERDIFF);
+ DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: failed to open registry root (%d)"), lResult));
+ return FALSE;
+ }
+
+
+
+ //
+ // Enumerate the build numbers
+ //
+
+ dwSize = MAX_KEY_NAME;
+ lResult = RegEnumKeyEx(hKeyUserDiff, Index, szName, &dwSize, NULL,
+ NULL, NULL, &ftWrite);
+
+ if (lResult == ERROR_SUCCESS) {
+
+ do {
+
+ //
+ // Add the node
+ //
+
+ if (!AddUDNode (&lpList, szName)) {
+ break;
+ }
+
+ Index++;
+ dwSize = MAX_KEY_NAME;
+
+ lResult = RegEnumKeyEx(hKeyUserDiff, Index, szName, &dwSize, NULL,
+ NULL, NULL, &ftWrite);
+
+
+ } while (lResult == ERROR_SUCCESS);
+ }
+
+
+ //
+ // Close the open key
+ //
+
+ RegCloseKey(hKeyUserDiff);
+
+
+ //
+ // Map HKCU
+ //
+
+ if (OpenHKeyCurrentUser(lpProfile)) {
+
+ //
+ // Process the builds
+ //
+
+ lpItem = lpList;
+
+ while (lpItem) {
+
+ //
+ // Only want to apply changes that occurred in
+ // builds after the one the user is running.
+ //
+
+ if ( (lpItem->dwBuildNumber > dwBuildNumber) &&
+ (lpItem->dwBuildNumber <= g_dwBuildNumber) ) {
+ ProcessBuild(lpProfile, lpItem);
+ }
+
+ lpItem = lpItem->pNext;
+ }
+
+
+ //
+ // Unmap HKCU
+ //
+
+ CloseHKeyCurrentUser(lpProfile);
+
+ } else {
+ DebugMsg((DM_WARNING, TEXT("ProcessUserDiff: Failed to map HKCU")));
+ }
+
+ //
+ // Free the link list
+ //
+
+ FreeUDList (lpList);
+
+
+ //
+ // Unload the hive
+ //
+
+ MyRegUnLoadKey(HKEY_USERS, USERDIFF);
+
+
+ //
+ // Success
+ //
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessUserDiff: Leaving successfully.")));
+
+ return TRUE;
+
+}
+
+//*************************************************************
+//
+// AddUDNode()
+//
+// Purpose: Adds a build node to the link listed
+// sorted by build number
+//
+// Parameters: lpList - Link list of nodes
+// lpBuildNumber - New node name
+//
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments:
+//
+// History: Date Author Comment
+// 10/3/95 ericflo Created
+//
+//*************************************************************
+
+BOOL AddUDNode (LPUDNODE *lpList, LPTSTR lpBuildNumber)
+{
+ LPUDNODE lpNewItem;
+ LPUDNODE lpHead, lpPrev;
+
+ if (!lpBuildNumber || !*lpBuildNumber) {
+ return TRUE;
+ }
+
+
+ //
+ // Setup the new node
+ //
+
+ lpNewItem = (LPUDNODE) LocalAlloc(LPTR, sizeof(UDNODE));
+
+ if (!lpNewItem) {
+ return FALSE;
+ }
+
+ lstrcpy (lpNewItem->szBuildNumber, lpBuildNumber);
+ lpNewItem->dwBuildNumber = StringToInt(lpBuildNumber);
+ lpNewItem->pNext = NULL;
+
+
+ //
+ // Now add it to the list sorted
+ //
+
+ lpHead = *lpList;
+ lpPrev = NULL;
+
+
+ if (!lpHead) {
+
+ //
+ // First item in the list
+ //
+
+ *lpList = lpNewItem;
+
+ return TRUE;
+ }
+
+
+ //
+ // If we made it here, there is one or more items in the list
+ //
+
+
+ while (lpHead) {
+
+ if (lpNewItem->dwBuildNumber <= lpHead->dwBuildNumber) {
+
+ if (lpPrev) {
+
+ //
+ // Insert the item
+ //
+
+ lpPrev->pNext = lpNewItem;
+ lpNewItem->pNext = lpHead;
+ return TRUE;
+
+ } else {
+
+ //
+ // Head of the list
+ //
+
+ lpNewItem->pNext = lpHead;
+ *lpList = lpNewItem;
+ return TRUE;
+
+ }
+
+ }
+
+ lpPrev = lpHead;
+ lpHead = lpHead->pNext;
+ }
+
+
+ //
+ // Add node to the end of the list
+ //
+
+ lpPrev->pNext = lpNewItem;
+
+
+ return TRUE;
+}
+
+
+//*************************************************************
+//
+// FreeUDList()
+//
+// Purpose: Free's a UDNODE link list
+//
+// Parameters: lpList - List to be freed
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments:
+//
+// History: Date Author Comment
+// 10/3/95 ericflo Created
+//
+//*************************************************************
+
+BOOL FreeUDList (LPUDNODE lpList)
+{
+ LPUDNODE lpNext;
+
+
+ if (!lpList) {
+ return TRUE;
+ }
+
+
+ lpNext = lpList->pNext;
+
+ while (lpList) {
+ LocalFree (lpList);
+ lpList = lpNext;
+
+ if (lpList) {
+ lpNext = lpList->pNext;
+ }
+ }
+
+ return TRUE;
+}
+
+//*************************************************************
+//
+// ProcessBuild()
+//
+// Purpose: Processes the changes for a specific build
+//
+// Parameters: lpProfile - Profile information
+// lpItem - Build item to process
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments:
+//
+// History: Date Author Comment
+// 10/3/95 ericflo Created
+//
+//*************************************************************
+
+BOOL ProcessBuild(LPPROFILE lpProfile, LPUDNODE lpItem)
+{
+ TCHAR szSubKey[MAX_PATH];
+ LONG lResult;
+ HKEY hKey;
+
+ //
+ // Verbose output
+ //
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessBuild: Entering with build <%s>."),
+ lpItem->szBuildNumber));
+
+
+ //
+ // Open "Hive" subkey
+ //
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Hive"), USERDIFF, lpItem->szBuildNumber);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
+
+ if (lResult == ERROR_SUCCESS) {
+ ProcessHive(lpProfile, lpItem, hKey);
+ RegCloseKey (hKey);
+ }
+
+
+ //
+ // Open "Files" subkey
+ //
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Files"), USERDIFF, lpItem->szBuildNumber);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
+
+ if (lResult == ERROR_SUCCESS) {
+ ProcessFiles(lpProfile, lpItem, hKey);
+ RegCloseKey (hKey);
+ }
+
+
+ //
+ // Open "Execute" subkey
+ //
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Execute"), USERDIFF, lpItem->szBuildNumber);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKey);
+
+ if (lResult == ERROR_SUCCESS) {
+ ProcessPrograms(lpProfile, lpItem, hKey);
+ RegCloseKey (hKey);
+ }
+
+ //
+ // Success
+ //
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessBuild: Leaving successfully.")));
+
+ return TRUE;
+
+}
+
+//*************************************************************
+//
+// ProcessHive()
+//
+// Purpose: Processes the Hive entry for a build
+//
+// Parameters: lpProfile - Profile information
+// lpItem - Build item
+// hKey - Registry key to enumerate
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments:
+//
+// History: Date Author Comment
+// 10/3/95 ericflo Created
+//
+//*************************************************************
+
+BOOL ProcessHive(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey)
+{
+ TCHAR szSubKey[MAX_PATH];
+ TCHAR szValueName[MAX_KEY_NAME];
+ DWORD dwSize, dwType, dwAction, dwDisp, dwFlags, dwProductType;
+ LPBYTE lpValueData;
+ LONG lResult;
+ UINT Index = 1;
+ FILETIME ftWrite;
+ HKEY hKeyEntry, hKeyTemp;
+ LPTSTR lpName;
+
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Entering.")));
+
+ //
+ // Process the entry
+ //
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Hive\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: No hive entries.")));
+ goto Exit;
+ }
+
+
+ do {
+
+ //
+ // Query for the product type
+ //
+
+ dwSize = sizeof(dwProductType);
+ lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
+ (LPBYTE)&dwProductType, &dwSize);
+
+
+ //
+ // It's ok to not have a product type listed in userdiff.ini.
+ // In this case, we always apply the change regardless of the
+ // platform.
+ //
+
+ if (lResult == ERROR_SUCCESS) {
+
+ //
+ // A specific product was listed. Check if
+ // we can process this entry.
+ //
+
+ if (!OkToProcessItem(dwProductType)) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Skipping Item %d due to product type mismatch."), Index));
+ goto LoopAgain;
+ }
+ }
+
+
+ //
+ // Query for the action type
+ //
+
+ dwSize = sizeof(dwAction);
+ lResult = RegQueryValueEx(hKeyEntry, UD_ACTION, NULL, &dwType,
+ (LPBYTE)&dwAction, &dwSize);
+
+ if (lResult == ERROR_SUCCESS) {
+
+ switch (dwAction) {
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Item %d has an action of %d."),
+ Index, dwAction));
+
+ case 1: {
+ //
+ // Add New Key
+ //
+ // Get the key name
+ //
+
+ dwSize = MAX_PATH * sizeof(TCHAR);
+ lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
+ (LPBYTE)szSubKey, &dwSize);
+
+ if (lResult == ERROR_SUCCESS) {
+
+ lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
+ szSubKey, 0, NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL,
+ &hKeyTemp, &dwDisp);
+
+ if (lResult == ERROR_SUCCESS) {
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Created subkey <%s>."),
+ szSubKey));
+
+ RegCloseKey(hKeyTemp);
+ } else {
+
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create subkey <%s> with error %d."),
+ szSubKey, lResult));
+ }
+ }
+
+ }
+ break;
+
+ case 2: {
+ //
+ // Delete a key and all it's subkeys
+ //
+ // Get the key name
+ //
+
+ dwSize = MAX_PATH * sizeof(TCHAR);
+ lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
+ (LPBYTE)szSubKey, &dwSize);
+
+ if (lResult == ERROR_SUCCESS) {
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Calling RegDelnode on <%s>."),
+ szSubKey));
+
+ RegDelnode (lpProfile->hKeyCurrentUser, szSubKey);
+ }
+
+ }
+ break;
+
+ case 3: {
+ //
+ // Add a new value
+ //
+ // Get the key name
+ //
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Adding a new value.")));
+
+ dwSize = MAX_PATH * sizeof(TCHAR);
+ lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
+ (LPBYTE)szSubKey, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to get UD_KEYNAME with error %d."), lResult));
+ goto LoopAgain;
+ }
+
+ lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
+ szSubKey, 0, NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL,
+ &hKeyTemp, &dwDisp);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create UD_KEYNAME with error %d."), lResult));
+ goto LoopAgain;
+ }
+
+
+ //
+ // Query for the value name
+ //
+
+ dwSize = MAX_KEY_NAME * sizeof(TCHAR);
+ lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAME, NULL, &dwType,
+ (LPBYTE)szValueName, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query UD_VALUENAME with error %d."), lResult));
+ RegCloseKey(hKeyTemp);
+ goto LoopAgain;
+ }
+
+
+ //
+ // Query for the value data size
+ //
+
+ dwSize = 0;
+ lResult = RegQueryValueEx(hKeyEntry, UD_VALUE, NULL, &dwType,
+ NULL, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query UD_VALUE with error %d."), lResult));
+ RegCloseKey(hKeyTemp);
+ goto LoopAgain;
+ }
+
+
+ //
+ // Allocate space for the data
+ //
+
+ lpValueData = LocalAlloc (LPTR, dwSize);
+
+ if (!lpValueData) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: LocalAlloc failed (%d)."), GetLastError()));
+ RegCloseKey(hKeyTemp);
+ goto LoopAgain;
+ }
+
+
+ //
+ // Query for the value data
+ //
+
+ lResult = RegQueryValueEx(hKeyEntry, UD_VALUE, NULL, &dwType,
+ lpValueData, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query value data with error %d."), lResult));
+ LocalFree (lpValueData);
+ RegCloseKey(hKeyTemp);
+ goto LoopAgain;
+ }
+
+
+ //
+ // Set the new value
+ //
+
+ RegSetValueEx(hKeyTemp, szValueName, 0, dwType,
+ lpValueData, dwSize);
+
+
+ //
+ // Clean up
+ //
+
+ LocalFree (lpValueData);
+
+ RegCloseKey(hKeyTemp);
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Finished adding value <%s>."), szValueName));
+ }
+ break;
+
+ case 4: {
+ //
+ // Delete value(s)
+ //
+ // Get the key name
+ //
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Entering delete a value.")));
+
+ dwSize = ARRAYSIZE(szSubKey);
+ lResult = RegQueryValueEx(hKeyEntry, UD_KEYNAME, NULL, &dwType,
+ (LPBYTE)szSubKey, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value to delete (%d)."), lResult));
+ goto LoopAgain;
+ }
+
+ lResult = RegCreateKeyEx (lpProfile->hKeyCurrentUser,
+ szSubKey, 0, NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL,
+ &hKeyTemp, &dwDisp);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to create key (%s) for value to delete (%d)."), szSubKey, lResult));
+ goto LoopAgain;
+ }
+
+
+ //
+ // Query for the flags
+ //
+
+ dwSize = sizeof(dwFlags);
+ lResult = RegQueryValueEx(hKeyEntry, UD_FLAGS, NULL, &dwType,
+ (LPBYTE)&dwFlags, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ dwFlags = 0;
+ }
+
+
+ //
+ // Process the flags
+ //
+
+ if (dwFlags == 2) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Calling DeleteAllValues.")));
+ DeleteAllValues (hKeyTemp);
+ RegCloseKey(hKeyTemp);
+ goto LoopAgain;
+ }
+
+
+ //
+ // Query for the value names size
+ //
+
+ dwSize = 0;
+ lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAMES, NULL, &dwType,
+ NULL, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value names to delete (%d)."), lResult));
+ RegCloseKey(hKeyTemp);
+ goto LoopAgain;
+ }
+
+
+ //
+ // Allocate space for the data
+ //
+
+ lpValueData = LocalAlloc (LPTR, dwSize);
+
+ if (!lpValueData) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: LocalAlloc failed (%d)."), GetLastError()));
+ RegCloseKey(hKeyTemp);
+ goto LoopAgain;
+ }
+
+
+ //
+ // Query for the value data
+ //
+
+ lResult = RegQueryValueEx(hKeyEntry, UD_VALUENAMES, NULL, &dwType,
+ lpValueData, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessHive: Failed to query for value data to delete (%d)."), lResult));
+ LocalFree (lpValueData);
+ RegCloseKey(hKeyTemp);
+ goto LoopAgain;
+ }
+
+
+ //
+ // Delete the values
+ //
+
+ lpName = (LPTSTR) lpValueData;
+
+ while (*lpName) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Deleting (%s)."), lpName));
+ RegDeleteValue (hKeyTemp, lpName);
+ lpName += lstrlen(lpName) + 1;
+ }
+
+
+ //
+ // Delete the no-name value if appropriate
+ //
+
+ if (dwFlags == 1) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Deleting no name value.")));
+ RegDeleteValue (hKeyTemp, NULL);
+ }
+
+
+ //
+ // Clean up
+ //
+
+ LocalFree (lpValueData);
+ RegCloseKey(hKeyTemp);
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Leaving deletion code.")));
+ }
+
+ break;
+ }
+
+ }
+
+LoopAgain:
+
+ //
+ // Close the registry key
+ //
+
+ RegCloseKey(hKeyEntry);
+
+
+ //
+ // Enumerate again
+ //
+
+ Index++;
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Hive\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
+
+ } while (lResult == ERROR_SUCCESS);
+
+Exit:
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessHive: Leaving.")));
+
+ return TRUE;
+}
+
+//*************************************************************
+//
+// ProcessFiles()
+//
+// Purpose: Processes the Files entry for a build
+//
+// Parameters: lpProfile - Profile information
+// lpItem - Build item
+// hKey - Registry key to enumerate
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments:
+//
+// History: Date Author Comment
+// 10/3/95 ericflo Created
+//
+//*************************************************************
+
+BOOL ProcessFiles(LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey)
+{
+ TCHAR szSubKey[MAX_PATH];
+ TCHAR szSrc[MAX_PATH];
+ TCHAR szDest[MAX_PATH];
+ TCHAR szItem[MAX_PATH];
+ LPTSTR lpEnd, lpTemp;
+ DWORD dwSize, dwType, dwAction, dwProductType;
+ LONG lResult;
+ UINT Index = 1;
+ FILETIME ftWrite;
+ HKEY hKeyEntry;
+
+
+ //
+ // Verbose Output
+ //
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Entering.")));
+
+
+ //
+ // Process the entry
+ //
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Files\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: No Files entries.")));
+ goto Exit;
+ }
+
+
+ do {
+
+ //
+ // Query for the product type
+ //
+
+ dwSize = sizeof(dwProductType);
+ lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
+ (LPBYTE)&dwProductType, &dwSize);
+
+
+ //
+ // It's ok to not have a product type listed in userdiff.ini.
+ // In this case, we always apply the change regardless of the
+ // platform.
+ //
+
+ if (lResult == ERROR_SUCCESS) {
+
+ //
+ // A specific product was listed. Check if
+ // we can process this entry.
+ //
+
+ if (!OkToProcessItem(dwProductType)) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Skipping Item %d due to product type mismatch."), Index));
+ goto LoopAgain;
+ }
+ }
+
+
+ //
+ // Query for the action type
+ //
+
+ dwSize = sizeof(dwAction);
+ lResult = RegQueryValueEx(hKeyEntry, UD_ACTION, NULL, &dwType,
+ (LPBYTE)&dwAction, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to query action type (%d)."), lResult));
+ goto LoopAgain;
+ }
+
+
+ //
+ // Query for the item
+ //
+
+ dwSize = ARRAYSIZE(szItem);
+ lResult = RegQueryValueEx(hKeyEntry, UD_ITEM, NULL, &dwType,
+ (LPBYTE)szItem, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to query UD_ITEM type (%d)."), lResult));
+ goto LoopAgain;
+ }
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Item %d has an action of %d."),
+ Index, dwAction));
+
+ switch (dwAction) {
+
+ case 1:
+
+ //
+ // Create new program group
+ //
+
+ GetProgramsDirectory (FALSE, szDest);
+ lpEnd = CheckSlash(szDest);
+ lstrcpy (lpEnd, szItem);
+
+ if (CreateNestedDirectory(szDest, NULL)) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Created new group (%s)."), szDest));
+ } else {
+ DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to created new group (%s) with (%d)."),
+ szDest, GetLastError()));
+ }
+
+ break;
+
+ case 2:
+ //
+ // Delete a program group
+ //
+
+ GetProgramsDirectory (FALSE, szDest);
+ lpEnd = CheckSlash(szDest);
+ lstrcpy (lpEnd, szItem);
+
+ Delnode(szDest);
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted group (%s)."), szDest));
+
+ break;
+
+ case 3:
+ {
+ TCHAR szStartMenu [MAX_FOLDER_SIZE];
+
+ //
+ // Add a new item
+ //
+
+ ExpandEnvironmentStrings (DEFAULT_PROFILE, szSrc, MAX_PATH);
+ lpEnd = CheckSlash(szSrc);
+
+ if (LoadString (g_hDllInstance, IDS_SH_PROGRAMS, szStartMenu,
+ MAX_FOLDER_SIZE)) {
+
+ lstrcpy (lpEnd, szStartMenu);
+ lpEnd = CheckSlash(szSrc);
+ lstrcpy (lpEnd, szItem);
+
+
+ GetProgramsDirectory (FALSE, szDest);
+ lpEnd = CheckSlash(szDest);
+ lstrcpy (lpEnd, szItem);
+
+ if (CopyFile (szSrc, szDest, FALSE)) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: <%s> ==> <%s> [OK]."),
+ szSrc, szDest));
+ } else {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: <%s> ==> <%s> [FAILED %d]."),
+ szSrc, szDest, GetLastError()));
+ }
+ }
+ }
+
+ break;
+
+ case 4:
+ //
+ // Delete a program item
+ //
+
+ GetProgramsDirectory (FALSE, szDest);
+ lpEnd = CheckSlash(szDest);
+ lstrcpy (lpEnd, szItem);
+
+ if (DeleteFile(szDest)) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted <%s>"), szDest));
+ } else {
+ DebugMsg((DM_WARNING, TEXT("ProcessFiles: Failed to deleted <%s> with %d"), szDest, GetLastError()));
+ }
+
+
+ //
+ // Attempt to delete the directory
+ //
+
+ lpTemp = szDest + lstrlen(szDest) - 1;
+ lpEnd--;
+
+ while ((*lpTemp != TEXT('\\')) && lpTemp > lpEnd) {
+ lpTemp--;
+ }
+
+ if (lpTemp == lpEnd) {
+ break;
+ }
+
+ *lpTemp = TEXT('\0');
+
+ if (RemoveDirectory(szDest)) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Deleted directory <%s>"), szDest));
+ } else {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Failed to delete directory <%s> with %d"), szDest, GetLastError()));
+ }
+
+ break;
+ }
+
+
+LoopAgain:
+
+ //
+ // Close the registry key
+ //
+
+ RegCloseKey(hKeyEntry);
+
+
+ //
+ // Enumerate again
+ //
+
+ Index++;
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Files\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
+
+ } while (lResult == ERROR_SUCCESS);
+
+Exit:
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessFiles: Leaving.")));
+
+ return TRUE;
+}
+
+//*************************************************************
+//
+// ProcessPrograms()
+//
+// Purpose: Processes the Execute entry for a build
+//
+// Parameters: lpProfile - Profile information
+// lpItem - Build item
+// hKey - Registry key to enumerate
+//
+// Return: TRUE if successful
+// FALSE if an error occurs
+//
+// Comments:
+//
+// History: Date Author Comment
+// 11/16/95 ericflo Created
+//
+//*************************************************************
+
+BOOL ProcessPrograms (LPPROFILE lpProfile, LPUDNODE lpItem, HKEY hKey)
+{
+ TCHAR szSubKey[MAX_PATH];
+ TCHAR szCmdLine[MAX_PATH];
+ TCHAR szFullPath[MAX_PATH];
+ DWORD dwSize, dwType, dwProductType;
+ LONG lResult;
+ UINT Index = 1;
+ HKEY hKeyEntry;
+ STARTUPINFO si;
+ PROCESS_INFORMATION ProcessInformation;
+ BOOL Result;
+
+
+ //
+ // Verbose output
+ //
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Entering.")));
+
+
+ //
+ // Process the entry
+ //
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
+
+ if (lResult != ERROR_SUCCESS) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: No execute entries.")));
+ goto Exit;
+ }
+
+
+ do {
+
+ //
+ // Query for the product type
+ //
+
+ dwSize = sizeof(dwProductType);
+ lResult = RegQueryValueEx(hKeyEntry, UD_PRODUCTTYPE, NULL, &dwType,
+ (LPBYTE)&dwProductType, &dwSize);
+
+
+ //
+ // It's ok to not have a product type listed in userdiff.ini.
+ // In this case, we always apply the change regardless of the
+ // platform.
+ //
+
+ if (lResult == ERROR_SUCCESS) {
+
+ //
+ // A specific product was listed. Check if
+ // we can process this entry.
+ //
+
+ if (!OkToProcessItem(dwProductType)) {
+ DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Skipping Item %d due to product type mismatch."), Index));
+ goto LoopAgain;
+ }
+ }
+
+
+ //
+ // Query for the command line
+ //
+
+
+ dwSize = MAX_PATH * sizeof(TCHAR);
+ lResult = RegQueryValueEx(hKeyEntry, UD_COMMANDLINE, NULL, &dwType,
+ (LPBYTE)szCmdLine, &dwSize);
+
+ if (lResult != ERROR_SUCCESS) {
+ goto LoopAgain;
+ }
+
+
+ //
+ // If we have a NULL path, loop again.
+ //
+
+ if (szCmdLine[0] == TEXT('\0')) {
+ goto LoopAgain;
+ }
+
+
+ //
+ // Expand the command line
+ //
+
+ ExpandEnvironmentStrings (szCmdLine, szFullPath, MAX_PATH);
+
+
+ //
+ // Initialize process startup info
+ //
+
+ si.cb = sizeof(STARTUPINFO);
+ si.lpReserved = NULL;
+ si.lpTitle = NULL;
+ si.lpDesktop = NULL;
+ si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ si.wShowWindow = SW_SHOWNORMAL;
+ si.lpReserved2 = NULL;
+ si.cbReserved2 = 0;
+
+
+ //
+ // Start the app
+ //
+
+ Result = CreateProcessAsUser(lpProfile->hToken, NULL, szFullPath,
+ NULL, NULL, FALSE,
+ NORMAL_PRIORITY_CLASS, NULL, NULL,
+ &si, &ProcessInformation);
+
+ if (Result) {
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Spawned <%s>. Waiting for it to complete."),
+ szFullPath));
+
+ //
+ // Wait for the app to complete (3 minutes max)
+ //
+
+ WaitForSingleObject(ProcessInformation.hProcess, 180000);
+
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Finished waiting for <%s>."),
+ szFullPath));
+
+
+ //
+ // Close our handles to the process and thread
+ //
+
+ CloseHandle(ProcessInformation.hProcess);
+ CloseHandle(ProcessInformation.hThread);
+
+ } else {
+ DebugMsg((DM_WARNING, TEXT("ProcessPrograms: Failed to execute <%s>, error = %d"),
+ szFullPath, GetLastError()));
+ }
+
+LoopAgain:
+
+ //
+ // Close the registry key
+ //
+
+ RegCloseKey(hKeyEntry);
+
+
+ //
+ // Enumerate again
+ //
+
+ Index++;
+
+ wsprintf (szSubKey, TEXT("%s\\%s\\Execute\\%d"), USERDIFF, lpItem->szBuildNumber, Index);
+ lResult = RegOpenKeyEx (HKEY_USERS, szSubKey, 0, KEY_READ, &hKeyEntry);
+
+ } while (lResult == ERROR_SUCCESS);
+
+Exit:
+
+ DebugMsg((DM_VERBOSE, TEXT("ProcessPrograms: Leaving.")));
+
+ return TRUE;
+}
+
+//*************************************************************
+//
+// OkToProcessItem()
+//
+// Purpose: Determines if the platform currently running
+// on should have the change in userdiff.ini applied.
+//
+// Parameters: dwProductType - ProductType for a specific entry
+// in userdiff.ini
+//
+// Return: TRUE if change should be applied
+// FALSE if not
+//
+// Comments: dwProductType can be one of these values:
+//
+// 0 = All platforms
+// 1 = All server platforms
+// 2 = Workstation
+// 3 = Server
+// 4 = Domain Controller
+//
+// History: Date Author Comment
+// 4/08/96 ericflo Created
+//
+//*************************************************************
+
+BOOL OkToProcessItem(DWORD dwProductType)
+{
+ BOOL bRetVal = FALSE;
+
+
+ switch (g_ProductType) {
+
+ case PT_WORKSTATION:
+
+ if ( (dwProductType == 0) ||
+ (dwProductType == 2) ) {
+
+ bRetVal = TRUE;
+ }
+
+ break;
+
+ case PT_SERVER:
+
+ if ( (dwProductType == 0) ||
+ (dwProductType == 1) ||
+ (dwProductType == 3) ) {
+
+ bRetVal = TRUE;
+ }
+
+ break;
+
+ case PT_DC:
+ if ( (dwProductType == 0) ||
+ (dwProductType == 1) ||
+ (dwProductType == 4) ) {
+
+ bRetVal = TRUE;
+ }
+
+ break;
+
+ }
+
+ return bRetVal;
+}