[NTOS]: Rewrite boot driver loading code (not the driver code itself) to use the...
authorSir Richard <sir_richard@svn.reactos.org>
Fri, 2 Apr 2010 17:57:33 +0000 (17:57 +0000)
committerSir Richard <sir_richard@svn.reactos.org>
Fri, 2 Apr 2010 17:57:33 +0000 (17:57 +0000)
[NTOS]: Use group prioritiy, tag numbers, and tag priority to determine the correct loading order for boot drivers, instead of just parsing the linked list. Dependencies work now!
[NTOS]: Load any DLLs that are driver-dependent with MmCallDllInitialize. Previously, these .DLLS were ignored and drivers could lose dependencies.

svn path=/trunk/; revision=46690

reactos/ntoskrnl/include/internal/io.h
reactos/ntoskrnl/io/iomgr/driver.c
reactos/ntoskrnl/io/iomgr/iomgr.c
reactos/ntoskrnl/io/pnpmgr/pnpinit.c [new file with mode: 0644]
reactos/ntoskrnl/io/pnpmgr/pnputil.c [new file with mode: 0644]
reactos/ntoskrnl/ntoskrnl-generic.rbuild

index 2519a81..dc80ff2 100644 (file)
@@ -395,6 +395,33 @@ typedef struct _LOAD_UNLOAD_PARAMS
     PDRIVER_OBJECT DriverObject;
 } LOAD_UNLOAD_PARAMS, *PLOAD_UNLOAD_PARAMS;
 
+//
+// Boot Driver List Entry
+//
+typedef struct _DRIVER_INFORMATION
+{
+    LIST_ENTRY Link;
+    PDRIVER_OBJECT DriverObject;
+    PBOOT_DRIVER_LIST_ENTRY DataTableEntry;
+    HANDLE ServiceHandle;
+    USHORT TagPosition;
+    ULONG Failed;
+    ULONG Processed;
+    NTSTATUS Status;
+} DRIVER_INFORMATION, *PDRIVER_INFORMATION;
+
+//
+// Boot Driver Node
+//
+typedef struct _BOOT_DRIVER_NODE
+{
+    BOOT_DRIVER_LIST_ENTRY ListEntry;
+    UNICODE_STRING Group;
+    UNICODE_STRING Name;
+    ULONG Tag;
+    ULONG ErrorControl;
+} BOOT_DRIVER_NODE, *PBOOT_DRIVER_NODE;
 //
 // List of Bus Type GUIDs
 //
@@ -605,6 +632,43 @@ IopGetRegistryValue(IN HANDLE Handle,
                     OUT PKEY_VALUE_FULL_INFORMATION *Information);
 
 
+//
+// PnP Routines
+//
+NTSTATUS
+NTAPI
+PiInitCacheGroupInformation(
+    VOID
+);
+
+USHORT
+NTAPI
+PpInitGetGroupOrderIndex(
+    IN HANDLE ServiceHandle
+);
+
+USHORT
+NTAPI
+PipGetDriverTagPriority(
+    IN HANDLE ServiceHandle
+);
+
+NTSTATUS
+NTAPI
+PnpRegMultiSzToUnicodeStrings(
+    IN PKEY_VALUE_FULL_INFORMATION KeyValueInformation,
+    OUT PUNICODE_STRING *UnicodeStringList,
+    OUT PULONG UnicodeStringCount
+);
+
+BOOLEAN
+NTAPI
+PnpRegSzToString(
+    IN PWCHAR RegSzData,
+    IN ULONG RegSzLength,
+    OUT PUSHORT StringLength OPTIONAL
+);
+                                               
 //
 // Initialization Routines
 //
index ef1b789..f00a87d 100644 (file)
@@ -34,6 +34,9 @@ POBJECT_TYPE IoDriverObjectType = NULL;
 extern BOOLEAN ExpInTextModeSetup;
 extern BOOLEAN PnpSystemInit;
 
+USHORT IopGroupIndex;
+PLIST_ENTRY IopGroupTable;
+
 /* PRIVATE FUNCTIONS **********************************************************/
 
 NTSTATUS NTAPI
@@ -880,14 +883,17 @@ VOID
 FASTCALL
 IopInitializeBootDrivers(VOID)
 {
-    PLIST_ENTRY ListHead, NextEntry;
+    PLIST_ENTRY ListHead, NextEntry, NextEntry2;
     PLDR_DATA_TABLE_ENTRY LdrEntry;
     PDEVICE_NODE DeviceNode;
     PDRIVER_OBJECT DriverObject;
     LDR_DATA_TABLE_ENTRY ModuleObject;
     NTSTATUS Status;
     UNICODE_STRING DriverName;
-
+    ULONG i, Index;
+    PDRIVER_INFORMATION DriverInfo, DriverInfoTag;
+    HANDLE KeyHandle;
+    PBOOT_DRIVER_LIST_ENTRY BootEntry;
     DPRINT("IopInitializeBootDrivers()\n");
 
     /* Use IopRootDeviceNode for now */
@@ -931,6 +937,19 @@ IopInitializeBootDrivers(VOID)
         return;
     }
 
+    /* Get highest group order index */
+    IopGroupIndex = PpInitGetGroupOrderIndex(NULL);
+    if (IopGroupIndex == 0xFFFF) ASSERT(FALSE);
+    
+    /* Allocate the group table */
+    IopGroupTable = ExAllocatePoolWithTag(PagedPool,
+                                          IopGroupIndex * sizeof(LIST_ENTRY),
+                                          TAG_IO);
+    if (IopGroupTable == NULL) ASSERT(FALSE);
+    
+    /* Initialize the group table lists */
+    for (i = 0; i < IopGroupIndex; i++) InitializeListHead(&IopGroupTable[i]);
+    
     /* Loop the boot modules */
     ListHead = &KeLoaderBlock->LoadOrderListHead;
     NextEntry = ListHead->Flink;
@@ -940,19 +959,83 @@ IopInitializeBootDrivers(VOID)
         LdrEntry = CONTAINING_RECORD(NextEntry,
                                      LDR_DATA_TABLE_ENTRY,
                                      InLoadOrderLinks);
-
-        /*
-         * HACK: Make sure we're loading a driver
-         * (we should be using BootDriverListHead!)
-         */
-        if (wcsstr(_wcsupr(LdrEntry->BaseDllName.Buffer), L".SYS"))
+                                     
+        /* Check if the DLL needs to be initialized */
+        if (LdrEntry->Flags & LDRP_DRIVER_DEPENDENT_DLL)
+        {
+            /* Call its entrypoint */
+            MmCallDllInitialize(LdrEntry, NULL);
+        }
+        
+        /* Go to the next driver */
+        NextEntry = NextEntry->Flink;
+    }
+    
+    /* Loop the boot drivers */
+    ListHead = &KeLoaderBlock->BootDriverListHead;
+    NextEntry = ListHead->Flink;
+    while (ListHead != NextEntry)
+    {
+        /* Get the entry */
+        BootEntry = CONTAINING_RECORD(NextEntry,
+                                      BOOT_DRIVER_LIST_ENTRY,
+                                      Link);
+        
+        /* Get the driver loader entry */
+        LdrEntry = BootEntry->LdrEntry;
+        
+        /* Allocate our internal accounting structure */
+        DriverInfo = ExAllocatePoolWithTag(PagedPool,
+                                           sizeof(DRIVER_INFORMATION),
+                                           TAG_IO);
+        if (DriverInfo)
         {
-            /* Make sure we didn't load this driver already */
-            if (!(LdrEntry->Flags & LDRP_ENTRY_INSERTED))
+            /* Zero it and initialize it */
+            RtlZeroMemory(DriverInfo, sizeof(DRIVER_INFORMATION));
+            InitializeListHead(&DriverInfo->Link);
+            DriverInfo->DataTableEntry = BootEntry;
+            
+            /* Open the registry key */
+            Status = IopOpenRegistryKeyEx(&KeyHandle,
+                                          NULL,
+                                          &BootEntry->RegistryPath,
+                                          KEY_READ);
+            if ((NT_SUCCESS(Status)) || /* ReactOS HACK for SETUPLDR */
+                ((KeLoaderBlock->SetupLdrBlock) && (KeyHandle = (PVOID)1)))
             {
-                DPRINT("Initializing bootdriver %wZ\n", &LdrEntry->BaseDllName);
-                /* Initialize it */
-                IopInitializeBuiltinDriver(LdrEntry);
+                /* Save the handle */
+                DriverInfo->ServiceHandle = KeyHandle;
+                
+                /* Get the group oder index */
+                Index = PpInitGetGroupOrderIndex(KeyHandle);
+                
+                /* Get the tag position */
+                DriverInfo->TagPosition = PipGetDriverTagPriority(KeyHandle);
+                
+                /* Insert it into the list, at the right place */
+                ASSERT(Index < IopGroupIndex);
+                NextEntry2 = IopGroupTable[Index].Flink;
+                while (NextEntry2 != &IopGroupTable[Index])
+                {
+                    /* Get the driver info */
+                    DriverInfoTag = CONTAINING_RECORD(NextEntry2,
+                                                      DRIVER_INFORMATION,
+                                                      Link);
+                    
+                    /* Check if we found the right tag position */
+                    if (DriverInfoTag->TagPosition > DriverInfo->TagPosition)
+                    {
+                        /* We're done */
+                        break;
+                    }
+                    
+                    /* Next entry */
+                    NextEntry2 = NextEntry2->Flink;
+                }
+                
+                /* Insert us right before the next entry */
+                NextEntry2 = NextEntry2->Blink;
+                InsertHeadList(NextEntry2, &DriverInfo->Link);
             }
         }
 
@@ -960,6 +1043,29 @@ IopInitializeBootDrivers(VOID)
         NextEntry = NextEntry->Flink;
     }
 
+    /* Loop each group index */
+    for (i = 0; i < IopGroupIndex; i++)
+    {
+        /* Loop each group table */
+        NextEntry = IopGroupTable[i].Flink;
+        while (NextEntry != &IopGroupTable[i])
+        {
+            /* Get the entry */
+            DriverInfo = CONTAINING_RECORD(NextEntry,
+                                           DRIVER_INFORMATION,
+                                           Link);
+            
+            /* Get the driver loader entry */
+            LdrEntry = DriverInfo->DataTableEntry->LdrEntry;
+            
+            /* Initialize it */
+            IopInitializeBuiltinDriver(LdrEntry);
+            
+            /* Next entry */
+            NextEntry = NextEntry->Flink;
+        }
+    }
+    
     /* In old ROS, the loader list became empty after this point. Simulate. */
     InitializeListHead(&KeLoaderBlock->LoadOrderListHead);
 }
index cb32297..c799966 100644 (file)
@@ -489,6 +489,9 @@ IoInitSystem(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
 
     /* Initialize PnP manager */
     PnpInit();
+    
+    /* Setup the group cache */
+    if (!NT_SUCCESS(PiInitCacheGroupInformation())) return FALSE;
 
     /* Create the group driver list */
     IoCreateDriverList();
diff --git a/reactos/ntoskrnl/io/pnpmgr/pnpinit.c b/reactos/ntoskrnl/io/pnpmgr/pnpinit.c
new file mode 100644 (file)
index 0000000..8c56072
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
+ * FILE:            ntoskrnl/io/pnpmgr/pnpinit.c
+ * PURPOSE:         PnP Initialization Code
+ * PROGRAMMERS:     ReactOS Portable Systems Group
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+PUNICODE_STRING PiInitGroupOrderTable;
+ULONG PiInitGroupOrderTableCount;
+/* FUNCTIONS ******************************************************************/
+
+NTSTATUS
+NTAPI
+PiInitCacheGroupInformation(VOID)
+{
+    HANDLE KeyHandle;
+    NTSTATUS Status;
+    PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
+    PUNICODE_STRING GroupTable;
+    ULONG Count;
+    UNICODE_STRING GroupString =
+        RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
+                            L"\\Control\\ServiceGroupOrder");
+    
+    /* ReactOS HACK for SETUPLDR */
+    if (KeLoaderBlock->SetupLdrBlock)
+    {
+        /* Bogus data */
+        PiInitGroupOrderTableCount = 0;
+        PiInitGroupOrderTable = (PVOID)0xBABEB00B;
+        return STATUS_SUCCESS;
+    }
+    
+    /* Open the registry key */
+    Status = IopOpenRegistryKeyEx(&KeyHandle,
+                                  NULL,
+                                  &GroupString,
+                                  KEY_READ);
+    if (NT_SUCCESS(Status))
+    {
+        /* Get the list */
+        Status = IopGetRegistryValue(KeyHandle, L"List", &KeyValueInformation);
+        ZwClose(KeyHandle);
+        
+        /* Make sure we got it */
+        if (NT_SUCCESS(Status))
+        {
+            /* Make sure it's valid */
+            if ((KeyValueInformation->Type == REG_MULTI_SZ) &&
+                (KeyValueInformation->DataLength))
+            {
+                /* Convert it to unicode strings */
+                Status = PnpRegMultiSzToUnicodeStrings(KeyValueInformation,
+                                                       &GroupTable,
+                                                       &Count);
+                
+                /* Cache it for later */
+                PiInitGroupOrderTable = GroupTable;
+                PiInitGroupOrderTableCount = Count;
+            }
+            else
+            {
+                /* Fail */
+                Status = STATUS_UNSUCCESSFUL;
+            }
+            
+            /* Free the information */
+            ExFreePool(KeyValueInformation);
+        }
+    }
+    
+    /* Return status */
+    return Status;
+}
+
+USHORT
+NTAPI
+PpInitGetGroupOrderIndex(IN HANDLE ServiceHandle)
+{
+    NTSTATUS Status;
+    PKEY_VALUE_FULL_INFORMATION KeyValueInformation;
+    ULONG i;
+    PVOID Buffer;
+    UNICODE_STRING Group;
+    PAGED_CODE();
+       
+    /* Make sure we have a cache */
+    if (!PiInitGroupOrderTable) return -1;
+    
+    /* If we don't have a handle, the rest is easy -- return the count */
+    if (!ServiceHandle) return PiInitGroupOrderTableCount + 1;
+    
+    /* Otherwise, get the group value */
+    Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
+    if (!NT_SUCCESS(Status)) return PiInitGroupOrderTableCount;
+
+    /* Make sure we have a valid string */
+    ASSERT(KeyValueInformation->Type == REG_SZ);
+    ASSERT(KeyValueInformation->DataLength);
+    
+    /* Convert to unicode string */
+    Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
+    PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
+    Group.MaximumLength = KeyValueInformation->DataLength;
+    Group.Buffer = Buffer;
+    
+    /* Loop the groups */
+    for (i = 0; i < PiInitGroupOrderTableCount; i++)
+    {
+        /* Try to find a match */
+        if (RtlEqualUnicodeString(&Group, &PiInitGroupOrderTable[i], TRUE)) break;
+    }
+    
+    /* We're done */
+    ExFreePool(KeyValueInformation);
+    return i;
+}
+
+USHORT
+NTAPI
+PipGetDriverTagPriority(IN HANDLE ServiceHandle)
+{
+    NTSTATUS Status;
+    HANDLE KeyHandle = NULL;
+    PKEY_VALUE_FULL_INFORMATION KeyValueInformation = NULL;
+    PKEY_VALUE_FULL_INFORMATION KeyValueInformationTag;
+    PKEY_VALUE_FULL_INFORMATION KeyValueInformationGroupOrderList;
+    PVOID Buffer;
+    UNICODE_STRING Group;
+    PULONG GroupOrder;
+    ULONG i = -1, Count, Tag = 0;
+    UNICODE_STRING GroupString =
+    RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet"
+                        L"\\Control\\ServiceGroupOrder");
+    
+    /* Open the key */
+    Status = IopOpenRegistryKeyEx(&KeyHandle, NULL, &GroupString, KEY_READ);
+    if (!NT_SUCCESS(Status)) goto Quickie;
+    
+    /* Read the group */
+    Status = IopGetRegistryValue(ServiceHandle, L"Group", &KeyValueInformation);
+    if (!NT_SUCCESS(Status)) goto Quickie;
+    
+    /* Make sure we have a group */
+    if ((KeyValueInformation->Type == REG_SZ) &&
+        (KeyValueInformation->DataLength))
+    {
+        /* Convert to unicode string */
+        Buffer = (PVOID)((ULONG_PTR)KeyValueInformation + KeyValueInformation->DataOffset);
+        PnpRegSzToString(Buffer, KeyValueInformation->DataLength, &Group.Length);
+        Group.MaximumLength = KeyValueInformation->DataLength;
+        Group.Buffer = Buffer;
+    }
+
+    /* Now read the tag */
+    Status = IopGetRegistryValue(ServiceHandle, L"Tag", &KeyValueInformationTag);
+    if (!NT_SUCCESS(Status)) goto Quickie;
+
+    /* Make sure we have a tag */
+    if ((KeyValueInformationTag->Type == REG_DWORD) &&
+        (KeyValueInformationTag->DataLength))
+    {
+        /* Read it */
+        Tag = *(PULONG)((ULONG_PTR)KeyValueInformationTag +
+                        KeyValueInformationTag->DataOffset);
+    }
+    
+    /* We can get rid of this now */
+    ExFreePool(KeyValueInformationTag);
+
+    /* Now let's read the group's tag order */
+    Status = IopGetRegistryValue(KeyHandle,
+                                 Group.Buffer,
+                                 &KeyValueInformationGroupOrderList);
+    
+    /* We can get rid of this now */
+Quickie:
+    if (KeyValueInformation) ExFreePool(KeyValueInformation);
+    if (KeyHandle) NtClose(KeyHandle);
+    if (!NT_SUCCESS(Status)) return -1;
+    
+    /* We're on the success path -- validate the tag order*/
+    if ((KeyValueInformationGroupOrderList->Type == REG_BINARY) &&
+        (KeyValueInformationGroupOrderList->DataLength))
+    {
+        /* Get the order array */
+        GroupOrder = (PULONG)((ULONG_PTR)KeyValueInformationGroupOrderList +
+                              KeyValueInformationGroupOrderList->DataOffset);
+        
+        /* Get the count */
+        Count = *GroupOrder;
+        ASSERT(((Count + 1) * sizeof(ULONG)) <=
+               KeyValueInformationGroupOrderList->DataLength);
+        
+        /* Now loop each tag */
+        GroupOrder++;
+        for (i = 1; i <= Count; i++)
+        {
+            /* If we found it, we're out */
+            if (Tag == *GroupOrder) break;
+
+            /* Try the next one */
+            GroupOrder++;
+        }
+    }
+    
+    /* Last buffer to free */
+    ExFreePool(KeyValueInformationGroupOrderList);
+    return i;
+}
+
+/* EOF */
diff --git a/reactos/ntoskrnl/io/pnpmgr/pnputil.c b/reactos/ntoskrnl/io/pnpmgr/pnputil.c
new file mode 100644 (file)
index 0000000..f274f3d
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * PROJECT:         ReactOS Kernel
+ * LICENSE:         BSD - See COPYING.ARM in the top level directory
+ * FILE:            ntoskrnl/io/pnpmgr/pnputil.c
+ * PURPOSE:         PnP Utility Code
+ * PROGRAMMERS:     ReactOS Portable Systems Group
+ */
+
+/* INCLUDES *******************************************************************/
+
+#include <ntoskrnl.h>
+#define NDEBUG
+#include <debug.h>
+
+/* GLOBALS ********************************************************************/
+
+/* FUNCTIONS ******************************************************************/
+
+VOID
+NTAPI
+PnpFreeUnicodeStringList(IN PUNICODE_STRING UnicodeStringList,
+                         IN ULONG StringCount)
+{
+    ULONG i;
+    
+    /* Go through the list */
+    if (UnicodeStringList)
+    {
+        /* Go through each string */
+        for (i = 0; i < StringCount; i++)
+        {
+            /* Check if it exists */
+            if (UnicodeStringList[i].Buffer)
+            {
+                /* Free it */
+                ExFreePool(UnicodeStringList[i].Buffer);
+            }
+        }
+        
+        /* Free the whole list */
+        ExFreePool(UnicodeStringList);
+    }
+}
+
+NTSTATUS
+NTAPI
+PnpRegMultiSzToUnicodeStrings(IN PKEY_VALUE_FULL_INFORMATION KeyValueInformation,
+                              OUT PUNICODE_STRING *UnicodeStringList,
+                              OUT PULONG UnicodeStringCount)
+{
+    PWCHAR p, pp, ps;
+    ULONG i = 0, n;
+    ULONG Count = 0;
+    
+    /* Validate the key information */
+    if (KeyValueInformation->Type != REG_MULTI_SZ) return STATUS_INVALID_PARAMETER;
+    
+    /* Set the pointers */
+    p = (PWCHAR)((ULONG_PTR)KeyValueInformation +
+                 KeyValueInformation->DataOffset);
+    pp = (PWCHAR)((ULONG_PTR)p + KeyValueInformation->DataLength);
+    
+    /* Loop the data */
+    while (p != pp)
+    {
+        /* If we find a NULL, that means one string is done */
+        if (!*p)
+        {
+            /* Add to our string count */
+            Count++;
+            
+            /* Check for a double-NULL, which means we're done */
+            if (((p + 1) == pp) || !(*(p + 1))) break;
+        }
+    
+        /* Go to the next character */
+        p++;
+    }
+
+    /* If we looped the whole list over, we missed increment a string, do it */
+    if (p == pp) Count++;
+    
+    /* Allocate the list now that we know how big it is */
+    *UnicodeStringList = ExAllocatePoolWithTag(PagedPool,
+                                               sizeof(UNICODE_STRING) * Count,
+                                               'sUpP');
+    if (!(*UnicodeStringList)) return STATUS_INSUFFICIENT_RESOURCES;
+    
+    /* Set pointers for second loop */
+    ps = p = (PWCHAR)((ULONG_PTR)KeyValueInformation +
+                     KeyValueInformation->DataOffset);
+    
+    /* Loop again, to do the copy this time */
+    while (p != pp)
+    {
+        /* If we find a NULL, that means one string is done */
+        if (!*p)
+        {
+            /* Check how long this string is */
+            n = (ULONG_PTR)p - (ULONG_PTR)ps + sizeof(UNICODE_NULL);
+            
+            /* Allocate the buffer */
+            (*UnicodeStringList)[i].Buffer = ExAllocatePoolWithTag(PagedPool,
+                                                                   n,
+                                                                   'sUpP');
+            if (!(*UnicodeStringList)[i].Buffer)
+            {
+                /* Back out of everything */
+                PnpFreeUnicodeStringList(*UnicodeStringList, i);
+                return STATUS_INSUFFICIENT_RESOURCES;
+            }
+            
+            /* Copy the string into the buffer */
+            RtlCopyMemory((*UnicodeStringList)[i].Buffer, ps, n);
+            
+            /* Set the lengths */
+            (*UnicodeStringList)[i].MaximumLength = n;
+            (*UnicodeStringList)[i].Length = n - sizeof(UNICODE_NULL);
+            
+            /* One more entry done */
+            i++;
+            
+            /* Check for a double-NULL, which means we're done */
+            if (((p + 1) == pp) || !(*(p + 1))) break;
+
+            /* New string */
+            ps = p + 1;
+        }
+        
+        /* New string */
+        p++;
+    }
+    
+    /* Check if we've reached the last string */
+    if (p == pp)
+    {
+        /* Calculate the string length */
+        n = (ULONG_PTR)p - (ULONG_PTR)ps;
+        
+        /* Allocate the buffer for it */
+        (*UnicodeStringList)[i].Buffer = ExAllocatePoolWithTag(PagedPool,
+                                                               n +
+                                                               sizeof(UNICODE_NULL),
+                                                               'sUpP');
+        if (!(*UnicodeStringList)[i].Buffer)
+        {
+            /* Back out of everything */
+            PnpFreeUnicodeStringList(*UnicodeStringList, i);
+            return STATUS_INSUFFICIENT_RESOURCES;
+        }
+        
+        /* Make sure there's an actual string here */
+        if (n) RtlCopyMemory((*UnicodeStringList)[i].Buffer, ps, n);
+
+        /* Null-terminate the string ourselves */
+        (*UnicodeStringList)[i].Buffer[n / sizeof(WCHAR)] = UNICODE_NULL;
+        
+        /* Set the lenghts */
+        (*UnicodeStringList)[i].Length = n;
+        (*UnicodeStringList)[i].MaximumLength = n + sizeof(UNICODE_NULL);
+    }
+    
+    /* And we're done */
+    *UnicodeStringCount = Count;
+    return STATUS_SUCCESS;
+}
+
+BOOLEAN
+NTAPI
+PnpRegSzToString(IN PWCHAR RegSzData,
+                 IN ULONG RegSzLength,
+                 OUT PUSHORT StringLength OPTIONAL)
+{
+    PWCHAR p, pp;
+    
+    /* Find the end */
+    pp = RegSzData + RegSzLength;
+    for (p = RegSzData; p < pp; p++) if (!*p) break;
+    
+    /* Return it */
+    if (StringLength) *StringLength = p - RegSzData;
+    return TRUE;
+}
+
+/* EOF */
index a605ee1..b6ed182 100644 (file)
                <directory name="pnpmgr">
                        <file>plugplay.c</file>
                        <file>pnpdma.c</file>
+                       <file>pnpinit.c</file>
                        <file>pnpmgr.c</file>
                        <file>pnpnotify.c</file>
                        <file>pnpreport.c</file>
                        <file>pnproot.c</file>
+                       <file>pnputil.c</file>
                </directory>
        </directory>
        <if property="_WINKD_" value="0">