ReactOS  0.4.14-dev-323-g6fe6a88
NtSetValueKey.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS API Tests
3  * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
4  * PURPOSE: Test for NtSetValueKey
5  * COPYRIGHT: Copyright 2016-2019 Thomas Faber (thomas.faber@reactos.org)
6  */
7 
8 #include "precomp.h"
9 
10 #include <winreg.h>
11 
13 {
15  HANDLE ParentKeyHandle;
17  UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SOFTWARE\\ntdll-apitest-NtSetValueKey");
20  WCHAR Default[] = L"Default";
21  WCHAR Hello[] = L"Hello";
22  WCHAR Empty[] = L"";
23  NTSTATUS QueryStatus;
25  ULONG PartialInfoLength;
28  PWCHAR LargeBuffer;
29  ULONG LargeBufferLength;
30  const struct
31  {
32  ULONG Type;
33  PVOID Data;
35  NTSTATUS StatusExisting;
36  NTSTATUS StatusNew;
37  NTSTATUS StatusExisting2;
38  NTSTATUS StatusNew2;
39  } Tests[] =
40  {
41  { REG_NONE, NULL, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Empty REG_NONE value */
42  { REG_SZ, Hello, sizeof(Hello), STATUS_SUCCESS, STATUS_SUCCESS }, /* Regular string */
43  { REG_SZ, Empty, sizeof(Empty), STATUS_SUCCESS, STATUS_SUCCESS }, /* Empty string */
44  { REG_SZ, NULL, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length */
45  { REG_SZ, Hello, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length, non-null data */
46  { REG_SZ, (PVOID)(LONG_PTR)-4, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length, kernel data */
47  { REG_SZ, NULL, 1, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* Non-zero length (odd), null data */
48  { REG_SZ, NULL, 2, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* Non-zero length (even), null data */
49  { REG_SZ, NULL, 4, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* CM_KEY_VALUE_SMALL, null data */
50  { REG_SZ, NULL, 5, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* CM_KEY_VALUE_SMALL+1, null data */
52  { REG_SZ, NULL, 6, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* CM_KEY_VALUE_SMALL+2, null data */
54  { REG_SZ, NULL, 0x7fff0000, STATUS_INVALID_PARAMETER, STATUS_INSUFFICIENT_RESOURCES, /* MI_USER_PROBE_ADDRESS, null data */
56  { REG_SZ, NULL, 0x7fff0001, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* MI_USER_PROBE_ADDRESS+1, null data */
58  { REG_SZ, NULL, 0x7fffffff, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* <2GB, null data */
60  { REG_SZ, NULL, 0x80000000, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* 2GB, null data */
64  };
65  ULONG i;
66 
67  Status = RtlOpenCurrentUser(READ_CONTROL, &ParentKeyHandle);
68  ok(Status == STATUS_SUCCESS, "RtlOpenCurrentUser returned %lx\n", Status);
69  if (!NT_SUCCESS(Status))
70  {
71  skip("No user key handle\n");
72  return;
73  }
74 
76  &KeyName,
78  ParentKeyHandle,
79  NULL);
83  0,
84  NULL,
86  NULL);
87  ok(Status == STATUS_SUCCESS, "NtCreateKey returned %lx\n", Status);
88  if (!NT_SUCCESS(Status))
89  {
90  NtClose(ParentKeyHandle);
91  skip("No key handle\n");
92  return;
93  }
94 
95  LargeBufferLength = 0x20000;
96  LargeBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, LargeBufferLength);
97 
98  PartialInfoLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[LargeBufferLength]);
99  PartialInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, PartialInfoLength);
100 
101  if (LargeBuffer == NULL || PartialInfo == NULL)
102  {
103  RtlFreeHeap(GetProcessHeap(), 0, LargeBuffer);
104  RtlFreeHeap(GetProcessHeap(), 0, PartialInfo);
107  NtClose(ParentKeyHandle);
108  skip("Could not allocate buffers\n");
109  return;
110  }
111 
112  for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
113  {
114  /*
115  * Existing value
116  */
117  /* Make sure it exists */
118  RtlInitUnicodeString(&ValueName, L"ExistingValue");
120  ok(Status == STATUS_SUCCESS, "[%lu] NtSetValueKey failed with %lx", i, Status);
121 
122  /* Set it */
124  if (Status == Tests[i].StatusExisting2)
125  ok(Status == Tests[i].StatusExisting || Status == Tests[i].StatusExisting2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n",
126  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting, Tests[i].StatusExisting2);
127  else
128  ok(Status == Tests[i].StatusExisting, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n",
129  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting);
130 
131  /* Check it */
132  RtlZeroMemory(PartialInfo, PartialInfoLength);
133  QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
134  ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n",
135  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
136  if (NT_SUCCESS(QueryStatus))
137  {
138  if (NT_SUCCESS(Status))
139  {
140  ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
141  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
142  ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n",
143  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
144  ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n",
145  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
146  ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n",
147  Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
148  }
149  else
150  {
151  ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
152  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
153  ok(PartialInfo->Type == REG_SZ, "[%lu, %p, %lu] Type = %lu\n",
154  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
155  ok(PartialInfo->DataLength == sizeof(Default), "[%lu, %p, %lu] DataLength = %lu\n",
156  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
157  ok(!memcmp(PartialInfo->Data, Default, sizeof(Default)), "[%lu, %p, %lu] Data does not match default\n",
158  Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
159  }
160  }
161 
162  /*
163  * New value
164  */
165  /* Make sure it doesn't exist */
166  RtlInitUnicodeString(&ValueName, L"NewValue");
169  "[%lu] NtDeleteValueKey failed with %lx", i, Status);
170 
171  /* Set it */
173  if (Tests[i].StatusNew2)
174  ok(Status == Tests[i].StatusNew || Status == Tests[i].StatusNew2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n",
175  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew, Tests[i].StatusNew2);
176  else
177  ok(Status == Tests[i].StatusNew, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n",
178  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew);
179 
180  /* Check it */
181  RtlZeroMemory(PartialInfo, PartialInfoLength);
182  QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
183  if (NT_SUCCESS(Status))
184  {
185  ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n",
186  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
187  if (NT_SUCCESS(QueryStatus))
188  {
189  ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
190  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
191  ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n",
192  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
193  ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n",
194  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
195  ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n",
196  Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
197  }
198  }
199  else
200  {
201  ok(QueryStatus == STATUS_OBJECT_NAME_NOT_FOUND, "[%lu, %p, %lu] QueryStatus = %lx\n",
202  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
203  }
204  }
205 
206  /* String value larger than MAXUSHORT */
207  {
208  const ULONG DataLengths[] = { 0x10000, 0x10002, 0x20000 };
209 
210  RtlInitUnicodeString(&ValueName, L"ExistingValue");
211  for (i = 0; i < RTL_NUMBER_OF(DataLengths); i++)
212  {
213  DataLength = DataLengths[i];
214  RtlFillMemoryUlong(LargeBuffer, DataLength, '\0B\0A');
215  LargeBuffer[DataLength / sizeof(WCHAR) - 2] = L'C';
216  LargeBuffer[DataLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
217  Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, LargeBuffer, DataLength);
218  ok(Status == STATUS_SUCCESS, "[0x%lx] NtSetValueKey failed with %lx", DataLength, Status);
219 
220  RtlZeroMemory(PartialInfo, PartialInfoLength);
221  Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
222  ok(Status == STATUS_SUCCESS, "[0x%lx] NtQueryValueKey failed with %lx\n", DataLength, Status);
223  ok(PartialInfo->TitleIndex == 0, "[0x%lx] TitleIndex = %lu\n", DataLength, PartialInfo->TitleIndex);
224  ok(PartialInfo->Type == REG_SZ, "[0x%lx] Type = %lu\n", DataLength, PartialInfo->Type);
225  ok(PartialInfo->DataLength == DataLength, "[0x%lx] DataLength = %lu\n", DataLength, PartialInfo->DataLength);
226  ok(!memcmp(PartialInfo->Data, LargeBuffer, DataLength), "[0x%lx] Data does not match set value\n", DataLength);
227  }
228  }
229 
230  RtlFreeHeap(GetProcessHeap(), 0, LargeBuffer);
231  RtlFreeHeap(GetProcessHeap(), 0, PartialInfo);
233  ok(Status == STATUS_SUCCESS, "NtDeleteKey returned %lx\n", Status);
235  ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status);
236  Status = NtClose(ParentKeyHandle);
237  ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status);
238 }
IN CINT OUT PVOID IN ULONG OUT PULONG ResultLength
Definition: conport.c:47
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING KeyName
Definition: ndis.h:4711
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
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
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
Type
Definition: Type.h:6
#define KEY_SET_VALUE
Definition: nt_native.h:1017
_Must_inspect_result_ _Out_ PNDIS_STATUS _In_ NDIS_HANDLE _In_ ULONG _Out_ PNDIS_STRING _Out_ PNDIS_HANDLE KeyHandle
Definition: ndis.h:4711
#define REG_BINARY
Definition: nt_native.h:1496
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
uint16_t * PWCHAR
Definition: typedefs.h:54
_In_ PUNICODE_STRING ValueName
Definition: cmfuncs.h:264
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define UNICODE_NULL
smooth NULL
Definition: ftsmooth.c:416
_In_ LPGUID _In_ PVOID Data
Definition: classpnp.h:778
void * PVOID
Definition: retypes.h:9
#define RtlFillMemoryUlong(dst, len, val)
Definition: mkhive.h:55
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
NTSYSAPI NTSTATUS NTAPI NtDeleteValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName)
Definition: ntapi.c:994
NTSYSAPI NTSTATUS NTAPI NtQueryValueKey(IN HANDLE KeyHandle, IN PUNICODE_STRING ValueName, IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, IN PVOID KeyValueInformation, IN ULONG Length, IN PULONG ResultLength)
#define GetProcessHeap()
Definition: compat.h:395
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3399
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define READ_CONTROL
Definition: nt_native.h:58
static const WCHAR L[]
Definition: oid.c:1250
NTSYSAPI NTSTATUS NTAPI RtlOpenCurrentUser(_In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE KeyHandle)
Status
Definition: gdiplustypes.h:24
NTSTATUS NTAPI NtDeleteKey(IN HANDLE KeyHandle)
Definition: ntapi.c:408
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
#define STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:228
#define RTL_NUMBER_OF(x)
Definition: RtlRegistry.c:12
#define KEY_QUERY_VALUE
Definition: nt_native.h:1016
#define ok(value,...)
Definition: atltest.h:57
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
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 skip(...)
Definition: atltest.h:64
START_TEST(NtSetValueKey)
Definition: NtSetValueKey.c:12
unsigned int ULONG
Definition: retypes.h:1
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1060
#define REG_NONE
Definition: nt_native.h:1492
_Must_inspect_result_ _Out_writes_to_ DataLength PHIDP_DATA _Inout_ PULONG DataLength
Definition: hidpi.h:333
return STATUS_SUCCESS
Definition: btrfs.c:2938
_In_ NDIS_STATUS _In_ ULONG _In_ USHORT _In_opt_ PVOID _In_ ULONG DataSize
Definition: ndis.h:4751
struct test_data Tests[]
#define DELETE
Definition: nt_native.h:57
Definition: npfs.h:125
#define RTL_CONSTANT_STRING(s)
Definition: tunneltest.c:14
#define REG_SZ
Definition: layer.c:22