1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Kernel Streaming 4 * FILE: drivers/wdm/audio/backpln/portcls/registry.cpp 5 * PURPOSE: Registry access object 6 * PROGRAMMER: Johannes Anderwald 7 */ 8 9 #include "private.hpp" 10 11 #define NDEBUG 12 #include <debug.h> 13 14 class CRegistryKey : public CUnknownImpl<IRegistryKey> 15 { 16 public: 17 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface); 18 19 IMP_IRegistryKey; 20 CRegistryKey(IUnknown * OuterUnknown, HANDLE hKey, BOOL CanDelete) : 21 m_hKey(hKey), 22 m_Deleted(FALSE), 23 m_CanDelete(CanDelete) 24 { 25 } 26 virtual ~CRegistryKey(); 27 28 protected: 29 30 HANDLE m_hKey; 31 BOOL m_Deleted; 32 BOOL m_CanDelete; 33 }; 34 35 CRegistryKey::~CRegistryKey() 36 { 37 if (!m_Deleted) 38 { 39 // close key only when has not been deleted yet 40 ZwClose(m_hKey); 41 } 42 } 43 44 NTSTATUS 45 NTAPI 46 CRegistryKey::QueryInterface( 47 IN REFIID refiid, 48 OUT PVOID* Output) 49 { 50 UNICODE_STRING GuidString; 51 52 DPRINT("CRegistryKey::QueryInterface entered\n"); 53 if (IsEqualGUIDAligned(refiid, IID_IRegistryKey) || 54 IsEqualGUIDAligned(refiid, IID_IUnknown)) 55 { 56 *Output = PVOID(PREGISTRYKEY(this)); 57 PUNKNOWN(*Output)->AddRef(); 58 return STATUS_SUCCESS; 59 } 60 61 if (RtlStringFromGUID(refiid, &GuidString) == STATUS_SUCCESS) 62 { 63 DPRINT1("CRegistryKey::QueryInterface no interface!!! iface %S\n", GuidString.Buffer); 64 RtlFreeUnicodeString(&GuidString); 65 } 66 67 return STATUS_UNSUCCESSFUL; 68 } 69 70 NTSTATUS 71 NTAPI 72 CRegistryKey::DeleteKey() 73 { 74 NTSTATUS Status; 75 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 76 77 if (m_Deleted) 78 { 79 // key already deleted 80 return STATUS_INVALID_HANDLE; 81 } 82 83 if (!m_CanDelete) 84 { 85 // only general keys can be deleted 86 return STATUS_ACCESS_DENIED; 87 } 88 89 // delete key 90 Status = ZwDeleteKey(m_hKey); 91 if (NT_SUCCESS(Status)) 92 { 93 m_Deleted = TRUE; 94 m_hKey = NULL; 95 } 96 return Status; 97 } 98 99 NTSTATUS 100 NTAPI 101 CRegistryKey::EnumerateKey( 102 IN ULONG Index, 103 IN KEY_INFORMATION_CLASS KeyInformationClass, 104 OUT PVOID KeyInformation, 105 IN ULONG Length, 106 OUT PULONG ResultLength) 107 { 108 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 109 110 if (m_Deleted) 111 { 112 return STATUS_INVALID_HANDLE; 113 } 114 115 return ZwEnumerateKey(m_hKey, Index, KeyInformationClass, KeyInformation, Length, ResultLength); 116 } 117 118 NTSTATUS 119 NTAPI 120 CRegistryKey::EnumerateValueKey( 121 IN ULONG Index, 122 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 123 OUT PVOID KeyValueInformation, 124 IN ULONG Length, 125 OUT PULONG ResultLength) 126 { 127 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 128 129 if (m_Deleted) 130 { 131 return STATUS_INVALID_HANDLE; 132 } 133 134 return ZwEnumerateValueKey(m_hKey, Index, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); 135 } 136 137 NTSTATUS 138 NTAPI 139 CRegistryKey::NewSubKey( 140 OUT PREGISTRYKEY *RegistrySubKey, 141 IN PUNKNOWN OuterUnknown, 142 IN ACCESS_MASK DesiredAccess, 143 IN PUNICODE_STRING SubKeyName, 144 IN ULONG CreateOptions, 145 OUT PULONG Disposition OPTIONAL) 146 { 147 OBJECT_ATTRIBUTES Attributes; 148 NTSTATUS Status; 149 HANDLE hKey; 150 CRegistryKey * RegistryKey; 151 152 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 153 154 DPRINT("CRegistryKey::NewSubKey entered %S\n", SubKeyName->Buffer); 155 156 if (m_Deleted) 157 { 158 return STATUS_INVALID_HANDLE; 159 } 160 161 InitializeObjectAttributes(&Attributes, SubKeyName, OBJ_INHERIT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_KERNEL_HANDLE, m_hKey, NULL); 162 Status = ZwCreateKey(&hKey, DesiredAccess, &Attributes, 0, NULL, CreateOptions, Disposition); 163 if (!NT_SUCCESS(Status)) 164 { 165 DPRINT("CRegistryKey::NewSubKey failed with %x\n", Status); 166 return Status; 167 } 168 169 RegistryKey = new(NonPagedPool, TAG_PORTCLASS)CRegistryKey(OuterUnknown, hKey, TRUE); 170 if (!RegistryKey) 171 return STATUS_INSUFFICIENT_RESOURCES; 172 173 Status = RegistryKey->QueryInterface(IID_IRegistryKey, (PVOID*)RegistrySubKey); 174 175 if (!NT_SUCCESS(Status)) 176 { 177 delete RegistryKey; 178 return Status; 179 } 180 181 DPRINT("CRegistryKey::NewSubKey RESULT %p\n", *RegistrySubKey); 182 return STATUS_SUCCESS; 183 } 184 185 NTSTATUS 186 NTAPI 187 CRegistryKey::QueryKey( 188 IN KEY_INFORMATION_CLASS KeyInformationClass, 189 OUT PVOID KeyInformation, 190 IN ULONG Length, 191 OUT PULONG ResultLength) 192 { 193 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 194 195 if (m_Deleted) 196 { 197 return STATUS_INVALID_HANDLE; 198 } 199 200 return ZwQueryKey(m_hKey, KeyInformationClass, KeyInformation, Length, ResultLength); 201 } 202 203 NTSTATUS 204 NTAPI 205 CRegistryKey::QueryRegistryValues( 206 IN PRTL_QUERY_REGISTRY_TABLE QueryTable, 207 IN PVOID Context OPTIONAL) 208 { 209 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 210 211 if (m_Deleted) 212 { 213 return STATUS_INVALID_HANDLE; 214 } 215 216 return RtlQueryRegistryValues(RTL_REGISTRY_HANDLE, (PCWSTR)m_hKey, QueryTable, Context, NULL); 217 } 218 219 NTSTATUS 220 NTAPI 221 CRegistryKey::QueryValueKey( 222 IN PUNICODE_STRING ValueName, 223 IN KEY_VALUE_INFORMATION_CLASS KeyValueInformationClass, 224 OUT PVOID KeyValueInformation, 225 IN ULONG Length, 226 OUT PULONG ResultLength) 227 { 228 NTSTATUS Status; 229 230 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 231 232 if (m_Deleted) 233 { 234 return STATUS_INVALID_HANDLE; 235 } 236 237 Status = ZwQueryValueKey(m_hKey, ValueName, KeyValueInformationClass, KeyValueInformation, Length, ResultLength); 238 DPRINT("CRegistryKey::QueryValueKey entered %p value %wZ Status %x\n", this, ValueName, Status); 239 return Status; 240 } 241 242 NTSTATUS 243 NTAPI 244 CRegistryKey::SetValueKey( 245 IN PUNICODE_STRING ValueName OPTIONAL, 246 IN ULONG Type, 247 IN PVOID Data, 248 IN ULONG DataSize 249 ) 250 { 251 DPRINT("CRegistryKey::SetValueKey entered %S\n", ValueName->Buffer); 252 PC_ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 253 254 if (m_Deleted) 255 { 256 return STATUS_INVALID_HANDLE; 257 } 258 259 return ZwSetValueKey(m_hKey, ValueName, 0, Type, Data, DataSize); 260 } 261 262 NTSTATUS 263 NTAPI 264 PcNewRegistryKey( 265 OUT PREGISTRYKEY* OutRegistryKey, 266 IN PUNKNOWN OuterUnknown OPTIONAL, 267 IN ULONG RegistryKeyType, 268 IN ACCESS_MASK DesiredAccess, 269 IN PVOID DeviceObject OPTIONAL, 270 IN PVOID SubDevice OPTIONAL, 271 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 272 IN ULONG CreateOptions OPTIONAL, 273 OUT PULONG Disposition OPTIONAL) 274 { 275 HANDLE hHandle; 276 NTSTATUS Status = STATUS_UNSUCCESSFUL; 277 CRegistryKey * RegistryKey; 278 PPCLASS_DEVICE_EXTENSION DeviceExt; 279 PSUBDEVICE_DESCRIPTOR SubDeviceDescriptor; 280 ISubdevice * Device; 281 PSYMBOLICLINK_ENTRY SymEntry; 282 BOOL CanDelete = FALSE; 283 284 DPRINT("PcNewRegistryKey entered\n"); 285 286 if (!OutRegistryKey) 287 return STATUS_INVALID_PARAMETER; 288 289 if (RegistryKeyType != GeneralRegistryKey && 290 RegistryKeyType != DeviceRegistryKey && 291 RegistryKeyType != DriverRegistryKey && 292 RegistryKeyType != HwProfileRegistryKey && 293 RegistryKeyType != DeviceInterfaceRegistryKey) 294 { 295 return STATUS_INVALID_PARAMETER; 296 } 297 298 // check for the key type 299 if (RegistryKeyType == GeneralRegistryKey) 300 { 301 // do we have the required object attributes 302 if (!ObjectAttributes) 303 { 304 // object attributes is mandatory 305 return STATUS_INVALID_PARAMETER; 306 } 307 // try to create the key 308 Status = ZwCreateKey(&hHandle, DesiredAccess, ObjectAttributes, 0, NULL, CreateOptions, Disposition); 309 310 // key can be deleted 311 CanDelete = TRUE; 312 } 313 else if (RegistryKeyType == DeviceRegistryKey || 314 RegistryKeyType == DriverRegistryKey || 315 RegistryKeyType == HwProfileRegistryKey) 316 { 317 // check for HwProfileRegistryKey case 318 if (RegistryKeyType == HwProfileRegistryKey) 319 { 320 // IoOpenDeviceRegistryKey used different constant 321 RegistryKeyType = PLUGPLAY_REGKEY_CURRENT_HWPROFILE | PLUGPLAY_REGKEY_DEVICE; 322 } 323 324 // obtain the new device extension 325 DeviceExt = (PPCLASS_DEVICE_EXTENSION) ((PDEVICE_OBJECT)DeviceObject)->DeviceExtension; 326 327 Status = IoOpenDeviceRegistryKey(DeviceExt->PhysicalDeviceObject, RegistryKeyType, DesiredAccess, &hHandle); 328 } 329 else if (RegistryKeyType == DeviceInterfaceRegistryKey) 330 { 331 if (SubDevice == NULL) 332 { 333 // invalid parameter 334 return STATUS_INVALID_PARAMETER; 335 } 336 337 // look up our undocumented interface 338 Status = ((PUNKNOWN)SubDevice)->QueryInterface(IID_ISubdevice, (LPVOID*)&Device); 339 340 if (!NT_SUCCESS(Status)) 341 { 342 DPRINT("No ISubdevice interface\n"); 343 // invalid parameter 344 return STATUS_INVALID_PARAMETER; 345 } 346 347 // get the subdevice descriptor 348 Status = Device->GetDescriptor(&SubDeviceDescriptor); 349 if (!NT_SUCCESS(Status)) 350 { 351 DPRINT("Failed to get subdevice descriptor %x\n", Status); 352 ((PUNKNOWN)SubDevice)->Release(); 353 return STATUS_UNSUCCESSFUL; 354 } 355 356 // is there an registered device interface 357 if (IsListEmpty(&SubDeviceDescriptor->SymbolicLinkList)) 358 { 359 DPRINT("No device interface registered\n"); 360 ((PUNKNOWN)SubDevice)->Release(); 361 return STATUS_UNSUCCESSFUL; 362 } 363 364 // get the first symbolic link 365 SymEntry = (PSYMBOLICLINK_ENTRY)CONTAINING_RECORD(SubDeviceDescriptor->SymbolicLinkList.Flink, SYMBOLICLINK_ENTRY, Entry); 366 367 // open device interface 368 Status = IoOpenDeviceInterfaceRegistryKey(&SymEntry->SymbolicLink, DesiredAccess, &hHandle); 369 370 // release subdevice interface 371 ((PUNKNOWN)SubDevice)->Release(); 372 } 373 374 // check for success 375 if (!NT_SUCCESS(Status)) 376 { 377 DPRINT1("PcNewRegistryKey failed with %lx\n", Status); 378 return Status; 379 } 380 381 // allocate new registry key object 382 RegistryKey = new(NonPagedPool, TAG_PORTCLASS)CRegistryKey(OuterUnknown, hHandle, CanDelete); 383 if (!RegistryKey) 384 { 385 // not enough memory 386 ZwClose(hHandle); 387 return STATUS_INSUFFICIENT_RESOURCES; 388 } 389 390 // query for interface 391 Status = RegistryKey->QueryInterface(IID_IRegistryKey, (PVOID*)OutRegistryKey); 392 393 if (!NT_SUCCESS(Status)) 394 { 395 // out of memory 396 delete RegistryKey; 397 } 398 399 DPRINT("PcNewRegistryKey result %p\n", *OutRegistryKey); 400 return STATUS_SUCCESS; 401 } 402