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 } 205