Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygendeviface.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/io/iomgr/deviface.c 00005 * PURPOSE: Device interface functions 00006 * 00007 * PROGRAMMERS: Filip Navara (xnavara@volny.cz) 00008 * Matthew Brace (ismarc@austin.rr.com) 00009 * Hervé Poussineau (hpoussin@reactos.org) 00010 */ 00011 00012 /* INCLUDES ******************************************************************/ 00013 00014 #include <ntoskrnl.h> 00015 00016 #define NDEBUG 00017 #include <debug.h> 00018 00019 /* FUNCTIONS *****************************************************************/ 00020 00021 static PWCHAR BaseKeyString = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\DeviceClasses\\"; 00022 00023 static 00024 NTSTATUS 00025 OpenRegistryHandlesFromSymbolicLink(IN PUNICODE_STRING SymbolicLinkName, 00026 IN ACCESS_MASK DesiredAccess, 00027 IN OPTIONAL PHANDLE GuidKey, 00028 IN OPTIONAL PHANDLE DeviceKey, 00029 IN OPTIONAL PHANDLE InstanceKey) 00030 { 00031 OBJECT_ATTRIBUTES ObjectAttributes; 00032 WCHAR PathBuffer[MAX_PATH]; 00033 UNICODE_STRING BaseKeyU; 00034 UNICODE_STRING GuidString, SubKeyName, ReferenceString; 00035 PWCHAR StartPosition, EndPosition; 00036 HANDLE ClassesKey; 00037 PHANDLE GuidKeyRealP, DeviceKeyRealP, InstanceKeyRealP; 00038 HANDLE GuidKeyReal, DeviceKeyReal, InstanceKeyReal; 00039 NTSTATUS Status; 00040 00041 SubKeyName.Buffer = NULL; 00042 00043 if (GuidKey != NULL) 00044 GuidKeyRealP = GuidKey; 00045 else 00046 GuidKeyRealP = &GuidKeyReal; 00047 00048 if (DeviceKey != NULL) 00049 DeviceKeyRealP = DeviceKey; 00050 else 00051 DeviceKeyRealP = &DeviceKeyReal; 00052 00053 if (InstanceKey != NULL) 00054 InstanceKeyRealP = InstanceKey; 00055 else 00056 InstanceKeyRealP = &InstanceKeyReal; 00057 00058 *GuidKeyRealP = INVALID_HANDLE_VALUE; 00059 *DeviceKeyRealP = INVALID_HANDLE_VALUE; 00060 *InstanceKeyRealP = INVALID_HANDLE_VALUE; 00061 00062 BaseKeyU.Buffer = PathBuffer; 00063 BaseKeyU.Length = 0; 00064 BaseKeyU.MaximumLength = MAX_PATH * sizeof(WCHAR); 00065 00066 RtlAppendUnicodeToString(&BaseKeyU, BaseKeyString); 00067 00068 /* Open the DeviceClasses key */ 00069 InitializeObjectAttributes(&ObjectAttributes, 00070 &BaseKeyU, 00071 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00072 NULL, 00073 NULL); 00074 Status = ZwOpenKey(&ClassesKey, 00075 DesiredAccess | KEY_ENUMERATE_SUB_KEYS, 00076 &ObjectAttributes); 00077 if (!NT_SUCCESS(Status)) 00078 { 00079 DPRINT1("Failed to open %wZ\n", &BaseKeyU); 00080 goto cleanup; 00081 } 00082 00083 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{'); 00084 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}'); 00085 if (!StartPosition || !EndPosition || StartPosition > EndPosition) 00086 { 00087 DPRINT1("Bad symbolic link: %wZ\n", SymbolicLinkName); 00088 return STATUS_INVALID_PARAMETER_1; 00089 } 00090 GuidString.Buffer = StartPosition; 00091 GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition); 00092 00093 InitializeObjectAttributes(&ObjectAttributes, 00094 &GuidString, 00095 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00096 ClassesKey, 00097 NULL); 00098 Status = ZwOpenKey(GuidKeyRealP, 00099 DesiredAccess | KEY_ENUMERATE_SUB_KEYS, 00100 &ObjectAttributes); 00101 ZwClose(ClassesKey); 00102 if (!NT_SUCCESS(Status)) 00103 { 00104 DPRINT1("Failed to open %wZ%wZ (%x)\n", &BaseKeyU, &GuidString, Status); 00105 goto cleanup; 00106 } 00107 00108 SubKeyName.MaximumLength = SymbolicLinkName->Length + sizeof(WCHAR); 00109 SubKeyName.Length = 0; 00110 SubKeyName.Buffer = ExAllocatePool(PagedPool, SubKeyName.MaximumLength); 00111 if (!SubKeyName.Buffer) 00112 { 00113 Status = STATUS_INSUFFICIENT_RESOURCES; 00114 goto cleanup; 00115 } 00116 00117 RtlAppendUnicodeStringToString(&SubKeyName, 00118 SymbolicLinkName); 00119 00120 SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = UNICODE_NULL; 00121 00122 SubKeyName.Buffer[0] = L'#'; 00123 SubKeyName.Buffer[1] = L'#'; 00124 SubKeyName.Buffer[2] = L'?'; 00125 SubKeyName.Buffer[3] = L'#'; 00126 00127 ReferenceString.Buffer = wcsrchr(SubKeyName.Buffer, '\\'); 00128 if (ReferenceString.Buffer != NULL) 00129 { 00130 ReferenceString.Buffer[0] = L'#'; 00131 00132 SubKeyName.Length = (USHORT)((ULONG_PTR)(ReferenceString.Buffer) - (ULONG_PTR)SubKeyName.Buffer); 00133 ReferenceString.Length = SymbolicLinkName->Length - SubKeyName.Length; 00134 } 00135 else 00136 { 00137 RtlInitUnicodeString(&ReferenceString, L"#"); 00138 } 00139 00140 InitializeObjectAttributes(&ObjectAttributes, 00141 &SubKeyName, 00142 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00143 *GuidKeyRealP, 00144 NULL); 00145 Status = ZwOpenKey(DeviceKeyRealP, 00146 DesiredAccess | KEY_ENUMERATE_SUB_KEYS, 00147 &ObjectAttributes); 00148 if (!NT_SUCCESS(Status)) 00149 { 00150 DPRINT1("Failed to open %wZ%wZ\\%wZ\n", &BaseKeyU, &GuidString, &SubKeyName); 00151 goto cleanup; 00152 } 00153 00154 InitializeObjectAttributes(&ObjectAttributes, 00155 &ReferenceString, 00156 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 00157 *DeviceKeyRealP, 00158 NULL); 00159 Status = ZwOpenKey(InstanceKeyRealP, 00160 DesiredAccess, 00161 &ObjectAttributes); 00162 if (!NT_SUCCESS(Status)) 00163 { 00164 DPRINT1("Failed to open %wZ%wZ\\%wZ%\\%wZ (%x)\n", &BaseKeyU, &GuidString, &SubKeyName, &ReferenceString, Status); 00165 goto cleanup; 00166 } 00167 00168 Status = STATUS_SUCCESS; 00169 00170 cleanup: 00171 if (SubKeyName.Buffer != NULL) 00172 ExFreePool(SubKeyName.Buffer); 00173 00174 if (NT_SUCCESS(Status)) 00175 { 00176 if (!GuidKey) 00177 ZwClose(*GuidKeyRealP); 00178 00179 if (!DeviceKey) 00180 ZwClose(*DeviceKeyRealP); 00181 00182 if (!InstanceKey) 00183 ZwClose(*InstanceKeyRealP); 00184 } 00185 else 00186 { 00187 if (*GuidKeyRealP != INVALID_HANDLE_VALUE) 00188 ZwClose(*GuidKeyRealP); 00189 00190 if (*DeviceKeyRealP != INVALID_HANDLE_VALUE) 00191 ZwClose(*DeviceKeyRealP); 00192 00193 if (*InstanceKeyRealP != INVALID_HANDLE_VALUE) 00194 ZwClose(*InstanceKeyRealP); 00195 } 00196 00197 return Status; 00198 } 00199 /*++ 00200 * @name IoOpenDeviceInterfaceRegistryKey 00201 * @unimplemented 00202 * 00203 * Provides a handle to the device's interface instance registry key. 00204 * Documented in WDK. 00205 * 00206 * @param SymbolicLinkName 00207 * Pointer to a string which identifies the device interface instance 00208 * 00209 * @param DesiredAccess 00210 * Desired ACCESS_MASK used to access the key (like KEY_READ, 00211 * KEY_WRITE, etc) 00212 * 00213 * @param DeviceInterfaceKey 00214 * If a call has been succesfull, a handle to the registry key 00215 * will be stored there 00216 * 00217 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS 00218 * otherwise (see WDK for details) 00219 * 00220 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread 00221 * 00222 *--*/ 00223 NTSTATUS 00224 NTAPI 00225 IoOpenDeviceInterfaceRegistryKey(IN PUNICODE_STRING SymbolicLinkName, 00226 IN ACCESS_MASK DesiredAccess, 00227 OUT PHANDLE DeviceInterfaceKey) 00228 { 00229 HANDLE InstanceKey, DeviceParametersKey; 00230 NTSTATUS Status; 00231 OBJECT_ATTRIBUTES ObjectAttributes; 00232 UNICODE_STRING DeviceParametersU = RTL_CONSTANT_STRING(L"Device Parameters"); 00233 00234 Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName, 00235 KEY_CREATE_SUB_KEY, 00236 NULL, 00237 NULL, 00238 &InstanceKey); 00239 if (!NT_SUCCESS(Status)) 00240 return Status; 00241 00242 InitializeObjectAttributes(&ObjectAttributes, 00243 &DeviceParametersU, 00244 OBJ_CASE_INSENSITIVE | OBJ_OPENIF, 00245 InstanceKey, 00246 NULL); 00247 Status = ZwCreateKey(&DeviceParametersKey, 00248 DesiredAccess, 00249 &ObjectAttributes, 00250 0, 00251 NULL, 00252 REG_OPTION_NON_VOLATILE, 00253 NULL); 00254 ZwClose(InstanceKey); 00255 00256 if (NT_SUCCESS(Status)) 00257 *DeviceInterfaceKey = DeviceParametersKey; 00258 00259 return Status; 00260 } 00261 00262 /*++ 00263 * @name IoGetDeviceInterfaceAlias 00264 * @unimplemented 00265 * 00266 * Returns the alias device interface of the specified device interface 00267 * instance, if the alias exists. 00268 * Documented in WDK. 00269 * 00270 * @param SymbolicLinkName 00271 * Pointer to a string which identifies the device interface instance 00272 * 00273 * @param AliasInterfaceClassGuid 00274 * See WDK 00275 * 00276 * @param AliasSymbolicLinkName 00277 * See WDK 00278 * 00279 * @return Three different NTSTATUS values in case of errors, and STATUS_SUCCESS 00280 * otherwise (see WDK for details) 00281 * 00282 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a system thread 00283 * 00284 *--*/ 00285 NTSTATUS 00286 NTAPI 00287 IoGetDeviceInterfaceAlias(IN PUNICODE_STRING SymbolicLinkName, 00288 IN CONST GUID *AliasInterfaceClassGuid, 00289 OUT PUNICODE_STRING AliasSymbolicLinkName) 00290 { 00291 return STATUS_NOT_IMPLEMENTED; 00292 } 00293 00294 /*++ 00295 * @name IopOpenInterfaceKey 00296 * 00297 * Returns the alias device interface of the specified device interface 00298 * 00299 * @param InterfaceClassGuid 00300 * FILLME 00301 * 00302 * @param DesiredAccess 00303 * FILLME 00304 * 00305 * @param pInterfaceKey 00306 * FILLME 00307 * 00308 * @return Usual NTSTATUS 00309 * 00310 * @remarks None 00311 * 00312 *--*/ 00313 static NTSTATUS 00314 IopOpenInterfaceKey(IN CONST GUID *InterfaceClassGuid, 00315 IN ACCESS_MASK DesiredAccess, 00316 OUT HANDLE *pInterfaceKey) 00317 { 00318 UNICODE_STRING LocalMachine = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\"); 00319 UNICODE_STRING GuidString; 00320 UNICODE_STRING KeyName; 00321 OBJECT_ATTRIBUTES ObjectAttributes; 00322 HANDLE InterfaceKey = INVALID_HANDLE_VALUE; 00323 NTSTATUS Status; 00324 00325 GuidString.Buffer = KeyName.Buffer = NULL; 00326 00327 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString); 00328 if (!NT_SUCCESS(Status)) 00329 { 00330 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status); 00331 goto cleanup; 00332 } 00333 00334 KeyName.Length = 0; 00335 KeyName.MaximumLength = LocalMachine.Length + ((USHORT)wcslen(REGSTR_PATH_DEVICE_CLASSES) + 1) * sizeof(WCHAR) + GuidString.Length; 00336 KeyName.Buffer = ExAllocatePool(PagedPool, KeyName.MaximumLength); 00337 if (!KeyName.Buffer) 00338 { 00339 DPRINT("ExAllocatePool() failed\n"); 00340 Status = STATUS_INSUFFICIENT_RESOURCES; 00341 goto cleanup; 00342 } 00343 00344 Status = RtlAppendUnicodeStringToString(&KeyName, &LocalMachine); 00345 if (!NT_SUCCESS(Status)) 00346 { 00347 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status); 00348 goto cleanup; 00349 } 00350 Status = RtlAppendUnicodeToString(&KeyName, REGSTR_PATH_DEVICE_CLASSES); 00351 if (!NT_SUCCESS(Status)) 00352 { 00353 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status); 00354 goto cleanup; 00355 } 00356 Status = RtlAppendUnicodeToString(&KeyName, L"\\"); 00357 if (!NT_SUCCESS(Status)) 00358 { 00359 DPRINT("RtlAppendUnicodeToString() failed with status 0x%08lx\n", Status); 00360 goto cleanup; 00361 } 00362 Status = RtlAppendUnicodeStringToString(&KeyName, &GuidString); 00363 if (!NT_SUCCESS(Status)) 00364 { 00365 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status); 00366 goto cleanup; 00367 } 00368 00369 InitializeObjectAttributes( 00370 &ObjectAttributes, 00371 &KeyName, 00372 OBJ_CASE_INSENSITIVE, 00373 NULL, 00374 NULL); 00375 Status = ZwOpenKey( 00376 &InterfaceKey, 00377 DesiredAccess, 00378 &ObjectAttributes); 00379 if (!NT_SUCCESS(Status)) 00380 { 00381 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 00382 goto cleanup; 00383 } 00384 00385 *pInterfaceKey = InterfaceKey; 00386 Status = STATUS_SUCCESS; 00387 00388 cleanup: 00389 if (!NT_SUCCESS(Status)) 00390 { 00391 if (InterfaceKey != INVALID_HANDLE_VALUE) 00392 ZwClose(InterfaceKey); 00393 } 00394 RtlFreeUnicodeString(&GuidString); 00395 RtlFreeUnicodeString(&KeyName); 00396 return Status; 00397 } 00398 00399 /*++ 00400 * @name IoGetDeviceInterfaces 00401 * @implemented 00402 * 00403 * Returns a list of device interfaces of a particular device interface class. 00404 * Documented in WDK 00405 * 00406 * @param InterfaceClassGuid 00407 * Points to a class GUID specifying the device interface class 00408 * 00409 * @param PhysicalDeviceObject 00410 * Points to an optional PDO that narrows the search to only the 00411 * device interfaces of the device represented by the PDO 00412 * 00413 * @param Flags 00414 * Specifies flags that modify the search for device interfaces. The 00415 * DEVICE_INTERFACE_INCLUDE_NONACTIVE flag specifies that the list of 00416 * returned symbolic links should contain also disabled device 00417 * interfaces in addition to the enabled ones. 00418 * 00419 * @param SymbolicLinkList 00420 * Points to a character pointer that is filled in on successful return 00421 * with a list of unicode strings identifying the device interfaces 00422 * that match the search criteria. The newly allocated buffer contains 00423 * a list of symbolic link names. Each unicode string in the list is 00424 * null-terminated; the end of the whole list is marked by an additional 00425 * NULL. The caller is responsible for freeing the buffer (ExFreePool) 00426 * when it is no longer needed. 00427 * If no device interfaces match the search criteria, this routine 00428 * returns STATUS_SUCCESS and the string contains a single NULL 00429 * character. 00430 * 00431 * @return Usual NTSTATUS 00432 * 00433 * @remarks None 00434 * 00435 *--*/ 00436 NTSTATUS 00437 NTAPI 00438 IoGetDeviceInterfaces(IN CONST GUID *InterfaceClassGuid, 00439 IN PDEVICE_OBJECT PhysicalDeviceObject OPTIONAL, 00440 IN ULONG Flags, 00441 OUT PWSTR *SymbolicLinkList) 00442 { 00443 UNICODE_STRING Control = RTL_CONSTANT_STRING(L"Control"); 00444 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink"); 00445 HANDLE InterfaceKey = INVALID_HANDLE_VALUE; 00446 HANDLE DeviceKey = INVALID_HANDLE_VALUE; 00447 HANDLE ReferenceKey = INVALID_HANDLE_VALUE; 00448 HANDLE ControlKey = INVALID_HANDLE_VALUE; 00449 PKEY_BASIC_INFORMATION DeviceBi = NULL; 00450 PKEY_BASIC_INFORMATION ReferenceBi = NULL; 00451 PKEY_VALUE_PARTIAL_INFORMATION bip = NULL; 00452 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo; 00453 UNICODE_STRING KeyName; 00454 OBJECT_ATTRIBUTES ObjectAttributes; 00455 BOOLEAN FoundRightPDO = FALSE; 00456 ULONG i = 0, j, Size, NeededLength, ActualLength, LinkedValue; 00457 UNICODE_STRING ReturnBuffer = { 0, 0, NULL }; 00458 NTSTATUS Status; 00459 00460 PAGED_CODE(); 00461 00462 Status = IopOpenInterfaceKey(InterfaceClassGuid, KEY_ENUMERATE_SUB_KEYS, &InterfaceKey); 00463 if (!NT_SUCCESS(Status)) 00464 { 00465 DPRINT("IopOpenInterfaceKey() failed with status 0x%08lx\n", Status); 00466 goto cleanup; 00467 } 00468 00469 /* Enumerate subkeys (ie the different device objets) */ 00470 while (TRUE) 00471 { 00472 Status = ZwEnumerateKey( 00473 InterfaceKey, 00474 i, 00475 KeyBasicInformation, 00476 NULL, 00477 0, 00478 &Size); 00479 if (Status == STATUS_NO_MORE_ENTRIES) 00480 { 00481 break; 00482 } 00483 else if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) 00484 { 00485 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 00486 goto cleanup; 00487 } 00488 00489 DeviceBi = ExAllocatePool(PagedPool, Size); 00490 if (!DeviceBi) 00491 { 00492 DPRINT("ExAllocatePool() failed\n"); 00493 Status = STATUS_INSUFFICIENT_RESOURCES; 00494 goto cleanup; 00495 } 00496 Status = ZwEnumerateKey( 00497 InterfaceKey, 00498 i++, 00499 KeyBasicInformation, 00500 DeviceBi, 00501 Size, 00502 &Size); 00503 if (!NT_SUCCESS(Status)) 00504 { 00505 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 00506 goto cleanup; 00507 } 00508 00509 /* Open device key */ 00510 KeyName.Length = KeyName.MaximumLength = (USHORT)DeviceBi->NameLength; 00511 KeyName.Buffer = DeviceBi->Name; 00512 InitializeObjectAttributes( 00513 &ObjectAttributes, 00514 &KeyName, 00515 OBJ_CASE_INSENSITIVE, 00516 InterfaceKey, 00517 NULL); 00518 Status = ZwOpenKey( 00519 &DeviceKey, 00520 KEY_ENUMERATE_SUB_KEYS, 00521 &ObjectAttributes); 00522 if (!NT_SUCCESS(Status)) 00523 { 00524 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 00525 goto cleanup; 00526 } 00527 00528 if (PhysicalDeviceObject) 00529 { 00530 /* Check if we are on the right physical device object, 00531 * by reading the DeviceInstance string 00532 */ 00533 DPRINT1("PhysicalDeviceObject != NULL. Case not implemented.\n"); 00534 //FoundRightPDO = TRUE; 00535 Status = STATUS_NOT_IMPLEMENTED; 00536 goto cleanup; 00537 } 00538 00539 /* Enumerate subkeys (ie the different reference strings) */ 00540 j = 0; 00541 while (TRUE) 00542 { 00543 Status = ZwEnumerateKey( 00544 DeviceKey, 00545 j, 00546 KeyBasicInformation, 00547 NULL, 00548 0, 00549 &Size); 00550 if (Status == STATUS_NO_MORE_ENTRIES) 00551 { 00552 break; 00553 } 00554 else if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) 00555 { 00556 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 00557 goto cleanup; 00558 } 00559 00560 ReferenceBi = ExAllocatePool(PagedPool, Size); 00561 if (!ReferenceBi) 00562 { 00563 DPRINT("ExAllocatePool() failed\n"); 00564 Status = STATUS_INSUFFICIENT_RESOURCES; 00565 goto cleanup; 00566 } 00567 Status = ZwEnumerateKey( 00568 DeviceKey, 00569 j++, 00570 KeyBasicInformation, 00571 ReferenceBi, 00572 Size, 00573 &Size); 00574 if (!NT_SUCCESS(Status)) 00575 { 00576 DPRINT("ZwEnumerateKey() failed with status 0x%08lx\n", Status); 00577 goto cleanup; 00578 } 00579 00580 KeyName.Length = KeyName.MaximumLength = (USHORT)ReferenceBi->NameLength; 00581 KeyName.Buffer = ReferenceBi->Name; 00582 if (RtlEqualUnicodeString(&KeyName, &Control, TRUE)) 00583 { 00584 /* Skip Control subkey */ 00585 goto NextReferenceString; 00586 } 00587 00588 /* Open reference key */ 00589 InitializeObjectAttributes( 00590 &ObjectAttributes, 00591 &KeyName, 00592 OBJ_CASE_INSENSITIVE, 00593 DeviceKey, 00594 NULL); 00595 Status = ZwOpenKey( 00596 &ReferenceKey, 00597 KEY_QUERY_VALUE, 00598 &ObjectAttributes); 00599 if (!NT_SUCCESS(Status)) 00600 { 00601 DPRINT("ZwOpenKey() failed with status 0x%08lx\n", Status); 00602 goto cleanup; 00603 } 00604 00605 if (!(Flags & DEVICE_INTERFACE_INCLUDE_NONACTIVE)) 00606 { 00607 /* We have to check if the interface is enabled, by 00608 * reading the Linked value in the Control subkey 00609 */ 00610 InitializeObjectAttributes( 00611 &ObjectAttributes, 00612 &Control, 00613 OBJ_CASE_INSENSITIVE, 00614 ReferenceKey, 00615 NULL); 00616 Status = ZwOpenKey( 00617 &ControlKey, 00618 KEY_QUERY_VALUE, 00619 &ObjectAttributes); 00620 if (Status == STATUS_OBJECT_NAME_NOT_FOUND) 00621 { 00622 /* That's OK. The key doesn't exist (yet) because 00623 * the interface is not activated. 00624 */ 00625 goto NextReferenceString; 00626 } 00627 else if (!NT_SUCCESS(Status)) 00628 { 00629 DPRINT1("ZwOpenKey() failed with status 0x%08lx\n", Status); 00630 goto cleanup; 00631 } 00632 00633 RtlInitUnicodeString(&KeyName, L"Linked"); 00634 Status = ZwQueryValueKey(ControlKey, 00635 &KeyName, 00636 KeyValuePartialInformation, 00637 NULL, 00638 0, 00639 &NeededLength); 00640 if (Status == STATUS_BUFFER_TOO_SMALL) 00641 { 00642 ActualLength = NeededLength; 00643 PartialInfo = ExAllocatePool(NonPagedPool, ActualLength); 00644 if (!PartialInfo) 00645 { 00646 Status = STATUS_INSUFFICIENT_RESOURCES; 00647 goto cleanup; 00648 } 00649 00650 Status = ZwQueryValueKey(ControlKey, 00651 &KeyName, 00652 KeyValuePartialInformation, 00653 PartialInfo, 00654 ActualLength, 00655 &NeededLength); 00656 if (!NT_SUCCESS(Status)) 00657 { 00658 DPRINT1("ZwQueryValueKey #2 failed (%x)\n", Status); 00659 ExFreePool(PartialInfo); 00660 goto cleanup; 00661 } 00662 00663 if (PartialInfo->Type != REG_DWORD || PartialInfo->DataLength != sizeof(ULONG)) 00664 { 00665 DPRINT1("Bad registry read\n"); 00666 ExFreePool(PartialInfo); 00667 goto cleanup; 00668 } 00669 00670 RtlCopyMemory(&LinkedValue, 00671 PartialInfo->Data, 00672 PartialInfo->DataLength); 00673 00674 ExFreePool(PartialInfo); 00675 if (LinkedValue == 0) 00676 { 00677 /* This interface isn't active */ 00678 goto NextReferenceString; 00679 } 00680 } 00681 else 00682 { 00683 DPRINT1("ZwQueryValueKey #1 failed (%x)\n", Status); 00684 goto cleanup; 00685 } 00686 } 00687 00688 /* Read the SymbolicLink string and add it into SymbolicLinkList */ 00689 Status = ZwQueryValueKey( 00690 ReferenceKey, 00691 &SymbolicLink, 00692 KeyValuePartialInformation, 00693 NULL, 00694 0, 00695 &Size); 00696 if (!NT_SUCCESS(Status) && Status != STATUS_BUFFER_TOO_SMALL) 00697 { 00698 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 00699 goto cleanup; 00700 } 00701 bip = ExAllocatePool(PagedPool, Size); 00702 if (!bip) 00703 { 00704 DPRINT("ExAllocatePool() failed\n"); 00705 Status = STATUS_INSUFFICIENT_RESOURCES; 00706 goto cleanup; 00707 } 00708 Status = ZwQueryValueKey( 00709 ReferenceKey, 00710 &SymbolicLink, 00711 KeyValuePartialInformation, 00712 bip, 00713 Size, 00714 &Size); 00715 if (!NT_SUCCESS(Status)) 00716 { 00717 DPRINT("ZwQueryValueKey() failed with status 0x%08lx\n", Status); 00718 goto cleanup; 00719 } 00720 else if (bip->Type != REG_SZ) 00721 { 00722 DPRINT("Unexpected registry type 0x%lx (expected 0x%lx)\n", bip->Type, REG_SZ); 00723 Status = STATUS_UNSUCCESSFUL; 00724 goto cleanup; 00725 } 00726 else if (bip->DataLength < 5 * sizeof(WCHAR)) 00727 { 00728 DPRINT("Registry string too short (length %lu, expected %lu at least)\n", bip->DataLength < 5 * sizeof(WCHAR)); 00729 Status = STATUS_UNSUCCESSFUL; 00730 goto cleanup; 00731 } 00732 KeyName.Length = KeyName.MaximumLength = (USHORT)bip->DataLength - 4 * sizeof(WCHAR); 00733 KeyName.Buffer = &((PWSTR)bip->Data)[4]; 00734 00735 /* Add new symbolic link to symbolic link list */ 00736 if (ReturnBuffer.Length + KeyName.Length + sizeof(WCHAR) > ReturnBuffer.MaximumLength) 00737 { 00738 PWSTR NewBuffer; 00739 ReturnBuffer.MaximumLength = (USHORT)max(ReturnBuffer.MaximumLength * 2, 00740 (USHORT)(ReturnBuffer.Length + 00741 KeyName.Length + 00742 2 * sizeof(WCHAR))); 00743 NewBuffer = ExAllocatePool(PagedPool, ReturnBuffer.MaximumLength); 00744 if (!NewBuffer) 00745 { 00746 DPRINT("ExAllocatePool() failed\n"); 00747 Status = STATUS_INSUFFICIENT_RESOURCES; 00748 goto cleanup; 00749 } 00750 RtlCopyMemory(NewBuffer, ReturnBuffer.Buffer, ReturnBuffer.Length); 00751 if (ReturnBuffer.Buffer) 00752 ExFreePool(ReturnBuffer.Buffer); 00753 ReturnBuffer.Buffer = NewBuffer; 00754 } 00755 DPRINT("Adding symbolic link %wZ\n", &KeyName); 00756 Status = RtlAppendUnicodeStringToString(&ReturnBuffer, &KeyName); 00757 if (!NT_SUCCESS(Status)) 00758 { 00759 DPRINT("RtlAppendUnicodeStringToString() failed with status 0x%08lx\n", Status); 00760 goto cleanup; 00761 } 00762 /* RtlAppendUnicodeStringToString added a NULL at the end of the 00763 * destination string, but didn't increase the Length field. 00764 * Do it for it. 00765 */ 00766 ReturnBuffer.Length += sizeof(WCHAR); 00767 00768 NextReferenceString: 00769 ExFreePool(ReferenceBi); 00770 ReferenceBi = NULL; 00771 if (bip) 00772 ExFreePool(bip); 00773 bip = NULL; 00774 if (ReferenceKey != INVALID_HANDLE_VALUE) 00775 { 00776 ZwClose(ReferenceKey); 00777 ReferenceKey = INVALID_HANDLE_VALUE; 00778 } 00779 if (ControlKey != INVALID_HANDLE_VALUE) 00780 { 00781 ZwClose(ControlKey); 00782 ControlKey = INVALID_HANDLE_VALUE; 00783 } 00784 } 00785 if (FoundRightPDO) 00786 { 00787 /* No need to go further, as we already have found what we searched */ 00788 break; 00789 } 00790 00791 ExFreePool(DeviceBi); 00792 DeviceBi = NULL; 00793 ZwClose(DeviceKey); 00794 DeviceKey = INVALID_HANDLE_VALUE; 00795 } 00796 00797 /* Add final NULL to ReturnBuffer */ 00798 if (ReturnBuffer.Length >= ReturnBuffer.MaximumLength) 00799 { 00800 PWSTR NewBuffer; 00801 ReturnBuffer.MaximumLength += sizeof(WCHAR); 00802 NewBuffer = ExAllocatePool(PagedPool, ReturnBuffer.MaximumLength); 00803 if (!NewBuffer) 00804 { 00805 DPRINT("ExAllocatePool() failed\n"); 00806 Status = STATUS_INSUFFICIENT_RESOURCES; 00807 goto cleanup; 00808 } 00809 if (ReturnBuffer.Buffer) 00810 { 00811 RtlCopyMemory(NewBuffer, ReturnBuffer.Buffer, ReturnBuffer.Length); 00812 ExFreePool(ReturnBuffer.Buffer); 00813 } 00814 ReturnBuffer.Buffer = NewBuffer; 00815 } 00816 ReturnBuffer.Buffer[ReturnBuffer.Length / sizeof(WCHAR)] = UNICODE_NULL; 00817 *SymbolicLinkList = ReturnBuffer.Buffer; 00818 Status = STATUS_SUCCESS; 00819 00820 cleanup: 00821 if (!NT_SUCCESS(Status) && ReturnBuffer.Buffer) 00822 ExFreePool(ReturnBuffer.Buffer); 00823 if (InterfaceKey != INVALID_HANDLE_VALUE) 00824 ZwClose(InterfaceKey); 00825 if (DeviceKey != INVALID_HANDLE_VALUE) 00826 ZwClose(DeviceKey); 00827 if (ReferenceKey != INVALID_HANDLE_VALUE) 00828 ZwClose(ReferenceKey); 00829 if (ControlKey != INVALID_HANDLE_VALUE) 00830 ZwClose(ControlKey); 00831 if (DeviceBi) 00832 ExFreePool(DeviceBi); 00833 if (ReferenceBi) 00834 ExFreePool(ReferenceBi); 00835 if (bip) 00836 ExFreePool(bip); 00837 return Status; 00838 } 00839 00840 /*++ 00841 * @name IoRegisterDeviceInterface 00842 * @implemented 00843 * 00844 * Registers a device interface class, if it has not been previously registered, 00845 * and creates a new instance of the interface class, which a driver can 00846 * subsequently enable for use by applications or other system components. 00847 * Documented in WDK. 00848 * 00849 * @param PhysicalDeviceObject 00850 * Points to an optional PDO that narrows the search to only the 00851 * device interfaces of the device represented by the PDO 00852 * 00853 * @param InterfaceClassGuid 00854 * Points to a class GUID specifying the device interface class 00855 * 00856 * @param ReferenceString 00857 * Optional parameter, pointing to a unicode string. For a full 00858 * description of this rather rarely used param (usually drivers 00859 * pass NULL here) see WDK 00860 * 00861 * @param SymbolicLinkName 00862 * Pointer to the resulting unicode string 00863 * 00864 * @return Usual NTSTATUS 00865 * 00866 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a 00867 * system thread 00868 * 00869 *--*/ 00870 NTSTATUS 00871 NTAPI 00872 IoRegisterDeviceInterface(IN PDEVICE_OBJECT PhysicalDeviceObject, 00873 IN CONST GUID *InterfaceClassGuid, 00874 IN PUNICODE_STRING ReferenceString OPTIONAL, 00875 OUT PUNICODE_STRING SymbolicLinkName) 00876 { 00877 PUNICODE_STRING InstancePath; 00878 UNICODE_STRING GuidString; 00879 UNICODE_STRING SubKeyName; 00880 UNICODE_STRING InterfaceKeyName; 00881 UNICODE_STRING BaseKeyName; 00882 UCHAR PdoNameInfoBuffer[sizeof(OBJECT_NAME_INFORMATION) + (256 * sizeof(WCHAR))]; 00883 POBJECT_NAME_INFORMATION PdoNameInfo = (POBJECT_NAME_INFORMATION)PdoNameInfoBuffer; 00884 UNICODE_STRING DeviceInstance = RTL_CONSTANT_STRING(L"DeviceInstance"); 00885 UNICODE_STRING SymbolicLink = RTL_CONSTANT_STRING(L"SymbolicLink"); 00886 HANDLE ClassKey; 00887 HANDLE InterfaceKey; 00888 HANDLE SubKey; 00889 ULONG StartIndex; 00890 OBJECT_ATTRIBUTES ObjectAttributes; 00891 ULONG i; 00892 NTSTATUS Status, SymLinkStatus; 00893 PEXTENDED_DEVOBJ_EXTENSION DeviceObjectExtension; 00894 00895 ASSERT_IRQL_EQUAL(PASSIVE_LEVEL); 00896 00897 DPRINT("IoRegisterDeviceInterface(): PDO %p, RefString: %wZ\n", 00898 PhysicalDeviceObject, ReferenceString); 00899 00900 /* Parameters must pass three border of checks */ 00901 DeviceObjectExtension = (PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension; 00902 00903 /* 1st level: Presence of a Device Node */ 00904 if (DeviceObjectExtension->DeviceNode == NULL) 00905 { 00906 DPRINT("PhysicalDeviceObject 0x%p doesn't have a DeviceNode\n", PhysicalDeviceObject); 00907 return STATUS_INVALID_DEVICE_REQUEST; 00908 } 00909 00910 /* 2nd level: Presence of an non-zero length InstancePath */ 00911 if (DeviceObjectExtension->DeviceNode->InstancePath.Length == 0) 00912 { 00913 DPRINT("PhysicalDeviceObject 0x%p's DOE has zero-length InstancePath\n", PhysicalDeviceObject); 00914 return STATUS_INVALID_DEVICE_REQUEST; 00915 } 00916 00917 /* 3rd level: Optional, based on WDK documentation */ 00918 if (ReferenceString != NULL) 00919 { 00920 /* Reference string must not contain path-separator symbols */ 00921 for (i = 0; i < ReferenceString->Length / sizeof(WCHAR); i++) 00922 { 00923 if ((ReferenceString->Buffer[i] == '\\') || 00924 (ReferenceString->Buffer[i] == '/')) 00925 return STATUS_INVALID_DEVICE_REQUEST; 00926 } 00927 } 00928 00929 Status = RtlStringFromGUID(InterfaceClassGuid, &GuidString); 00930 if (!NT_SUCCESS(Status)) 00931 { 00932 DPRINT("RtlStringFromGUID() failed with status 0x%08lx\n", Status); 00933 return Status; 00934 } 00935 00936 /* Create Pdo name: \Device\xxxxxxxx (unnamed device) */ 00937 Status = ObQueryNameString( 00938 PhysicalDeviceObject, 00939 PdoNameInfo, 00940 sizeof(PdoNameInfoBuffer), 00941 &i); 00942 if (!NT_SUCCESS(Status)) 00943 { 00944 DPRINT("ObQueryNameString() failed with status 0x%08lx\n", Status); 00945 return Status; 00946 } 00947 ASSERT(PdoNameInfo->Name.Length); 00948 00949 /* Create base key name for this interface: HKLM\SYSTEM\CurrentControlSet\Control\DeviceClasses\{GUID} */ 00950 ASSERT(((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode); 00951 InstancePath = &((PEXTENDED_DEVOBJ_EXTENSION)PhysicalDeviceObject->DeviceObjectExtension)->DeviceNode->InstancePath; 00952 BaseKeyName.Length = (USHORT)wcslen(BaseKeyString) * sizeof(WCHAR); 00953 BaseKeyName.MaximumLength = BaseKeyName.Length 00954 + GuidString.Length; 00955 BaseKeyName.Buffer = ExAllocatePool( 00956 PagedPool, 00957 BaseKeyName.MaximumLength); 00958 if (!BaseKeyName.Buffer) 00959 { 00960 DPRINT("ExAllocatePool() failed\n"); 00961 return STATUS_INSUFFICIENT_RESOURCES; 00962 } 00963 wcscpy(BaseKeyName.Buffer, BaseKeyString); 00964 RtlAppendUnicodeStringToString(&BaseKeyName, &GuidString); 00965 00966 /* Create BaseKeyName key in registry */ 00967 InitializeObjectAttributes( 00968 &ObjectAttributes, 00969 &BaseKeyName, 00970 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF, 00971 NULL, /* RootDirectory */ 00972 NULL); /* SecurityDescriptor */ 00973 00974 Status = ZwCreateKey( 00975 &ClassKey, 00976 KEY_WRITE, 00977 &ObjectAttributes, 00978 0, /* TileIndex */ 00979 NULL, /* Class */ 00980 REG_OPTION_VOLATILE, 00981 NULL); /* Disposition */ 00982 00983 if (!NT_SUCCESS(Status)) 00984 { 00985 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 00986 ExFreePool(BaseKeyName.Buffer); 00987 return Status; 00988 } 00989 00990 /* Create key name for this interface: ##?#ACPI#PNP0501#1#{GUID} */ 00991 InterfaceKeyName.Length = 0; 00992 InterfaceKeyName.MaximumLength = 00993 4 * sizeof(WCHAR) + /* 4 = size of ##?# */ 00994 InstancePath->Length + 00995 sizeof(WCHAR) + /* 1 = size of # */ 00996 GuidString.Length; 00997 InterfaceKeyName.Buffer = ExAllocatePool( 00998 PagedPool, 00999 InterfaceKeyName.MaximumLength); 01000 if (!InterfaceKeyName.Buffer) 01001 { 01002 DPRINT("ExAllocatePool() failed\n"); 01003 return STATUS_INSUFFICIENT_RESOURCES; 01004 } 01005 01006 RtlAppendUnicodeToString(&InterfaceKeyName, L"##?#"); 01007 StartIndex = InterfaceKeyName.Length / sizeof(WCHAR); 01008 RtlAppendUnicodeStringToString(&InterfaceKeyName, InstancePath); 01009 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++) 01010 { 01011 if (InterfaceKeyName.Buffer[StartIndex + i] == '\\') 01012 InterfaceKeyName.Buffer[StartIndex + i] = '#'; 01013 } 01014 RtlAppendUnicodeToString(&InterfaceKeyName, L"#"); 01015 RtlAppendUnicodeStringToString(&InterfaceKeyName, &GuidString); 01016 01017 /* Create the interface key in registry */ 01018 InitializeObjectAttributes( 01019 &ObjectAttributes, 01020 &InterfaceKeyName, 01021 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE | OBJ_OPENIF, 01022 ClassKey, 01023 NULL); /* SecurityDescriptor */ 01024 01025 Status = ZwCreateKey( 01026 &InterfaceKey, 01027 KEY_WRITE, 01028 &ObjectAttributes, 01029 0, /* TileIndex */ 01030 NULL, /* Class */ 01031 REG_OPTION_VOLATILE, 01032 NULL); /* Disposition */ 01033 01034 if (!NT_SUCCESS(Status)) 01035 { 01036 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 01037 ZwClose(ClassKey); 01038 ExFreePool(BaseKeyName.Buffer); 01039 return Status; 01040 } 01041 01042 /* Write DeviceInstance entry. Value is InstancePath */ 01043 Status = ZwSetValueKey( 01044 InterfaceKey, 01045 &DeviceInstance, 01046 0, /* TileIndex */ 01047 REG_SZ, 01048 InstancePath->Buffer, 01049 InstancePath->Length); 01050 if (!NT_SUCCESS(Status)) 01051 { 01052 DPRINT("ZwSetValueKey() failed with status 0x%08lx\n", Status); 01053 ZwClose(InterfaceKey); 01054 ZwClose(ClassKey); 01055 ExFreePool(InterfaceKeyName.Buffer); 01056 ExFreePool(BaseKeyName.Buffer); 01057 return Status; 01058 } 01059 01060 /* Create subkey. Name is #ReferenceString */ 01061 SubKeyName.Length = 0; 01062 SubKeyName.MaximumLength = sizeof(WCHAR); 01063 if (ReferenceString && ReferenceString->Length) 01064 SubKeyName.MaximumLength += ReferenceString->Length; 01065 SubKeyName.Buffer = ExAllocatePool( 01066 PagedPool, 01067 SubKeyName.MaximumLength); 01068 if (!SubKeyName.Buffer) 01069 { 01070 DPRINT("ExAllocatePool() failed\n"); 01071 ZwClose(InterfaceKey); 01072 ZwClose(ClassKey); 01073 ExFreePool(InterfaceKeyName.Buffer); 01074 ExFreePool(BaseKeyName.Buffer); 01075 return STATUS_INSUFFICIENT_RESOURCES; 01076 } 01077 RtlAppendUnicodeToString(&SubKeyName, L"#"); 01078 if (ReferenceString && ReferenceString->Length) 01079 RtlAppendUnicodeStringToString(&SubKeyName, ReferenceString); 01080 01081 /* Create SubKeyName key in registry */ 01082 InitializeObjectAttributes( 01083 &ObjectAttributes, 01084 &SubKeyName, 01085 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 01086 InterfaceKey, /* RootDirectory */ 01087 NULL); /* SecurityDescriptor */ 01088 01089 Status = ZwCreateKey( 01090 &SubKey, 01091 KEY_WRITE, 01092 &ObjectAttributes, 01093 0, /* TileIndex */ 01094 NULL, /* Class */ 01095 REG_OPTION_VOLATILE, 01096 NULL); /* Disposition */ 01097 01098 if (!NT_SUCCESS(Status)) 01099 { 01100 DPRINT("ZwCreateKey() failed with status 0x%08lx\n", Status); 01101 ZwClose(InterfaceKey); 01102 ZwClose(ClassKey); 01103 ExFreePool(InterfaceKeyName.Buffer); 01104 ExFreePool(BaseKeyName.Buffer); 01105 return Status; 01106 } 01107 01108 /* Create symbolic link name: \??\ACPI#PNP0501#1#{GUID}\ReferenceString */ 01109 SymbolicLinkName->Length = 0; 01110 SymbolicLinkName->MaximumLength = SymbolicLinkName->Length 01111 + 4 * sizeof(WCHAR) /* 4 = size of \??\ */ 01112 + InstancePath->Length 01113 + sizeof(WCHAR) /* 1 = size of # */ 01114 + GuidString.Length 01115 + sizeof(WCHAR); /* final NULL */ 01116 if (ReferenceString && ReferenceString->Length) 01117 SymbolicLinkName->MaximumLength += sizeof(WCHAR) + ReferenceString->Length; 01118 SymbolicLinkName->Buffer = ExAllocatePool( 01119 PagedPool, 01120 SymbolicLinkName->MaximumLength); 01121 if (!SymbolicLinkName->Buffer) 01122 { 01123 DPRINT("ExAllocatePool() failed\n"); 01124 ZwClose(SubKey); 01125 ZwClose(InterfaceKey); 01126 ZwClose(ClassKey); 01127 ExFreePool(InterfaceKeyName.Buffer); 01128 ExFreePool(SubKeyName.Buffer); 01129 ExFreePool(BaseKeyName.Buffer); 01130 return STATUS_INSUFFICIENT_RESOURCES; 01131 } 01132 RtlAppendUnicodeToString(SymbolicLinkName, L"\\??\\"); 01133 StartIndex = SymbolicLinkName->Length / sizeof(WCHAR); 01134 RtlAppendUnicodeStringToString(SymbolicLinkName, InstancePath); 01135 for (i = 0; i < InstancePath->Length / sizeof(WCHAR); i++) 01136 { 01137 if (SymbolicLinkName->Buffer[StartIndex + i] == '\\') 01138 SymbolicLinkName->Buffer[StartIndex + i] = '#'; 01139 } 01140 RtlAppendUnicodeToString(SymbolicLinkName, L"#"); 01141 RtlAppendUnicodeStringToString(SymbolicLinkName, &GuidString); 01142 SymbolicLinkName->Buffer[SymbolicLinkName->Length/sizeof(WCHAR)] = L'\0'; 01143 01144 /* Create symbolic link */ 01145 DPRINT("IoRegisterDeviceInterface(): creating symbolic link %wZ -> %wZ\n", SymbolicLinkName, &PdoNameInfo->Name); 01146 SymLinkStatus = IoCreateSymbolicLink(SymbolicLinkName, &PdoNameInfo->Name); 01147 01148 /* If the symbolic link already exists, return an informational success status */ 01149 if (SymLinkStatus == STATUS_OBJECT_NAME_COLLISION) 01150 { 01151 /* HACK: Delete the existing symbolic link and update it to the new PDO name */ 01152 IoDeleteSymbolicLink(SymbolicLinkName); 01153 IoCreateSymbolicLink(SymbolicLinkName, &PdoNameInfo->Name); 01154 SymLinkStatus = STATUS_OBJECT_NAME_EXISTS; 01155 } 01156 01157 if (!NT_SUCCESS(SymLinkStatus)) 01158 { 01159 DPRINT1("IoCreateSymbolicLink() failed with status 0x%08lx\n", SymLinkStatus); 01160 ZwClose(SubKey); 01161 ZwClose(InterfaceKey); 01162 ZwClose(ClassKey); 01163 ExFreePool(SubKeyName.Buffer); 01164 ExFreePool(InterfaceKeyName.Buffer); 01165 ExFreePool(BaseKeyName.Buffer); 01166 ExFreePool(SymbolicLinkName->Buffer); 01167 return SymLinkStatus; 01168 } 01169 01170 if (ReferenceString && ReferenceString->Length) 01171 { 01172 RtlAppendUnicodeToString(SymbolicLinkName, L"\\"); 01173 RtlAppendUnicodeStringToString(SymbolicLinkName, ReferenceString); 01174 } 01175 SymbolicLinkName->Buffer[SymbolicLinkName->Length/sizeof(WCHAR)] = L'\0'; 01176 01177 /* Write symbolic link name in registry */ 01178 SymbolicLinkName->Buffer[1] = '\\'; 01179 Status = ZwSetValueKey( 01180 SubKey, 01181 &SymbolicLink, 01182 0, /* TileIndex */ 01183 REG_SZ, 01184 SymbolicLinkName->Buffer, 01185 SymbolicLinkName->Length); 01186 if (!NT_SUCCESS(Status)) 01187 { 01188 DPRINT1("ZwSetValueKey() failed with status 0x%08lx\n", Status); 01189 ExFreePool(SymbolicLinkName->Buffer); 01190 } 01191 else 01192 { 01193 SymbolicLinkName->Buffer[1] = '?'; 01194 } 01195 01196 ZwClose(SubKey); 01197 ZwClose(InterfaceKey); 01198 ZwClose(ClassKey); 01199 ExFreePool(SubKeyName.Buffer); 01200 ExFreePool(InterfaceKeyName.Buffer); 01201 ExFreePool(BaseKeyName.Buffer); 01202 01203 return NT_SUCCESS(Status) ? SymLinkStatus : Status; 01204 } 01205 01206 /*++ 01207 * @name IoSetDeviceInterfaceState 01208 * @implemented 01209 * 01210 * Enables or disables an instance of a previously registered device 01211 * interface class. 01212 * Documented in WDK. 01213 * 01214 * @param SymbolicLinkName 01215 * Pointer to the string identifying instance to enable or disable 01216 * 01217 * @param Enable 01218 * TRUE = enable, FALSE = disable 01219 * 01220 * @return Usual NTSTATUS 01221 * 01222 * @remarks Must be called at IRQL = PASSIVE_LEVEL in the context of a 01223 * system thread 01224 * 01225 *--*/ 01226 NTSTATUS 01227 NTAPI 01228 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName, 01229 IN BOOLEAN Enable) 01230 { 01231 PDEVICE_OBJECT PhysicalDeviceObject; 01232 PFILE_OBJECT FileObject; 01233 UNICODE_STRING GuidString; 01234 UNICODE_STRING SymLink; 01235 PWCHAR StartPosition; 01236 PWCHAR EndPosition; 01237 NTSTATUS Status; 01238 LPCGUID EventGuid; 01239 HANDLE InstanceHandle, ControlHandle; 01240 UNICODE_STRING KeyName; 01241 OBJECT_ATTRIBUTES ObjectAttributes; 01242 ULONG LinkedValue; 01243 GUID DeviceGuid; 01244 01245 if (SymbolicLinkName == NULL) 01246 return STATUS_INVALID_PARAMETER_1; 01247 01248 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable); 01249 01250 /* Symbolic link name is \??\ACPI#PNP0501#1#{GUID}\ReferenceString */ 01251 /* Get GUID from SymbolicLinkName */ 01252 StartPosition = wcschr(SymbolicLinkName->Buffer, L'{'); 01253 EndPosition = wcschr(SymbolicLinkName->Buffer, L'}'); 01254 if (!StartPosition ||!EndPosition || StartPosition > EndPosition) 01255 { 01256 DPRINT1("IoSetDeviceInterfaceState() returning STATUS_INVALID_PARAMETER_1\n"); 01257 return STATUS_INVALID_PARAMETER_1; 01258 } 01259 GuidString.Buffer = StartPosition; 01260 GuidString.MaximumLength = GuidString.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)StartPosition); 01261 01262 SymLink.Buffer = SymbolicLinkName->Buffer; 01263 SymLink.MaximumLength = SymLink.Length = (USHORT)((ULONG_PTR)(EndPosition + 1) - (ULONG_PTR)SymLink.Buffer); 01264 DPRINT("IoSetDeviceInterfaceState('%wZ', %d)\n", SymbolicLinkName, Enable); 01265 01266 Status = OpenRegistryHandlesFromSymbolicLink(SymbolicLinkName, 01267 KEY_CREATE_SUB_KEY, 01268 NULL, 01269 NULL, 01270 &InstanceHandle); 01271 if (!NT_SUCCESS(Status)) 01272 return Status; 01273 01274 RtlInitUnicodeString(&KeyName, L"Control"); 01275 InitializeObjectAttributes(&ObjectAttributes, 01276 &KeyName, 01277 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, 01278 InstanceHandle, 01279 NULL); 01280 Status = ZwCreateKey(&ControlHandle, 01281 KEY_SET_VALUE, 01282 &ObjectAttributes, 01283 0, 01284 NULL, 01285 REG_OPTION_VOLATILE, 01286 NULL); 01287 ZwClose(InstanceHandle); 01288 if (!NT_SUCCESS(Status)) 01289 { 01290 DPRINT1("Failed to create the Control subkey\n"); 01291 return Status; 01292 } 01293 01294 LinkedValue = (Enable ? 1 : 0); 01295 01296 RtlInitUnicodeString(&KeyName, L"Linked"); 01297 Status = ZwSetValueKey(ControlHandle, 01298 &KeyName, 01299 0, 01300 REG_DWORD, 01301 &LinkedValue, 01302 sizeof(ULONG)); 01303 ZwClose(ControlHandle); 01304 if (!NT_SUCCESS(Status)) 01305 { 01306 DPRINT1("Failed to write the Linked value\n"); 01307 return Status; 01308 } 01309 01310 /* Get pointer to the PDO */ 01311 Status = IoGetDeviceObjectPointer( 01312 &SymLink, 01313 0, /* DesiredAccess */ 01314 &FileObject, 01315 &PhysicalDeviceObject); 01316 if (!NT_SUCCESS(Status)) 01317 { 01318 DPRINT1("IoGetDeviceObjectPointer() failed with status 0x%08lx\n", Status); 01319 return Status; 01320 } 01321 01322 Status = RtlGUIDFromString(&GuidString, &DeviceGuid); 01323 if (!NT_SUCCESS(Status)) 01324 { 01325 DPRINT1("RtlGUIDFromString() failed with status 0x%08lx\n", Status); 01326 return Status; 01327 } 01328 01329 EventGuid = Enable ? &GUID_DEVICE_INTERFACE_ARRIVAL : &GUID_DEVICE_INTERFACE_REMOVAL; 01330 IopNotifyPlugPlayNotification( 01331 PhysicalDeviceObject, 01332 EventCategoryDeviceInterfaceChange, 01333 EventGuid, 01334 &DeviceGuid, 01335 (PVOID)SymbolicLinkName); 01336 01337 ObDereferenceObject(FileObject); 01338 DPRINT("Status %x\n", Status); 01339 return STATUS_SUCCESS; 01340 } 01341 01342 /* EOF */ Generated on Sun May 27 2012 04:28:39 for ReactOS by
1.7.6.1
|