//
//  REGQKEY.C
//
//  Copyright (C) Microsoft Corporation, 1995
//
//  Implementation of RegQueryInfoKey.
//

#include "pch.h"

//
//  VMMRegQueryInfoKey
//
//  See Win32 documentation of RegQueryInfoKey.  When VXD is defined, this
//  function does not take all of the parameters that we end up ignoring anyway
//  (class, security, timestamp parameters).
//

#ifdef VXD
LONG
REGAPI
VMMRegQueryInfoKey(
    HKEY hKey,
    LPDWORD lpcSubKeys,
    LPDWORD lpcbMaxSubKeyLen,
    LPDWORD lpcValues,
    LPDWORD lpcbMaxValueName,
    LPDWORD lpcbMaxValueData
    )
#else
LONG
REGAPI
VMMRegQueryInfoKey(
    HKEY hKey,
    LPSTR lpClass,
    LPDWORD lpcbClass,
    LPDWORD lpReserved,
    LPDWORD lpcSubKeys,
    LPDWORD lpcbMaxSubKeyLen,
    LPDWORD lpcbMaxClassLen,
    LPDWORD lpcValues,
    LPDWORD lpcbMaxValueName,
    LPDWORD lpcbMaxValueData,
    LPVOID lpcbSecurityDescriptor,
    LPVOID lpftLastWriteTime
    )
#endif
{

    int ErrorCode;
    LPVALUE_RECORD lpValueRecord;
    UINT cItems;
    DWORD cbValueData;
    DWORD cbMaxValueData;
    DWORD cbStringLen;
    DWORD cbMaxStringLen;

    if (IsBadHugeOptionalWritePtr(lpcSubKeys, sizeof(DWORD)) ||
        IsBadHugeOptionalWritePtr(lpcbMaxSubKeyLen, sizeof(DWORD)) ||
        IsBadHugeOptionalWritePtr(lpcValues, sizeof(DWORD)) ||
        IsBadHugeOptionalWritePtr(lpcbMaxValueName, sizeof(DWORD)) ||
        IsBadHugeOptionalWritePtr(lpcbMaxValueData, sizeof(DWORD)))
        return ERROR_INVALID_PARAMETER;

    if (!RgLockRegistry())
        return ERROR_LOCK_FAILED;

    if ((ErrorCode = RgValidateAndConvertKeyHandle(&hKey)) != ERROR_SUCCESS)
        goto ReturnErrorCode;

    //
    //  Compute cValues, cbMaxValueName, and cbMaxValueData.
    //

    if (!IsNullPtr(lpcValues) || !IsNullPtr(lpcbMaxValueName) ||
        !IsNullPtr(lpcbMaxValueData)) {

        cItems = 0;
        cbMaxStringLen = 0;
        cbMaxValueData = 0;

        while ((ErrorCode = RgLookupValueByIndex(hKey, cItems,
            &lpValueRecord)) == ERROR_SUCCESS) {

            cItems++;

            if (lpValueRecord-> NameLength > cbMaxStringLen)
                cbMaxStringLen = lpValueRecord-> NameLength;

            //  RgCopyFromValueRecord will handle static and dynamic keys...
            ErrorCode = RgCopyFromValueRecord(hKey, lpValueRecord, NULL, NULL,
                NULL, NULL, &cbValueData);

            RgUnlockDatablock(hKey-> lpFileInfo, hKey-> BigKeyLockedBlockIndex, FALSE);

            if (ErrorCode != ERROR_SUCCESS)
                goto ReturnErrorCode;

            if (cbValueData > cbMaxValueData)
                cbMaxValueData = cbValueData;

        }

        if (ErrorCode == ERROR_NO_MORE_ITEMS) {

            if (!IsNullPtr(lpcValues))
                *lpcValues = cItems;

            if (!IsNullPtr(lpcbMaxValueName))
                *lpcbMaxValueName = cbMaxStringLen;

            if (!IsNullPtr(lpcbMaxValueData))
                *lpcbMaxValueData = cbMaxValueData;

            ErrorCode = ERROR_SUCCESS;

        }

    }

    //
    //  Compute cSubKeys and cbMaxSubKeyLen.  Somewhat painful because we must
    //  touch each child keynode and datablock.
    //

    if (!IsNullPtr(lpcSubKeys) || !IsNullPtr(lpcbMaxSubKeyLen)) {

        cItems = 0;
        cbMaxStringLen = 0;
        cbStringLen = 0;

        while (TRUE) {
            ErrorCode = RgLookupKeyByIndex(hKey, cItems, NULL,
                &cbStringLen, 0);

            if ((ErrorCode != ERROR_SUCCESS) && (ErrorCode != ERROR_MORE_DATA))
                break;
            cItems++;

            // Win95 compatibility: the old code included the null terminator, even
            // though the documentation for RegQueryInfoKey states that it doesn't.
            if (cbStringLen && (cbStringLen + 1 > cbMaxStringLen))
                cbMaxStringLen = cbStringLen + 1;

        }

        if (ErrorCode == ERROR_NO_MORE_ITEMS) {

            if (!IsNullPtr(lpcSubKeys))
                *lpcSubKeys = cItems;

            if (!IsNullPtr(lpcbMaxSubKeyLen))
                *lpcbMaxSubKeyLen = cbMaxStringLen;

            ErrorCode = ERROR_SUCCESS;

        }

    }

ReturnErrorCode:
    RgUnlockRegistry();

    return ErrorCode;

#ifndef VXD
    UNREFERENCED_PARAMETER(lpClass);
    UNREFERENCED_PARAMETER(lpcbClass);
    UNREFERENCED_PARAMETER(lpReserved);
    UNREFERENCED_PARAMETER(lpcbMaxClassLen);
    UNREFERENCED_PARAMETER(lpcbSecurityDescriptor);
    UNREFERENCED_PARAMETER(lpftLastWriteTime);
#endif

}
