windows-nt/Source/XPSP1/NT/base/screg/winreg/client/regqmval.c
2020-09-26 16:20:57 +08:00

447 lines
14 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
regqmval.c
Abstract:
This module contains the client side wrappers for the Win32 Registry
query multiple values APIs:
- RegQueryMultipleValuesA
- RegQueryMultipleValuesW
Author:
John Vert (jvert) 15-Jun-1995
Revision History:
--*/
#include <rpc.h>
#include "regrpc.h"
#include "client.h"
WINADVAPI
LONG
APIENTRY
RegQueryMultipleValuesA (
HKEY hKey,
PVALENTA val_list,
DWORD num_vals,
LPSTR lpValueBuf,
LPDWORD ldwTotsize
)
/*++
Routine Description:
The RegQueryMultipleValues function retrieves a list of
data type/data pairs for a list of value names associated
with an open registry key.
Parameters:
hKey
Identifies a currently open key or any of the pre-defined reserved handle values:
HKEY_CLASSES_ROOT
HEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
valList
Points to an array of structures describing one or more value entries. This
contains the value names of the values to be queried. Refer to Appendix A for a
description of VALUE_ENTRY structure.
num_vals
Size of valList in bytes. If valListLength is not a multiple of the sizeof pvalue, the
fractional extra space pointed to by valList is ignored.
lpValueBuf
The output buffer for returning value information (value names and value data). Data
is DWORD aligned with pads inserted as necessary.
ldwTotsize
The total size of the output buffer pointed to by lpvalueBuf. On output ldwTotsize
contains the number of bytes used including pads. If lpValueBuf was too short, then on
output ldwTotsize will be the size needed, and caller should assume that lpValueBuf was
filled up to the size specified by ldwTotsize on input.
Return value:
If the function succeeds, the return value is ERROR_SUCCESS; otherwise it is one
of the error value which can be returned by RegQueryValueEx. In addition, if
either valList or lpValueBuf is too small then ERROR_INSUFFICIENT_BUFFER is returned
If the function is unable to instantiate/access the provider of the
dynamic key, it will return ERROR_CANTREAD. If the total length of the
requested data (valListLength + ldwTotSize) is more than the system limit of one
megabytes, then the function returns ERROR_TRANSFER_TOO_LONG and only the first
megabyte of data is returned.
--*/
{
NTSTATUS Status;
PRVALENT Values;
PUNICODE_STRING Names;
LONG Error;
ULONG i;
ULONG DataLength;
ULONG InputLength;
LPDWORD pTotalSize;
DWORD TotalSize;
ANSI_STRING AnsiString;
LPSTR NewValueBuf = NULL;
DWORD DataOffset;
ULONG AnsiLength;
HKEY TempHandle = NULL;
hKey = MapPredefinedHandle(hKey, &TempHandle);
if (hKey == NULL) {
Error = ERROR_INVALID_HANDLE;
goto ExitCleanup;
}
//
// Allocate an array of RVALENTs to describe the input value names
//
Values = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(RVALENT));
if (Values == NULL) {
Error = ERROR_OUTOFMEMORY;
goto ExitCleanup;
}
ZeroMemory(Values, sizeof(RVALENT)*num_vals);
//
// Allocate an array of UNICODE_STRINGs to contain the input names
//
Names = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(UNICODE_STRING));
if (Names == NULL) {
Error = ERROR_OUTOFMEMORY;
goto ExitCleanup;
}
ZeroMemory(Names, num_vals*sizeof(UNICODE_STRING));
//
// Convert the value names to UNICODE_STRINGs
//
for (i=0; i<num_vals; i++) {
RtlInitAnsiString(&AnsiString, val_list[i].ve_valuename);
Status = RtlAnsiStringToUnicodeString(&Names[i], &AnsiString, TRUE);
if (!NT_SUCCESS(Status)) {
Error = RtlNtStatusToDosError( Status );
goto Cleanup;
}
//
// Add the terminating NULL to the Length so that RPC transmits
// it.
//
Names[i].Length += sizeof( UNICODE_NULL );
Values[i].rv_valuename = &Names[i];
}
//
// Allocate a data buffer twice the size of the input buffer
// so that any Unicode value data will fit before it is converted
// to Ansi.
//
if ((ldwTotsize == NULL) || (*ldwTotsize == 0)) {
TotalSize = 0;
} else {
TotalSize = *ldwTotsize * sizeof(WCHAR);
NewValueBuf = RtlAllocateHeap(RtlProcessHeap(),0,TotalSize);
if (NewValueBuf == NULL) {
Error = ERROR_OUTOFMEMORY;
goto Cleanup;
}
}
pTotalSize = &TotalSize;
//
// Call the Base API, passing it the supplied parameters and the
// counted Unicode strings.
//
if (IsLocalHandle(hKey)) {
Error = (LONG)LocalBaseRegQueryMultipleValues(hKey,
Values,
num_vals,
NewValueBuf,
pTotalSize);
} else {
DWORD dwVersion;
Error = (LONG)BaseRegQueryMultipleValues(DereferenceRemoteHandle( hKey ),
Values,
num_vals,
NewValueBuf,
pTotalSize);
if ((Error == ERROR_SUCCESS) &&
(IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion))) {
//
// Win95's RegQueryMultipleValues doesn't return Unicode
// value data, so do not try and convert it back to Ansi.
//
for (i=0; i<num_vals; i++) {
val_list[i].ve_valuelen = Values[i].rv_valuelen;
val_list[i].ve_type = Values[i].rv_type;
val_list[i].ve_valueptr = (DWORD_PTR)(lpValueBuf + Values[i].rv_valueptr);
}
CopyMemory(lpValueBuf,NewValueBuf,TotalSize);
if (ldwTotsize != NULL) {
*ldwTotsize = TotalSize;
}
goto Cleanup;
}
}
if (Error == ERROR_SUCCESS) {
//
// Convert results back.
//
DataOffset = 0;
for (i=0; i < num_vals; i++) {
val_list[i].ve_valuelen = Values[i].rv_valuelen;
val_list[i].ve_type = Values[i].rv_type;
val_list[i].ve_valueptr = (DWORD_PTR)(lpValueBuf + DataOffset);
if ((val_list[i].ve_type == REG_SZ) ||
(val_list[i].ve_type == REG_EXPAND_SZ) ||
(val_list[i].ve_type == REG_MULTI_SZ)) {
Status = RtlUnicodeToMultiByteN(lpValueBuf + DataOffset,
Values[i].rv_valuelen/sizeof(WCHAR),
&AnsiLength,
(PWCH)(NewValueBuf + Values[i].rv_valueptr),
Values[i].rv_valuelen);
if (!NT_SUCCESS(Status)) {
Error = RtlNtStatusToDosError( Status );
}
val_list[i].ve_valuelen = AnsiLength;
DataOffset += AnsiLength;
} else {
CopyMemory(lpValueBuf + DataOffset,
NewValueBuf + Values[i].rv_valueptr,
Values[i].rv_valuelen);
DataOffset += Values[i].rv_valuelen;
}
//
// Round DataOffset up to dword boundary.
//
DataOffset = (DataOffset + sizeof(DWORD) - 1) & ~(sizeof(DWORD)-1);
}
if (ldwTotsize != NULL) {
*ldwTotsize = DataOffset;
}
} else if (Error == ERROR_MORE_DATA) {
//
// We need to thunk the Unicode required bytes back to Ansi. But
// there is not really any way to do this without having the data
// available. So just return the required bytes for the Unicode
// data, as this will always be enough.
//
if (ldwTotsize != NULL) {
*ldwTotsize = *pTotalSize;
}
}
Cleanup:
if (NewValueBuf != NULL) {
RtlFreeHeap(RtlProcessHeap(),0,NewValueBuf);
}
for (i=0; i<num_vals; i++) {
if (Names[i].Buffer != NULL) {
RtlFreeUnicodeString(&Names[i]);
}
}
RtlFreeHeap(RtlProcessHeap(),0,Values);
RtlFreeHeap(RtlProcessHeap(),0,Names);
ExitCleanup:
CLOSE_LOCAL_HANDLE(TempHandle);
return Error;
}
WINADVAPI
LONG
APIENTRY
RegQueryMultipleValuesW (
HKEY hKey,
PVALENTW val_list,
DWORD num_vals,
LPWSTR lpValueBuf,
LPDWORD ldwTotsize
)
/*++
Routine Description:
The RegQueryMultipleValues function retrieves a list of
data type/data pairs for a list of value names associated
with an open registry key.
Parameters:
hKey
Identifies a currently open key or any of the pre-defined reserved handle values:
HKEY_CLASSES_ROOT
HEY_CURRENT_USER
HKEY_LOCAL_MACHINE
HKEY_USERS
valList
Points to an array of structures describing one or more value entries. This
contains the value names of the values to be queried. Refer to Appendix A for a
description of VALUE_ENTRY structure.
num_vals
Size of valList in bytes. If valListLength is not a multiple of the sizeof pvalue, the
fractional extra space pointed to by valList is ignored.
lpValueBuf
The output buffer for returning value information (value names and value data). Data
is DWORD aligned with pads inserted as necessary.
ldwTotsize
The total size of the output buffer pointed to by lpValueBuf. On output ldwTotsize
contains the number of bytes used including pads. If lpValueBuf was too short, then on
output ldwTotsize will be the size needed, and caller should assume that lpValueBuf was
filled up to the size specified by ldwTotsize on input.
Return value:
If the function succeeds, the return value is ERROR_SUCCESS; otherwise it is one
of the error value which can be returned by RegQueryValueEx. In addition, if
either valList or lpValueBuf is too small then ERROR_INSUFFICIENT_BUFFER is returned
If the function is unable to instantiate/access the provider of the
dynamic key, it will return ERROR_CANTREAD. If the total length of the
requested data (valListLength + ldwTotSize) is more than the system limit of one
megabytes, then the function returns ERROR_TRANSFER_TOO_LONG and only the first
megabyte of data is returned.
--*/
{
NTSTATUS Status;
PRVALENT Values;
PUNICODE_STRING Names;
LONG Error;
ULONG i;
ULONG DataLength;
ULONG InputLength;
LPDWORD pTotalSize;
DWORD TotalSize;
DWORD StringLength;
HKEY TempHandle = NULL;
hKey = MapPredefinedHandle(hKey, &TempHandle);
if (hKey == NULL) {
Error = ERROR_INVALID_HANDLE;
goto ExitCleanup;
}
//
// Allocate an array of RVALENTs to describe the input value names
//
Values = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(RVALENT));
if (Values == NULL) {
Error = ERROR_OUTOFMEMORY;
goto ExitCleanup;
}
ZeroMemory(Values, sizeof(RVALENT)*num_vals);
//
// Allocate an array of UNICODE_STRINGs to contain the input names
//
Names = RtlAllocateHeap(RtlProcessHeap(),0,num_vals * sizeof(UNICODE_STRING));
if (Names == NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, Values);
Error = ERROR_OUTOFMEMORY;
goto ExitCleanup;
}
ZeroMemory(Names, num_vals*sizeof(UNICODE_STRING));
//
// Copy and convert the value names to UNICODE_STRINGs
// Note that we have to copy the value names because RPC tromps
// on them.
//
for (i=0; i<num_vals; i++) {
StringLength = wcslen(val_list[i].ve_valuename)*sizeof(WCHAR);
Names[i].Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, StringLength + sizeof(UNICODE_NULL));
if (Names[i].Buffer == NULL) {
goto error_exit;
}
Names[i].Length = Names[i].MaximumLength = (USHORT)StringLength + sizeof(UNICODE_NULL);
CopyMemory(Names[i].Buffer, val_list[i].ve_valuename, StringLength + sizeof(UNICODE_NULL));
Values[i].rv_valuename = &Names[i];
}
if (ldwTotsize == NULL) {
TotalSize = 0;
pTotalSize = &TotalSize;
} else {
pTotalSize = ldwTotsize;
}
//
// Call the Base API, passing it the supplied parameters and the
// counted Unicode strings.
//
if (IsLocalHandle(hKey)) {
Error = (LONG)LocalBaseRegQueryMultipleValues(hKey,
Values,
num_vals,
(LPSTR)lpValueBuf,
pTotalSize);
} else {
DWORD dwVersion;
if (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion)) {
//
// We cannot support RegQueryMultipleValuesW to Win95 servers
// since they do not return Unicode value data.
//
Error = ERROR_CALL_NOT_IMPLEMENTED;
} else {
Error = (LONG)BaseRegQueryMultipleValues(DereferenceRemoteHandle( hKey ),
Values,
num_vals,
(LPSTR)lpValueBuf,
pTotalSize);
}
}
if (Error == ERROR_SUCCESS) {
//
// Convert results back.
//
for (i=0; i < num_vals; i++) {
val_list[i].ve_valuelen = Values[i].rv_valuelen;
val_list[i].ve_valueptr = (DWORD_PTR)((LPCSTR)lpValueBuf + Values[i].rv_valueptr);
val_list[i].ve_type = Values[i].rv_type;
}
}
error_exit:
for (i=0; i < num_vals; i++) {
if (Names[i].Buffer != NULL) {
RtlFreeHeap(RtlProcessHeap(), 0, Names[i].Buffer);
}
}
RtlFreeHeap(RtlProcessHeap(),0,Values);
RtlFreeHeap(RtlProcessHeap(),0,Names);
ExitCleanup:
CLOSE_LOCAL_HANDLE(TempHandle);
return Error;
}