ReactOS  0.4.15-dev-3203-gacde1e0
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 #if defined(_M_AMD64)
69  {
70  skip("ROSTESTS-365: Skipping ntdll_apitest:NtSetValueKey because it hangs on Windows Server 2003 x64-Testbot. Set winetest_interactive to run it anyway.\n");
71  return;
72  }
73 #endif
74 
75  Status = RtlOpenCurrentUser(READ_CONTROL, &ParentKeyHandle);
76  ok(Status == STATUS_SUCCESS, "RtlOpenCurrentUser returned %lx\n", Status);
77  if (!NT_SUCCESS(Status))
78  {
79  skip("No user key handle\n");
80  return;
81  }
82 
84  &KeyName,
86  ParentKeyHandle,
87  NULL);
91  0,
92  NULL,
94  NULL);
95  ok(Status == STATUS_SUCCESS, "NtCreateKey returned %lx\n", Status);
96  if (!NT_SUCCESS(Status))
97  {
98  NtClose(ParentKeyHandle);
99  skip("No key handle\n");
100  return;
101  }
102 
103  LargeBufferLength = 0x20000;
104  LargeBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, LargeBufferLength);
105 
106  PartialInfoLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[LargeBufferLength]);
107  PartialInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, PartialInfoLength);
108 
109  if (LargeBuffer == NULL || PartialInfo == NULL)
110  {
111  RtlFreeHeap(GetProcessHeap(), 0, LargeBuffer);
112  RtlFreeHeap(GetProcessHeap(), 0, PartialInfo);
115  NtClose(ParentKeyHandle);
116  skip("Could not allocate buffers\n");
117  return;
118  }
119 
120  for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
121  {
122  /*
123  * Existing value
124  */
125  /* Make sure it exists */
126  RtlInitUnicodeString(&ValueName, L"ExistingValue");
128  ok(Status == STATUS_SUCCESS, "[%lu] NtSetValueKey failed with %lx", i, Status);
129 
130  /* Set it */
132  if (Status == Tests[i].StatusExisting2)
133  ok(Status == Tests[i].StatusExisting || Status == Tests[i].StatusExisting2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n",
134  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting, Tests[i].StatusExisting2);
135  else
136  ok(Status == Tests[i].StatusExisting, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n",
137  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting);
138 
139  /* Check it */
140  RtlZeroMemory(PartialInfo, PartialInfoLength);
141  QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
142  ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n",
143  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
144  if (NT_SUCCESS(QueryStatus))
145  {
146  if (NT_SUCCESS(Status))
147  {
148  ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
149  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
150  ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n",
151  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
152  ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n",
153  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
154  ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n",
155  Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
156  }
157  else
158  {
159  ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
160  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
161  ok(PartialInfo->Type == REG_SZ, "[%lu, %p, %lu] Type = %lu\n",
162  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
163  ok(PartialInfo->DataLength == sizeof(Default), "[%lu, %p, %lu] DataLength = %lu\n",
164  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
165  ok(!memcmp(PartialInfo->Data, Default, sizeof(Default)), "[%lu, %p, %lu] Data does not match default\n",
166  Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
167  }
168  }
169 
170  /*
171  * New value
172  */
173  /* Make sure it doesn't exist */
174  RtlInitUnicodeString(&ValueName, L"NewValue");
177  "[%lu] NtDeleteValueKey failed with %lx", i, Status);
178 
179  /* Set it */
181  if (Tests[i].StatusNew2)
182  ok(Status == Tests[i].StatusNew || Status == Tests[i].StatusNew2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n",
183  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew, Tests[i].StatusNew2);
184  else
185  ok(Status == Tests[i].StatusNew, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n",
186  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew);
187 
188  /* Check it */
189  RtlZeroMemory(PartialInfo, PartialInfoLength);
190  QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
191  if (NT_SUCCESS(Status))
192  {
193  ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n",
194  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
195  if (NT_SUCCESS(QueryStatus))
196  {
197  ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
198  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
199  ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n",
200  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
201  ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n",
202  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
203  ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n",
204  Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
205  }
206  }
207  else
208  {
209  ok(QueryStatus == STATUS_OBJECT_NAME_NOT_FOUND, "[%lu, %p, %lu] QueryStatus = %lx\n",
210  Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
211  }
212  }
213 
214  /* String value larger than MAXUSHORT */
215  {
216  const ULONG DataLengths[] = { 0x10000, 0x10002, 0x20000 };
217 
218  RtlInitUnicodeString(&ValueName, L"ExistingValue");
219  for (i = 0; i < RTL_NUMBER_OF(DataLengths); i++)
220  {
221  DataLength = DataLengths[i];
222  RtlFillMemoryUlong(LargeBuffer, DataLength, '\0B\0A');
223  LargeBuffer[DataLength / sizeof(WCHAR) - 2] = L'C';
224  LargeBuffer[DataLength / sizeof(WCHAR) - 1] = UNICODE_NULL;
225  Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, LargeBuffer, DataLength);
226  ok(Status == STATUS_SUCCESS, "[0x%lx] NtSetValueKey failed with %lx", DataLength, Status);
227 
228  RtlZeroMemory(PartialInfo, PartialInfoLength);
229  Status = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
230  ok(Status == STATUS_SUCCESS, "[0x%lx] NtQueryValueKey failed with %lx\n", DataLength, Status);
231  ok(PartialInfo->TitleIndex == 0, "[0x%lx] TitleIndex = %lu\n", DataLength, PartialInfo->TitleIndex);
232  ok(PartialInfo->Type == REG_SZ, "[0x%lx] Type = %lu\n", DataLength, PartialInfo->Type);
233  ok(PartialInfo->DataLength == DataLength, "[0x%lx] DataLength = %lu\n", DataLength, PartialInfo->DataLength);
234  ok(!memcmp(PartialInfo->Data, LargeBuffer, DataLength), "[0x%lx] Data does not match set value\n", DataLength);
235  }
236  }
237 
238  RtlFreeHeap(GetProcessHeap(), 0, LargeBuffer);
239  RtlFreeHeap(GetProcessHeap(), 0, PartialInfo);
241  ok(Status == STATUS_SUCCESS, "NtDeleteKey returned %lx\n", Status);
243  ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status);
244  Status = NtClose(ParentKeyHandle);
245  ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status);
246 }
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:35
#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
#define KEY_SET_VALUE
Definition: nt_native.h:1017
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
_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
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG _In_opt_ PVOID Data
Definition: wdfdevice.h:4527
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
int winetest_interactive
uint16_t * PWCHAR
Definition: typedefs.h:56
#define UNICODE_NULL
_In_ ULONG _In_opt_ WDFREQUEST _In_opt_ PVOID _In_ size_t _In_ PVOID _In_ size_t _Out_ size_t * DataLength
Definition: cdrom.h:1437
void * PVOID
Definition: retypes.h:9
_Must_inspect_result_ _In_ WDFDEVICE _In_ PCUNICODE_STRING KeyName
Definition: wdfdevice.h:2697
#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:1014
Status
Definition: gdiplustypes.h:24
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:595
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
Type
Definition: Type.h:6
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3398
#define READ_CONTROL
Definition: nt_native.h:58
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING ValueName
Definition: wdfregistry.h:240
static const WCHAR L[]
Definition: oid.c:1250
NTSYSAPI NTSTATUS NTAPI RtlOpenCurrentUser(_In_ ACCESS_MASK DesiredAccess, _Out_ PHANDLE KeyHandle)
NTSTATUS NTAPI NtDeleteKey(IN HANDLE KeyHandle)
Definition: ntapi.c:408
#define STATUS_OBJECT_NAME_NOT_FOUND
Definition: udferr_usr.h:149
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 STATUS_ACCESS_VIOLATION
Definition: ntstatus.h:242
#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:255
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
#define NULL
Definition: types.h:112
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:262
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
_Must_inspect_result_ _In_ WDFDEVICE _In_ DEVICE_REGISTRY_PROPERTY _In_ ULONG _Out_ PULONG ResultLength
Definition: wdfdevice.h:3776
#define STATUS_SUCCESS
Definition: shellext.h:65
#define REG_OPTION_VOLATILE
Definition: nt_native.h:1060
#define REG_NONE
Definition: nt_native.h:1492
_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