ReactOS 0.4.17-dev-812-ged4f258
NtNotifyChangeMultipleKeys.c File Reference
#include "precomp.h"
#include <winreg.h>
Include dependency graph for NtNotifyChangeMultipleKeys.c:

Go to the source code of this file.

Classes

struct  _WATCH_THREAD_CONTEXT
 
struct  _APC_CONTEXT
 

Typedefs

typedef struct _WATCH_THREAD_CONTEXT WATCH_THREAD_CONTEXT
 
typedef struct _WATCH_THREAD_CONTEXTPWATCH_THREAD_CONTEXT
 
typedef struct _APC_CONTEXT APC_CONTEXT
 
typedef struct _APC_CONTEXTPAPC_CONTEXT
 

Functions

DWORD WINAPI NtNotifyChangeMultipleKeys_WatchThread (LPVOID lpParameter)
 
VOID WINAPI NtNotifyChangeMultipleKeys_ApcRoutine (PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved)
 
 START_TEST (NtNotifyChangeMultipleKeys)
 

Typedef Documentation

◆ APC_CONTEXT

◆ PAPC_CONTEXT

◆ PWATCH_THREAD_CONTEXT

◆ WATCH_THREAD_CONTEXT

Function Documentation

◆ NtNotifyChangeMultipleKeys_ApcRoutine()

VOID WINAPI NtNotifyChangeMultipleKeys_ApcRoutine ( PVOID  ApcContext,
PIO_STATUS_BLOCK  IoStatusBlock,
ULONG  Reserved 
)

Definition at line 40 of file NtNotifyChangeMultipleKeys.c.

41{
44
46 ApcState->ApcRan = TRUE;
47}
_In_ PIO_STATUS_BLOCK IoStatusBlock
Definition: dispmprt.h:608
#define TRUE
Definition: types.h:120
_In_opt_ HANDLE _In_opt_ PIO_APC_ROUTINE _In_opt_ PVOID ApcContext
Definition: iofuncs.h:727
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:329
_Out_ PKAPC_STATE ApcState
Definition: mm.h:1769
_Reserved_ PVOID Reserved
Definition: winddi.h:3974

Referenced by START_TEST().

◆ NtNotifyChangeMultipleKeys_WatchThread()

DWORD WINAPI NtNotifyChangeMultipleKeys_WatchThread ( LPVOID  lpParameter)

Definition at line 20 of file NtNotifyChangeMultipleKeys.c.

21{
23
24 State->Status = NtNotifyChangeMultipleKeys(State->KeyHandle, 0,
25 NULL, NULL, NULL, NULL,
26 State->IoStatusBlock,
28 FALSE, NULL, 0, FALSE);
29
30 return 0;
31}
struct _WATCH_THREAD_CONTEXT * PWATCH_THREAD_CONTEXT
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
NTSTATUS NTAPI NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle, IN ULONG Count, IN POBJECT_ATTRIBUTES SlaveObjects, IN HANDLE Event, IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, IN PVOID ApcContext OPTIONAL, OUT PIO_STATUS_BLOCK IoStatusBlock, IN ULONG CompletionFilter, IN BOOLEAN WatchTree, OUT PVOID Buffer, IN ULONG Length, IN BOOLEAN Asynchronous)
Definition: ntapi.c:1457
#define REG_NOTIFY_CHANGE_LAST_SET
Definition: winreg.h:40

Referenced by START_TEST().

◆ START_TEST()

START_TEST ( NtNotifyChangeMultipleKeys  )

Definition at line 49 of file NtNotifyChangeMultipleKeys.c.

50{
52 DWORD WaitStatus;
54 OBJECT_ATTRIBUTES SubordinateObjects[1];
55
56 PWATCH_THREAD_CONTEXT WatchThread1State = NULL, WatchThread2State = NULL;
58
59 /* Registry key object attributes */
60 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SOFTWARE\\TestKey");
61 UNICODE_STRING SubKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\SOFTWARE\\TestKey\\TestSubKey");
62 UNICODE_STRING SecondaryKeyName = RTL_CONSTANT_STRING(L"\\Registry\\User\\.DEFAULT\\SOFTWARE\\TestKey");
63 UNICODE_STRING ThirdKeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Microsoft\\Windows");
66 OBJECT_ATTRIBUTES SecondaryObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(&SecondaryKeyName, OBJ_CASE_INSENSITIVE);
68 DWORD Value1 = 0x12345678, Value2 = 0x87654321;
69
70 /* Handles */
71 HANDLE KeyHandle = NULL, SubKeyHandle = NULL, SecondaryKeyHandle = NULL;
72 HANDLE WatchThread1Handle = NULL, WatchThread2Handle = NULL;
74
75 /* Create event */
77 if (EventHandle == NULL)
78 {
79 skip("Failed to create event");
80 return;
81 }
82 /* Create registry keys */
84 if (!NT_SUCCESS(Status))
85 {
86 skip("Failed to create registry key");
87 goto Cleanup;
88 }
89 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_DWORD, &Value1, sizeof(Value1));
90 if (!NT_SUCCESS(Status))
91 {
92 skip("Failed to set initial test value");
93 goto Cleanup;
94 }
95
96 /* Synchronous mode */
97
98 /* Create a thread */
99 WatchThread1State = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*WatchThread1State));
100 if (WatchThread1State == NULL)
101 {
102 skip("Failed to allocate memory for watch thread state");
103 goto Cleanup;
104 }
105 WatchThread1State->KeyHandle = KeyHandle;
106 WatchThread1State->IoStatusBlock = &IoStatusBlock;
107 WatchThread1Handle = CreateThread(NULL, 0, NtNotifyChangeMultipleKeys_WatchThread, WatchThread1State, 0, NULL);
108 if (WatchThread1Handle)
109 {
110 /* Verify the thread is still running */
111 WaitStatus = WaitForSingleObject(WatchThread1Handle, 100);
112 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
113 /* Make change to the registry key */
114 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_DWORD, &Value2, sizeof(Value2));
116 /* Verify that the thread is notified */
117 WaitStatus = WaitForSingleObject(WatchThread1Handle, 100);
118 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
119 /* Verify the status code */
120 ok_ntstatus(WatchThread1State->Status, STATUS_NOTIFY_ENUM_DIR);
122 /* cleanup */
123 CloseHandle(WatchThread1Handle);
124 WatchThread1Handle = NULL;
125 }
126 else
127 {
128 skip("Failed to create watch thread");
129 }
130 HeapFree(GetProcessHeap(), 0, WatchThread1State);
131 WatchThread1State = NULL;
132 /* Watch again, but this time close the handle without making any change */
133 WatchThread2State = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*WatchThread2State));
134 if (WatchThread2State == NULL)
135 {
136 skip("Failed to allocate memory for watch thread state");
137 goto Cleanup;
138 }
139 WatchThread2State->KeyHandle = KeyHandle;
140 WatchThread2State->IoStatusBlock = &IoStatusBlock;
141 WatchThread2Handle = CreateThread(NULL, 0, NtNotifyChangeMultipleKeys_WatchThread, WatchThread2State, 0, NULL);
142 if (WatchThread2Handle)
143 {
144 WaitStatus = WaitForSingleObject(WatchThread2Handle, 100);
145 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
147 KeyHandle = NULL;
148 WaitStatus = WaitForSingleObject(WatchThread2Handle, 100);
149 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
150 ok_ntstatus(WatchThread2State->Status, STATUS_NOTIFY_CLEANUP);
151 ok_ntstatus(WatchThread2State->IoStatusBlock->Status, STATUS_NOTIFY_CLEANUP);
152 /* cleanup */
153 CloseHandle(WatchThread2Handle);
154 WatchThread2Handle = NULL;
155 }
156 else
157 {
158 skip("Failed to create watch thread");
159 }
160 HeapFree(GetProcessHeap(), 0, WatchThread2State);
161 WatchThread2State = NULL;
162
163 /* Event-based asynchronous mode */
164
165 if (!KeyHandle)
166 {
168 if (!NT_SUCCESS(Status))
169 {
170 skip("Failed to open registry key");
171 goto Cleanup;
172 }
173 }
174 /* Start watching for changes */
179 FALSE, NULL, 0, TRUE);
181 /* Check event state */
182 WaitStatus = WaitForSingleObject(EventHandle, 0);
183 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
184 /* Make change to the registry key */
185 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_DWORD, &Value1, sizeof(Value1));
187 /* Verify that the event is signaled */
188 NtTestAlert();
189 WaitStatus = WaitForSingleObject(EventHandle, 100);
190 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
191 /* Verify the status code */
193
194 /* Watch again, but this time close the handle without making any change */
199 FALSE, NULL, 0, TRUE);
201 WaitStatus = WaitForSingleObject(EventHandle, 0);
202 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
204 KeyHandle = NULL;
205 NtTestAlert();
206 WaitStatus = WaitForSingleObject(EventHandle, 100);
207 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
209
210 /* Watching subtree */
211
212 if (!KeyHandle)
213 {
215 if (!NT_SUCCESS(Status))
216 {
217 skip("Failed to open registry key");
218 goto Cleanup;
219 }
220 }
222 if (NT_SUCCESS(Status))
223 {
224 /* Start watching for changes */
229 TRUE, NULL, 0, TRUE);
231 /* Check event state */
232 WaitStatus = WaitForSingleObject(EventHandle, 0);
233 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
234 /* Make change to the subkey */
235 Status = NtSetValueKey(SubKeyHandle, &ValueName, 0, REG_DWORD, &Value1, sizeof(Value1));
237 /* Verify that the event is signaled */
238 NtTestAlert();
239 WaitStatus = WaitForSingleObject(EventHandle, 100);
240 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
241 }
242 else
243 {
244 skip("Failed to create subkey");
245 }
246
247 /* Watching multiple keys */
248
249 Status = NtCreateKey(&SecondaryKeyHandle, KEY_ALL_ACCESS, &SecondaryObjectAttributes, 0, NULL, REG_OPTION_NON_VOLATILE, NULL);
250 if (NT_SUCCESS(Status))
251 {
252 NtClose(SecondaryKeyHandle);
253 InitializeObjectAttributes(&SubordinateObjects[0], &SecondaryKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
255 _countof(SubordinateObjects),
256 SubordinateObjects,
258 NULL,
259 NULL,
262 TRUE,
263 NULL,
264 0,
265 TRUE);
267 /* Check event state */
268 WaitStatus = WaitForSingleObject(EventHandle, 0);
269 ok_eq_ulong(WaitStatus, WAIT_TIMEOUT);
270 /* Make change to the secondary key */
271 Status = NtOpenKey(&SecondaryKeyHandle, KEY_SET_VALUE | KEY_NOTIFY | DELETE, &SecondaryObjectAttributes);
272 if (NT_SUCCESS(Status))
273 {
274 Status = NtSetValueKey(SecondaryKeyHandle, &ValueName, 0, REG_DWORD, &Value1, sizeof(Value1));
276 NtClose(SecondaryKeyHandle);
277 }
278 /* Verify that the event is signaled */
279 NtTestAlert();
280 WaitStatus = WaitForSingleObject(EventHandle, 100);
281 ok_eq_ulong(WaitStatus, WAIT_OBJECT_0);
282 }
283 else
284 {
285 skip("Failed to create secondary key");
286 }
287 /* Test if the function fails if the given subordinate key is same with master key */
290 _countof(SubordinateObjects),
291 SubordinateObjects,
293 NULL,
294 NULL,
297 TRUE,
298 NULL,
299 0,
300 TRUE);
301 /* The status is STATUS_INVALID_PARAMETER on Windows Server 2003 and STATUS_INVALID_OBJECT_NAME on Windows 10 */
302 ok(!NT_SUCCESS(Status), "NtNotifyChangeMultipleKeys succeeded unexpectedly.\n");
303 /* Test if the function fails if the the given subordinate key is in the same hive as the master key */
304 InitializeObjectAttributes(&SubordinateObjects[0], &ThirdKeyName, OBJ_CASE_INSENSITIVE, NULL, NULL);
306 _countof(SubordinateObjects),
307 SubordinateObjects,
309 NULL,
310 NULL,
313 TRUE,
314 NULL,
315 0,
316 TRUE);
317 ok(!NT_SUCCESS(Status), "NtNotifyChangeMultipleKeys succeeded unexpectedly.\n");
318
319 /* APC-based asynchronous mode */
321 if (ApcContext == NULL)
322 {
323 skip("Failed to allocate memory for APC context");
324 goto Cleanup;
325 }
330 FALSE, NULL, 0, TRUE);
332 /* Make change to the registry key */
333 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_DWORD, &Value2, sizeof(Value2));
335 /* Force system to run queued APC routines */
336 NtTestAlert();
337 ok(ApcContext->ApcRan == TRUE, "The APC routine did not ran.\n");
338
339Cleanup:
340 if (WatchThread1Handle)
341 {
342 CloseHandle(WatchThread1Handle);
343 }
344 if (WatchThread2Handle)
345 {
346 CloseHandle(WatchThread2Handle);
347 }
348 if (EventHandle)
349 {
351 }
352 if (ApcContext)
353 {
355 }
356 if (SubKeyHandle)
357 {
360 }
361 if (!KeyHandle)
362 {
364 if (!NT_SUCCESS(Status))
365 {
366 KeyHandle = NULL;
367 }
368 }
369 if (KeyHandle)
370 {
373 }
374 Status = NtOpenKey(&SecondaryKeyHandle, DELETE, &SecondaryObjectAttributes);
375 if (NT_SUCCESS(Status))
376 {
377 NtDeleteKey(SecondaryKeyHandle);
378 NtClose(SecondaryKeyHandle);
379 }
380}
VOID WINAPI NtNotifyChangeMultipleKeys_ApcRoutine(PVOID ApcContext, PIO_STATUS_BLOCK IoStatusBlock, ULONG Reserved)
DWORD WINAPI NtNotifyChangeMultipleKeys_WatchThread(LPVOID lpParameter)
#define ok_eq_ulong(value, expected)
Definition: apitest.h:120
#define ok_ntstatus(status, expected)
Definition: atltest.h:135
#define ok(value,...)
Definition: atltest.h:57
#define skip(...)
Definition: atltest.h:64
LONG NTSTATUS
Definition: precomp.h:26
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define WAIT_TIMEOUT
Definition: dderror.h:14
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
#define RTL_CONSTANT_STRING(s)
Definition: combase.c:35
#define CloseHandle
Definition: compat.h:739
#define GetProcessHeap()
Definition: compat.h:736
#define HeapAlloc
Definition: compat.h:733
#define HeapFree(x, y, z)
Definition: compat.h:735
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
static const WCHAR Cleanup[]
Definition: register.c:80
#define L(x)
Definition: resources.c:13
unsigned long DWORD
Definition: ntddk_ex.h:95
Status
Definition: gdiplustypes.h:24
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:115
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ PNDIS_STRING SubKeyName
Definition: ndis.h:4725
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ PNDIS_STRING _Out_ PNDIS_HANDLE SubKeyHandle
Definition: ndis.h:4726
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4715
NTSYSAPI NTSTATUS NTAPI NtOpenKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes)
Definition: ntapi.c:336
NTSYSAPI NTSTATUS NTAPI NtSetValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN ULONG TitleIndex OPTIONAL, IN ULONG Type, IN PVOID Data, IN ULONG DataSize)
Definition: ntapi.c:859
#define KEY_ALL_ACCESS
Definition: nt_native.h:1044
#define REG_OPTION_NON_VOLATILE
Definition: nt_native.h:1060
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3429
#define DELETE
Definition: nt_native.h:57
#define KEY_NOTIFY
Definition: nt_native.h:1023
#define KEY_SET_VALUE
Definition: nt_native.h:1020
NTSTATUS NTAPI NtDeleteKey(IN HANDLE KeyHandle)
Definition: ntapi.c:408
NTSTATUS NTAPI NtCreateKey(OUT PHANDLE KeyHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN ULONG TitleIndex, IN PUNICODE_STRING Class OPTIONAL, IN ULONG CreateOptions, OUT PULONG Disposition OPTIONAL)
Definition: ntapi.c:240
#define RTL_CONSTANT_OBJECT_ATTRIBUTES(n, a)
NTSTATUS NTAPI NtTestAlert(VOID)
Definition: state.c:465
#define STATUS_NOTIFY_CLEANUP
Definition: ntstatus.h:143
#define STATUS_NOTIFY_ENUM_DIR
Definition: ntstatus.h:144
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define REG_DWORD
Definition: sdbapi.c:615
#define STATUS_SUCCESS
Definition: shellext.h:65
#define _countof(array)
Definition: sndvol32.h:70
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
#define STATUS_PENDING
Definition: telnetd.h:14
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2705
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:243
#define CreateEvent
Definition: winbase.h:3470
#define WAIT_OBJECT_0
Definition: winbase.h:383
_Out_ PHANDLE EventHandle
Definition: iofuncs.h:857