Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

403 lines
13 KiB

/******************************************************************************
*
* $RCSfile: DrvReg.cpp $
* $Source: u:/si/VXP/Wdm/Classes/DrvReg.cpp $
* $Author: Max $
* $Date: 1998/09/28 23:22:38 $
* $Revision: 1.5 $
*
* Written by: Max Paklin
* Purpose: Implementation of registry class
*
*******************************************************************************
*
* Copyright © 1996-98, AuraVision Corporation. All rights reserved.
*
* AuraVision Corporation makes no warranty of any kind, express or implied,
* with regard to this software. In no event shall AuraVision Corporation
* be liable for incidental or consequential damages in connection with or
* arising from the furnishing, performance, or use of this software.
*
* Tab step is to be set to 4 to achive the best readability for this code.
*
*******************************************************************************/
#include "Comwdm.h"
#pragma hdrstop
// Convert GUID to WCHAR (or WCHAR to GUID) string MAX_GUIDLENGTH characters
void CKsRegKey::GuidToWChar( const GUID guid, LPWSTR pwszString )
{
UNICODE_STRING usString;
usString.Length = 0;
usString.MaximumLength = MAX_GUIDLENGTH*sizeof( WCHAR );
usString.Buffer = pwszString;
RtlStringFromGUID( guid, &usString );
}
NTSTATUS CKsRegKey::WCharToGuid( LPCWSTR pwszString, GUID guid )
{
UNICODE_STRING usString;
usString.Length = (wcslen( pwszString )+1)*sizeof( WCHAR );
usString.MaximumLength = MAX_GUIDLENGTH*sizeof( WCHAR );
usString.Buffer = (PWSTR)pwszString;
return RtlGUIDFromString( &usString, &guid );
}
// Constructor helper function
void CKsRegKey::Create( LPCWSTR pwszKey, LPCWSTR pwszSubKey,
PVOID hHandle, PDEVICE_OBJECT pDeviceObject )
{
int nLength;
// Calculating the length of key
if( pwszKey )
nLength = wcslen( pwszKey )+1;
else
nLength = 0;
if( pwszSubKey )
nLength += wcslen( pwszSubKey )+1;
if( nLength > 0 )
{
// Allocating memory for key
m_pwszKey = (PWCHAR)ExAllocatePool( PagedPool, nLength*sizeof( WCHAR ) );
if( m_pwszKey == NULL )
{
DebugPrint(( DebugLevelFatal, "%s: out of memory\n", __FILE__ ));
DEBUG_BREAKPOINT();
}
else
{
if( pwszKey )
wcscpy( m_pwszKey, pwszKey );
else
wcscpy( m_pwszKey, L"" );
if( pwszSubKey )
wcscat( m_pwszKey, pwszSubKey );
}
}
else
m_pwszKey = NULL;
m_hHandle = hHandle;
m_pDeviceObject = pDeviceObject;
}
// Helper function that is used to get currently used registry path to get/set values.
// Returned values are used as a parameters to RtlQueryRegistryValues/RtlWriteRegistryValues.
// The first parameter is flag (first parameter) to abovementioned Windows' registry
// functions. It can be or RTL_REGISTRY_HANDLE or RTL_REGISTRY_ABSOLUTE. The first one means
// that return value of this function is actually handle of registry key, while the second
// tells caller that return value is absolute registry key string. The last parameter is
// used to store registry key to close if it was temporary opened
PWSTR CKsRegKey::GetInputData( PULONG puRelativeTo, PHANDLE phHandleToDelete,
ACCESS_MASK amDesiredAccess, BOOL bCreateHandle )
{
*phHandleToDelete = NULL;
PWSTR pKey = NULL;
NTSTATUS ntStatus;
if( m_hHandle || bCreateHandle )
{
// We have handle to key to work with. Open specified subkey and return it telling
// that it is handle and that subkey should be closed when it is not needed
*puRelativeTo = RTL_REGISTRY_HANDLE;
if( m_pwszKey && wcslen( m_pwszKey ) > 0 )
{
HANDLE hHandle;
OBJECT_ATTRIBUTES objAttr;
UNICODE_STRING usValue;
RtlInitUnicodeString( &usValue, m_pwszKey );
InitializeObjectAttributes( &objAttr, &usValue, OBJ_CASE_INSENSITIVE, m_hHandle, NULL );
if( (ntStatus = ZwOpenKey( &hHandle, amDesiredAccess, &objAttr )) == STATUS_SUCCESS )
{
// Subkey was successfully opened, so mark it as "to be released when
// it is not needed anymore"
*phHandleToDelete = hHandle;
pKey = (PWSTR)hHandle;
}
else
DebugPrint(( DebugLevelWarning, "ZwOpenKey() failed: 0x%X\n", ntStatus ));
}
else
pKey = (PWSTR)m_hHandle;
}
else if( m_pDeviceObject )
{
// We have handle to driver key and we are going to work with data store under it.
// Open specified subkey and return it telling that it is handle and that subkey
// should be closed when it is not needed
*puRelativeTo = RTL_REGISTRY_HANDLE;
// First open key for our device object
ntStatus = IoOpenDeviceRegistryKey( (PDEVICE_OBJECT)m_pDeviceObject, PLUGPLAY_REGKEY_DRIVER,
amDesiredAccess, phHandleToDelete );
if( ntStatus == STATUS_SUCCESS )
{
if( m_pwszKey && wcslen( m_pwszKey ) > 0 )
{
// Subkey specified. So open it and mark it as "to be released when
// it is not needed anymore"
HANDLE hHandle = NULL;
OBJECT_ATTRIBUTES objAttr;
UNICODE_STRING usValue;
RtlInitUnicodeString( &usValue, m_pwszKey );
InitializeObjectAttributes( &objAttr, &usValue, OBJ_CASE_INSENSITIVE,
*phHandleToDelete, NULL );
if( ZwOpenKey( &hHandle, amDesiredAccess, &objAttr ) == STATUS_SUCCESS )
pKey = (PWSTR)hHandle;
ZwClose( *phHandleToDelete );
*phHandleToDelete = hHandle;
}
else
pKey = (PWSTR)(*phHandleToDelete);
}
else
DebugPrint(( DebugLevelWarning, "IoOpenDeviceRegistryKey() failed: 0x%X\n", ntStatus ));
}
else if( m_pwszKey )
{
// We have registry key object created as an absolute path to registry key
*puRelativeTo = RTL_REGISTRY_ABSOLUTE;
pKey = m_pwszKey;
}
return pKey;
}
// Set textual and integer values to registry key
BOOL CKsRegKey::SetValue( LPCWSTR pwszValue, LPCWSTR pwszSetTo )
{
if( IsKey() )
{
ULONG uRelativeTo;
HANDLE hHandleToDelete;
PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_WRITE );
if( pKey )
{
NTSTATUS ntStatus = RtlWriteRegistryValue( uRelativeTo, pKey, pwszValue, REG_SZ,
(PVOID)pwszSetTo, (wcslen( pwszSetTo )+1)*sizeof( WCHAR ) );
// Close key after the information is read and the key is not needed anymore
if( hHandleToDelete )
{
ZwClose( hHandleToDelete );
}
#ifdef DEBUG
if( ntStatus != STATUS_SUCCESS )
{
DebugPrint(( DebugLevelWarning, "RtlWriteRegistryValue() failed: 0x%X\n", ntStatus ));
}
#endif // DEBUG
return (BOOL)(ntStatus == STATUS_SUCCESS);
}
}
return FALSE;
}
BOOL CKsRegKey::SetValue( LPCWSTR pwszValue, int nSetTo )
{
if( IsKey() )
{
ULONG uRelativeTo;
HANDLE hHandleToDelete;
PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_WRITE );
if( pKey )
{
DWORD dwSetTo = (DWORD)nSetTo;
NTSTATUS ntStatus = RtlWriteRegistryValue( uRelativeTo, pKey, pwszValue,
REG_DWORD, &dwSetTo, sizeof( dwSetTo ) );
// Close key after the information is read and the key is not needed anymore
if( hHandleToDelete )
{
ZwClose( hHandleToDelete );
}
#ifdef DEBUG
if( ntStatus != STATUS_SUCCESS )
{
DebugPrint(( DebugLevelWarning, "RtlWriteRegistryValue() failed: 0x%X\n", ntStatus ));
}
#endif // DEBUG
return (BOOL)(ntStatus == STATUS_SUCCESS);
}
}
return FALSE;
}
// Get string and integer value from key. We use this a little bit ugly technique because
// it is the easiest way to do what we want to do. The optimal way would be to put all the
// nessessary data to a number of RTL_QUERY_REGISTRY_TABLE tables and read all of them
// at once but it would be inconvinient for user of this class
BOOL CKsRegKey::GetValue( LPCWSTR pwszGetFrom, LPWSTR pwszValue,
USHORT ushSize, LPCWSTR pwszDefault )
{
BOOL bResult = FALSE;
if( IsKey() )
{
ULONG uRelativeTo;
HANDLE hHandleToDelete;
PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_READ );
if( pKey )
{
RTL_QUERY_REGISTRY_TABLE qTable[2];
UNICODE_STRING usValue, usDefault;
NTSTATUS ntStatus;
// Prepare UNICODE strings for buffer to put data into and for default value
usValue.Length = 0;
usValue.MaximumLength = ushSize;
usValue.Buffer = pwszValue;
RtlInitUnicodeString( &usDefault, pwszDefault );
RtlZeroMemory( qTable, sizeof( qTable ) );
qTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
qTable[0].Name = (PWSTR)pwszGetFrom;
qTable[0].EntryContext = &usValue;
qTable[0].DefaultType = REG_SZ;
qTable[0].DefaultData = &usDefault;
qTable[0].DefaultLength = 0;
ntStatus = RtlQueryRegistryValues( uRelativeTo, pKey, qTable, NULL, NULL );
if( ntStatus == STATUS_SUCCESS )
bResult = TRUE;
else
DebugPrint(( DebugLevelWarning, "RtlQueryRegistryValues() failed: 0x%X\n", ntStatus ));
// Close key after the information is read and the key is not needed anymore
if( hHandleToDelete )
ZwClose( hHandleToDelete );
}
}
return bResult;
}
BOOL CKsRegKey::GetValue( LPCWSTR pwszGetFrom, PDWORD pdwValue, ULONG ulSize )
{
BOOL bResult = FALSE;
if( IsKey() )
{
ULONG uRelativeTo;
HANDLE hHandleToDelete;
PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_READ, TRUE );
if( pKey )
{
ULONG ulReadSize;
UNICODE_STRING usName;
// Here we will be using the nasty trick. Use user's buffer not only for data that
// user requested but also for storing KEY_VALUE_PARTIAL_INFORMATION structure.
// ZwQueryValueKey() will fill out KEY_VALUE_PARTIAL_INFORMATION structure that
// will contain real data at the end of it. All that we have to do is to move the
// tail with data to the beginning of the user's buffer. Of course, it introduces
// potential danger when, for example, user provides buffer of size of 20 bytes for
// reading the data that is 15 bytes long. In this example only a few bytes of
// registry data will be read. However it is not as ugly as it could seem at a first
// glance because in this case we will return FALSE to the user to signal that the
// buffer size is probably not enough for storing the data ('ulSize > ulReadSize'
// check will do it). Therefore the size of buffer should be greater or equal to
// RealSizeOfRegistryData+sizeof( KEY_VALUE_PARTIAL_INFORMATION )-
// sizeof( KEY_VALUE_PARTIAL_INFORMATION.Data )+1
ASSERT( ulSize > sizeof( KEY_VALUE_PARTIAL_INFORMATION ) );
PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo = (PKEY_VALUE_PARTIAL_INFORMATION)pdwValue;
ASSERT( hHandleToDelete );
RtlInitUnicodeString( &usName, pwszGetFrom );
NTSTATUS ntStatus = ZwQueryValueKey( (HANDLE)pKey, &usName, KeyValuePartialInformation,
pKeyInfo, ulSize, &ulReadSize );
if( ntStatus != STATUS_SUCCESS )
DebugPrint(( DebugLevelWarning, "ZwQueryValueKey() failed: 0x%X\n", ntStatus ));
else if( ulSize > ulReadSize )
{
// We succeeded only if the read size is less than the size of our buffer.
// Otherwise the size of data in registry could be bigger than supplied buffer
bResult = TRUE;
// Move the actual data at the beginning of user's buffer
ASSERT( pKeyInfo->Type == REG_BINARY );
ULONG ulDataLength = pKeyInfo->DataLength;
PBYTE pbData = (PBYTE)&pKeyInfo->Data, pbValue = (PBYTE)pdwValue;
for( ULONG i = 0; i < ulDataLength; i++, pbData++, pbValue++ )
*pbValue = *pbData;
#ifdef _DEBUG
for( ; i < ulSize; i++, pbValue++ )
*pbValue = 0;
#endif
}
// Close key after the information is read and the key is not needed anymore
if( hHandleToDelete )
ZwClose( hHandleToDelete );
}
}
return bResult;
}
BOOL CKsRegKey::GetValue( LPCWSTR pwszGetFrom, long& lValue, long lDefault )
{
BOOL bResult = FALSE;
if( IsKey() )
{
ULONG uRelativeTo;
HANDLE hHandleToDelete;
PWSTR pKey = GetInputData( &uRelativeTo, &hHandleToDelete, KEY_READ );
if( pKey )
{
RTL_QUERY_REGISTRY_TABLE qTable[2];
DWORD dwData = 0;
NTSTATUS ntStatus;
RtlZeroMemory( qTable, sizeof( qTable ) );
qTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
qTable[0].Name = (PWSTR)pwszGetFrom;
qTable[0].EntryContext = &dwData;
qTable[0].DefaultType = REG_DWORD;
qTable[0].DefaultData = &lDefault;
qTable[0].DefaultLength = sizeof( lDefault );
ntStatus = RtlQueryRegistryValues( uRelativeTo, pKey, qTable, NULL, NULL );
if( ntStatus == STATUS_SUCCESS )
{
lValue = (int)dwData;
bResult = TRUE;
}
else
DebugPrint(( DebugLevelWarning, "RtlQueryRegistryValues() failed: 0x%X\n", ntStatus ));
// Close key after the information is read and the key is not needed anymore
if( hHandleToDelete )
ZwClose( hHandleToDelete );
}
}
return bResult;
}
// Delete registry subkey
void DeleteSubKey( LPWSTR pwszKey, LPCWSTR pwszSubKey )
{
if( pwszKey )
{
HANDLE hHandle;
OBJECT_ATTRIBUTES objAttr;
UNICODE_STRING usKey;
RtlInitUnicodeString( &usKey, pwszKey );
RtlZeroMemory( &objAttr, sizeof( objAttr ) );
objAttr.Length = sizeof( objAttr );
objAttr.ObjectName = &usKey;
NTSTATUS ntStatus = ZwOpenKey( &hHandle, KEY_SET_VALUE | KEY_CREATE_SUB_KEY, &objAttr );
if( ntStatus == STATUS_SUCCESS )
{
ntStatus = ZwDeleteKey( hHandle );
ASSERT( ntStatus == STATUS_SUCCESS );
}
else
DebugPrint(( DebugLevelWarning, "ZwOpenKey() failed: 0x%X\n", ntStatus ));
}
}