windows-nt/Source/XPSP1/NT/base/screg/winreg/client/regqval.c

817 lines
20 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1992 Microsoft Corporation
Module Name:
Regqval.c
Abstract:
This module contains the client side wrappers for the Win32 Registry
query value APIs. That is:
- RegQueryValueA
- RegQueryValueW
- RegQueryValueExA
- RegQueryValueExW
Author:
David J. Gilman (davegi) 18-Mar-1992
Notes:
See the notes in server\regqval.c.
--*/
#include <rpc.h>
#include "regrpc.h"
#include "client.h"
LONG
RegQueryValueA (
HKEY hKey,
LPCSTR lpSubKey,
LPSTR lpData,
PLONG lpcbData
)
/*++
Routine Description:
Win 3.1 ANSI RPC wrapper for querying a value.
--*/
{
HKEY ChildKey;
LONG Error;
DWORD ValueType;
LONG InitialCbData;
HKEY TempHandle = NULL;
#if DBG
if ( BreakPointOnEntry ) {
DbgBreakPoint();
}
#endif
//
// Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
//
if( hKey == HKEY_PERFORMANCE_DATA ) {
return ERROR_INVALID_HANDLE;
}
hKey = MapPredefinedHandle( hKey, &TempHandle );
if( hKey == NULL ) {
Error = ERROR_INVALID_HANDLE;
goto ExitCleanup;
}
//
// If the sub-key is NULL or points to an empty string then the value is
// to be queried from this key (i.e. hKey) otherwise the sub-key needs
// to be opened.
//
if(( lpSubKey == NULL ) || ( *lpSubKey == '\0' )) {
ChildKey = hKey;
} else {
//
// The sub-key was supplied so impersonate the
// client and attempt to open it.
//
Error = RegOpenKeyExA(
hKey,
lpSubKey,
0,
KEY_QUERY_VALUE,
&ChildKey
);
if( Error != ERROR_SUCCESS ) {
goto ExitCleanup;
}
}
InitialCbData = ARGUMENT_PRESENT(lpcbData) ? (*lpcbData) : 0;
//
// ChildKey contains an HKEY which may be the one supplied (hKey) or
// returned from RegOpenKeyExA. Query the value using the special value
// name NULL.
//
Error = RegQueryValueExA(
ChildKey,
NULL,
NULL,
&ValueType,
lpData,
lpcbData
);
//
// If the sub key was opened, close it.
//
if( ChildKey != hKey ) {
if( IsLocalHandle( ChildKey )) {
LocalBaseRegCloseKey( &ChildKey );
} else {
ChildKey = DereferenceRemoteHandle( ChildKey );
BaseRegCloseKey( &ChildKey );
}
}
//
// If the type of the value is not a null terminate string, then return
// an error. (Win 3.1 compatibility)
//
if (!Error && ((ValueType != REG_SZ) && (ValueType != REG_EXPAND_SZ))) {
Error = ERROR_INVALID_DATA;
}
//
// If value doesn't exist, return ERROR_SUCCESS and an empty string.
// (Win 3.1 compatibility)
//
if( Error == ERROR_FILE_NOT_FOUND ) {
if( ARGUMENT_PRESENT( lpcbData ) ) {
*lpcbData = sizeof( CHAR );
}
if( ARGUMENT_PRESENT( lpData ) ) {
*lpData = '\0';
}
Error = ERROR_SUCCESS;
}
//
// Expand if necessary (VB compatibility)
//
if (!Error && (ValueType == REG_EXPAND_SZ)) {
if ( (!ARGUMENT_PRESENT(lpcbData)) || (!ARGUMENT_PRESENT(lpData)) ) {
Error = ERROR_INVALID_DATA;
} else {
LPSTR ExpandBuffer;
LONG ExpandedSize;
LONG BufferSize = (InitialCbData>*lpcbData)?InitialCbData:*lpcbData;
//
// if InitialCbData was 0, allocate a buffer of the real size
//
ExpandBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, BufferSize);
if (ExpandBuffer == NULL) {
Error = ERROR_NOT_ENOUGH_MEMORY;
} else {
RtlCopyMemory(ExpandBuffer, lpData, *lpcbData);
ExpandedSize = ExpandEnvironmentStringsA(ExpandBuffer, lpData, BufferSize);
if (ExpandedSize > InitialCbData) {
Error = ERROR_MORE_DATA;
}
*lpcbData = ExpandedSize;
RtlFreeHeap( RtlProcessHeap(), 0, ExpandBuffer );
}
}
}
//
// Return the results of querying the value.
//
ExitCleanup:
CLOSE_LOCAL_HANDLE(TempHandle);
return Error;
}
LONG
RegQueryValueW (
HKEY hKey,
LPCWSTR lpSubKey,
LPWSTR lpData,
PLONG lpcbData
)
/*++
Routine Description:
Win 3.1 Unicode RPC wrapper for querying a value.
--*/
{
HKEY ChildKey;
LONG Error;
DWORD ValueType;
LONG InitialCbData;
HKEY TempHandle = NULL;
#if DBG
if ( BreakPointOnEntry ) {
DbgBreakPoint();
}
#endif
//
// Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
//
if( hKey == HKEY_PERFORMANCE_DATA ) {
return ERROR_INVALID_HANDLE;
}
hKey = MapPredefinedHandle( hKey, &TempHandle );
if( hKey == NULL ) {
Error = ERROR_INVALID_HANDLE;
goto ExitCleanup;
}
//
// If the sub-key is NULL or points to an empty string then the value is
// to be queried from this key (i.e. hKey) otherwise the sub-key needs
// to be opened.
//
if(( lpSubKey == NULL ) || ( *lpSubKey == '\0' )) {
ChildKey = hKey;
} else {
//
// The sub-key was supplied so attempt to open it.
//
Error = RegOpenKeyExW(
hKey,
lpSubKey,
0,
KEY_QUERY_VALUE,
&ChildKey
);
if( Error != ERROR_SUCCESS ) {
goto ExitCleanup;
}
}
InitialCbData = ARGUMENT_PRESENT(lpcbData) ? (*lpcbData) : 0;
//
// ChildKey contains an HKEY which may be the one supplied (hKey) or
// returned from RegOpenKeyExA. Query the value using the special value
// name NULL.
//
Error = RegQueryValueExW(
ChildKey,
NULL,
NULL,
&ValueType,
( LPBYTE )lpData,
lpcbData
);
//
// If the sub key was opened, close it.
//
if( ChildKey != hKey ) {
if( IsLocalHandle( ChildKey )) {
LocalBaseRegCloseKey( &ChildKey );
} else {
ChildKey = DereferenceRemoteHandle( ChildKey );
BaseRegCloseKey( &ChildKey );
}
}
//
// If the type of the value is not a null terminate string, then return
// an error. (Win 3.1 compatibility)
//
if (!Error && ((ValueType != REG_SZ) && (ValueType != REG_EXPAND_SZ))) {
Error = ERROR_INVALID_DATA;
}
//
// If value doesn't exist, return ERROR_SUCCESS and an empty string.
// (Win 3.1 compatibility)
//
if( Error == ERROR_FILE_NOT_FOUND ) {
if( ARGUMENT_PRESENT( lpcbData ) ) {
*lpcbData = sizeof( WCHAR );
}
if( ARGUMENT_PRESENT( lpData ) ) {
*lpData = ( WCHAR )'\0';
}
Error = ERROR_SUCCESS;
}
//
// Expand if necessary (VB compatibility)
//
if (!Error && (ValueType == REG_EXPAND_SZ)) {
if ( (!ARGUMENT_PRESENT(lpcbData)) || (!ARGUMENT_PRESENT(lpData)) ) {
Error = ERROR_INVALID_DATA;
} else {
LPWSTR ExpandBuffer;
LONG ExpandedSize;
LONG BufferSize = (InitialCbData>*lpcbData)?InitialCbData:*lpcbData;
//
// if InitialCbData was 0, allocate a buffer of the real size
//
ExpandBuffer = RtlAllocateHeap( RtlProcessHeap(), 0, BufferSize);
if (ExpandBuffer == NULL) {
Error = ERROR_NOT_ENOUGH_MEMORY;
} else {
RtlCopyMemory(ExpandBuffer, lpData, *lpcbData);
ExpandedSize = ExpandEnvironmentStringsW(ExpandBuffer, lpData, BufferSize / sizeof(WCHAR));
if (ExpandedSize > (LONG)(InitialCbData / sizeof(WCHAR))) {
Error = ERROR_MORE_DATA;
}
*lpcbData = ExpandedSize;
RtlFreeHeap( RtlProcessHeap(), 0, ExpandBuffer );
}
}
}
//
// Return the results of querying the value.
//
ExitCleanup:
CLOSE_LOCAL_HANDLE(TempHandle);
return Error;
}
LONG
APIENTRY
RegQueryValueExA (
HKEY hKey,
LPCSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpdwType,
LPBYTE lpData,
LPDWORD lpcbData
)
/*++
Routine Description:
Win32 ANSI RPC wrapper for querying a value.
RegQueryValueExA converts the lpValueName argument to a counted Unicode
string and then calls BaseRegQueryValue.
--*/
{
PUNICODE_STRING ValueName;
UNICODE_STRING StubValueName;
DWORD ValueType;
ANSI_STRING AnsiString;
NTSTATUS Status;
LONG Error;
DWORD ValueLength;
DWORD InputLength;
PWSTR UnicodeValueBuffer;
ULONG UnicodeValueLength;
PSTR AnsiValueBuffer;
ULONG AnsiValueLength;
ULONG Index;
ULONG cbAnsi = 0;
HKEY TempHandle = NULL;
#if DBG
if ( BreakPointOnEntry ) {
DbgBreakPoint();
}
#endif
//
// Validate dependency between lpData and lpcbData parameters.
//
if( ARGUMENT_PRESENT( lpReserved ) ||
(ARGUMENT_PRESENT( lpData ) && ( ! ARGUMENT_PRESENT( lpcbData )))) {
return ERROR_INVALID_PARAMETER;
}
hKey = MapPredefinedHandle( hKey, &TempHandle );
if( hKey == NULL ) {
Error = ERROR_INVALID_HANDLE;
goto ExitCleanup;
}
//
// Convert the value name to a counted Unicode string using the static
// Unicode string in the TEB.
//
StubValueName.Buffer = NULL;
ValueName = &NtCurrentTeb( )->StaticUnicodeString;
ASSERT( ValueName != NULL );
RtlInitAnsiString( &AnsiString, lpValueName );
Status = RtlAnsiStringToUnicodeString(
ValueName,
&AnsiString,
FALSE
);
if( ! NT_SUCCESS( Status )) {
//
// The StaticUnicodeString is not long enough; Try to allocate a bigger one
//
Status = RtlAnsiStringToUnicodeString(
&StubValueName,
&AnsiString,
TRUE
);
if( ! NT_SUCCESS( Status )) {
Error = RtlNtStatusToDosError( Status );
goto ExitCleanup;
}
ValueName = &StubValueName;
}
//
// Add the terminating NULL to the Length so that RPC transmits
// it.
//
ValueName->Length += sizeof( UNICODE_NULL );
//
// Call the Base API, passing it the supplied parameters and the
// counted Unicode strings. Note that zero bytes are transmitted (i.e.
// InputLength = 0) for the data.
//
ValueLength = ARGUMENT_PRESENT( lpcbData )? *lpcbData : 0;
InputLength = 0;
if( IsLocalHandle( hKey )) {
Error = (LONG)LocalBaseRegQueryValue (
hKey,
ValueName,
&ValueType,
lpData,
&ValueLength,
&InputLength
);
//
// Make sure that the local side didn't destroy the Buffer in
// the StaticUnicodeString
//
ASSERT( ValueName->Buffer );
} else {
Error = (LONG)BaseRegQueryValue (
DereferenceRemoteHandle( hKey ),
ValueName,
&ValueType,
lpData,
&ValueLength,
&InputLength
);
}
//
// If no error or callers buffer too small, and type is one of the null
// terminated string types, then do the UNICODE to ANSI translation.
// We handle the buffer too small case, because the callers buffer may
// be big enough for the ANSI representation, but not the UNICODE one.
// In this case, we need to allocate a buffer big enough, do the query
// again and then the translation into the callers buffer. We only do
// this if the caller actually wants the value data (lpData != NULL)
//
if ((Error == ERROR_SUCCESS || Error == ERROR_MORE_DATA) &&
(ARGUMENT_PRESENT( lpData ) || ARGUMENT_PRESENT( lpcbData ))&&
(ValueType == REG_SZ ||
ValueType == REG_EXPAND_SZ ||
ValueType == REG_MULTI_SZ)
) {
UnicodeValueLength = ValueLength;
AnsiValueBuffer = lpData;
AnsiValueLength = ARGUMENT_PRESENT( lpcbData )?
*lpcbData : 0;
//
// Allocate a buffer for the UNICODE value and reissue the query.
//
UnicodeValueBuffer = RtlAllocateHeap( RtlProcessHeap(), 0,
UnicodeValueLength
);
if (UnicodeValueBuffer == NULL) {
Error = ERROR_NOT_ENOUGH_MEMORY;
} else {
InputLength = 0;
if( IsLocalHandle( hKey )) {
//
// Add the terminating NULL to the Length
// (remember that in the local case, ValueName->Length
// was decremented by sizeof( UNICODE_NULL ) in the first
// call to LocalBaseRegQueryValue).
// This won't happen in the remote case, since the
// server side will decrement ValueName->Length on
// the transmitted structure (a copy of ValueName), and
// the new Valuename->Length won't be transmitted back to
// the client.
//
ValueName->Length += sizeof( UNICODE_NULL );
Error = (LONG)LocalBaseRegQueryValue (
hKey,
ValueName,
&ValueType,
(LPBYTE)UnicodeValueBuffer,
&ValueLength,
&InputLength
);
//
// Make sure that the local side didn't destroy the
// Buffer in the StaticUnicodeString
//
ASSERT(ValueName->Buffer);
} else {
Error = (LONG)BaseRegQueryValue (
DereferenceRemoteHandle( hKey ),
ValueName,
&ValueType,
(LPBYTE)UnicodeValueBuffer,
&ValueLength,
&InputLength
);
}
if( Error == ERROR_SUCCESS ) {
// Compute needed buffer size , cbAnsi will keeps the byte
// counts to keep MBCS string after following step.
RtlUnicodeToMultiByteSize( &cbAnsi ,
UnicodeValueBuffer ,
ValueLength );
// If we could not store all MBCS string to buffer that
// Apps gives me. We set ERROR_MORE_DATA to Error
if( ARGUMENT_PRESENT( lpcbData ) ) {
if( cbAnsi > *lpcbData && lpData != NULL ) {
Error = ERROR_MORE_DATA;
}
}
} else {
// to be used below
cbAnsi = ValueLength;
}
}
if ((Error == ERROR_SUCCESS) && (AnsiValueBuffer != NULL) ) {
//
// We have a UNICODE value, so translate it to ANSI in the callers
// buffer. In the case where the caller's buffer was big enough
// for the UNICODE version, we do the conversion in place, which
// works since the ANSI version is smaller than the UNICODE version.
//
Index = 0;
Status = RtlUnicodeToMultiByteN( AnsiValueBuffer,
AnsiValueLength,
&Index,
UnicodeValueBuffer,
UnicodeValueLength
);
if (!NT_SUCCESS( Status )) {
Error = RtlNtStatusToDosError( Status );
}
// Now Index keeps Byte counts of MBCS string in AnsiValueBuffer
cbAnsi = Index;
}
//
// Free the buffer if it was successfully allocated
//
if (UnicodeValueBuffer != NULL) {
RtlFreeHeap( RtlProcessHeap(), 0, UnicodeValueBuffer );
}
//
// Return the length of the ANSI version to the caller.
//
ValueLength = cbAnsi;
//
// Special hack to help out all the people who
// believe the length of a NULL terminated string is
// strlen(foo) instead of strlen(foo) + 1.
// If the last character of the buffer is not a NULL
// and there is enough space left in the caller's buffer,
// slap a NULL in there to prevent him from going nuts
// trying to do a strlen().
//
if (ARGUMENT_PRESENT( lpData ) &&
(*lpcbData > ValueLength) &&
(ValueLength > 0) &&
(lpData[ValueLength-1] != '\0')) {
lpData[ValueLength] = '\0';
}
}
//
// Stored the returned length in the caller specified location and
// return the error code.
//
if (lpdwType != NULL) {
*lpdwType = ValueType;
}
if( ARGUMENT_PRESENT( lpcbData ) ) {
*lpcbData = ValueLength;
}
//
// Free the temporary Unicode string stub allocated for the ValueName
//
RtlFreeUnicodeString(&StubValueName);
ExitCleanup:
CLOSE_LOCAL_HANDLE(TempHandle);
return Error;
}
LONG
APIENTRY
RegQueryValueExW (
HKEY hKey,
LPCWSTR lpValueName,
LPDWORD lpReserved,
LPDWORD lpdwType,
LPBYTE lpData,
LPDWORD lpcbData
)
/*++
Routine Description:
Win32 Unicode RPC wrapper for querying a value.
RegQueryValueExW converts the lpValueName argument to a counted Unicode
string and then calls BaseRegQueryValue.
--*/
{
UNICODE_STRING ValueName;
DWORD InputLength;
DWORD ValueLength;
DWORD ValueType;
LONG Error;
UNALIGNED WCHAR *String;
HKEY TempHandle = NULL;
#if DBG
if ( BreakPointOnEntry ) {
DbgBreakPoint();
}
#endif
//
// Validate dependency between lpData and lpcbData parameters.
//
if( ARGUMENT_PRESENT( lpReserved ) ||
(ARGUMENT_PRESENT( lpData ) && ( ! ARGUMENT_PRESENT( lpcbData )))) {
return ERROR_INVALID_PARAMETER;
}
hKey = MapPredefinedHandle( hKey, &TempHandle );
if( hKey == NULL ) {
Error = ERROR_INVALID_HANDLE;
goto ExitCleanup;
}
//
// Convert the value name to a counted Unicode string.
//
RtlInitUnicodeString( &ValueName, lpValueName );
//
// Add the terminating NULL to the Length so that RPC transmits
// it.
//
ValueName.Length += sizeof( UNICODE_NULL );
//
// Call the Base API, passing it the supplied parameters and the
// counted Unicode strings. Note that zero bytes are transmitted (i.e.
// InputLength = 0) for the data.
//
InputLength = 0;
ValueLength = ( ARGUMENT_PRESENT( lpcbData ) )? *lpcbData : 0;
if( IsLocalHandle( hKey )) {
Error = (LONG)LocalBaseRegQueryValue (
hKey,
&ValueName,
&ValueType,
lpData,
&ValueLength,
&InputLength
);
} else {
Error = (LONG)BaseRegQueryValue (
DereferenceRemoteHandle( hKey ),
&ValueName,
&ValueType,
lpData,
&ValueLength,
&InputLength
);
}
//
// Special hack to help out all the people who
// believe the length of a NULL terminated string is
// strlen(foo) instead of strlen(foo) + 1.
// If the last character of the buffer is not a NULL
// and there is enough space left in the caller's buffer,
// slap a NULL in there to prevent him from going nuts
// trying to do a strlen().
//
if ( (Error == ERROR_SUCCESS) &&
ARGUMENT_PRESENT( lpData ) &&
( (ValueType == REG_SZ) ||
(ValueType == REG_EXPAND_SZ) ||
(ValueType==REG_MULTI_SZ)) &&
( ValueLength > sizeof(WCHAR))) {
UNALIGNED WCHAR *String = (UNALIGNED WCHAR *)lpData;
DWORD Length = ValueLength/sizeof(WCHAR);
if ((String[Length-1] != UNICODE_NULL) &&
(ValueLength+sizeof(WCHAR) <= *lpcbData)) {
String[Length] = UNICODE_NULL;
}
}
if( ARGUMENT_PRESENT( lpcbData ) ) {
*lpcbData = ValueLength;
}
if ( ARGUMENT_PRESENT( lpdwType )) {
*lpdwType = ValueType;
}
ExitCleanup:
CLOSE_LOCAL_HANDLE(TempHandle);
return Error;
}