1130 lines
27 KiB
C
1130 lines
27 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
Apitest.c
|
||
|
||
Abstract:
|
||
|
||
This module contains the function test for the Win32 Registry API.
|
||
|
||
Author:
|
||
|
||
David J. Gilman (davegi) 28-Dec-1991
|
||
|
||
Environment:
|
||
|
||
Windows, Crt - User Mode
|
||
|
||
Notes:
|
||
|
||
This test can be compiled for Unicode by defining the compiler symbol
|
||
UNICODE.
|
||
|
||
Since this is a test program it relies on assertions for error checking
|
||
rather than a more robust mechanism.
|
||
|
||
--*/
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include <windows.h>
|
||
|
||
#include "crtools.h"
|
||
|
||
|
||
|
||
#define HKEY_ROOT HKEY_CURRENT_USER
|
||
#define SAVE_RESTORE_FILE TEXT( "srkey.reg" )
|
||
#define KEY_PATH \
|
||
TEXT( "TestUser1\\TestUser1_1\\TestUser1_2" )
|
||
|
||
|
||
#define PREDEFINED_HANDLE HKEY_USERS
|
||
#define PREDEFINED_HANDLE_STRING \
|
||
TEXT( "HKEY_USERS\\.Default\\TestUser1" )
|
||
|
||
|
||
#define KEY_NAME_1 TEXT( "TestUser1" )
|
||
#define KEY_NAME_1_TITLE_INDEX ( 0 )
|
||
#define KEY_NAME_1_CLASS TEXT( "Test User Class" )
|
||
#define KEY_NAME_1_CLASS_LENGTH LENGTH( KEY_NAME_1_CLASS )
|
||
|
||
#define KEY_NAME_1_1 TEXT( "TestUser1_1" )
|
||
#define KEY_NAME_1_1_LENGTH LENGTH( KEY_NAME_1_1 )
|
||
#define KEY_NAME_1_1_TITLE_INDEX ( 0 )
|
||
#define KEY_NAME_1_1_CLASS TEXT( "Test User Class" )
|
||
#define KEY_NAME_1_1_CLASS_LENGTH LENGTH( KEY_NAME_1_1_CLASS )
|
||
|
||
#define KEY_NAME_1_2 TEXT( "TestUser1_2" )
|
||
#define KEY_NAME_1_2_LENGTH LENGTH( KEY_NAME_1_2 )
|
||
#define KEY_NAME_1_2_TITLE_INDEX (0 )
|
||
#define KEY_NAME_1_2_CLASS TEXT( "Test User Class" )
|
||
#define KEY_NAME_1_2_CLASS_LENGTH LENGTH( KEY_NAME_1_2_CLASS )
|
||
|
||
#define VALUE_NAME_1 TEXT( "One" )
|
||
#define VALUE_NAME_1_LENGTH LENGTH( VALUE_NAME_1 )
|
||
#define VALUE_NAME_1_TITLE_INDEX 0
|
||
#define VALUE_DATA_1 "Number One"
|
||
#define VALUE_DATA_1_LENGTH 11
|
||
#define VALUE_DATA_1_TYPE REG_SZ
|
||
|
||
#define VALUE_NAME_2 TEXT( "Second" )
|
||
#define VALUE_NAME_2_LENGTH LENGTH( VALUE_NAME_2 )
|
||
#define VALUE_NAME_2_TITLE_INDEX ( 0 )
|
||
#define VALUE_DATA_2 ( 2 )
|
||
#define VALUE_DATA_2_LENGTH ( sizeof( VALUE_DATA_2 ))
|
||
#define VALUE_DATA_2_TYPE REG_DWORD
|
||
|
||
#define MAX_DATA_LENGTH ( 32 )
|
||
|
||
//
|
||
// Root handle for apitest's nodes.
|
||
//
|
||
|
||
HKEY RootHandle;
|
||
|
||
//
|
||
// Error and informational messages.
|
||
//
|
||
|
||
PSTR UsageMessage =
|
||
|
||
"Usage: apitest [-?] [-q] [\\machinename]\n";
|
||
|
||
PSTR HelpMessage =
|
||
|
||
"\n where:\n" \
|
||
" -? - display this message.\n" \
|
||
" -q - quiet - suppresses all output\n" \
|
||
" machinename - remote machine.\n";
|
||
|
||
PSTR InvalidSwitchMessage =
|
||
|
||
"Invalid switch - %s\n";
|
||
|
||
PSTR InvalidMachineNameMessage =
|
||
|
||
"Invalid machine name - %s\n";
|
||
|
||
//
|
||
// Event handle used for synchronization.
|
||
//
|
||
|
||
HANDLE _EventHandle;
|
||
HANDLE _EventHandle1;
|
||
HANDLE _EventHandle2;
|
||
|
||
BOOL Quiet;
|
||
|
||
|
||
|
||
VOID
|
||
DeleteTree(
|
||
IN HKEY KeyHandle
|
||
)
|
||
|
||
{
|
||
LONG Error;
|
||
DWORD Index;
|
||
HKEY ChildHandle;
|
||
|
||
|
||
TSTR KeyName[ MAX_PATH ];
|
||
DWORD KeyNameLength;
|
||
TSTR ClassName[ MAX_PATH ];
|
||
DWORD ClassNameLength;
|
||
DWORD TitleIndex;
|
||
DWORD NumberOfSubKeys;
|
||
DWORD MaxSubKeyLength;
|
||
DWORD MaxClassLength;
|
||
DWORD NumberOfValues;
|
||
DWORD MaxValueNameLength;
|
||
DWORD MaxValueDataLength;
|
||
DWORD SecurityDescriptorLength;
|
||
FILETIME LastWriteTime;
|
||
|
||
ClassNameLength = MAX_PATH;
|
||
|
||
Error = RegQueryInfoKey(
|
||
KeyHandle,
|
||
ClassName,
|
||
&ClassNameLength,
|
||
NULL,
|
||
&NumberOfSubKeys,
|
||
&MaxSubKeyLength,
|
||
&MaxClassLength,
|
||
&NumberOfValues,
|
||
&MaxValueNameLength,
|
||
&MaxValueDataLength,
|
||
&SecurityDescriptorLength,
|
||
&LastWriteTime
|
||
);
|
||
REG_API_SUCCESS( RegQueryInfoKey );
|
||
|
||
for( Index = 0; Index < NumberOfSubKeys; Index++ ) {
|
||
|
||
KeyNameLength = MAX_PATH;
|
||
|
||
Error = RegEnumKey(
|
||
KeyHandle,
|
||
0,
|
||
// Index,
|
||
KeyName,
|
||
KeyNameLength
|
||
);
|
||
REG_API_SUCCESS( RegEnumKey );
|
||
|
||
Error = RegOpenKey(
|
||
KeyHandle,
|
||
KeyName,
|
||
&ChildHandle
|
||
);
|
||
|
||
REG_API_SUCCESS( RegOpenKey );
|
||
|
||
DeleteTree( ChildHandle );
|
||
|
||
Error = RegCloseKey(
|
||
ChildHandle
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
Error = RegDeleteKey(
|
||
KeyHandle,
|
||
KeyName
|
||
);
|
||
REG_API_SUCCESS( RegDeleteKey );
|
||
}
|
||
}
|
||
VOID
|
||
DeleteTestTree(
|
||
)
|
||
|
||
{
|
||
LONG Error;
|
||
HKEY KeyHandle;
|
||
|
||
Error = RegOpenKey(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
&KeyHandle
|
||
);
|
||
|
||
if( Error == ERROR_SUCCESS ) {
|
||
|
||
DeleteTree( KeyHandle );
|
||
|
||
Error = RegCloseKey(
|
||
KeyHandle
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
Error = RegDeleteKey(
|
||
RootHandle,
|
||
KEY_NAME_1
|
||
);
|
||
REG_API_SUCCESS( RegDeleteKey );
|
||
}
|
||
}
|
||
|
||
DWORD
|
||
NotifyThread(
|
||
LPVOID Parameters
|
||
)
|
||
|
||
{
|
||
LONG Error;
|
||
BOOL ErrorFlag;
|
||
HANDLE EventHandle;
|
||
|
||
UNREFERENCED_PARAMETER( Parameters );
|
||
|
||
//
|
||
// Create the notification event.
|
||
//
|
||
|
||
EventHandle = CreateEvent(
|
||
NULL,
|
||
FALSE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
ASSERT( EventHandle != NULL );
|
||
|
||
//
|
||
// Set-up an asynchronous notify.
|
||
//
|
||
|
||
Error = RegNotifyChangeKeyValue(
|
||
RootHandle,
|
||
FALSE,
|
||
REG_LEGAL_CHANGE_FILTER,
|
||
EventHandle,
|
||
TRUE
|
||
);
|
||
REG_API_SUCCESS( RegNotifyChangeKeyValue );
|
||
|
||
//
|
||
// Release the main thread.
|
||
//
|
||
|
||
ErrorFlag = SetEvent( _EventHandle );
|
||
ASSERT( ErrorFlag == TRUE );
|
||
|
||
//
|
||
// Wait for a notification.
|
||
//
|
||
|
||
Error = (LONG)WaitForSingleObject( EventHandle, (DWORD)-1 );
|
||
ASSERT( Error == 0 );
|
||
|
||
if( ! Quiet ) {
|
||
printf( "First notification triggered\n" );
|
||
}
|
||
|
||
CloseHandle( EventHandle );
|
||
|
||
EventHandle = CreateEvent(
|
||
NULL,
|
||
FALSE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
ASSERT( EventHandle != NULL );
|
||
|
||
//
|
||
// Set-up an asynchronous notify.
|
||
//
|
||
|
||
Error = RegNotifyChangeKeyValue(
|
||
RootHandle,
|
||
FALSE,
|
||
REG_LEGAL_CHANGE_FILTER,
|
||
EventHandle,
|
||
TRUE
|
||
);
|
||
REG_API_SUCCESS( RegNotifyChangeKeyValue );
|
||
|
||
//
|
||
// Release the main thread.
|
||
//
|
||
|
||
ErrorFlag = SetEvent( _EventHandle1 );
|
||
ASSERT( ErrorFlag == TRUE );
|
||
|
||
//
|
||
// Wait for a notification.
|
||
//
|
||
|
||
Error = (LONG)WaitForSingleObject( EventHandle, (DWORD)-1 );
|
||
ASSERT( Error == 0 );
|
||
|
||
if( ! Quiet ) {
|
||
printf( "Second notification triggered\n" );
|
||
}
|
||
|
||
CloseHandle( EventHandle );
|
||
ErrorFlag = SetEvent( _EventHandle2 );
|
||
ASSERT( ErrorFlag == TRUE );
|
||
|
||
|
||
|
||
|
||
#endif
|
||
|
||
|
||
|
||
return ( DWORD ) TRUE;
|
||
}
|
||
|
||
VOID
|
||
main(
|
||
INT argc,
|
||
PCHAR argv[ ]
|
||
)
|
||
|
||
{
|
||
LONG Error;
|
||
BOOL ErrorFlag;
|
||
DWORD Index;
|
||
|
||
PTSTR MachineName;
|
||
|
||
PKEY Key;
|
||
TSTR NameString[ MAX_PATH ];
|
||
|
||
HANDLE NotifyThreadHandle;
|
||
DWORD ThreadID;
|
||
|
||
HKEY PredefinedHandle;
|
||
HKEY Handle1;
|
||
HKEY Handle1_1;
|
||
HKEY Handle1_2;
|
||
|
||
PSECURITY_DESCRIPTOR SecurityDescriptor;
|
||
SECURITY_ATTRIBUTES SecurityAttributes;
|
||
|
||
DWORD Disposition;
|
||
TSTR KeyName[ MAX_PATH ];
|
||
DWORD KeyNameLength;
|
||
TSTR ClassName[ MAX_PATH ];
|
||
DWORD ClassNameLength;
|
||
DWORD NumberOfSubKeys;
|
||
DWORD MaxSubKeyLength;
|
||
DWORD MaxClassLength;
|
||
DWORD NumberOfValues;
|
||
DWORD MaxValueNameLength;
|
||
DWORD MaxValueDataLength;
|
||
DWORD SecurityDescriptorLength;
|
||
FILETIME LastWriteTime;
|
||
|
||
|
||
TSTR ValueName[ MAX_PATH ];
|
||
DWORD ValueNameLength;
|
||
|
||
BYTE Data[ MAX_DATA_LENGTH ];
|
||
DWORD DataLength;
|
||
|
||
BYTE Data_1[ ] = VALUE_DATA_1;
|
||
DWORD Data_2 = VALUE_DATA_2;
|
||
|
||
DWORD TitleIndex;
|
||
DWORD Type;
|
||
|
||
|
||
UNREFERENCED_PARAMETER( argc );
|
||
|
||
//
|
||
// By default, be verbose and operate on the local machine.
|
||
//
|
||
|
||
Quiet = FALSE;
|
||
MachineName = NULL;
|
||
|
||
//
|
||
// Initialize options based on the command line.
|
||
//
|
||
|
||
while( *++argv ) {
|
||
|
||
//
|
||
// If the command line argument is a switch character...
|
||
//
|
||
|
||
if( isswitch(( *argv )[ 0 ] )) {
|
||
|
||
switch( tolower(( *argv )[ 1 ] )) {
|
||
|
||
//
|
||
// Display the detailed help message and quit.
|
||
//
|
||
|
||
case '?':
|
||
|
||
DisplayMessage( FALSE, UsageMessage );
|
||
DisplayMessage( TRUE, HelpMessage );
|
||
break;
|
||
|
||
//
|
||
// Quiet - no output.
|
||
//
|
||
|
||
case 'q':
|
||
|
||
Quiet = TRUE;
|
||
break;
|
||
|
||
//
|
||
// Display invalid switch message and quit.
|
||
//
|
||
|
||
default:
|
||
|
||
DisplayMessage( FALSE, InvalidSwitchMessage, *argv );
|
||
DisplayMessage( TRUE, UsageMessage );
|
||
}
|
||
} else {
|
||
|
||
MachineName = *argv;
|
||
}
|
||
}
|
||
|
||
//
|
||
// If a machine name was passed on the command line, connect to
|
||
// the Registry on that machine else use the local Registry.
|
||
// In either case construct a string representation of the
|
||
// test's main key (i.e. \\machine\HKEY_USERS\.Default\TestUser1 or
|
||
// HKEY_USERS\.Default\TestUser1.
|
||
//
|
||
|
||
if( MachineName ) {
|
||
|
||
Error = RegConnectRegistry(
|
||
MachineName,
|
||
PREDEFINED_HANDLE,
|
||
&PredefinedHandle
|
||
);
|
||
|
||
REG_API_SUCCESS( RegConnectRegistry );
|
||
|
||
strcpy( NameString, MachineName );
|
||
strcat( NameString, "\\\\" );
|
||
strcat( NameString, PREDEFINED_HANDLE_STRING );
|
||
|
||
} else {
|
||
|
||
PredefinedHandle = PREDEFINED_HANDLE;
|
||
strcpy( NameString, PREDEFINED_HANDLE_STRING );
|
||
}
|
||
|
||
//
|
||
// Open ".Default" key as the root for the remainder of the test.
|
||
//
|
||
|
||
Error = RegOpenKeyEx(
|
||
PredefinedHandle,
|
||
".Default",
|
||
REG_OPTION_RESERVED,
|
||
MAXIMUM_ALLOWED,
|
||
&RootHandle
|
||
);
|
||
REG_API_SUCCESS( RegOpenKeyEx );
|
||
|
||
//
|
||
// Predefined handle is no longer needed.
|
||
//
|
||
|
||
Error = RegCloseKey(
|
||
PredefinedHandle
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
//
|
||
// Delete the save / restore file (in case it exists from a previous
|
||
// run of the test) as RegSaveKey requires a new file.
|
||
//
|
||
|
||
DeleteFile( SAVE_RESTORE_FILE );
|
||
|
||
//
|
||
// Remove any leftover keys from previous runs of this test.
|
||
//
|
||
|
||
DeleteTestTree( );
|
||
|
||
//
|
||
// Use the Win 3.1 API (which calls the Win32 API) to create a path.
|
||
//
|
||
|
||
Error = RegCreateKey(
|
||
RootHandle,
|
||
KEY_PATH,
|
||
&Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCreateKey );
|
||
|
||
//
|
||
// Close the key so the delete (DeleteTestTree) will work.
|
||
//
|
||
|
||
Error = RegCloseKey(
|
||
Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
//
|
||
// Remove the path.
|
||
//
|
||
|
||
DeleteTestTree( );
|
||
|
||
//
|
||
// Create the synchronization event.
|
||
//
|
||
|
||
_EventHandle = CreateEvent(
|
||
NULL,
|
||
FALSE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
ASSERT( _EventHandle != NULL );
|
||
|
||
_EventHandle1 = CreateEvent(
|
||
NULL,
|
||
FALSE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
ASSERT( _EventHandle1 != NULL );
|
||
|
||
_EventHandle2 = CreateEvent(
|
||
NULL,
|
||
FALSE,
|
||
FALSE,
|
||
NULL
|
||
);
|
||
ASSERT( _EventHandle2 != NULL );
|
||
|
||
//
|
||
// Create the notify thread.
|
||
//
|
||
|
||
NotifyThreadHandle = CreateThread(
|
||
NULL,
|
||
0,
|
||
NotifyThread,
|
||
NULL,
|
||
0,
|
||
&ThreadID
|
||
);
|
||
ASSERT( NotifyThreadHandle != NULL );
|
||
|
||
//
|
||
// Wait for the notify thread to create its event.
|
||
//
|
||
|
||
Error = (LONG)WaitForSingleObject( _EventHandle, (DWORD)-1 );
|
||
ASSERT( Error == 0 );
|
||
|
||
//
|
||
// Use Win 3.1 compatible APIs to create/close, open/close and delete
|
||
// the key TestUser1.
|
||
//
|
||
|
||
Error = RegCreateKey(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
&Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCreateKey );
|
||
|
||
Error = RegCloseKey(
|
||
Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
//
|
||
// Wait for the notify thread to create its event.
|
||
//
|
||
|
||
Error = (LONG)WaitForSingleObject( _EventHandle1, (DWORD)-1 );
|
||
ASSERT( Error == 0 );
|
||
|
||
Error = RegOpenKey(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
&Handle1
|
||
);
|
||
REG_API_SUCCESS( RegOpenKey );
|
||
|
||
Error = RegCloseKey(
|
||
Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
Error = RegDeleteKey(
|
||
RootHandle,
|
||
KEY_NAME_1
|
||
);
|
||
REG_API_SUCCESS( RegDeleteKey );
|
||
|
||
//
|
||
// Use Win32 APIs to create/close, open/close and create (open) the
|
||
// key TestUser1.
|
||
//
|
||
|
||
//
|
||
// Allocate and initialize the SecurityDescriptor.
|
||
//
|
||
|
||
SecurityDescriptor = malloc( sizeof( SECURITY_DESCRIPTOR ));
|
||
ASSERT( SecurityDescriptor != NULL );
|
||
ErrorFlag = InitializeSecurityDescriptor(
|
||
SecurityDescriptor,
|
||
SECURITY_DESCRIPTOR_REVISION
|
||
);
|
||
ASSERT( ErrorFlag == TRUE );
|
||
|
||
SecurityAttributes.nLength = sizeof( SECURITY_ATTRIBUTES );
|
||
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
|
||
SecurityAttributes.bInheritHandle = FALSE;
|
||
|
||
Error = RegCreateKeyEx(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
0,
|
||
KEY_NAME_1_CLASS,
|
||
REG_OPTION_RESERVED,
|
||
KEY_ALL_ACCESS,
|
||
&SecurityAttributes,
|
||
&Handle1,
|
||
&Disposition
|
||
);
|
||
REG_API_SUCCESS( RegCreateKeyEx );
|
||
|
||
ASSERT( Disposition == REG_CREATED_NEW_KEY );
|
||
|
||
Error = RegCloseKey(
|
||
Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
|
||
//
|
||
// Wait for the notify thread to create its event.
|
||
//
|
||
|
||
Error = RegOpenKeyEx(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
REG_OPTION_RESERVED,
|
||
KEY_ALL_ACCESS,
|
||
&Handle1
|
||
);
|
||
REG_API_SUCCESS( RegOpenKeyEx );
|
||
|
||
Error = RegCloseKey(
|
||
Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
Error = RegCreateKeyEx(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
0,
|
||
KEY_NAME_1_CLASS,
|
||
REG_OPTION_RESERVED,
|
||
KEY_ALL_ACCESS,
|
||
NULL,
|
||
&Handle1,
|
||
&Disposition
|
||
);
|
||
REG_API_SUCCESS( RegCreateKeyEx );
|
||
|
||
ASSERT( Disposition == REG_OPENED_EXISTING_KEY );
|
||
|
||
//
|
||
// Get and set the key's SECURITY_DESCRIPTOR. Setting will trigger
|
||
// a notification.
|
||
//
|
||
|
||
SecurityDescriptorLength = 0;
|
||
|
||
//
|
||
// Get the SECURITY_DESCRIPTOR's length.
|
||
//
|
||
|
||
Error = RegGetKeySecurity(
|
||
Handle1,
|
||
OWNER_SECURITY_INFORMATION
|
||
| GROUP_SECURITY_INFORMATION
|
||
| DACL_SECURITY_INFORMATION,
|
||
SecurityDescriptor,
|
||
&SecurityDescriptorLength
|
||
);
|
||
ASSERT( Error == ERROR_INSUFFICIENT_BUFFER );
|
||
|
||
SecurityDescriptor = realloc(
|
||
SecurityDescriptor,
|
||
SecurityDescriptorLength
|
||
);
|
||
ASSERT( SecurityDescriptor != NULL );
|
||
ErrorFlag = InitializeSecurityDescriptor(
|
||
SecurityDescriptor,
|
||
SECURITY_DESCRIPTOR_REVISION
|
||
);
|
||
ASSERT( ErrorFlag == TRUE );
|
||
|
||
Error = RegSetKeySecurity(
|
||
Handle1,
|
||
OWNER_SECURITY_INFORMATION
|
||
| GROUP_SECURITY_INFORMATION
|
||
| DACL_SECURITY_INFORMATION,
|
||
SecurityDescriptor
|
||
);
|
||
REG_API_SUCCESS( RegSetKeySecurity );
|
||
|
||
Error = (LONG)WaitForSingleObject( _EventHandle2, (DWORD)-1 );
|
||
ASSERT( Error == 0 );
|
||
|
||
//
|
||
// Reinitialize after the realloc.
|
||
//
|
||
|
||
SecurityAttributes.lpSecurityDescriptor = SecurityDescriptor;
|
||
|
||
//
|
||
// Create two sub-keys.
|
||
//
|
||
|
||
Error = RegCreateKeyEx(
|
||
Handle1,
|
||
KEY_NAME_1_1,
|
||
0,
|
||
KEY_NAME_1_1_CLASS,
|
||
REG_OPTION_RESERVED,
|
||
KEY_ALL_ACCESS,
|
||
&SecurityAttributes,
|
||
&Handle1_1,
|
||
&Disposition
|
||
);
|
||
REG_API_SUCCESS( RegCreateKeyEx );
|
||
|
||
ASSERT( Disposition == REG_CREATED_NEW_KEY );
|
||
|
||
Error = RegCreateKeyEx(
|
||
Handle1,
|
||
KEY_NAME_1_2,
|
||
0,
|
||
KEY_NAME_1_2_CLASS,
|
||
0,
|
||
KEY_ALL_ACCESS,
|
||
&SecurityAttributes,
|
||
&Handle1_2,
|
||
&Disposition
|
||
);
|
||
REG_API_SUCCESS( RegCreateKeyEx );
|
||
|
||
ASSERT( Disposition == REG_CREATED_NEW_KEY );
|
||
|
||
//
|
||
// Enumerate the two sub-keys using the Win 3.1 and the the Win32
|
||
// enumeration APIs.
|
||
//
|
||
|
||
KeyNameLength = MAX_PATH;
|
||
|
||
Error = RegEnumKey(
|
||
Handle1,
|
||
0,
|
||
KeyName,
|
||
KeyNameLength
|
||
);
|
||
REG_API_SUCCESS( RegEnumKey );
|
||
|
||
ASSERT( Compare( KeyName, KEY_NAME_1_1, KEY_NAME_1_1_LENGTH ));
|
||
|
||
KeyNameLength = MAX_PATH;
|
||
ClassNameLength = MAX_PATH;
|
||
|
||
Error = RegEnumKeyEx(
|
||
Handle1,
|
||
1,
|
||
KeyName,
|
||
&KeyNameLength,
|
||
NULL,
|
||
ClassName,
|
||
&ClassNameLength,
|
||
&LastWriteTime
|
||
);
|
||
REG_API_SUCCESS( RegEnumKeyEx );
|
||
|
||
ASSERT( Compare( KeyName, KEY_NAME_1_2, KEY_NAME_1_2_LENGTH ));
|
||
ASSERT( KeyNameLength == KEY_NAME_1_2_LENGTH );
|
||
//ASSERT( TitleIndex == KEY_NAME_1_2_TITLE_INDEX );
|
||
ASSERT( Compare( ClassName, KEY_NAME_1_2_CLASS, KEY_NAME_1_2_CLASS_LENGTH ));
|
||
ASSERT( ClassNameLength == KEY_NAME_1_2_CLASS_LENGTH );
|
||
|
||
//
|
||
// If the Quiet command line option wasn't set, display the TestUser1 key.
|
||
//
|
||
|
||
if( ! Quiet ) {
|
||
Key = ParseKey( NameString );
|
||
REG_API_SUCCESS( Key != NULL );
|
||
DisplayKeys( Key, TRUE, TRUE, TRUE );
|
||
FreeKey( Key );
|
||
}
|
||
|
||
//
|
||
// Close the two sub-keys.
|
||
//
|
||
|
||
Error = RegCloseKey(
|
||
Handle1_1
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
Error = RegCloseKey(
|
||
Handle1_2
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
|
||
Error = RegFlushKey(
|
||
Handle1
|
||
);
|
||
|
||
REG_API_SUCCESS( RegFlushKey );
|
||
|
||
//
|
||
// Save the TestUser1 tree to a file.
|
||
//
|
||
#if 0
|
||
Error = RegSaveKey(
|
||
Handle1,
|
||
SAVE_RESTORE_FILE,
|
||
SecurityDescriptor
|
||
);
|
||
REG_API_SUCCESS( RegSaveKey );
|
||
|
||
RegCloseKey( Handle1 );
|
||
|
||
//
|
||
// Delete the TestUser1 tree.
|
||
//
|
||
|
||
DeleteTestTree( );
|
||
|
||
|
||
//
|
||
// Load TestUser1 from the file
|
||
//
|
||
Error = RegLoadKey(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
SAVE_RESTORE_FILE
|
||
);
|
||
REG_API_SUCCESS( RegLoadKey );
|
||
|
||
//
|
||
// Unload TestUser1
|
||
//
|
||
Error = RegUnLoadKey(
|
||
RootHandle,
|
||
KEY_NAME_1
|
||
);
|
||
REG_API_SUCCESS( RegUnLoadKey );
|
||
|
||
|
||
//
|
||
// Restore the TestUser1 tree from a file.
|
||
//
|
||
|
||
Error = RegCreateKey(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
&Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCreateKey );
|
||
|
||
Error = RegRestoreKey(
|
||
Handle1,
|
||
SAVE_RESTORE_FILE,
|
||
0
|
||
);
|
||
REG_API_SUCCESS( RegRestoreKey );
|
||
#endif
|
||
|
||
//
|
||
// Delete the two sub-keys.
|
||
//
|
||
|
||
Error = RegDeleteKey(
|
||
Handle1,
|
||
KEY_NAME_1_1
|
||
);
|
||
REG_API_SUCCESS( RegDeleteKey );
|
||
|
||
Error = RegDeleteKey(
|
||
Handle1,
|
||
KEY_NAME_1_2
|
||
);
|
||
REG_API_SUCCESS( RegDeleteKey );
|
||
|
||
//
|
||
// Set a value in the TestUser1 key using the Win 3.1 compatible API.
|
||
//
|
||
|
||
Error = RegSetValue(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
VALUE_DATA_1_TYPE,
|
||
Data_1,
|
||
VALUE_DATA_1_LENGTH
|
||
);
|
||
REG_API_SUCCESS( RegSetValue );
|
||
|
||
//
|
||
// Set a value in the TestUser1 key using the Win32 API.
|
||
//
|
||
Error = RegSetValueEx(
|
||
Handle1,
|
||
VALUE_NAME_2,
|
||
0,
|
||
VALUE_DATA_2_TYPE,
|
||
( PVOID ) &Data_2,
|
||
VALUE_DATA_2_LENGTH
|
||
);
|
||
REG_API_SUCCESS( RegSetValueEx );
|
||
|
||
//
|
||
// Commit the Key to the Registry.
|
||
//
|
||
|
||
Error = RegFlushKey(
|
||
Handle1
|
||
);
|
||
REG_API_SUCCESS( RegFlushKey );
|
||
|
||
//
|
||
// If the Quiet command line option wasn't set, display the TestUser1 key.
|
||
//
|
||
|
||
if( ! Quiet ) {
|
||
Key = ParseKey( NameString );
|
||
REG_API_SUCCESS( Key != NULL );
|
||
DisplayKeys( Key, TRUE, TRUE, TRUE );
|
||
FreeKey( Key );
|
||
}
|
||
|
||
//
|
||
// Query a value in the TestUser1 key using the Win 3.1 compatible API.
|
||
//
|
||
|
||
DataLength = MAX_DATA_LENGTH;
|
||
|
||
Error = RegQueryValue(
|
||
RootHandle,
|
||
KEY_NAME_1,
|
||
Data,
|
||
&DataLength
|
||
);
|
||
REG_API_SUCCESS( RegQueryValue );
|
||
|
||
ASSERT( Compare( Data, &Data_1, VALUE_DATA_1_LENGTH ));
|
||
ASSERT( DataLength == VALUE_DATA_1_LENGTH );
|
||
|
||
//
|
||
// Query a value in the TestUser1 key using the Win32 API.
|
||
//
|
||
|
||
DataLength = MAX_DATA_LENGTH;
|
||
|
||
Error = RegQueryValueEx(
|
||
Handle1,
|
||
VALUE_NAME_2,
|
||
NULL,
|
||
&Type,
|
||
Data,
|
||
&DataLength
|
||
);
|
||
REG_API_SUCCESS( RegQueryValueEx );
|
||
|
||
//ASSERT( TitleIndex == VALUE_NAME_2_TITLE_INDEX );
|
||
ASSERT( Type == VALUE_DATA_2_TYPE );
|
||
ASSERT(( DWORD ) Data[ 0 ] == Data_2 );
|
||
ASSERT( DataLength == VALUE_DATA_2_LENGTH );
|
||
|
||
//
|
||
// Query information about the key.
|
||
//
|
||
|
||
ClassNameLength = MAX_PATH;
|
||
|
||
Error = RegQueryInfoKey(
|
||
Handle1,
|
||
ClassName,
|
||
&ClassNameLength,
|
||
NULL,
|
||
&NumberOfSubKeys,
|
||
&MaxSubKeyLength,
|
||
&MaxClassLength,
|
||
&NumberOfValues,
|
||
&MaxValueNameLength,
|
||
&MaxValueDataLength,
|
||
&SecurityDescriptorLength,
|
||
&LastWriteTime
|
||
);
|
||
REG_API_SUCCESS( RegQueryInfoKey );
|
||
|
||
ASSERT( Compare( ClassName, KEY_NAME_1_CLASS, KEY_NAME_1_CLASS_LENGTH ));
|
||
ASSERT( ClassNameLength == KEY_NAME_1_CLASS_LENGTH );
|
||
//ASSERT( TitleIndex == KEY_NAME_1_TITLE_INDEX );
|
||
ASSERT( NumberOfSubKeys == 0 );
|
||
|
||
ASSERT( MaxSubKeyLength == 0 );
|
||
ASSERT( MaxClassLength == 0 );
|
||
|
||
|
||
ASSERT( NumberOfValues == 2 );
|
||
|
||
ASSERT( MaxValueNameLength == VALUE_NAME_2_LENGTH * sizeof(WCHAR) );
|
||
ASSERT( MaxValueDataLength == VALUE_DATA_1_LENGTH * sizeof(WCHAR) );
|
||
|
||
//
|
||
// Enumerate the values.
|
||
//
|
||
|
||
for( Index = 0; Index < 2; Index++ ) {
|
||
|
||
ValueNameLength = MAX_PATH;
|
||
DataLength = MAX_DATA_LENGTH;
|
||
|
||
Error = RegEnumValue(
|
||
Handle1,
|
||
Index,
|
||
ValueName,
|
||
&ValueNameLength,
|
||
NULL,
|
||
&Type,
|
||
Data,
|
||
&DataLength
|
||
);
|
||
REG_API_SUCCESS( RegEnumValue );
|
||
|
||
//
|
||
// Check specifics depending on the value being queried.
|
||
//
|
||
|
||
switch( Index ) {
|
||
|
||
case 0:
|
||
|
||
//
|
||
// No name - win 3.1 compatible value.
|
||
//
|
||
|
||
ASSERT( ValueNameLength == 0 );
|
||
//ASSERT( TitleIndex == VALUE_NAME_1_TITLE_INDEX );
|
||
ASSERT( Type == VALUE_DATA_1_TYPE );
|
||
ASSERT( Compare( Data, Data_1, VALUE_DATA_1_LENGTH ));
|
||
ASSERT( DataLength == VALUE_DATA_1_LENGTH );
|
||
break;
|
||
|
||
case 1:
|
||
|
||
ASSERT( Compare( ValueName, VALUE_NAME_2, VALUE_NAME_2_LENGTH ));
|
||
ASSERT( ValueNameLength == VALUE_NAME_2_LENGTH );
|
||
//ASSERT( TitleIndex == VALUE_NAME_2_TITLE_INDEX );
|
||
ASSERT( Type == VALUE_DATA_2_TYPE );
|
||
ASSERT(( DWORD ) Data[ 0 ] == Data_2 );
|
||
ASSERT( DataLength == VALUE_DATA_2_LENGTH );
|
||
break;
|
||
|
||
default:
|
||
|
||
ASSERT_MESSAGE( FALSE, "Valid value enumeration index - " );
|
||
}
|
||
}
|
||
|
||
//
|
||
// All done! Get rid of the key and close it.
|
||
//
|
||
|
||
Error = RegDeleteKey(
|
||
RootHandle,
|
||
KEY_NAME_1
|
||
);
|
||
REG_API_SUCCESS( RegDeleteKey );
|
||
|
||
Error = RegCloseKey(
|
||
Handle1
|
||
);
|
||
REG_API_SUCCESS( RegCloseKey );
|
||
}
|