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.
483 lines
10 KiB
483 lines
10 KiB
/*++
|
|
|
|
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 ))) ||
|
|
(!ARGUMENT_PRESENT( lpcbName ))
|
|
) {
|
|
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 ))) ||
|
|
(!ARGUMENT_PRESENT( lpcbName ))
|
|
) {
|
|
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;
|
|
}
|