/*++

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;
}