/*++ Copyright (c) 1992 Microsoft Corporation Module Name: rtnotify.c Abstract: NT level registry test program, basic non-error paths. Wait for notification. This program tests waiting for notification on a change to a registry node. It can wait synchronously, for an event, for for an Apc. It can use any filter. Only the first letter of option control are significant. rtnotify {key|tree|event|Apc|hold|name|write|security|prop|*} key = key only [default] (last of these two wins) tree = subtree event = wait on an event (overrides hold) Apc = use an Apc (overrides hold) hold = be synchronous [default] (overrides event and Apc) name = watch for create/delete of children write = last set change security = acl change prop = any attr == security change * = all Example: rtflush \REGISTRY\MACHINE\TEST\bigkey Author: Bryan Willman (bryanwi) 10-Jan-92 Revision History: --*/ #include "cmp.h" #include #include #include #define WORK_SIZE 1024 void main(); void processargs(); ULONG CallCount = 0L; VOID ApcTest( PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock ); UNICODE_STRING KeyName; WCHAR workbuffer[WORK_SIZE]; BOOLEAN WatchTree; BOOLEAN UseEvent; BOOLEAN UseApc; BOOLEAN ApcSeen; BOOLEAN Hold; BOOLEAN Filter; IO_STATUS_BLOCK RtIoStatusBlock; void main( int argc, char *argv[] ) { NTSTATUS status; OBJECT_ATTRIBUTES ObjectAttributes; HANDLE BaseHandle; HANDLE EventHandle; PIO_APC_ROUTINE ApcRoutine; // // Process args // KeyName.MaximumLength = WORK_SIZE; KeyName.Length = 0L; KeyName.Buffer = &(workbuffer[0]); processargs(argc, argv); // // Set up and open KeyPath // printf("rtnotify: starting\n"); InitializeObjectAttributes( &ObjectAttributes, &KeyName, 0, (HANDLE)NULL, NULL ); ObjectAttributes.Attributes |= OBJ_CASE_INSENSITIVE; status = NtOpenKey( &BaseHandle, KEY_NOTIFY, &ObjectAttributes ); if (!NT_SUCCESS(status)) { printf("rtnotify: t0: %08lx\n", status); exit(1); } EventHandle = (HANDLE)NULL; if (UseEvent == TRUE) { status = NtCreateEvent( &EventHandle, GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE, NULL, NotificationEvent, FALSE ); if (!NT_SUCCESS(status)) { printf("rtnotify: t1: %08lx\n", status); exit(1); } } ApcRoutine = NULL; if (UseApc) { ApcRoutine = ApcTest; } printf("rtnotify:\n"); printf("\tUseEvent = %08lx\n", UseEvent); printf("\tApcRoutine = %08lx\n", ApcRoutine); printf("\tHold = %08lx\n", Hold); printf("\tFilter = %08lx\n", Filter); printf("\tWatchTree = %08lx\n", WatchTree); while (TRUE) { ApcSeen = FALSE; printf("\nCallCount = %dt\n", CallCount); CallCount++; status = NtNotifyChangeKey( BaseHandle, EventHandle, ApcRoutine, (PVOID)1992, // arbitrary context value &RtIoStatusBlock, Filter, WatchTree, NULL, 0, ! Hold ); exit(0); if ( ! NT_SUCCESS(status)) { printf("rtnotify: t2: %08lx\n", status); exit(1); } if (Hold) { printf("rtnotify: Synchronous Status = %08lx\n", RtIoStatusBlock.Status); } if (UseEvent) { status = NtWaitForSingleObject( EventHandle, TRUE, NULL ); if (!NT_SUCCESS(status)) { printf("rtnotify: t3: status = %08lx\n", status); exit(1); } printf("rtnotify: Event Status = %08lx\n", RtIoStatusBlock.Status); } if (UseApc) { while ((volatile)ApcSeen == FALSE) { NtTestAlert(); } } } NtClose(BaseHandle); exit(0); } VOID ApcTest( PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock ) { ApcSeen = TRUE; if (ApcContext != (PVOID)1992) { printf("rtnotify: Apc: Apccontext is wrong %08lx\n", ApcContext); exit(1); } if (IoStatusBlock != &RtIoStatusBlock) { printf("rtnotify: Apc: IoStatusBlock is wrong %08ln", IoStatusBlock); exit(1); } printf("rtnotify: Apc status = %08lx\n", IoStatusBlock->Status); return; } void processargs( int argc, char *argv[] ) { ANSI_STRING temp; ULONG i; if (argc < 2) { goto Usage; } // // name // RtlInitAnsiString( &temp, argv[1] ); RtlAnsiStringToUnicodeString( &KeyName, &temp, FALSE ); WatchTree = FALSE; UseEvent = FALSE; UseApc = FALSE; Hold = TRUE; Filter = 0; // // switches // for (i = 2; i < (ULONG)argc; i++) { switch (*argv[i]) { case 'a': // Apc case 'A': Hold = FALSE; UseApc = TRUE; break; case 'e': // event case 'E': Hold = FALSE; UseEvent = TRUE; break; case 'h': // hold case 'H': UseApc = FALSE; UseEvent = FALSE; Hold = TRUE; break; case 'k': // key only case 'K': WatchTree = FALSE; break; case 'n': case 'N': Filter |= REG_NOTIFY_CHANGE_NAME; break; case 'p': case 'P': Filter |= REG_NOTIFY_CHANGE_ATTRIBUTES; break; case 's': case 'S': Filter |= REG_NOTIFY_CHANGE_SECURITY; break; case 't': // subtree case 'T': WatchTree = TRUE; break; case 'w': case 'W': Filter |= REG_NOTIFY_CHANGE_LAST_SET; break; case '*': Filter = REG_LEGAL_CHANGE_FILTER; break; default: goto Usage; break; } } if (Filter == 0) { Filter = REG_LEGAL_CHANGE_FILTER; } return; Usage: printf("Usage: %s {key|tree|event|Apc|sync|name|write|security|attribute|*}\n", argv[0]); exit(1); }