Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1258 lines
34 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
registry.c
Abstract:
Registry interface routines for Windows NT Setup API Dll.
Author:
Ted Miller (tedm) 6-Feb-1995
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
//
// Private function prototypes.
//
DWORD
QueryMultiSzDevRegPropToArray(
IN DEVINST DevInst,
IN ULONG CmPropertyCode,
OUT PTSTR **StringArray,
OUT PUINT StringCount
);
DWORD
SetArrayToMultiSzDevRegProp(
IN DEVINST DevInst,
IN ULONG CmPropertyCode,
IN PTSTR *StringArray,
IN UINT StringCount
);
#if MEM_DBG
DWORD
TrackedQueryRegistryValue(
IN TRACK_ARG_DECLARE TRACK_ARG_COMMA
IN HKEY KeyHandle,
IN PCTSTR ValueName,
OUT PTSTR *Value,
OUT PDWORD DataType,
OUT PDWORD DataSizeBytes
)
{
DWORD d;
TRACK_PUSH
// defined again below
#undef QueryRegistryValue
d = QueryRegistryValue (
KeyHandle,
ValueName,
Value,
DataType,
DataSizeBytes
);
TRACK_POP
return d;
}
#endif
DWORD
QueryRegistryValue(
IN HKEY KeyHandle,
IN PCTSTR ValueName,
OUT PTSTR *Value,
OUT PDWORD DataType,
OUT PDWORD DataSizeBytes
)
/*++
Routine Description:
Return an allocated buffer holding a copy of what's in registry
buffer is padded with two extra NULL's so that caller never has
to worry about unterminated strings.
Caller does have to worry about size of fixed-size data
Arguments:
KeyHandle - Key to query value in
ValueName - name of value to query
Value - returned pointer containing value, release with MyFree
DataType - type of returned data
DataSizeBytes - size of returned data in bytes (not TCHAR's!!!)
Return Value:
NO_ERROR iff success
--*/
{
LONG l;
DWORD sz;
sz = 0;
l = RegQueryValueEx(KeyHandle,ValueName,NULL,DataType,NULL,&sz);
*DataSizeBytes = sz;
if(l != NO_ERROR) {
return((DWORD)l);
}
//
// If the size of the value entry is 0 bytes, then return success, but with
// Value set to NULL.
//
if(!sz) {
*Value = NULL;
return NO_ERROR;
}
sz += sizeof(TCHAR)*2; // always pad the buffer with extra zero's
*Value = MyMalloc(sz);
if(*Value == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
l = RegQueryValueEx(KeyHandle,ValueName,NULL,DataType,(PVOID)*Value,DataSizeBytes);
if(l != NO_ERROR) {
MyFree(*Value);
} else {
//
// write 2 NULL chars to end of buffer
//
ZeroMemory(((LPBYTE)*Value)+*DataSizeBytes,sizeof(TCHAR)*2);
}
return((DWORD)l);
}
#if MEM_DBG
#define QueryRegistryValue(a,b,c,d,e) TrackedQueryRegistryValue(TRACK_ARG_CALL,a,b,c,d,e)
#endif
DWORD
QueryRegistryDwordValue(
IN HKEY KeyHandle,
IN PCTSTR ValueName,
OUT PDWORD Value
)
/*++
Routine Description:
Return a DWORD value
If registry is DWORD, return as IS
otherwise convert if data type indicates that's possible
Arguments:
KeyHandle - Key to query value in
ValueName - name of value to query
Value - caller allocated, filled with returned DWORD value
Return Value:
NO_ERROR iff success
--*/
{
DWORD Err;
DWORD DataType;
DWORD DataSize;
PTSTR Data;
Err = QueryRegistryValue(KeyHandle,ValueName,&Data,&DataType,&DataSize);
if(Err != NO_ERROR) {
*Value = 0;
return Err;
}
switch (DataType) {
case REG_DWORD:
if(DataSize != sizeof(DWORD)) {
MyFree(Data);
*Value = 0;
return ERROR_INVALID_DATA;
}
*Value = *(PDWORD)Data;
break;
case REG_SZ:
case REG_EXPAND_SZ:
case REG_MULTI_SZ:
*Value = (DWORD)_tcstoul(Data,NULL,0);
break;
default:
*Value = 0;
break;
}
MyFree(Data);
return NO_ERROR;
}
#if MEM_DBG
DWORD
TrackedQueryDeviceRegistryProperty(
IN TRACK_ARG_DECLARE TRACK_ARG_COMMA
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN DWORD Property,
OUT PTSTR *Value,
OUT PDWORD DataType,
OUT PDWORD DataSizeBytes
)
{
DWORD d;
TRACK_PUSH
// defined again below
#undef QueryDeviceRegistryProperty
d = QueryDeviceRegistryProperty (
DeviceInfoSet,
DeviceInfoData,
Property,
Value,
DataType,
DataSizeBytes
);
TRACK_POP
return d;
}
#endif
DWORD
QueryDeviceRegistryProperty(
IN HDEVINFO DeviceInfoSet,
IN PSP_DEVINFO_DATA DeviceInfoData,
IN DWORD Property,
OUT PTSTR *Value,
OUT PDWORD DataType,
OUT PDWORD DataSizeBytes
)
/*++
Routine Description:
Return an allocated buffer holding a copy of device registry property
Buffer is padded with two extra NULL's so that caller never has
to worry about unterminated strings.
Caller does have to worry about size of fixed-size data
Arguments:
DeviceInfoSet/DeviceInfoData/Property passed to SetupDiGetDeviceRegistryProperty
Value - returned pointer containing value, release with MyFree
DataType - type of returned data
DataSizeBytes - size of returned data in bytes (not TCHAR's!!!)
Return Value:
NO_ERROR iff success
--*/
{
DWORD Err;
DWORD sz;
sz = 0;
Err = SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
DeviceInfoData,
Property,
DataType,
NULL,
0,
&sz)
? NO_ERROR : GetLastError();
*DataSizeBytes = sz;
if((Err != NO_ERROR) && (Err != ERROR_INSUFFICIENT_BUFFER)) {
return Err;
}
//
// If the size of the value entry is 0 bytes, then return success, but with
// Value set to NULL.
//
if(!sz) {
*Value = NULL;
return NO_ERROR;
}
sz += sizeof(TCHAR)*2; // always pad the buffer with extra zero's
*Value = MyMalloc(sz);
if(*Value == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
Err = SetupDiGetDeviceRegistryProperty(DeviceInfoSet,
DeviceInfoData,
Property,
DataType,
(PVOID)*Value,
*DataSizeBytes,
DataSizeBytes)
? NO_ERROR : GetLastError();
if(Err != NO_ERROR) {
MyFree(*Value);
} else {
//
// write 2 NULL chars to end of buffer
//
ZeroMemory(((LPBYTE)*Value)+*DataSizeBytes,sizeof(TCHAR)*2);
}
return Err;
}
#if MEM_DBG
#define QueryDeviceRegistryProperty(a,b,c,d,e,f) TrackedQueryDeviceRegistryProperty(TRACK_ARG_CALL,a,b,c,d,e,f)
#endif
DWORD
pSetupQueryMultiSzValueToArray(
IN HKEY Root,
IN PCTSTR Subkey,
IN PCTSTR ValueName,
OUT PTSTR **Array,
OUT PUINT StringCount,
IN BOOL FailIfDoesntExist
)
{
DWORD d;
HKEY hKey;
DWORD DataType;
DWORD DataSizeBytes;
PTSTR Value;
DWORD DataSizeChars;
INT Count,i;
PTSTR *array;
PTSTR p;
//
// Open the subkey
//
d = RegOpenKeyEx(Root,Subkey,0,KEY_READ,&hKey);
if((d != NO_ERROR) && FailIfDoesntExist) {
return(d);
}
if(d != NO_ERROR) {
Value = MyMalloc(sizeof(TCHAR));
if(!Value) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
*Value = 0;
DataSizeChars = 1;
Count = 0;
} else {
//
// Query the value and close the subkey.
// If the data is not multisz type, we don't know what to
// do with it here.
// note that QueryRegistryValue ensures that the string is
// always correctly double-NULL terminated
//
d = QueryRegistryValue(hKey,ValueName,&Value,&DataType,&DataSizeBytes);
RegCloseKey(hKey);
if(d != NO_ERROR) {
if(FailIfDoesntExist) {
return(d);
}
} else if(!DataSizeBytes) {
//
// Value entry was zero bytes in length--that's OK as long as the
// datatype is right.
//
if(DataType != REG_MULTI_SZ) {
return(ERROR_INVALID_DATA);
}
}
if((d != NO_ERROR) || !DataSizeBytes) {
Value = MyMalloc(sizeof(TCHAR));
if(!Value) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
*Value = 0;
DataSizeChars = 1;
Count = 0;
} else {
if(DataType != REG_MULTI_SZ) {
MyFree(Value);
return(ERROR_INVALID_DATA);
}
DataSizeChars = DataSizeBytes/sizeof(TCHAR);
for(i=0,p=Value; p[0]; i++,p+=lstrlen(p)+1) {
//
// this will always be ok as QueryRegistryValue
// appends two NULLS onto end of string
//
MYASSERT((DWORD)(p-Value) < DataSizeChars);
}
Count = i;
}
}
//
// Allocate an array to hold the pointers (never allocate a zero-length array!)
//
if(!(array = MyMalloc(Count ? (Count * sizeof(PTSTR)) : sizeof(PTSTR)))) {
MyFree(Value);
return(ERROR_INVALID_DATA);
}
//
// Walk through the multi sz and build the string array.
//
for(i=0,p=Value; p[0]; i++,p+=lstrlen(p)+1) {
MYASSERT(i<Count);
array[i] = DuplicateString(p);
if(array[i] == NULL) {
for(Count=0; Count<i; Count++) {
MyFree(array[Count]);
}
MyFree(array);
MyFree(Value);
return(ERROR_NOT_ENOUGH_MEMORY);
}
}
MyFree(Value);
*Array = array;
*StringCount = Count;
return(NO_ERROR);
}
DWORD
pSetupSetArrayToMultiSzValue(
IN HKEY Root,
IN PCTSTR Subkey,
IN PCTSTR ValueName,
IN PTSTR *Array,
IN UINT StringCount
)
{
UINT i;
UINT Length;
UINT BufferSize;
PTCHAR Buffer;
PTCHAR p;
DWORD d;
HKEY hKey;
DWORD ActionTaken;
//
// Calculate the length of the buffer needed to hold the
// multi sz value. Note that empty strings are not allowed.
//
BufferSize = sizeof(TCHAR);
for(i=0; i<StringCount; i++) {
if(Length = lstrlen(Array[i])) {
BufferSize += (Length + 1) * sizeof(TCHAR);
} else {
return(ERROR_INVALID_DATA);
}
}
//
// Allocate a buffer to hold the data.
//
Buffer = MyMalloc(BufferSize);
if(Buffer == NULL) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
//
// Copy the string data into the buffer, forming a multi sz.
//
for(p=Buffer,i=0; i<StringCount; i++,p+=Length+1) {
Length = lstrlen(Array[i]);
lstrcpy(p,Array[i]);
}
*p = 0;
//
// Open/create the subkey.
//
if(Subkey && *Subkey) {
d = RegCreateKeyEx(
Root,
Subkey,
0,
NULL,
REG_OPTION_NON_VOLATILE,
KEY_SET_VALUE,
NULL,
&hKey,
&ActionTaken
);
} else {
hKey = Root;
d = NO_ERROR;
}
if(d == NO_ERROR) {
d = RegSetValueEx(
hKey,
ValueName,
0,
REG_MULTI_SZ,
(PVOID)Buffer,
BufferSize
);
if(hKey != Root) {
RegCloseKey(hKey);
}
}
MyFree(Buffer);
return(d);
}
DWORD
pSetupAppendStringToMultiSz(
IN HKEY Key,
IN PCTSTR SubKeyName, OPTIONAL
IN DWORD DevInst, OPTIONAL
IN PCTSTR ValueName, OPTIONAL
IN PCTSTR String,
IN BOOL AllowDuplicates
)
/*++
Routine Description:
"Old" Exported version of pSetupAppendStringToMultiSz
This doesn't seem to be used anywhere
--*/
{
REGMOD_CONTEXT RegContext;
RegContext.Flags = DevInst ? INF_PFLAG_DEVPROP : 0;
RegContext.UserRootKey = Key;
RegContext.DevInst = DevInst;
return _AppendStringToMultiSz(SubKeyName,ValueName,String,AllowDuplicates,&RegContext,0);
}
DWORD
_AppendStringToMultiSz(
IN PCTSTR SubKeyName, OPTIONAL
IN PCTSTR ValueName, OPTIONAL
IN PCTSTR String,
IN BOOL AllowDuplicates,
IN PREGMOD_CONTEXT RegContext, OPTIONAL
IN UINT Flags OPTIONAL
)
/*++
Routine Description:
Append a string value to a multi_sz.
Arguments:
RegContext->UserRootKey - supplies handle to open registry key. The key must have
KEY_SET_VALUE access.
SubKeyName - if specified, supplies the name of a subkey of Key
where the value is to be stored. If not specified or if ""
then the value is stored in Key. If supplied and the key
doesn't exist, the key is created.
RegContext->DevInst - Optionally, supplies a DEVINST handle for the device
instance corresponding to the hardware storage key specified
by 'Key'. If this handle is specified, and if SubKeyName is
not specified, then the value name being appended will be
checked to see whether it is the name of a device registry
property. If so, then CM APIs will be used to modify the
the corresponding registry property, since the Key handle
represents a separate location under Windows NT.
ValueName - supplies the value entry name of the multi_sz.
If not specified or "" then the unnamed entry is used.
If the value entry does not exist it is created.
String - supplies the string to be added in to the multi_sz.
Must not be an empty string.
AllowDuplicates - if TRUE, then the string is simply appended
to the multi_sz. Otherwise the string is only appended if
no instance of it currently exists in the multi_sz.
RegContext - Passed in from _SetupInstallFromInfSection
Flags - Flags that may have been got from the INF and passed to us
Return Value:
Handle to setup file queue. INVALID_HANDLE_VALUE if insufficient
memory to create the queue.
--*/
{
DWORD d;
DWORD Disposition;
HKEY hKey;
PTSTR *Array;
PVOID p;
BOOL Append;
UINT StringCount;
UINT i;
BOOL IsDevRegProp = FALSE;
BOOL IsClassRegProp = FALSE;
UINT_PTR CmPropertyCode;
MYASSERT(RegContext);
//
// Empty strings really mess up a multi_sz.
//
if(!String || !(*String)) {
return(ERROR_INVALID_PARAMETER);
}
//
// Open/create the key.
//
if(SubKeyName && *SubKeyName) {
d = RegCreateKeyEx(
RegContext->UserRootKey,
SubKeyName,
0,
NULL,
REG_OPTION_NON_VOLATILE,
#ifdef _WIN64
(( Flags & FLG_ADDREG_32BITKEY ) ? KEY_WOW64_32KEY:0) |
#else
(( Flags & FLG_ADDREG_64BITKEY ) ? KEY_WOW64_64KEY:0) |
#endif
KEY_SET_VALUE,
NULL,
&hKey,
&Disposition
);
if(d != NO_ERROR) {
return(d);
}
} else {
//
// If DevInst was specified, then determine whether the specified value is a Plug&Play
// device registry property.
//
if (ValueName && *ValueName) {
if((RegContext->Flags & INF_PFLAG_CLASSPROP) &&
(IsClassRegProp = LookUpStringInTable(InfRegValToClassRegProp, ValueName, &CmPropertyCode))) {
//
// This value is a class registry property. Retrieve the current property's data, and
// format it into the same string array as returned by the pSetupQueryMultiSzValueToArray call
// below.
//
//d = QueryMultiSzClassRegPropToArray(RegModContext->ClassGuid, CmPropertyCode, &Array, &StringCount);
//
// No class properties have MultiSz characteristics, so not implemented
//
d = ERROR_INVALID_DATA;
} else if((RegContext->Flags & INF_PFLAG_DEVPROP) &&
(IsDevRegProp = LookUpStringInTable(InfRegValToDevRegProp, ValueName, &CmPropertyCode))) {
//
// This value is a device registry property. Retrieve the current property's data, and
// format it into the same string array as returned by the pSetupQueryMultiSzValueToArray call
// below.
//
d = QueryMultiSzDevRegPropToArray(RegContext->DevInst, (ULONG)CmPropertyCode, &Array, &StringCount);
}
}
hKey = RegContext->UserRootKey;
}
if(!IsDevRegProp && !IsClassRegProp) {
//
// Query the existing registry value.
//
d = pSetupQueryMultiSzValueToArray(hKey,NULL,ValueName,&Array,&StringCount,FALSE);
}
if(d == NO_ERROR) {
//
// Determine whether to append or replace.
// If replacing, we don't need to do anything!
//
Append = TRUE;
if(!AllowDuplicates) {
for(i=0; i<StringCount; i++) {
if(!lstrcmpi(Array[i],String)) {
Append = FALSE;
break;
}
}
}
if(Append) {
//
// Stick the string on the end.
//
if(p = MyRealloc(Array, (StringCount+1)*sizeof(PTSTR))) {
Array = p;
p = DuplicateString(String);
if(p) {
Array[StringCount++] = p;
} else {
d = ERROR_NOT_ENOUGH_MEMORY;
}
} else {
d = ERROR_NOT_ENOUGH_MEMORY;
}
if(IsDevRegProp) {
d = SetArrayToMultiSzDevRegProp(RegContext->DevInst, (ULONG)CmPropertyCode, Array, StringCount);
} else if(IsClassRegProp) {
//
// not implemented yet, and should return an error before getting here
//
MYASSERT(IsClassRegProp == FALSE);
} else {
d = pSetupSetArrayToMultiSzValue(hKey,NULL,ValueName,Array,StringCount);
}
}
pSetupFreeStringArray(Array,StringCount);
}
if(hKey != RegContext->UserRootKey) {
RegCloseKey(hKey);
}
return(d);
}
DWORD
_DeleteStringFromMultiSz(
IN PCTSTR SubKeyName, OPTIONAL
IN PCTSTR ValueName, OPTIONAL
IN PCTSTR String,
IN UINT Flags,
IN PREGMOD_CONTEXT RegContext OPTIONAL
)
/*++
Routine Description:
Delete a string value from a multi_sz.
Arguments:
RegContext->UserRootKey - supplies handle to open registry key. The key must have
KEY_SET_VALUE access.
SubKeyName - if specified, supplies the name of a subkey of Key
where the value is to be stored. If not specified or if ""
then the value is stored in Key.
RegContext->DevInst - Optionally, supplies a DEVINST handle for the device
instance corresponding to the hardware storage key specified
by 'Key'. If this handle is specified, and if SubKeyName is
not specified, then the value name being appended will be
checked to see whether it is the name of a device registry
property. If so, then CM APIs will be used to modify the
the corresponding registry property, since the Key handle
represents a separate location under Windows NT.
ValueName - supplies the value entry name of the multi_sz.
If not specified or "" then the unnamed entry is used.
String - supplies the string to be added in to the multi_sz.
Must not be an empty string.
Flags - indicates what kind of delete operation
FLG_DELREG_MULTI_SZ_DELSTRING - delete all occurances of string
RegContext - Passed in from _SetupInstallFromInfSection
Return Value:
Handle to setup file queue. INVALID_HANDLE_VALUE if insufficient
memory to create the queue.
--*/
{
DWORD d;
DWORD Disposition;
HKEY hKey;
PTSTR *Array;
PVOID p;
UINT StringCount;
UINT i;
BOOL IsDevRegProp = FALSE;
BOOL IsClassRegProp = FALSE;
BOOL Modified = FALSE;
UINT_PTR CmPropertyCode;
MYASSERT(RegContext);
//
// Can't delete an empty string from multi-sz
//
if(!String || !(*String)) {
return(ERROR_INVALID_PARAMETER);
}
//
// Open the key.
//
if(SubKeyName && *SubKeyName) {
d = RegOpenKeyEx(
RegContext->UserRootKey,
SubKeyName,
0,
#ifdef _WIN64
((Flags & FLG_DELREG_32BITKEY) ? KEY_WOW64_32KEY:0) |
#else
((Flags & FLG_DELREG_64BITKEY) ? KEY_WOW64_64KEY:0) |
#endif
KEY_SET_VALUE | KEY_QUERY_VALUE,
&hKey
);
if(d != NO_ERROR) {
return(d);
}
} else {
if (ValueName && *ValueName) {
//
// If DevInst was specified, then determine whether the specified value is a Plug&Play
// device registry property.
//
if((RegContext->Flags & INF_PFLAG_CLASSPROP) &&
(IsClassRegProp = LookUpStringInTable(InfRegValToClassRegProp, ValueName, &CmPropertyCode))) {
//
// This value is a class registry property. Retrieve the current property's data, and
// format it into the same string array as returned by the pSetupQueryMultiSzValueToArray call
// below.
//
//d = QueryMultiSzClassRegPropToArray(RegModContext->ClassGuid, CmPropertyCode, &Array, &StringCount);
//
// No class properties have MultiSz characteristics, so not implemented
//
d = ERROR_INVALID_DATA;
} else if((RegContext->Flags & INF_PFLAG_DEVPROP) &&
(IsDevRegProp = LookUpStringInTable(InfRegValToDevRegProp, ValueName, &CmPropertyCode))) {
//
// This value is a device registry property. Retrieve the current property's data, and
// format it into the same string array as returned by the pSetupQueryMultiSzValueToArray call
// below.
// fails if not multi-sz
//
d = QueryMultiSzDevRegPropToArray(RegContext->DevInst, (ULONG)CmPropertyCode, &Array, &StringCount);
}
}
hKey = RegContext->UserRootKey;
}
if(!IsDevRegProp && !IsClassRegProp) {
//
// Query the existing registry value.
// fails if not multi-sz
//
d = pSetupQueryMultiSzValueToArray(hKey,NULL,ValueName,&Array,&StringCount,FALSE);
}
if(d == NO_ERROR) {
switch (Flags) {
case FLG_DELREG_32BITKEY | FLG_DELREG_MULTI_SZ_DELSTRING:
case FLG_DELREG_64BITKEY | FLG_DELREG_MULTI_SZ_DELSTRING:
case FLG_DELREG_MULTI_SZ_DELSTRING:
for(i=0; i<StringCount; i++) {
if(lstrcmpi(Array[i],String)==0) {
//
// Need to remove this item.
// and re-adjust the list
//
MyFree(Array[i]);
StringCount--;
if (i<StringCount) {
MoveMemory(
&Array[i],
&Array[i+1],
(StringCount - i) * sizeof(PTSTR)
);
}
i--;
Modified = TRUE;
}
}
break;
default:
MYASSERT(FALSE);
break;
}
if (Modified) {
if(IsDevRegProp) {
d = SetArrayToMultiSzDevRegProp(RegContext->DevInst, (ULONG)CmPropertyCode, Array, StringCount);
} else if(IsClassRegProp) {
//
// not implemented yet, and should return an error before getting here
//
MYASSERT(IsClassRegProp == FALSE);
} else {
d = pSetupSetArrayToMultiSzValue(hKey,NULL,ValueName,Array,StringCount);
}
}
pSetupFreeStringArray(Array,StringCount);
}
if(hKey != RegContext->UserRootKey) {
RegCloseKey(hKey);
}
return(d);
}
VOID
pSetupFreeStringArray(
IN PTSTR *Array,
IN UINT StringCount
)
{
UINT i;
for(i=0; i<StringCount; i++) {
MyFree(Array[i]);
}
MyFree(Array);
}
DWORD
QueryMultiSzDevRegPropToArray(
IN DEVINST DevInst,
IN ULONG CmPropertyCode,
OUT PTSTR **StringArray,
OUT PUINT StringCount
)
/*++
Routine Description:
This routine retrieves a multi-sz device registry property, and
formats it into an array of strings. The caller must free this
string array by calling pSetupFreeStringArray().
Arguments:
DevInst - supplies the handle to the device instance for which the
registry property is to be retrieved.
CmPropertyCode - specifies the property to be retrieved. This is
a CM_DRP value.
StringArray - supplies the address of a variable that will be set to
point to the newly-allocated array of strings.
StringCount - supplies the address of a variable that will receive
the number of strings in the string array.
Return Value:
If successful, the return value is NO_ERROR, otherwise, it is an
ERROR_* code.
--*/
{
DWORD Err = NO_ERROR;
CONFIGRET cr;
ULONG PropDataType, BufferSize = 0;
PTSTR Buffer = NULL;
PTSTR *Array = NULL;
UINT Count, i;
PTSTR CurString;
try {
//
// Retrieve the device registry property.
//
do {
if((cr = CM_Get_DevInst_Registry_Property(DevInst,
CmPropertyCode,
&PropDataType,
Buffer,
&BufferSize,
0)) != CR_SUCCESS) {
switch(cr) {
case CR_BUFFER_SMALL :
//
// Allocate a larger buffer.
//
if(Buffer) {
MyFree(Buffer);
Buffer = NULL;
}
if(!(Buffer = MyMalloc(BufferSize))) {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
break;
case CR_NO_SUCH_VALUE :
//
// The specified property doesn't currently exist. That's
// OK--we'll just return an empty string array.
//
break;
case CR_INVALID_DEVINST :
Err = ERROR_NO_SUCH_DEVINST;
goto clean0;
default :
Err = ERROR_INVALID_DATA;
goto clean0;
}
}
} while(cr == CR_BUFFER_SMALL);
//
// By this point, we've either retrieved the property data (CR_SUCCESS), or we've
// discovered that it doesn't presently exist (CR_NO_SUCH_VALUE). Allocate space
// for the array (at least one element, even if there are no strings).
//
Count = 0;
if(cr == CR_SUCCESS) {
if(PropDataType != REG_MULTI_SZ) {
Err = ERROR_INVALID_DATA;
goto clean0;
}
if (Buffer) {
for(CurString = Buffer;
*CurString;
CurString += (lstrlen(CurString) + 1)) {
Count++;
}
}
}
i = 0;
if(!(Array = MyMalloc(Count ? (Count * sizeof(PTSTR)) : sizeof(PTSTR)))) {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
if(cr == CR_SUCCESS) {
if (Buffer) {
for(CurString = Buffer;
*CurString;
CurString += (lstrlen(CurString) + 1)) {
if(Array[i] = DuplicateString(CurString)) {
i++;
} else {
Err = ERROR_NOT_ENOUGH_MEMORY;
goto clean0;
}
}
}
}
*StringArray = Array;
*StringCount = Count;
clean0: ; // nothing to do
} except(EXCEPTION_EXECUTE_HANDLER) {
Err = ERROR_INVALID_PARAMETER;
//
// Access the following variables here so that the compiler will respect our statement
// ordering w.r.t. these values. Otherwise, we can't be sure that the values are accurate
// at the point where the exception occurred.
//
Buffer = Buffer;
Array = Array;
i = i;
}
if(Buffer) {
MyFree(Buffer);
}
if((Err != NO_ERROR) && Array) {
pSetupFreeStringArray(Array, i);
}
return Err;
}
DWORD
SetArrayToMultiSzDevRegProp(
IN DEVINST DevInst,
IN ULONG CmPropertyCode,
IN PTSTR *StringArray,
IN UINT StringCount
)
/*++
Routine Description:
This routine converts a string array into a multi-sz buffer, and
sets the specified device registry property to its contents.
Arguments:
DevInst - supplies the handle to the device instance for which the
registry property is to be set.
CmPropertyCode - specifies the property to be set. This is a
CM_DRP value.
StringArray - supplies the string array to use in creating the
multi-sz buffer.
StringCount - supplies the number of strings in the array.
Return Value:
If successful, the return value is NO_ERROR, otherwise, it is an
ERROR_* code.
--*/
{
UINT i;
UINT Length;
UINT BufferSize;
PTCHAR Buffer;
PTCHAR p;
DWORD d;
CONFIGRET cr;
//
// Calculate the length of the buffer needed to hold the
// multi sz value. Note that empty strings are not allowed.
//
BufferSize = StringCount ? sizeof(TCHAR) : (2 * sizeof(TCHAR));
for(i=0; i<StringCount; i++) {
if(Length = lstrlen(StringArray[i])) {
BufferSize += (Length + 1) * sizeof(TCHAR);
} else {
return(ERROR_INVALID_DATA);
}
}
d = NO_ERROR;
//
// Allocate a buffer to hold the data.
//
if(!(Buffer = MyMalloc(BufferSize))) {
return(ERROR_NOT_ENOUGH_MEMORY);
}
try {
//
// Copy the string data into the buffer, forming a multi sz.
//
p = Buffer;
if(StringCount) {
for(i=0; i<StringCount; i++, p+=Length+1) {
Length = lstrlen(StringArray[i]);
lstrcpy(p, StringArray[i]);
}
} else {
*(p++) = TEXT('\0');
}
*p = TEXT('\0');
if((cr = CM_Set_DevInst_Registry_Property(DevInst,
CmPropertyCode,
Buffer,
BufferSize,
0)) != CR_SUCCESS) {
d = (cr == CR_INVALID_DEVINST) ? ERROR_NO_SUCH_DEVINST
: ERROR_INVALID_DATA;
}
} except(EXCEPTION_EXECUTE_HANDLER) {
d = ERROR_INVALID_PARAMETER;
}
MyFree(Buffer);
return(d);
}