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 );
|
|||
|
}
|