ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

deviface.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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.