caa2e34ef4c4e19683c99c561078faef36cff5da
[reactos.git] / modules / rostests / apitests / ntdll / NtSetValueKey.c
1 /*
2 * PROJECT: ReactOS API tests
3 * LICENSE: LGPLv2.1+ - See COPYING.LIB in the top level directory
4 * PURPOSE: Test for NtSetValueKey
5 * PROGRAMMER: Thomas Faber <thomas.faber@reactos.org>
6 */
7
8 #include "precomp.h"
9
10 #include <winreg.h>
11
12 START_TEST(NtSetValueKey)
13 {
14 NTSTATUS Status;
15 HANDLE ParentKeyHandle;
16 HANDLE KeyHandle;
17 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"SOFTWARE\\ntdll-apitest-NtSetValueKey");
18 OBJECT_ATTRIBUTES ObjectAttributes;
19 UNICODE_STRING ValueName;
20 WCHAR Default[] = L"Default";
21 WCHAR Hello[] = L"Hello";
22 WCHAR Empty[] = L"";
23 NTSTATUS QueryStatus;
24 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
25 ULONG PartialInfoLength;
26 ULONG ResultLength;
27 const struct
28 {
29 ULONG Type;
30 PVOID Data;
31 ULONG DataSize;
32 NTSTATUS StatusExisting;
33 NTSTATUS StatusNew;
34 NTSTATUS StatusExisting2;
35 NTSTATUS StatusNew2;
36 } Tests[] =
37 {
38 { REG_NONE, NULL, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Empty REG_NONE value */
39 { REG_SZ, Hello, sizeof(Hello), STATUS_SUCCESS, STATUS_SUCCESS }, /* Regular string */
40 { REG_SZ, Empty, sizeof(Empty), STATUS_SUCCESS, STATUS_SUCCESS }, /* Empty string */
41 { REG_SZ, NULL, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length */
42 { REG_SZ, Hello, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length, non-null data */
43 { REG_SZ, (PVOID)(LONG_PTR)-4, 0, STATUS_SUCCESS, STATUS_SUCCESS }, /* Zero length, kernel data */
44 { REG_SZ, NULL, 1, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* Non-zero length (odd), null data */
45 { REG_SZ, NULL, 2, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* Non-zero length (even), null data */
46 { REG_SZ, NULL, 4, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION }, /* CM_KEY_VALUE_SMALL, null data */
47 { REG_SZ, NULL, 5, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* CM_KEY_VALUE_SMALL+1, null data */
48 STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
49 { REG_SZ, NULL, 6, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* CM_KEY_VALUE_SMALL+2, null data */
50 STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
51 { REG_SZ, NULL, 0x7fff0000, STATUS_INVALID_PARAMETER, STATUS_INSUFFICIENT_RESOURCES, /* MI_USER_PROBE_ADDRESS, null data */
52 STATUS_INSUFFICIENT_RESOURCES, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
53 { REG_SZ, NULL, 0x7fff0001, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* MI_USER_PROBE_ADDRESS+1, null data */
54 STATUS_INSUFFICIENT_RESOURCES, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
55 { REG_SZ, NULL, 0x7fffffff, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* <2GB, null data */
56 STATUS_INVALID_PARAMETER, STATUS_INVALID_PARAMETER }, /* win7 */
57 { REG_SZ, NULL, 0x80000000, STATUS_ACCESS_VIOLATION, STATUS_ACCESS_VIOLATION, /* 2GB, null data */
58 STATUS_INVALID_PARAMETER, STATUS_INVALID_PARAMETER }, /* win7 */
59 { REG_BINARY, NULL, 5, STATUS_INVALID_PARAMETER, STATUS_ACCESS_VIOLATION, /* ROSTESTS-200 */
60 STATUS_ACCESS_VIOLATION, STATUS_INSUFFICIENT_RESOURCES }, /* win7 */
61 };
62 ULONG i;
63
64 Status = RtlOpenCurrentUser(READ_CONTROL, &ParentKeyHandle);
65 ok(Status == STATUS_SUCCESS, "RtlOpenCurrentUser returned %lx\n", Status);
66 if (!NT_SUCCESS(Status))
67 {
68 skip("No user key handle\n");
69 return;
70 }
71
72 InitializeObjectAttributes(&ObjectAttributes,
73 &KeyName,
74 OBJ_CASE_INSENSITIVE,
75 ParentKeyHandle,
76 NULL);
77 Status = NtCreateKey(&KeyHandle,
78 KEY_QUERY_VALUE | KEY_SET_VALUE | DELETE,
79 &ObjectAttributes,
80 0,
81 NULL,
82 REG_OPTION_VOLATILE,
83 NULL);
84 ok(Status == STATUS_SUCCESS, "NtCreateKey returned %lx\n", Status);
85 if (!NT_SUCCESS(Status))
86 {
87 NtClose(ParentKeyHandle);
88 skip("No key handle\n");
89 return;
90 }
91
92 PartialInfoLength = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data[128]);
93 PartialInfo = HeapAlloc(GetProcessHeap(), 0, PartialInfoLength);
94 if (PartialInfo == NULL)
95 {
96 NtDeleteKey(KeyHandle);
97 NtClose(KeyHandle);
98 NtClose(ParentKeyHandle);
99 skip("No key handle\n");
100 return;
101 }
102
103 for (i = 0; i < RTL_NUMBER_OF(Tests); i++)
104 {
105 /*
106 * Existing value
107 */
108 /* Make sure it exists */
109 RtlInitUnicodeString(&ValueName, L"ExistingValue");
110 Status = NtSetValueKey(KeyHandle, &ValueName, 0, REG_SZ, Default, sizeof(Default));
111 ok(Status == STATUS_SUCCESS, "[%lu] NtSetValueKey failed with %lx", i, Status);
112
113 /* Set it */
114 Status = NtSetValueKey(KeyHandle, &ValueName, 0, Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
115 if (Status == Tests[i].StatusExisting2)
116 ok(Status == Tests[i].StatusExisting || Status == Tests[i].StatusExisting2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n",
117 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting, Tests[i].StatusExisting2);
118 else
119 ok(Status == Tests[i].StatusExisting, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n",
120 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusExisting);
121
122 /* Check it */
123 RtlZeroMemory(PartialInfo, PartialInfoLength);
124 QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
125 ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n",
126 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
127 if (NT_SUCCESS(QueryStatus))
128 {
129 if (NT_SUCCESS(Status))
130 {
131 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
132 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
133 ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n",
134 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
135 ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n",
136 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
137 ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n",
138 Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
139 }
140 else
141 {
142 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
143 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
144 ok(PartialInfo->Type == REG_SZ, "[%lu, %p, %lu] Type = %lu\n",
145 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
146 ok(PartialInfo->DataLength == sizeof(Default), "[%lu, %p, %lu] DataLength = %lu\n",
147 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
148 ok(!memcmp(PartialInfo->Data, Default, sizeof(Default)), "[%lu, %p, %lu] Data does not match default\n",
149 Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
150 }
151 }
152
153 /*
154 * New value
155 */
156 /* Make sure it doesn't exist */
157 RtlInitUnicodeString(&ValueName, L"NewValue");
158 Status = NtDeleteValueKey(KeyHandle, &ValueName);
159 ok(Status == STATUS_SUCCESS || Status == STATUS_OBJECT_NAME_NOT_FOUND,
160 "[%lu] NtDeleteValueKey failed with %lx", i, Status);
161
162 /* Set it */
163 Status = NtSetValueKey(KeyHandle, &ValueName, 0, Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
164 if (Tests[i].StatusNew2)
165 ok(Status == Tests[i].StatusNew || Status == Tests[i].StatusNew2, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx or %lx\n",
166 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew, Tests[i].StatusNew2);
167 else
168 ok(Status == Tests[i].StatusNew, "[%lu, %p, %lu] NtSetValueKey returned %lx, expected %lx\n",
169 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, Status, Tests[i].StatusNew);
170
171 /* Check it */
172 RtlZeroMemory(PartialInfo, PartialInfoLength);
173 QueryStatus = NtQueryValueKey(KeyHandle, &ValueName, KeyValuePartialInformation, PartialInfo, PartialInfoLength, &ResultLength);
174 if (NT_SUCCESS(Status))
175 {
176 ok(QueryStatus == STATUS_SUCCESS, "[%lu, %p, %lu] NtQueryValueKey failed with %lx\n",
177 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
178 if (NT_SUCCESS(QueryStatus))
179 {
180 ok(PartialInfo->TitleIndex == 0, "[%lu, %p, %lu] TitleIndex = %lu\n",
181 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->TitleIndex);
182 ok(PartialInfo->Type == Tests[i].Type, "[%lu, %p, %lu] Type = %lu\n",
183 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->Type);
184 ok(PartialInfo->DataLength == Tests[i].DataSize, "[%lu, %p, %lu] DataLength = %lu\n",
185 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, PartialInfo->DataLength);
186 ok(!memcmp(PartialInfo->Data, Tests[i].Data, Tests[i].DataSize), "[%lu, %p, %lu] Data does not match set value\n",
187 Tests[i].Type, Tests[i].Data, Tests[i].DataSize);
188 }
189 }
190 else
191 {
192 ok(QueryStatus == STATUS_OBJECT_NAME_NOT_FOUND, "[%lu, %p, %lu] QueryStatus = %lx\n",
193 Tests[i].Type, Tests[i].Data, Tests[i].DataSize, QueryStatus);
194 }
195 }
196
197 HeapFree(GetProcessHeap(), 0, PartialInfo);
198 Status = NtDeleteKey(KeyHandle);
199 ok(Status == STATUS_SUCCESS, "NtDeleteKey returned %lx\n", Status);
200 Status = NtClose(KeyHandle);
201 ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status);
202 Status = NtClose(ParentKeyHandle);
203 ok(Status == STATUS_SUCCESS, "NtClose returned %lx\n", Status);
204 }