mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
461 lines
9.3 KiB
461 lines
9.3 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1995 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cutil.c
|
|
|
|
Abstract:
|
|
|
|
This module contains general utility routines used by both cfgmgr32
|
|
and umpnpmgr.
|
|
|
|
SplitDeviceInstanceString
|
|
DeletePrivateKey
|
|
RegDeleteNode
|
|
Split1
|
|
Split2
|
|
|
|
|
|
Author:
|
|
|
|
Paula Tomlinson (paulat) 7-12-1995
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
|
|
Revision History:
|
|
|
|
12-July-1995 paulat
|
|
|
|
Creation and initial implementation.
|
|
|
|
--*/
|
|
|
|
|
|
//
|
|
// includes
|
|
//
|
|
#include "precomp.h"
|
|
|
|
|
|
//
|
|
// Private prototypes
|
|
//
|
|
|
|
//
|
|
// global data
|
|
//
|
|
|
|
|
|
BOOL
|
|
InitPrivateResource(
|
|
OUT PLOCKINFO Lock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Initialize a lock structure to be used with Synchronization routines.
|
|
|
|
Arguments:
|
|
|
|
LockHandles - supplies structure to be initialized. This routine creates
|
|
the locking event and mutex and places handles in this structure.
|
|
|
|
Return Value:
|
|
|
|
TRUE if the lock structure was successfully initialized. FALSE if not.
|
|
|
|
--*/
|
|
|
|
{
|
|
if(Lock->LockHandles[DESTROYED_EVENT] = CreateEvent(NULL,TRUE,FALSE,NULL)) {
|
|
if(Lock->LockHandles[ACCESS_MUTEX] = CreateMutex(NULL,FALSE,NULL)) {
|
|
return(TRUE);
|
|
}
|
|
CloseHandle(Lock->LockHandles[DESTROYED_EVENT]);
|
|
}
|
|
|
|
return(FALSE);
|
|
|
|
} // InitPrivateResource
|
|
|
|
|
|
|
|
|
|
VOID
|
|
DestroyPrivateResource(
|
|
IN OUT PLOCKINFO Lock
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Tears down a lock structure created by InitPrivateResource.
|
|
ASSUMES THAT THE CALLING ROUTINE HAS ALREADY ACQUIRED THE LOCK!
|
|
|
|
Arguments:
|
|
|
|
LockHandle - supplies structure to be torn down. The structure itself
|
|
is not freed.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
HANDLE h1,h2;
|
|
|
|
h1 = Lock->LockHandles[DESTROYED_EVENT];
|
|
h2 = Lock->LockHandles[ACCESS_MUTEX];
|
|
|
|
Lock->LockHandles[DESTROYED_EVENT] = NULL;
|
|
Lock->LockHandles[ACCESS_MUTEX] = NULL;
|
|
|
|
CloseHandle(h2);
|
|
|
|
SetEvent(h1);
|
|
CloseHandle(h1);
|
|
|
|
} // DestroyPrivateResource
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
SplitDeviceInstanceString(
|
|
IN LPCWSTR pszDeviceInstance,
|
|
OUT LPWSTR pszBase,
|
|
OUT LPWSTR pszDeviceID,
|
|
OUT LPWSTR pszInstanceID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine parses a device instance string into it's three component
|
|
parts. Since this is an internal routine, NO error checking is done on
|
|
the pszBase, pszDeviceID, and pszInstanceID routines; I always assume that
|
|
valid pointers are passed in and that each of these buffers is at least
|
|
MAX_DEVICE_ID_LEN characters in length. I do some error checking on the
|
|
pszDeviceInstance string since it is passed in from the client side.
|
|
|
|
Arguments:
|
|
|
|
|
|
Return value:
|
|
|
|
The return value is TRUE if the function suceeds and FALSE if it fails.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT ulLength, i, j;
|
|
|
|
|
|
ulLength = lstrlen(pszDeviceInstance);
|
|
|
|
//
|
|
// parse the string for the first backslash character
|
|
//
|
|
|
|
for (i=0; i < ulLength && pszDeviceInstance[i] != '\0' &&
|
|
pszDeviceInstance[i] != '\\'; i++);
|
|
|
|
if (pszDeviceInstance[i] != '\\') {
|
|
lstrcpy(pszBase, pszDeviceInstance);
|
|
*pszDeviceID = '\0';
|
|
*pszInstanceID = '\0';
|
|
return FALSE; // not a complete device instance string
|
|
}
|
|
|
|
i++; // increment past the backslash character
|
|
if (i < ulLength && pszDeviceInstance[i] != '\0') {
|
|
lstrcpyn(pszBase, pszDeviceInstance, i);
|
|
}
|
|
else {
|
|
*pszBase = '\0';
|
|
*pszDeviceID = '\0';
|
|
*pszInstanceID = '\0';
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
//
|
|
// parse the string for second backslash character
|
|
//
|
|
for (j=i; j < ulLength && pszDeviceInstance[j] != '\0' &&
|
|
pszDeviceInstance[j] != '\\'; j++);
|
|
|
|
if (pszDeviceInstance[j] != '\\' || j > ulLength) {
|
|
lstrcpy(pszDeviceID, &pszDeviceInstance[i]);
|
|
*pszInstanceID = '\0';
|
|
return FALSE;
|
|
}
|
|
|
|
j++;
|
|
lstrcpyn(pszDeviceID, &pszDeviceInstance[i], j-i);
|
|
lstrcpyn(pszInstanceID, &pszDeviceInstance[j], ulLength-j+1);
|
|
|
|
return TRUE;
|
|
|
|
} // SplitDeviceInstanceString
|
|
|
|
|
|
|
|
|
|
CONFIGRET
|
|
DeletePrivateKey(
|
|
IN HKEY hBranchKey,
|
|
IN LPCWSTR pszParentKey,
|
|
IN LPCWSTR pszChildKey
|
|
)
|
|
{
|
|
CONFIGRET Status = CR_SUCCESS;
|
|
LONG RegStatus = ERROR_SUCCESS;
|
|
WCHAR RegStr[MAX_CM_PATH],
|
|
szKey1[MAX_DEVICE_ID_LEN],
|
|
szKey2[MAX_DEVICE_ID_LEN];
|
|
HKEY hKey = NULL;
|
|
ULONG ulSubKeys = 0;
|
|
|
|
|
|
//
|
|
// is the specified child key a compound registry key?
|
|
//
|
|
if (!Split1(pszChildKey, szKey1, szKey2)) {
|
|
|
|
//------------------------------------------------------------------
|
|
// Only a single child key was specified, so just open the parent
|
|
// registry key and delete the child (and any of its subkeys)
|
|
//------------------------------------------------------------------
|
|
|
|
if (RegOpenKeyEx(hBranchKey, pszParentKey, 0,
|
|
KEY_READ | KEY_WRITE, &hKey) != ERROR_SUCCESS) {
|
|
goto Clean0; // no error, nothing to delete
|
|
}
|
|
|
|
if (!RegDeleteNode(hKey, pszChildKey)) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
}
|
|
|
|
else {
|
|
|
|
//------------------------------------------------------------------
|
|
// if a compound registry path was passed in, such as key1\key2
|
|
// then always delete key2 but delete key1 only if it has no other
|
|
// subkeys besides key2.
|
|
//------------------------------------------------------------------
|
|
|
|
//
|
|
// open the first level key
|
|
//
|
|
wsprintf(RegStr, TEXT("%s\\%s"),
|
|
pszParentKey,
|
|
szKey1);
|
|
|
|
RegStatus = RegOpenKeyEx(
|
|
hBranchKey, RegStr, 0, KEY_QUERY_VALUE | KEY_SET_VALUE,
|
|
&hKey);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
goto Clean0; // no error, nothing to delete
|
|
}
|
|
|
|
//
|
|
// try to delete the second level key
|
|
//
|
|
if (!RegDeleteNode(hKey, szKey2)) {
|
|
goto Clean0; // no error, nothing to delete
|
|
}
|
|
|
|
//
|
|
// How many subkeys are remaining?
|
|
//
|
|
RegStatus = RegQueryInfoKey(
|
|
hKey, NULL, NULL, NULL, &ulSubKeys,
|
|
NULL, NULL, NULL, NULL, NULL, NULL, NULL);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
goto Clean0; // nothing to delete
|
|
}
|
|
|
|
//
|
|
// if no more subkeys, then delete the first level key
|
|
//
|
|
if (ulSubKeys == 0) {
|
|
|
|
RegCloseKey(hKey);
|
|
hKey = NULL;
|
|
|
|
RegStatus = RegOpenKeyEx(
|
|
hBranchKey, pszParentKey, 0,
|
|
KEY_QUERY_VALUE | KEY_SET_VALUE, &hKey);
|
|
|
|
if (RegStatus != ERROR_SUCCESS) {
|
|
goto Clean0; // no error, nothing to delete
|
|
}
|
|
|
|
if (!RegDeleteNode(hKey, szKey1)) {
|
|
Status = CR_REGISTRY_ERROR;
|
|
goto Clean0;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Clean0:
|
|
|
|
if (hKey != NULL) {
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // DeletePrivateKey
|
|
|
|
|
|
|
|
BOOL
|
|
RegDeleteNode(
|
|
HKEY hParentKey,
|
|
LPCWSTR szKey
|
|
)
|
|
{
|
|
ULONG ulSize = 0;
|
|
LONG RegStatus = ERROR_SUCCESS;
|
|
HKEY hKey = NULL;
|
|
WCHAR szSubKey[MAX_PATH];
|
|
|
|
|
|
//
|
|
// attempt to delete the key
|
|
//
|
|
if (RegDeleteKey(hParentKey, szKey) != ERROR_SUCCESS) {
|
|
|
|
RegStatus = RegOpenKeyEx(
|
|
hParentKey, szKey, 0, KEY_ALL_ACCESS, &hKey);
|
|
|
|
//
|
|
// enumerate subkeys and delete those nodes
|
|
//
|
|
while (RegStatus == ERROR_SUCCESS) {
|
|
//
|
|
// enumerate the first level children under the profile key
|
|
// (always use index 0, enumeration looses track when a key
|
|
// is added or deleted)
|
|
//
|
|
ulSize = MAX_PATH;
|
|
RegStatus = RegEnumKeyEx(
|
|
hKey, 0, szSubKey, &ulSize, NULL, NULL, NULL, NULL);
|
|
|
|
if (RegStatus == ERROR_SUCCESS) {
|
|
RegDeleteNode(hKey, szSubKey);
|
|
}
|
|
}
|
|
|
|
//
|
|
// either an error occured that prevents me from deleting the
|
|
// keys (like the key doesn't exist in the first place or an
|
|
// access violation) or the subkeys have been deleted, try
|
|
// deleting the top level key again
|
|
//
|
|
RegCloseKey(hKey);
|
|
RegDeleteKey(hParentKey, szKey);
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // RegDeleteNode
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
Split1(
|
|
IN LPCWSTR pszString,
|
|
OUT LPWSTR pszString1,
|
|
OUT LPWSTR pszString2
|
|
)
|
|
{
|
|
BOOL Status = TRUE;
|
|
LPWSTR p;
|
|
|
|
|
|
//
|
|
// Split the string at the first backslash character
|
|
//
|
|
|
|
try {
|
|
|
|
lstrcpy(pszString1, pszString);
|
|
for (p = pszString1; (*p) && (*p != TEXT('\\')); p++);
|
|
|
|
if (*p == TEXT('\0')) {
|
|
Status = FALSE;
|
|
goto Clean0;
|
|
}
|
|
|
|
*p = TEXT('\0'); // truncate string1
|
|
p++;
|
|
lstrcpy(pszString2, p); // the rest is string2
|
|
|
|
|
|
Clean0:
|
|
;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = FALSE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // Split1
|
|
|
|
|
|
|
|
|
|
BOOL
|
|
Split2(
|
|
IN LPCWSTR pszString,
|
|
OUT LPWSTR pszString1,
|
|
OUT LPWSTR pszString2
|
|
)
|
|
{
|
|
BOOL Status = TRUE;
|
|
LPWSTR p;
|
|
|
|
|
|
//
|
|
// Split the string at the second backslash character
|
|
//
|
|
|
|
try {
|
|
|
|
lstrcpy(pszString1, pszString);
|
|
for (p = pszString1; (*p) && (*p != TEXT('\\')); p++); // first
|
|
for (p++; (*p) && (*p != TEXT('\\')); p++); // second
|
|
|
|
*p = TEXT('\0'); // truncate string1
|
|
p++;
|
|
lstrcpy(pszString2, p); // the rest is string2
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Status = FALSE;
|
|
}
|
|
|
|
return Status;
|
|
|
|
} // Split2
|
|
|