404 lines
13 KiB
C++
404 lines
13 KiB
C++
/******************************************************************************
|
|
*
|
|
* $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 ));
|
|
}
|
|
}
|