/*++ Copyright (c) 1992 Microsoft Corporation Module Name: Regqkey.c Abstract: This module contains the client side wrappers for the Win32 Registry query key APIs. That is: - RegQueryInfoKeyA - RegQueryInfoKeyW Author: David J. Gilman (davegi) 18-Mar-1992 Notes: See the notes in server\regqkey.c. --*/ #include #include "regrpc.h" #include "client.h" LONG RegQueryInfoKeyA ( HKEY hKey, LPSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ) /*++ Routine Description: Win32 ANSI RPC wrapper for querying information about a previously opened key. --*/ { PUNICODE_STRING Class; UNICODE_STRING UnicodeString; ANSI_STRING AnsiString; NTSTATUS Status; LONG Error; DWORD cSubKeys; DWORD cbMaxSubKeyLen; DWORD cValues; DWORD cbMaxValueNameLen; DWORD cbMaxValueLen; FILETIME ftLastWriteTime; HKEY TempHandle = NULL; DWORD cbMaxClassLen; DWORD cbSecurityDescriptor; PDWORD pCbMaxClassLen = NULL; PDWORD pCbSecurityDescriptor = NULL; #if DBG if ( BreakPointOnEntry ) { DbgBreakPoint(); } #endif 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; } // // Make sure that the buffer size for lpClass is zero if lpClass is NULL // if( !ARGUMENT_PRESENT( lpClass ) && ARGUMENT_PRESENT( lpcbClass ) ) { *lpcbClass = 0; } if( ARGUMENT_PRESENT( lpcbMaxClassLen ) ) { pCbMaxClassLen = &cbMaxClassLen; } if( ARGUMENT_PRESENT( lpcbSecurityDescriptor ) ) { pCbSecurityDescriptor = &cbSecurityDescriptor; } // // If the count of bytes in the class is 0, pass a NULL pointer // instead of what was supplied. This ensures that RPC won't // attempt to copy data to a bogus pointer. Note that in this // case we use the unicode string allocated on the stack, because // we must not change the Buffer or MaximumLength fields of the // static unicode string in the TEB. // if ( !ARGUMENT_PRESENT( lpClass ) || *lpcbClass == 0 ) { Class = &UnicodeString; Class->Length = 0; Class->MaximumLength = 0; Class->Buffer = NULL; } else { // // Use the static Unicode string in the TEB as a temporary for the // key's class. // Class = &NtCurrentTeb( )->StaticUnicodeString; ASSERT( Class != NULL ); Class->Length = 0; } // // Call the Base API passing it a pointer to a counted Unicode string // for the class string. // if( IsLocalHandle( hKey )) { Error = (LONG)LocalBaseRegQueryInfoKey( hKey, Class, &cSubKeys, &cbMaxSubKeyLen, pCbMaxClassLen, &cValues, &cbMaxValueNameLen, &cbMaxValueLen, pCbSecurityDescriptor, &ftLastWriteTime ); } else { // // on RPC always send valid pointers!!! // pCbMaxClassLen = &cbMaxClassLen; pCbSecurityDescriptor = &cbSecurityDescriptor; Error = (LONG)BaseRegQueryInfoKey( DereferenceRemoteHandle( hKey ), Class, &cSubKeys, &cbMaxSubKeyLen, pCbMaxClassLen, &cValues, &cbMaxValueNameLen, &cbMaxValueLen, pCbSecurityDescriptor, &ftLastWriteTime ); if (Error == ERROR_SUCCESS) { DWORD dwVersion; // // Check for a downlevel Win95 server, which requires // us to work around their BaseRegQueryInfoKey bugs. // They do not account for Unicode correctly. // if (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion)) { // // This is a Win95 server. // Double the maximum value name length and // maximum value data length to account for // the Unicode translation that Win95 forgot // to account for. // cbMaxValueNameLen *= sizeof(WCHAR); cbMaxValueLen *= sizeof(WCHAR); } } } // // MaxSubKeyLen, MaxClassLen, and MaxValueNameLen should be in // number of characters, without counting the NULL. // Note that the server side will return the number of bytes, // without counting the NUL // cbMaxSubKeyLen /= sizeof( WCHAR ); if( pCbMaxClassLen != NULL ) { cbMaxClassLen /= sizeof( WCHAR ); ASSERT( *pCbMaxClassLen == cbMaxClassLen ); } cbMaxValueNameLen /= sizeof( WCHAR ); // // Subtract the NULL from the Length. This was added on // the server side so that RPC would transmit it. // if ( Class->Length > 0 ) { Class->Length -= sizeof( UNICODE_NULL ); } // // If all the information was succesfully queried from the key // convert the class name to ANSI and update the class length value. // if( ( Error == ERROR_SUCCESS ) && ARGUMENT_PRESENT( lpClass ) && ( *lpcbClass != 0 ) ) { if (*lpcbClass > (DWORD)0xFFFF) { AnsiString.MaximumLength = ( USHORT ) 0xFFFF; } else { AnsiString.MaximumLength = ( USHORT ) *lpcbClass; } AnsiString.Buffer = lpClass; Status = RtlUnicodeStringToAnsiString( &AnsiString, Class, FALSE ); ASSERTMSG( "Unicode->ANSI conversion of Class ", NT_SUCCESS( Status )); // // Update the class length return parameter. // *lpcbClass = AnsiString.Length; Error = RtlNtStatusToDosError( Status ); } else { // // Not all of the information was succesfully queried, or Class // doesn't have to be converted from UNICODE to ANSI // if( ARGUMENT_PRESENT( lpcbClass ) ) { if( Class->Length == 0 ) { *lpcbClass = 0; } else { *lpcbClass = ( Class->Length >> 1 ); } } } if( ARGUMENT_PRESENT( lpcSubKeys ) ) { *lpcSubKeys = cSubKeys; } if( ARGUMENT_PRESENT( lpcbMaxSubKeyLen ) ) { *lpcbMaxSubKeyLen = cbMaxSubKeyLen; } if( ARGUMENT_PRESENT( lpcbMaxClassLen ) ) { *lpcbMaxClassLen = cbMaxClassLen; ASSERT( *pCbMaxClassLen == cbMaxClassLen ); } if( ARGUMENT_PRESENT( lpcValues ) ) { *lpcValues = cValues; } if( ARGUMENT_PRESENT( lpcbMaxValueNameLen ) ) { *lpcbMaxValueNameLen = cbMaxValueNameLen; } if( ARGUMENT_PRESENT( lpcbMaxValueLen ) ) { *lpcbMaxValueLen = cbMaxValueLen; } if( ARGUMENT_PRESENT( lpcbSecurityDescriptor ) ) { *lpcbSecurityDescriptor = cbSecurityDescriptor; ASSERT( *pCbSecurityDescriptor == cbSecurityDescriptor ); } if( ARGUMENT_PRESENT( lpftLastWriteTime ) ) { *lpftLastWriteTime = ftLastWriteTime; } ExitCleanup: CLOSE_LOCAL_HANDLE(TempHandle); return Error; } LONG RegQueryInfoKeyW ( HKEY hKey, LPWSTR lpClass, LPDWORD lpcbClass, LPDWORD lpReserved, LPDWORD lpcSubKeys, LPDWORD lpcbMaxSubKeyLen, LPDWORD lpcbMaxClassLen, LPDWORD lpcValues, LPDWORD lpcbMaxValueNameLen, LPDWORD lpcbMaxValueLen, LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime ) /*++ Routine Description: Win32 Unicode RPC wrapper for querying information about a previously opened key. --*/ { UNICODE_STRING Class; LONG Error; DWORD cbClass; DWORD cSubKeys; DWORD cbMaxSubKeyLen; DWORD cValues; DWORD cbMaxValueNameLen; DWORD cbMaxValueLen; FILETIME ftLastWriteTime; HKEY TempHandle = NULL; DWORD cbMaxClassLen; DWORD cbSecurityDescriptor; PDWORD pCbMaxClassLen = NULL; PDWORD pCbSecurityDescriptor = NULL; #if DBG if ( BreakPointOnEntry ) { DbgBreakPoint(); } #endif 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; } // // Make sure that the buffer size for lpClass is zero if lpClass is NULL // if( !ARGUMENT_PRESENT( lpClass ) && ARGUMENT_PRESENT( lpcbClass ) ) { *lpcbClass = 0; } if( ARGUMENT_PRESENT( lpcbMaxClassLen ) ) { pCbMaxClassLen = &cbMaxClassLen; } if( ARGUMENT_PRESENT( lpcbSecurityDescriptor ) ) { pCbSecurityDescriptor = &cbSecurityDescriptor; } // // Use the supplied class Class buffer as the buffer in a counted // Unicode Class. // Class.Length = 0; if( ARGUMENT_PRESENT( lpcbClass ) && ( *lpcbClass != 0 ) ) { Class.MaximumLength = ( USHORT )( *lpcbClass << 1 ); Class.Buffer = lpClass; } else { // // If the count of bytes in the class is 0, pass a NULL pointer // instead of what was supplied. This ensures that RPC won't // attempt to copy data to a bogus pointer. // Class.MaximumLength = 0; Class.Buffer = NULL; } // // Call the Base API. // if( IsLocalHandle( hKey )) { Error = (LONG)LocalBaseRegQueryInfoKey( hKey, &Class, &cSubKeys, &cbMaxSubKeyLen, pCbMaxClassLen, &cValues, &cbMaxValueNameLen, &cbMaxValueLen, pCbSecurityDescriptor, &ftLastWriteTime ); } else { // // on RPC always send valid pointers!!! // pCbMaxClassLen = &cbMaxClassLen; pCbSecurityDescriptor = &cbSecurityDescriptor; Error = (LONG)BaseRegQueryInfoKey( DereferenceRemoteHandle( hKey ), &Class, &cSubKeys, &cbMaxSubKeyLen, pCbMaxClassLen, &cValues, &cbMaxValueNameLen, &cbMaxValueLen, pCbSecurityDescriptor, &ftLastWriteTime ); if (Error == ERROR_SUCCESS) { DWORD dwVersion; // // Check for a downlevel Win95 server, which requires // us to work around their BaseRegQueryInfoKey bugs. // They do not account for Unicode correctly. // if (IsWin95Server(DereferenceRemoteHandle(hKey),dwVersion)) { // // This is a Win95 server. // Double the maximum value name length and // maximum value data length to account for // the Unicode translation that Win95 forgot // to account for. // cbMaxValueNameLen *= sizeof(WCHAR); cbMaxValueLen *= sizeof(WCHAR); } } } // // MaxSubKeyLen, MaxClassLen, and MaxValueNameLen should be in // number of characters, without counting the NULL. // Note that the server side will return the number of bytes, // without counting the NUL // cbMaxSubKeyLen /= sizeof( WCHAR ); if( pCbMaxClassLen != NULL ) { cbMaxClassLen /= sizeof( WCHAR ); ASSERT( *pCbMaxClassLen == cbMaxClassLen ); } cbMaxValueNameLen /= sizeof( WCHAR ); if( ARGUMENT_PRESENT( lpcbClass ) ) { if( Class.Length == 0 ) { *lpcbClass = 0; } else { *lpcbClass = ( Class.Length >> 1 ) - 1; } } if( ARGUMENT_PRESENT( lpcSubKeys ) ) { *lpcSubKeys = cSubKeys; } if( ARGUMENT_PRESENT( lpcbMaxSubKeyLen ) ) { *lpcbMaxSubKeyLen = cbMaxSubKeyLen; } if( ARGUMENT_PRESENT( lpcbMaxClassLen ) ) { *lpcbMaxClassLen = cbMaxClassLen; ASSERT( *pCbMaxClassLen == cbMaxClassLen ); } if( ARGUMENT_PRESENT( lpcValues ) ) { *lpcValues = cValues; } if( ARGUMENT_PRESENT( lpcbMaxValueNameLen ) ) { *lpcbMaxValueNameLen = cbMaxValueNameLen; } if( ARGUMENT_PRESENT( lpcbMaxValueLen ) ) { *lpcbMaxValueLen = cbMaxValueLen; } if( ARGUMENT_PRESENT( lpcbSecurityDescriptor ) ) { *lpcbSecurityDescriptor = cbSecurityDescriptor; ASSERT( *pCbSecurityDescriptor == cbSecurityDescriptor ); } if( ARGUMENT_PRESENT( lpftLastWriteTime ) ) { *lpftLastWriteTime = ftLastWriteTime; } ExitCleanup: CLOSE_LOCAL_HANDLE(TempHandle); return Error; }