336 lines
6.8 KiB
C
336 lines
6.8 KiB
C
|
/*++
|
|||
|
|
|||
|
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 <keyname> {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 <stdio.h>
|
|||
|
#include <stdlib.h>
|
|||
|
#include <string.h>
|
|||
|
|
|||
|
#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 <KeyPath> {key|tree|event|Apc|sync|name|write|security|attribute|*}\n",
|
|||
|
argv[0]);
|
|||
|
exit(1);
|
|||
|
}
|
|||
|
|