481 lines
9.7 KiB
C
481 lines
9.7 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Regekey.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the client side wrappers for the Win32 Registry
|
||
enumerate key APIs. That is:
|
||
|
||
- RegEnumKeyA
|
||
- RegEnumKeyW
|
||
- RegEnumKeyExA
|
||
- RegEnumKeyExW
|
||
|
||
Author:
|
||
|
||
David J. Gilman (davegi) 18-Mar-1992
|
||
|
||
Notes:
|
||
|
||
See the notes in server\regekey.c.
|
||
|
||
--*/
|
||
|
||
#include <rpc.h>
|
||
#include "regrpc.h"
|
||
#include "client.h"
|
||
|
||
LONG
|
||
APIENTRY
|
||
RegEnumKeyA (
|
||
HKEY hKey,
|
||
DWORD dwIndex,
|
||
LPSTR lpName,
|
||
DWORD cbName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Win 3.1 ANSI RPC wrapper for enumerating keys.
|
||
|
||
--*/
|
||
|
||
{
|
||
#if DBG
|
||
if ( BreakPointOnEntry ) {
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
|
||
//
|
||
|
||
if( hKey == HKEY_PERFORMANCE_DATA ) {
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
return RegEnumKeyExA (
|
||
hKey,
|
||
dwIndex,
|
||
lpName,
|
||
&cbName,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
LONG
|
||
APIENTRY
|
||
RegEnumKeyW (
|
||
HKEY hKey,
|
||
DWORD dwIndex,
|
||
LPWSTR lpName,
|
||
DWORD cbName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Win 3.1 Unicode RPC wrapper for enumerating keys.
|
||
|
||
--*/
|
||
|
||
{
|
||
#if DBG
|
||
if ( BreakPointOnEntry ) {
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Limit the capabilities associated with HKEY_PERFORMANCE_DATA.
|
||
//
|
||
|
||
if( hKey == HKEY_PERFORMANCE_DATA ) {
|
||
return ERROR_INVALID_HANDLE;
|
||
}
|
||
|
||
return RegEnumKeyExW (
|
||
hKey,
|
||
dwIndex,
|
||
lpName,
|
||
&cbName,
|
||
NULL,
|
||
NULL,
|
||
NULL,
|
||
NULL
|
||
);
|
||
}
|
||
|
||
LONG
|
||
APIENTRY
|
||
RegEnumKeyExA (
|
||
HKEY hKey,
|
||
DWORD dwIndex,
|
||
LPSTR lpName,
|
||
LPDWORD lpcbName,
|
||
LPDWORD lpReserved,
|
||
LPSTR lpClass,
|
||
LPDWORD lpcbClass,
|
||
PFILETIME lpftLastWriteTime
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Win32 ANSI API for enumerating keys.
|
||
|
||
--*/
|
||
|
||
{
|
||
UNICODE_STRING Name;
|
||
UNICODE_STRING Class;
|
||
WCHAR ClassBuffer[ MAX_PATH ];
|
||
PUNICODE_STRING ClassPointer;
|
||
ANSI_STRING AnsiString;
|
||
NTSTATUS Status;
|
||
LONG Error = ERROR_SUCCESS;
|
||
HKEY TempHandle = NULL;
|
||
|
||
|
||
#if DBG
|
||
if ( BreakPointOnEntry ) {
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Validate dependency between lpClass and lpcbClass parameters.
|
||
//
|
||
|
||
if( ARGUMENT_PRESENT( lpReserved ) ||
|
||
(ARGUMENT_PRESENT( lpClass ) && ( ! ARGUMENT_PRESENT( lpcbClass )))) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
hKey = MapPredefinedHandle( hKey,&TempHandle );
|
||
if( hKey == NULL ) {
|
||
Error = ERROR_INVALID_HANDLE;
|
||
goto ExitCleanup;
|
||
}
|
||
|
||
//
|
||
// Allocate temporary buffer for the Name
|
||
//
|
||
Name.Length = 0;
|
||
Name.MaximumLength = (USHORT)((*lpcbName + 1) * sizeof( WCHAR ));
|
||
Name.Buffer = RtlAllocateHeap( RtlProcessHeap(), 0, Name.MaximumLength );
|
||
if( Name.Buffer == NULL ) {
|
||
Error = ERROR_NOT_ENOUGH_MEMORY;
|
||
goto ExitCleanup;
|
||
}
|
||
|
||
//
|
||
// If the class string is to be returned, initialize a UNICODE_STRING
|
||
//
|
||
|
||
ClassPointer = &Class;
|
||
ClassPointer->Length = 0;
|
||
|
||
if( ARGUMENT_PRESENT( lpClass )) {
|
||
|
||
ClassPointer->MaximumLength = MAX_PATH;
|
||
ClassPointer->Buffer = ( PVOID ) ClassBuffer;
|
||
|
||
} else {
|
||
|
||
ClassPointer->MaximumLength = 0;
|
||
ClassPointer->Buffer = NULL;
|
||
}
|
||
|
||
|
||
|
||
|
||
//
|
||
// Call the Base API passing it a pointer to the counted Unicode
|
||
// strings for the name and class.
|
||
//
|
||
|
||
if( IsLocalHandle( hKey )) {
|
||
|
||
Error = (LONG)LocalBaseRegEnumKey (
|
||
hKey,
|
||
dwIndex,
|
||
&Name,
|
||
ClassPointer,
|
||
lpftLastWriteTime
|
||
);
|
||
} else {
|
||
|
||
Error = (LONG)BaseRegEnumKey (
|
||
DereferenceRemoteHandle( hKey ),
|
||
dwIndex,
|
||
&Name,
|
||
ClassPointer,
|
||
lpftLastWriteTime
|
||
);
|
||
}
|
||
|
||
//
|
||
// If the information was not succesfully queried return the error.
|
||
//
|
||
|
||
if( Error != ERROR_SUCCESS ) {
|
||
// free allocated buffer
|
||
RtlFreeHeap( RtlProcessHeap(), 0, Name.Buffer );
|
||
goto ExitCleanup;
|
||
}
|
||
|
||
//
|
||
// Subtact the NULL from Length, which was added by the server
|
||
// so that RPC would transmit it.
|
||
//
|
||
|
||
Name.Length -= sizeof( UNICODE_NULL );
|
||
|
||
if ( ClassPointer->Length > 0 ) {
|
||
ClassPointer->Length -= sizeof( UNICODE_NULL );
|
||
}
|
||
|
||
//
|
||
// Convert the name to ANSI.
|
||
//
|
||
// If somebody passed in a really big buffer, pretend it's
|
||
// not quite so big so that it doesn't get truncated to zero.
|
||
//
|
||
if (*lpcbName > 0xFFFF) {
|
||
AnsiString.MaximumLength = ( USHORT ) 0xFFFF;
|
||
} else {
|
||
AnsiString.MaximumLength = ( USHORT ) *lpcbName;
|
||
}
|
||
|
||
AnsiString.Buffer = lpName;
|
||
|
||
Status = RtlUnicodeStringToAnsiString(
|
||
&AnsiString,
|
||
&Name,
|
||
FALSE
|
||
);
|
||
|
||
// free allocated buffer
|
||
RtlFreeHeap( RtlProcessHeap(), 0, Name.Buffer );
|
||
|
||
//
|
||
// If the name conversion failed, map and return the error.
|
||
//
|
||
|
||
if( ! NT_SUCCESS( Status )) {
|
||
Error = RtlNtStatusToDosError( Status );
|
||
goto ExitCleanup;
|
||
}
|
||
|
||
//
|
||
// Update the name length return parameter.
|
||
//
|
||
|
||
*lpcbName = AnsiString.Length;
|
||
|
||
//
|
||
// If requested, convert the class to ANSI.
|
||
//
|
||
|
||
if( ARGUMENT_PRESENT( lpClass )) {
|
||
|
||
AnsiString.MaximumLength = ( USHORT ) *lpcbClass;
|
||
AnsiString.Buffer = lpClass;
|
||
|
||
Status = RtlUnicodeStringToAnsiString(
|
||
&AnsiString,
|
||
ClassPointer,
|
||
FALSE
|
||
);
|
||
|
||
//
|
||
// If the class conversion failed, map and return the error.
|
||
//
|
||
|
||
if( ! NT_SUCCESS( Status )) {
|
||
Error = RtlNtStatusToDosError( Status );
|
||
goto ExitCleanup;
|
||
}
|
||
|
||
//
|
||
// If requested, return the class length parameter w/o the NUL.
|
||
//
|
||
|
||
if( ARGUMENT_PRESENT( lpcbClass )) {
|
||
*lpcbClass = AnsiString.Length;
|
||
}
|
||
|
||
//
|
||
// It is possible to ask for the size of the class w/o asking for the
|
||
// class itself.
|
||
//
|
||
|
||
} else if( ARGUMENT_PRESENT( lpcbClass )) {
|
||
*lpcbClass = ( ClassPointer->Length >> 1 );
|
||
}
|
||
|
||
|
||
ExitCleanup:
|
||
|
||
CLOSE_LOCAL_HANDLE(TempHandle);
|
||
return Error;
|
||
}
|
||
|
||
LONG
|
||
APIENTRY
|
||
RegEnumKeyExW (
|
||
HKEY hKey,
|
||
DWORD dwIndex,
|
||
LPWSTR lpName,
|
||
LPDWORD lpcbName,
|
||
LPDWORD lpReserved,
|
||
LPWSTR lpClass,
|
||
LPDWORD lpcbClass,
|
||
PFILETIME lpftLastWriteTime
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Win32 Unicode RPC wrapper for enumerating keys.
|
||
|
||
--*/
|
||
|
||
|
||
{
|
||
LONG Error;
|
||
UNICODE_STRING Name;
|
||
UNICODE_STRING Class;
|
||
PUNICODE_STRING ClassPointer;
|
||
HKEY TempHandle = NULL;
|
||
|
||
|
||
#if DBG
|
||
if ( BreakPointOnEntry ) {
|
||
DbgBreakPoint();
|
||
}
|
||
#endif
|
||
|
||
|
||
//
|
||
// Validate dependency between lpClass and lpcbClass parameters.
|
||
//
|
||
if( ARGUMENT_PRESENT( lpReserved ) ||
|
||
(ARGUMENT_PRESENT( lpClass ) && ( ! ARGUMENT_PRESENT( lpcbClass )))) {
|
||
return ERROR_INVALID_PARAMETER;
|
||
}
|
||
|
||
hKey = MapPredefinedHandle( hKey, &TempHandle );
|
||
if( hKey == NULL ) {
|
||
Error = ERROR_INVALID_HANDLE;
|
||
goto ExitCleanup;
|
||
}
|
||
|
||
//
|
||
// Use the supplied name string buffer as the buffer in a counted
|
||
// Unicode string.
|
||
//
|
||
|
||
Name.Length = 0;
|
||
if ((*lpcbName << 1) > 0xFFFE) {
|
||
Name.MaximumLength = ( USHORT ) 0xFFFE;
|
||
} else {
|
||
Name.MaximumLength = ( USHORT )( *lpcbName << 1 );
|
||
}
|
||
Name.Buffer = lpName;
|
||
|
||
//
|
||
// If supplied use the supplied name string buffer as the buffer in a
|
||
// counted Unicode string.
|
||
//
|
||
ClassPointer = &Class;
|
||
|
||
if( ARGUMENT_PRESENT( lpClass )) {
|
||
|
||
Class.Length = 0;
|
||
Class.MaximumLength = ( USHORT )( *lpcbClass << 1 );
|
||
Class.Buffer = lpClass;
|
||
|
||
} else {
|
||
|
||
Class.Length = 0;
|
||
Class.MaximumLength = 0;
|
||
Class.Buffer = NULL;
|
||
}
|
||
|
||
//
|
||
// Call the Base API passing it a pointer to the counted Unicode
|
||
// strings for the name and class and return the results.
|
||
//
|
||
|
||
if( IsLocalHandle( hKey )) {
|
||
|
||
Error = (LONG)LocalBaseRegEnumKey (
|
||
hKey,
|
||
dwIndex,
|
||
&Name,
|
||
ClassPointer,
|
||
lpftLastWriteTime
|
||
);
|
||
} else {
|
||
|
||
Error = (LONG)BaseRegEnumKey (
|
||
DereferenceRemoteHandle( hKey ),
|
||
dwIndex,
|
||
&Name,
|
||
ClassPointer,
|
||
lpftLastWriteTime
|
||
);
|
||
}
|
||
|
||
//
|
||
// Subtact the NULL from Length, which was added by the server
|
||
// so that RPC would transmit it.
|
||
//
|
||
|
||
if ( Name.Length > 0 ) {
|
||
Name.Length -= sizeof( UNICODE_NULL );
|
||
}
|
||
|
||
if ( ClassPointer->Length > 0 ) {
|
||
ClassPointer->Length -= sizeof( UNICODE_NULL );
|
||
}
|
||
|
||
//
|
||
// Return the name length parameter w/o the NUL.
|
||
//
|
||
|
||
if( Error == ERROR_SUCCESS ) {
|
||
|
||
*lpcbName = ( Name.Length >> 1 );
|
||
}
|
||
|
||
//
|
||
// If requested, return the class length parameter w/o the NUL.
|
||
//
|
||
|
||
if( ARGUMENT_PRESENT( lpcbClass )) {
|
||
*lpcbClass = ( Class.Length >> 1 );
|
||
}
|
||
|
||
ExitCleanup:
|
||
|
||
CLOSE_LOCAL_HANDLE(TempHandle);
|
||
return Error;
|
||
}
|