[SERVICES] Set default status to SERVICE_START_PENDING when starting a service.
[reactos.git] / reactos / base / services / umpnpmgr / umpnpmgr.c
index 824b51a..75080d5 100644 (file)
@@ -12,9 +12,9 @@
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  *  GNU General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 /*
  * COPYRIGHT:        See COPYING in the top level directory
  * PURPOSE:          User-mode Plug and Play manager
  * PROGRAMMER:       Eric Kohl
  *                   HervĂ© Poussineau (hpoussin@reactos.org)
+ *                   Colin Finck (colin@reactos.org)
  */
 
 /* INCLUDES *****************************************************************/
 //#define HAVE_SLIST_ENTRY_IMPLEMENTED
 #define WIN32_NO_STATUS
 #include <windows.h>
+#include <stdio.h>
 #include <cmtypes.h>
 #include <cmfuncs.h>
 #include <rtlfuncs.h>
+#include <setypes.h>
 #include <umpnpmgr/sysguid.h>
 #include <wdmguid.h>
 #include <cfgmgr32.h>
+#include <regstr.h>
+#include <userenv.h>
 
 #include <rpc.h>
 #include <rpcdce.h>
 
-#include "pnp_c.h"
+#include "pnp_s.h"
 
 #define NDEBUG
 #include <debug.h>
 
 /* GLOBALS ******************************************************************/
 
-static VOID CALLBACK
-ServiceMain(DWORD argc, LPTSTR *argv);
-
-static SERVICE_TABLE_ENTRY ServiceTable[2] =
+static VOID CALLBACK ServiceMain(DWORD, LPWSTR *);
+static WCHAR ServiceName[] = L"PlugPlay";
+static SERVICE_TABLE_ENTRYW ServiceTable[] =
 {
-    {TEXT("PlugPlay"), ServiceMain},
+    {ServiceName, ServiceMain},
     {NULL, NULL}
 };
 
@@ -120,13 +124,17 @@ RpcServerThread(LPVOID lpParameter)
         return 0;
     }
 
+    /* ROS HACK (this should never happen...) */
+    DPRINT1("*** Other devices won't be installed correctly. If something\n");
+    DPRINT1("*** doesn't work, try to reboot to get a new chance.\n");
+
     DPRINT("RpcServerThread() done\n");
 
     return 0;
 }
 
 
-void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
+void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
 {
     return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
 }
@@ -154,37 +162,57 @@ NtStatusToCrError(NTSTATUS Status)
 }
 
 
+/* Function 0 */
+DWORD PNP_Disconnect(
+    handle_t hBinding)
+{
+    UNREFERENCED_PARAMETER(hBinding);
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 1 */
+DWORD PNP_Connect(
+    handle_t hBinding)
+{
+    UNREFERENCED_PARAMETER(hBinding);
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
 /* Function 2 */
-CONFIGRET
-PNP_GetVersion(handle_t BindingHandle,
-               unsigned short *Version)
+DWORD PNP_GetVersion(
+    handle_t hBinding,
+    WORD *pVersion)
 {
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
 
-    *Version = 0x0400;
+    *pVersion = 0x0400;
     return CR_SUCCESS;
 }
 
 
 /* Function 3 */
-CONFIGRET
-PNP_GetGlobalState(handle_t BindingHandle,
-                   unsigned long *State,
-                   unsigned long Flags)
+DWORD PNP_GetGlobalState(
+    handle_t hBinding,
+    DWORD *pulState,
+    DWORD ulFlags)
 {
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
-    *State = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
+    *pulState = CM_GLOBAL_STATE_CAN_DO_UI | CM_GLOBAL_STATE_SERVICES_AVAILABLE;
     return CR_SUCCESS;
 }
 
 
 /* Function 4 */
-CONFIGRET
-PNP_InitDetection(handle_t BindingHandle)
+DWORD PNP_InitDetection(
+    handle_t hBinding)
 {
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
 
     DPRINT("PNP_InitDetection() called\n");
     return CR_SUCCESS;
@@ -192,59 +220,71 @@ PNP_InitDetection(handle_t BindingHandle)
 
 
 /* Function 5 */
-CONFIGRET
-PNP_ReportLogOn(handle_t BindingHandle,
-                unsigned long Admin,
-                unsigned long ProcessId)
+DWORD PNP_ReportLogOn(
+    handle_t hBinding,
+    BOOL Admin,
+    DWORD ProcessId)
 {
+    DWORD ReturnValue = CR_FAILURE;
     HANDLE hProcess;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(Admin);
 
-    DPRINT1("PNP_ReportLogOn(%lu, %lu) called\n", Admin, ProcessId);
+    DPRINT("PNP_ReportLogOn(%u, %u) called\n", Admin, ProcessId);
 
     /* Get the users token */
-    hProcess = OpenProcess(PROCESS_ALL_ACCESS,
-                           TRUE,
-                           ProcessId);
-    if (hProcess != NULL)
+    hProcess = OpenProcess(PROCESS_ALL_ACCESS, TRUE, ProcessId);
+
+    if(!hProcess)
     {
-        if (hUserToken != NULL)
-        {
-            CloseHandle(hUserToken);
-            hUserToken = NULL;
-        }
+        DPRINT1("OpenProcess failed with error %u\n", GetLastError());
+        goto cleanup;
+    }
 
-        OpenProcessToken(hProcess,
-                         TOKEN_ALL_ACCESS,
-                         &hUserToken);
-        CloseHandle(hProcess);
+    if (hUserToken)
+    {
+        CloseHandle(hUserToken);
+        hUserToken = NULL;
+    }
+
+    if(!OpenProcessToken(hProcess, TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY, &hUserToken))
+    {
+        DPRINT1("OpenProcessToken failed with error %u\n", GetLastError());
+        goto cleanup;
     }
 
     /* Trigger the installer thread */
-    if (hInstallEvent != NULL)
+    if (hInstallEvent)
         SetEvent(hInstallEvent);
 
-    return CR_SUCCESS;
+    ReturnValue = CR_SUCCESS;
+
+cleanup:
+    if(hProcess)
+        CloseHandle(hProcess);
+
+    return ReturnValue;
 }
 
 
 /* Function 6 */
-CONFIGRET
-PNP_ValidateDeviceInstance(handle_t BindingHandle,
-                           wchar_t *DeviceInstance,
-                           unsigned long Flags)
+DWORD PNP_ValidateDeviceInstance(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulFlags)
 {
     CONFIGRET ret = CR_SUCCESS;
     HKEY hDeviceKey = NULL;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_ValidateDeviceInstance(%S %lx) called\n",
-           DeviceInstance, Flags);
+           pDeviceID, ulFlags);
 
     if (RegOpenKeyExW(hEnumKey,
-                      DeviceInstance,
+                      pDeviceID,
                       0,
                       KEY_READ,
                       &hDeviceKey))
@@ -267,24 +307,29 @@ Done:
 
 
 /* Function 7 */
-CONFIGRET
-PNP_GetRootDeviceInstance(handle_t BindingHandle,
-                          wchar_t *DeviceInstance,
-                          unsigned long Length)
+DWORD PNP_GetRootDeviceInstance(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    PNP_RPC_STRING_LEN ulLength)
 {
     CONFIGRET ret = CR_SUCCESS;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
 
     DPRINT("PNP_GetRootDeviceInstance() called\n");
 
-    if (Length < lstrlenW(szRootDeviceId) + 1)
+    if (!pDeviceID)
+    {
+        ret = CR_INVALID_POINTER;
+        goto Done;
+    }
+    if (ulLength < lstrlenW(szRootDeviceId) + 1)
     {
         ret = CR_BUFFER_SMALL;
         goto Done;
     }
 
-    lstrcpyW(DeviceInstance,
+    lstrcpyW(pDeviceID,
              szRootDeviceId);
 
 Done:
@@ -295,32 +340,32 @@ Done:
 
 
 /* Function 8 */
-CONFIGRET
-PNP_GetRelatedDeviceInstance(handle_t BindingHandle,
-                             unsigned long Relationship,
-                             wchar_t *DeviceId,
-                             wchar_t *RelatedDeviceId,
-                             unsigned long Length,
-                             unsigned long Flags)
+DWORD PNP_GetRelatedDeviceInstance(
+    handle_t hBinding,
+    DWORD ulRelationship,
+    LPWSTR pDeviceID,
+    LPWSTR pRelatedDeviceId,
+    PNP_RPC_STRING_LEN *pulLength,
+    DWORD ulFlags)
 {
     PLUGPLAY_CONTROL_RELATED_DEVICE_DATA PlugPlayData;
     CONFIGRET ret = CR_SUCCESS;
     NTSTATUS Status;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_GetRelatedDeviceInstance() called\n");
-    DPRINT("  Relationship %ld\n", Relationship);
-    DPRINT("  DeviceId %S\n", DeviceId);
+    DPRINT("  Relationship %ld\n", ulRelationship);
+    DPRINT("  DeviceId %S\n", pDeviceID);
 
     RtlInitUnicodeString(&PlugPlayData.TargetDeviceInstance,
-                         DeviceId);
+                         pDeviceID);
 
-    PlugPlayData.Relation = Relationship;
+    PlugPlayData.Relation = ulRelationship;
 
-    PlugPlayData.RelatedDeviceInstanceLength = Length;
-    PlugPlayData.RelatedDeviceInstance = RelatedDeviceId;
+    PlugPlayData.RelatedDeviceInstanceLength = *pulLength;
+    PlugPlayData.RelatedDeviceInstance = pRelatedDeviceId;
 
     Status = NtPlugPlayControl(PlugPlayControlGetRelatedDevice,
                                (PVOID)&PlugPlayData,
@@ -341,31 +386,31 @@ PNP_GetRelatedDeviceInstance(handle_t BindingHandle,
 
 
 /* Function 9 */
-CONFIGRET
-PNP_EnumerateSubKeys(handle_t BindingHandle,
-                     unsigned long Branch,
-                     unsigned long Index,
-                     wchar_t *Buffer,
-                     unsigned long Length,
-                     unsigned long *RequiredLength,
-                     DWORD Flags)
+DWORD PNP_EnumerateSubKeys(
+    handle_t hBinding,
+    DWORD ulBranch,
+    DWORD ulIndex,
+    LPWSTR Buffer,
+    PNP_RPC_STRING_LEN ulLength,
+    PNP_RPC_STRING_LEN *pulRequiredLen,
+    DWORD ulFlags)
 {
     CONFIGRET ret = CR_SUCCESS;
     HKEY hKey;
     DWORD dwError;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_EnumerateSubKeys() called\n");
 
-    switch (Branch)
+    switch (ulBranch)
     {
-        case PNP_BRANCH_ENUM:
+        case PNP_ENUMERATOR_SUBKEYS:
             hKey = hEnumKey;
             break;
 
-        case PNP_BRANCH_CLASS:
+        case PNP_CLASS_SUBKEYS:
             hKey = hClassKey;
             break;
 
@@ -373,11 +418,11 @@ PNP_EnumerateSubKeys(handle_t BindingHandle,
             return CR_FAILURE;
     }
 
-    *RequiredLength = Length;
+    *pulRequiredLen = ulLength;
     dwError = RegEnumKeyExW(hKey,
-                            Index,
+                            ulIndex,
                             Buffer,
-                            RequiredLength,
+                            pulRequiredLen,
                             NULL,
                             NULL,
                             NULL,
@@ -388,7 +433,7 @@ PNP_EnumerateSubKeys(handle_t BindingHandle,
     }
     else
     {
-        (*RequiredLength)++;
+        (*pulRequiredLen)++;
     }
 
     DPRINT("PNP_EnumerateSubKeys() done (returns %lx)\n", ret);
@@ -397,51 +442,56 @@ PNP_EnumerateSubKeys(handle_t BindingHandle,
 }
 
 
-/* Function 11 */
-CONFIGRET
-PNP_GetDeviceListSize(handle_t BindingHandle,
-                      wchar_t *Filter,
-                      unsigned long *Length,
-                      DWORD Flags)
+/* Function 10 */
+DWORD PNP_GetDeviceList(
+    handle_t hBinding,
+    LPWSTR pszFilter,
+    LPWSTR Buffer,
+    PNP_RPC_STRING_LEN *pulLength,
+    DWORD ulFlags)
 {
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Filter);
-    UNREFERENCED_PARAMETER(Flags);
-
-    DPRINT("PNP_GetDeviceListSize() called\n");
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    /* FIXME */
-    *Length = 2;
 
-    return CR_SUCCESS;
+/* Function 11 */
+DWORD PNP_GetDeviceListSize(
+    handle_t hBinding,
+    LPWSTR pszFilter,
+    PNP_RPC_BUFFER_SIZE *pulLen,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
 /* Function 12 */
-CONFIGRET
-PNP_GetDepth(handle_t BindingHandle,
-             wchar_t *DeviceInstance,
-             unsigned long *Depth,
-             DWORD Flags)
+DWORD PNP_GetDepth(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    DWORD *pulDepth,
+    DWORD ulFlags)
 {
     PLUGPLAY_CONTROL_DEPTH_DATA PlugPlayData;
     CONFIGRET ret = CR_SUCCESS;
     NTSTATUS Status;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_GetDepth() called\n");
 
     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
-                         DeviceInstance);
+                         pszDeviceID);
 
     Status = NtPlugPlayControl(PlugPlayControlGetDeviceDepth,
                                (PVOID)&PlugPlayData,
                                sizeof(PLUGPLAY_CONTROL_DEPTH_DATA));
     if (NT_SUCCESS(Status))
     {
-        *Depth = PlugPlayData.Depth;
+        *pulDepth = PlugPlayData.Depth;
     }
     else
     {
@@ -455,15 +505,15 @@ PNP_GetDepth(handle_t BindingHandle,
 
 
 /* Function 13 */
-CONFIGRET
-PNP_GetDeviceRegProp(handle_t BindingHandle,
-                     wchar_t *DeviceInstance,
-                     unsigned long Property,
-                     unsigned long *DataType,
-                     char *Buffer,
-                     unsigned long *TransferLen,
-                     unsigned long *Length,
-                     DWORD Flags)
+DWORD PNP_GetDeviceRegProp(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulProperty,
+    DWORD *pulRegDataType,
+    BYTE *Buffer,
+    PNP_PROP_SIZE *pulTransferLen,
+    PNP_PROP_SIZE *pulLength,
+    DWORD ulFlags)
 {
     PLUGPLAY_CONTROL_PROPERTY_DATA PlugPlayData;
     CONFIGRET ret = CR_SUCCESS;
@@ -471,12 +521,12 @@ PNP_GetDeviceRegProp(handle_t BindingHandle,
     HKEY hKey = 0;
     NTSTATUS Status;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_GetDeviceRegProp() called\n");
 
-    switch (Property)
+    switch (ulProperty)
     {
         case CM_DRP_DEVICEDESC:
             lpValueName = L"DeviceDesc";
@@ -568,7 +618,7 @@ PNP_GetDeviceRegProp(handle_t BindingHandle,
     {
         /* Retrieve information from the Registry */
         if (RegOpenKeyExW(hEnumKey,
-                          DeviceInstance,
+                          pDeviceID,
                           0,
                           KEY_ALL_ACCESS,
                           &hKey))
@@ -577,9 +627,9 @@ PNP_GetDeviceRegProp(handle_t BindingHandle,
         if (RegQueryValueExW(hKey,
                              lpValueName,
                              NULL,
-                             DataType,
-                             (LPBYTE)Buffer,
-                             Length))
+                             pulRegDataType,
+                             Buffer,
+                             pulLength))
             ret = CR_REGISTRY_ERROR;
 
         /* FIXME: Check buffer size */
@@ -590,11 +640,11 @@ PNP_GetDeviceRegProp(handle_t BindingHandle,
     {
         /* Retrieve information from the Device Node */
         RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
-                             DeviceInstance);
+                             pDeviceID);
         PlugPlayData.Buffer = Buffer;
-        PlugPlayData.BufferSize = *TransferLen;
+        PlugPlayData.BufferSize = *pulTransferLen;
 
-        switch (Property)
+        switch (ulProperty)
         {
 #if 0
             case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
@@ -616,11 +666,11 @@ PNP_GetDeviceRegProp(handle_t BindingHandle,
             case CM_DRP_BUSNUMBER:
                 PlugPlayData.Property = DevicePropertyBusNumber;
                 break;
+#endif
 
             case CM_DRP_ENUMERATOR_NAME:
-                PlugPlayData.Property = DevicePropertyEnumeratorName;
+                PlugPlayData.Property = 15; //DevicePropertyEnumeratorName;
                 break;
-#endif
 
             default:
                 return CR_INVALID_PROPERTY;
@@ -631,7 +681,7 @@ PNP_GetDeviceRegProp(handle_t BindingHandle,
                                    sizeof(PLUGPLAY_CONTROL_PROPERTY_DATA));
         if (NT_SUCCESS(Status))
         {
-            *Length = PlugPlayData.BufferSize;
+            *pulLength = PlugPlayData.BufferSize;
         }
         else
         {
@@ -646,30 +696,30 @@ PNP_GetDeviceRegProp(handle_t BindingHandle,
 
 
 /* Function 14 */
-CONFIGRET
-PNP_SetDeviceRegProp(handle_t BindingHandle,
-                     wchar_t *DeviceId,
-                     unsigned long Property,
-                     unsigned long DataType,
-                     char *Buffer,
-                     unsigned long Length,
-                     unsigned long Flags)
+DWORD PNP_SetDeviceRegProp(
+    handle_t hBinding,
+    LPWSTR pDeviceId,
+    DWORD ulProperty,
+    DWORD ulDataType,
+    BYTE *Buffer,
+    PNP_PROP_SIZE ulLength,
+    DWORD ulFlags)
 {
     CONFIGRET ret = CR_SUCCESS;
     LPWSTR lpValueName = NULL;
     HKEY hKey = 0;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_SetDeviceRegProp() called\n");
 
-    DPRINT("DeviceId: %S\n", DeviceId);
-    DPRINT("Property: %lu\n", Property);
-    DPRINT("DataType: %lu\n", DataType);
-    DPRINT("Length: %lu\n", Length);
+    DPRINT("DeviceId: %S\n", pDeviceId);
+    DPRINT("Property: %lu\n", ulProperty);
+    DPRINT("DataType: %lu\n", ulDataType);
+    DPRINT("Length: %lu\n", ulLength);
 
-    switch (Property)
+    switch (ulProperty)
     {
         case CM_DRP_DEVICEDESC:
             lpValueName = L"DeviceDesc";
@@ -730,13 +780,13 @@ PNP_SetDeviceRegProp(handle_t BindingHandle,
     DPRINT("Value name: %S\n", lpValueName);
 
     if (RegOpenKeyExW(hEnumKey,
-                      DeviceId,
+                      pDeviceId,
                       0,
-                      KEY_ALL_ACCESS,
+                      KEY_ALL_ACCESS, /* FIXME: so much? */
                       &hKey))
         return CR_INVALID_DEVNODE;
 
-    if (Length == 0)
+    if (ulLength == 0)
     {
         if (RegDeleteValueW(hKey,
                             lpValueName))
@@ -747,9 +797,9 @@ PNP_SetDeviceRegProp(handle_t BindingHandle,
         if (RegSetValueExW(hKey,
                            lpValueName,
                            0,
-                           DataType,
-                           (const BYTE*)Buffer,
-                           Length))
+                           ulDataType,
+                           Buffer,
+                           ulLength))
             ret = CR_REGISTRY_ERROR;
     }
 
@@ -762,87 +812,72 @@ PNP_SetDeviceRegProp(handle_t BindingHandle,
 
 
 /* Function 15 */
-CONFIGRET
-PNP_GetClassInstance(handle_t BindingHandle,
-                     wchar_t *DeviceId, /* in */
-                     wchar_t *Buffer, /* out */
-                     unsigned long Length)
+DWORD PNP_GetClassInstance(
+    handle_t hBinding,
+    LPWSTR pDeviceId,
+    LPWSTR pszClassInstance,
+    PNP_RPC_STRING_LEN ulLength)
 {
-    CONFIGRET ret = CR_SUCCESS;
-
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceId);
-    UNREFERENCED_PARAMETER(Buffer);
-    UNREFERENCED_PARAMETER(Length);
-
-    DPRINT("PNP_Get_Class_Instance() called\n");
-
-    DPRINT("PNP_Get_Class_Instance() done (returns %lx)\n", ret);
-
-    return ret;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
 /* Function 16 */
-CONFIGRET
-PNP_CreateKey(handle_t BindingHandle,
-              wchar_t *SubKey,
-              unsigned long samDesired,
-              unsigned long Flags)
+DWORD PNP_CreateKey(
+    handle_t hBinding,
+    LPWSTR pszSubKey,
+    DWORD samDesired,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
+    HKEY hKey = 0;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(SubKey);
-    UNREFERENCED_PARAMETER(samDesired);
-    UNREFERENCED_PARAMETER(Flags);
+    if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                        pszSubKey,
+                        0,
+                        NULL,
+                        0,
+                        KEY_ALL_ACCESS,
+                        NULL,
+                        &hKey,
+                        NULL))
+        return CR_REGISTRY_ERROR;
 
-    DPRINT("PNP_CreateKey() called\n");
+    /* FIXME: Set security key */
 
-    DPRINT("PNP_CreateKey() done (returns %lx)\n", ret);
+    RegCloseKey(hKey);
 
-    return ret;
+    return CR_SUCCESS;
 }
 
 
 /* Function 17 */
-CONFIGRET
-PNP_DeleteRegistryKey(handle_t BindingHandle,
-                      wchar_t *DeviceId,
-                      wchar_t *ParentKey,
-                      wchar_t *ChildKey,
-                      unsigned long Flags)
+DWORD PNP_DeleteRegistryKey(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    LPWSTR pszParentKey,
+    LPWSTR pszChildKey,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
-
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceId);
-    UNREFERENCED_PARAMETER(ParentKey);
-    UNREFERENCED_PARAMETER(ChildKey);
-    UNREFERENCED_PARAMETER(Flags);
-
-    DPRINT("PNP_DeleteRegistryKey() called\n");
-
-    DPRINT("PNP_DeleteRegistryKey() done (returns %lx)\n", ret);
-
-    return ret;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
 /* Function 18 */
-#if 0
-CONFIGRET
-PNP_GetClassCount(handle_t BindingHandle,
-                  unsigned long *ClassCount,
-                  unsigned long Flags)
+DWORD PNP_GetClassCount(
+    handle_t hBinding,
+    DWORD *pulClassCount,
+    DWORD ulFlags)
 {
-    HANDLE hKey = NULL;
+    HKEY hKey;
     DWORD dwError;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-                            pszRegPathClass,
+                            REGSTR_PATH_CLASS,
                             0,
                             KEY_QUERY_VALUE,
                             &hKey);
@@ -853,7 +888,7 @@ PNP_GetClassCount(handle_t BindingHandle,
                                NULL,
                                NULL,
                                NULL,
-                               &ClassCount,
+                               pulClassCount,
                                NULL,
                                NULL,
                                NULL,
@@ -867,31 +902,29 @@ PNP_GetClassCount(handle_t BindingHandle,
 
     return CR_SUCCESS;
 }
-#endif
 
 
 /* Function 19 */
-CONFIGRET
-PNP_GetClassName(handle_t BindingHandle,
-                 wchar_t *ClassGuid,
-                 wchar_t *Buffer,
-                 unsigned long *Length,
-                 unsigned long Flags)
+DWORD PNP_GetClassName(
+    handle_t hBinding,
+    LPWSTR pszClassGuid,
+    LPWSTR Buffer,
+    PNP_RPC_STRING_LEN *pulLength,
+    DWORD ulFlags)
 {
     WCHAR szKeyName[MAX_PATH];
     CONFIGRET ret = CR_SUCCESS;
-    HKEY hKey = NULL;
+    HKEY hKey;
     DWORD dwSize;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_GetClassName() called\n");
 
-    lstrcpyW(szKeyName, L"System\\CurrentControlSet\\Control\\Class");
-    lstrcatW(szKeyName, L"\\");
-    if(lstrlenW(ClassGuid) < sizeof(szKeyName)/sizeof(WCHAR)-lstrlenW(szKeyName))
-        lstrcatW(szKeyName, ClassGuid);
+    lstrcpyW(szKeyName, L"System\\CurrentControlSet\\Control\\Class\\");
+    if(lstrlenW(pszClassGuid) + 1 < sizeof(szKeyName)/sizeof(WCHAR)-(lstrlenW(szKeyName) * sizeof(WCHAR)))
+        lstrcatW(szKeyName, pszClassGuid);
     else return CR_INVALID_DATA;
 
     if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
@@ -901,7 +934,7 @@ PNP_GetClassName(handle_t BindingHandle,
                       &hKey))
         return CR_REGISTRY_ERROR;
 
-    dwSize = *Length * sizeof(WCHAR);
+    dwSize = *pulLength * sizeof(WCHAR);
     if (RegQueryValueExW(hKey,
                          L"Class",
                          NULL,
@@ -909,12 +942,12 @@ PNP_GetClassName(handle_t BindingHandle,
                          (LPBYTE)Buffer,
                          &dwSize))
     {
-        *Length = 0;
+        *pulLength = 0;
         ret = CR_REGISTRY_ERROR;
     }
     else
     {
-        *Length = dwSize / sizeof(WCHAR);
+        *pulLength = dwSize / sizeof(WCHAR);
     }
 
     RegCloseKey(hKey);
@@ -926,25 +959,25 @@ PNP_GetClassName(handle_t BindingHandle,
 
 
 /* Function 20 */
-CONFIGRET
-PNP_DeleteClassKey(handle_t BindingHandle,
-                   wchar_t *ClassGuid,
-                   unsigned long Flags)
+DWORD PNP_DeleteClassKey(
+    handle_t hBinding,
+    LPWSTR pszClassGuid,
+    DWORD ulFlags)
 {
     CONFIGRET ret = CR_SUCCESS;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
 
-    DPRINT("PNP_GetClassName(%S, %lx) called\n", ClassGuid, Flags);
+    DPRINT("PNP_GetClassName(%S, %lx) called\n", pszClassGuid, ulFlags);
 
-    if (Flags & CM_DELETE_CLASS_SUBKEYS)
+    if (ulFlags & CM_DELETE_CLASS_SUBKEYS)
     {
-        if (RegDeleteTreeW(hClassKey, ClassGuid) != ERROR_SUCCESS)
+        if (RegDeleteTreeW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
             ret = CR_REGISTRY_ERROR;
     }
     else
     {
-        if (RegDeleteKeyW(hClassKey, ClassGuid) != ERROR_SUCCESS)
+        if (RegDeleteKeyW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
             ret = CR_REGISTRY_ERROR;
     }
 
@@ -954,81 +987,215 @@ PNP_DeleteClassKey(handle_t BindingHandle,
 }
 
 
+/* Function 21 */
+DWORD PNP_GetInterfaceDeviceAlias(
+    handle_t hBinding,
+    LPWSTR pszInterfaceDevice,
+    GUID *AliasInterfaceGuid,
+    LPWSTR pszAliasInterfaceDevice,
+    PNP_RPC_STRING_LEN *pulLength,
+    PNP_RPC_STRING_LEN *pulTransferLen,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 22 */
+DWORD PNP_GetInterfaceDeviceList(
+    handle_t hBinding,
+    GUID *InterfaceGuid,
+    LPWSTR pszDeviceID,
+    BYTE *Buffer,
+    PNP_RPC_BUFFER_SIZE *pulLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 23 */
+DWORD PNP_GetInterfaceDeviceListSize(
+    handle_t hBinding,
+    PNP_RPC_BUFFER_SIZE *pulLen,
+    GUID *InterfaceGuid,
+    LPWSTR pszDeviceID,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 24 */
+DWORD PNP_RegisterDeviceClassAssociation(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    GUID *InterfaceGuid,
+    LPWSTR pszReference,
+    LPWSTR pszSymLink,
+    PNP_RPC_STRING_LEN *pulLength,
+    PNP_RPC_STRING_LEN *pulTransferLen,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 25 */
+DWORD PNP_UnregisterDeviceClassAssociation(
+    handle_t hBinding,
+    LPWSTR pszInterfaceDevice,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 26 */
+DWORD PNP_GetClassRegProp(
+    handle_t hBinding,
+    LPWSTR pszClassGuid,
+    DWORD ulProperty,
+    DWORD *pulRegDataType,
+    BYTE *Buffer,
+    PNP_RPC_STRING_LEN *pulTransferLen,
+    PNP_RPC_STRING_LEN *pulLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 27 */
+DWORD PNP_SetClassRegProp(
+    handle_t hBinding,
+    LPWSTR *pszClassGuid,
+    DWORD ulProperty,
+    DWORD ulDataType,
+    BYTE *Buffer,
+    PNP_PROP_SIZE ulLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
 /* Function 28 */
-CONFIGRET
-PNP_CreateDevInst(handle_t BindingHandle,
-                  wchar_t *DeviceId,       /* [in, out, string, size_is(Length)] */
-                  wchar_t *ParentDeviceId, /* [in, string] */
-                  unsigned long Length,    /* [in] */
-                  unsigned long Flags)     /* [in] */
+DWORD PNP_CreateDevInst(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    LPWSTR pszParentDeviceID,
+    PNP_RPC_STRING_LEN ulLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+static CONFIGRET
+MoveDeviceInstance(LPWSTR pszDeviceInstanceDestination,
+                   LPWSTR pszDeviceInstanceSource)
+{
+    DPRINT("MoveDeviceInstance: not implemented\n");
+    /* FIXME */
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+static CONFIGRET
+SetupDeviceInstance(LPWSTR pszDeviceInstance,
+                    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_CALL_NOT_IMPLEMENTED;
+    DPRINT("SetupDeviceInstance: not implemented\n");
+    /* FIXME */
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceId);
-    UNREFERENCED_PARAMETER(ParentDeviceId);
-    UNREFERENCED_PARAMETER(Length);
-    UNREFERENCED_PARAMETER(Flags);
 
-    DPRINT1("PNP_CreateDevInst() called\n");
+static CONFIGRET
+EnableDeviceInstance(LPWSTR pszDeviceInstance)
+{
+    PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
+    CONFIGRET ret = CR_SUCCESS;
+    NTSTATUS Status;
+
+    DPRINT("Enable device instance\n");
 
-    DPRINT1("PNP_CreateDevInst() done (returns %lx)\n", ret);
+    RtlInitUnicodeString(&ResetDeviceData.DeviceInstance, pszDeviceInstance);
+    Status = NtPlugPlayControl(PlugPlayControlResetDevice, &ResetDeviceData, sizeof(PLUGPLAY_CONTROL_RESET_DEVICE_DATA));
+    if (!NT_SUCCESS(Status))
+        ret = NtStatusToCrError(Status);
 
     return ret;
 }
 
 
+static CONFIGRET
+DisableDeviceInstance(LPWSTR pszDeviceInstance)
+{
+    DPRINT("DisableDeviceInstance: not implemented\n");
+    /* FIXME */
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+static CONFIGRET
+ReenumerateDeviceInstance(LPWSTR pszDeviceInstance)
+{
+    DPRINT("ReenumerateDeviceInstance: not implemented\n");
+    /* FIXME */
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
 /* Function 29 */
-CONFIGRET
-PNP_DeviceInstanceAction(handle_t BindingHandle,
-                         unsigned long MajorAction,
-                         unsigned long MinorAction,
-                         wchar_t *DeviceInstance1,
-                         wchar_t *DeviceInstance2)
+DWORD PNP_DeviceInstanceAction(
+    handle_t hBinding,
+    DWORD ulAction,
+    DWORD ulFlags,
+    LPWSTR pszDeviceInstance1,
+    LPWSTR pszDeviceInstance2)
 {
     CONFIGRET ret = CR_SUCCESS;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(MinorAction);
-    UNREFERENCED_PARAMETER(DeviceInstance1);
-    UNREFERENCED_PARAMETER(DeviceInstance2);
+    UNREFERENCED_PARAMETER(hBinding);
 
     DPRINT("PNP_DeviceInstanceAction() called\n");
 
-    switch (MajorAction)
+    switch (ulAction)
     {
-        case 2:
-            DPRINT("Move device instance\n");
-            /* FIXME */
-            ret = CR_CALL_NOT_IMPLEMENTED;
+        case PNP_DEVINST_MOVE:
+            ret = MoveDeviceInstance(pszDeviceInstance1,
+                                     pszDeviceInstance2);
             break;
 
-        case 3:
-            DPRINT("Setup device instance\n");
-            /* FIXME */
-            ret = CR_CALL_NOT_IMPLEMENTED;
+        case PNP_DEVINST_SETUP:
+            ret = SetupDeviceInstance(pszDeviceInstance1,
+                                      ulFlags);
             break;
 
-        case 4:
-            DPRINT("Enable device instance\n");
-            /* FIXME */
-            ret = CR_CALL_NOT_IMPLEMENTED;
+        case PNP_DEVINST_ENABLE:
+            ret = EnableDeviceInstance(pszDeviceInstance1);
             break;
 
-        case 5:
-            DPRINT("Disable device instance\n");
-            /* FIXME */
-            ret = CR_CALL_NOT_IMPLEMENTED;
+        case PNP_DEVINST_DISABLE:
+            ret = DisableDeviceInstance(pszDeviceInstance1);
             break;
 
-        case 7:
-            DPRINT("Reenumerate device instance\n");
-            /* FIXME */
-            ret = CR_CALL_NOT_IMPLEMENTED;
+        case PNP_DEVINST_REENUMERATE:
+            ret = ReenumerateDeviceInstance(pszDeviceInstance1);
             break;
 
         default:
-            DPRINT1("Unknown function %lu\n", MajorAction);
+            DPRINT1("Unknown device action %lu: not implemented\n", ulAction);
             ret = CR_CALL_NOT_IMPLEMENTED;
     }
 
@@ -1039,24 +1206,24 @@ PNP_DeviceInstanceAction(handle_t BindingHandle,
 
 
 /* Function 30 */
-CONFIGRET
-PNP_GetDeviceStatus(handle_t BindingHandle,
-                    wchar_t *DeviceInstance,
-                    unsigned long *pStatus,
-                    unsigned long *pProblem,
-                    DWORD Flags)
+DWORD PNP_GetDeviceStatus(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD *pulStatus,
+    DWORD *pulProblem,
+    DWORD ulFlags)
 {
     PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
     CONFIGRET ret = CR_SUCCESS;
     NTSTATUS Status;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
+    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_GetDeviceStatus() called\n");
 
     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
-                         DeviceInstance);
+                         pDeviceID);
     PlugPlayData.Operation = 0; /* Get status */
 
     Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
@@ -1064,8 +1231,8 @@ PNP_GetDeviceStatus(handle_t BindingHandle,
                                sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
     if (NT_SUCCESS(Status))
     {
-        *pStatus = PlugPlayData.DeviceStatus;
-        *pProblem = PlugPlayData.DeviceProblem;
+        *pulStatus = PlugPlayData.DeviceStatus;
+        *pulProblem = PlugPlayData.DeviceProblem;
     }
     else
     {
@@ -1079,48 +1246,38 @@ PNP_GetDeviceStatus(handle_t BindingHandle,
 
 
 /* Function 31 */
-CONFIGRET
-PNP_SetDeviceProblem(handle_t BindingHandle,
-                     wchar_t *DeviceInstance,
-                     unsigned long Problem,
-                     DWORD Flags)
+DWORD PNP_SetDeviceProblem(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulProblem,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
-
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceInstance);
-    UNREFERENCED_PARAMETER(Problem);
-    UNREFERENCED_PARAMETER(Flags);
-
-    DPRINT1("PNP_SetDeviceProblem() called\n");
-
-    /* FIXME */
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    DPRINT1("PNP_SetDeviceProblem() done (returns %lx)\n", ret);
 
-    return ret;
+/* Function 32 */
+DWORD PNP_DisableDevInst(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    PPNP_VETO_TYPE pVetoType,
+    LPWSTR pszVetoName,
+    DWORD ulNameLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
-
 /* Function 33 */
-CONFIGRET
-PNP_UninstallDevInst(handle_t BindingHandle,
-                     wchar_t *DeviceInstance,
-                     DWORD Flags)
+DWORD PNP_UninstallDevInst(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
-
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceInstance);
-    UNREFERENCED_PARAMETER(Flags);
-
-    DPRINT1("PNP_UninstallDevInst() called\n");
-
-    /* FIXME */
-
-    DPRINT1("PNP_UninstallDevInst() done (returns %lx)\n", ret);
-
-    return ret;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
@@ -1167,27 +1324,28 @@ AppendDeviceId(LPWSTR lpDeviceIdList,
 
 
 /* Function 34 */
-CONFIGRET
-PNP_AddID(handle_t BindingHandle,
-          wchar_t *DeviceInstance,
-          wchar_t *DeviceId,
-          DWORD Flags)
+DWORD PNP_AddID(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    LPWSTR pszID,
+    DWORD ulFlags)
 {
     CONFIGRET ret = CR_SUCCESS;
     HKEY hDeviceKey;
     LPWSTR pszSubKey;
     DWORD dwDeviceIdListSize;
-    WCHAR szDeviceIdList[512];
+    DWORD dwNewDeviceIdSize;
+    WCHAR * pszDeviceIdList = NULL;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
 
     DPRINT("PNP_AddID() called\n");
-    DPRINT("  DeviceInstance: %S\n", DeviceInstance);
-    DPRINT("  DeviceId: %S\n", DeviceId);
-    DPRINT("  Flags: %lx\n", Flags);
+    DPRINT("  DeviceInstance: %S\n", pszDeviceID);
+    DPRINT("  DeviceId: %S\n", pszID);
+    DPRINT("  Flags: %lx\n", ulFlags);
 
     if (RegOpenKeyExW(hEnumKey,
-                      DeviceInstance,
+                      pszDeviceID,
                       0,
                       KEY_QUERY_VALUE | KEY_SET_VALUE,
                       &hDeviceKey) != ERROR_SUCCESS)
@@ -1196,14 +1354,42 @@ PNP_AddID(handle_t BindingHandle,
         return CR_INVALID_DEVNODE;
     }
 
-    pszSubKey = (Flags & CM_ADD_ID_COMPATIBLE) ? L"CompatibleIDs" : L"HardwareID";
+    pszSubKey = (ulFlags & CM_ADD_ID_COMPATIBLE) ? L"CompatibleIDs" : L"HardwareID";
+
+    if (RegQueryValueExW(hDeviceKey,
+                         pszSubKey,
+                         NULL,
+                         NULL,
+                         NULL,
+                         &dwDeviceIdListSize) != ERROR_SUCCESS)
+    {
+        DPRINT("Failed to query the desired ID string!\n");
+        ret = CR_REGISTRY_ERROR;
+        goto Done;
+    }
+
+    dwNewDeviceIdSize = lstrlenW(pszDeviceID);
+    if (!dwNewDeviceIdSize)
+    {
+        ret = CR_INVALID_POINTER;
+        goto Done;
+    }
+
+    dwDeviceIdListSize += (dwNewDeviceIdSize + 2) * sizeof(WCHAR);
+
+    pszDeviceIdList = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDeviceIdListSize);
+    if (!pszDeviceIdList)
+    {
+        DPRINT("Failed to allocate memory for the desired ID string!\n");
+        ret = CR_OUT_OF_MEMORY;
+        goto Done;
+    }
 
-    dwDeviceIdListSize = 512 * sizeof(WCHAR);
     if (RegQueryValueExW(hDeviceKey,
                          pszSubKey,
                          NULL,
                          NULL,
-                         (LPBYTE)szDeviceIdList,
+                         (LPBYTE)pszDeviceIdList,
                          &dwDeviceIdListSize) != ERROR_SUCCESS)
     {
         DPRINT("Failed to query the desired ID string!\n");
@@ -1212,7 +1398,7 @@ PNP_AddID(handle_t BindingHandle,
     }
 
     /* Check whether the device ID is already in use */
-    if (CheckForDeviceId(szDeviceIdList, DeviceId))
+    if (CheckForDeviceId(pszDeviceIdList, pszDeviceID))
     {
         DPRINT("Device ID was found in the ID string!\n");
         ret = CR_SUCCESS;
@@ -1220,13 +1406,13 @@ PNP_AddID(handle_t BindingHandle,
     }
 
     /* Append the Device ID */
-    AppendDeviceId(szDeviceIdList, &dwDeviceIdListSize, DeviceId);
+    AppendDeviceId(pszDeviceIdList, &dwDeviceIdListSize, pszID);
 
     if (RegSetValueExW(hDeviceKey,
                        pszSubKey,
                        0,
                        REG_MULTI_SZ,
-                       (LPBYTE)szDeviceIdList,
+                       (LPBYTE)pszDeviceIdList,
                        dwDeviceIdListSize) != ERROR_SUCCESS)
     {
         DPRINT("Failed to set the desired ID string!\n");
@@ -1235,6 +1421,8 @@ PNP_AddID(handle_t BindingHandle,
 
 Done:
     RegCloseKey(hDeviceKey);
+    if (pszDeviceIdList)
+        HeapFree(GetProcessHeap(), 0, pszDeviceIdList);
 
     DPRINT("PNP_AddID() done (returns %lx)\n", ret);
 
@@ -1242,10 +1430,48 @@ Done:
 }
 
 
+/* Function 35 */
+DWORD PNP_RegisterDriver(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 36 */
+DWORD PNP_QueryRemove(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    PPNP_VETO_TYPE pVetoType,
+    LPWSTR pszVetoName,
+    DWORD ulNameLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 37 */
+DWORD PNP_RequestDeviceEject(
+    handle_t hBinding,
+    LPWSTR pszDeviceID,
+    PPNP_VETO_TYPE pVetoType,
+    LPWSTR pszVetoName,
+    DWORD ulNameLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
 /* Function 38 */
 CONFIGRET
-PNP_IsDockStationPresent(handle_t BindingHandle,
-                         unsigned long *Present)
+PNP_IsDockStationPresent(handle_t hBinding,
+                         BOOL *Present)
 {
     HKEY hKey;
     DWORD dwType;
@@ -1253,7 +1479,7 @@ PNP_IsDockStationPresent(handle_t BindingHandle,
     DWORD dwSize;
     CONFIGRET ret = CR_SUCCESS;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
+    UNREFERENCED_PARAMETER(hBinding);
 
     DPRINT1("PNP_IsDockStationPresent() called\n");
 
@@ -1296,203 +1522,551 @@ PNP_IsDockStationPresent(handle_t BindingHandle,
 
 
 /* Function 39 */
-CONFIGRET
-PNP_RequestEjectPC(handle_t BindingHandle)
+DWORD PNP_RequestEjectPC(
+    handle_t hBinding)
 {
-    CONFIGRET ret = CR_SUCCESS;
-
-    UNREFERENCED_PARAMETER(BindingHandle);
-
-    DPRINT1("PNP_RequestEjectPC() called\n");
-
-    ret = CR_FAILURE; /* FIXME */
-
-    DPRINT1("PNP_RequestEjectPC() done (returns %lx)\n", ret);
-
-    return ret;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
 /* Function 40 */
-CONFIGRET
-PNP_HwProfFlags(handle_t BindingHandle,
-                unsigned long Action,
-                wchar_t *DeviceId,
-                unsigned long ProfileId,
-                unsigned long *Value, // out
-                unsigned long Flags)
+DWORD PNP_HwProfFlags(
+    handle_t hBinding,
+    DWORD ulAction,
+    LPWSTR pDeviceID,
+    DWORD ulConfig,
+    DWORD *pulValue,
+    PPNP_VETO_TYPE pVetoType,
+    LPWSTR pszVetoName,
+    DWORD ulNameLength,
+    DWORD ulFlags)
 {
     CONFIGRET ret = CR_SUCCESS;
+    WCHAR szKeyName[MAX_PATH];
+    HKEY hKey;
+    HKEY hDeviceKey;
+    DWORD dwSize;
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Action);
-    UNREFERENCED_PARAMETER(DeviceId);
-    UNREFERENCED_PARAMETER(ProfileId);
-    UNREFERENCED_PARAMETER(Value);
-    UNREFERENCED_PARAMETER(Flags);
+    UNREFERENCED_PARAMETER(hBinding);
 
-    DPRINT1("PNP_HwProfFlags() called\n");
+    DPRINT("PNP_HwProfFlags() called\n");
 
-    ret = CR_CALL_NOT_IMPLEMENTED; /* FIXME */
+    if (ulConfig == 0)
+    {
+        wcscpy(szKeyName,
+               L"System\\CurrentControlSet\\HardwareProfiles\\Current\\System\\CurrentControlSet\\Enum");
+    }
+    else
+    {
+        swprintf(szKeyName,
+                 L"System\\CurrentControlSet\\HardwareProfiles\\%04u\\System\\CurrentControlSet\\Enum",
+                 ulConfig);
+    }
 
-    DPRINT1("PNP_HwProfFlags() done (returns %lx)\n", ret);
+    if (RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                      szKeyName,
+                      0,
+                      KEY_QUERY_VALUE,
+                      &hKey) != ERROR_SUCCESS)
+        return CR_REGISTRY_ERROR;
+
+    if (ulAction == PNP_GET_HWPROFFLAGS)
+    {
+         if (RegOpenKeyExW(hKey,
+                           pDeviceID,
+                           0,
+                           KEY_QUERY_VALUE,
+                           &hDeviceKey) != ERROR_SUCCESS)
+         {
+            *pulValue = 0;
+         }
+         else
+         {
+             dwSize = sizeof(DWORD);
+             if (!RegQueryValueExW(hDeviceKey,
+                                   L"CSConfigFlags",
+                                   NULL,
+                                   NULL,
+                                   (LPBYTE)pulValue,
+                                   &dwSize) != ERROR_SUCCESS)
+             {
+                 *pulValue = 0;
+             }
+
+             RegCloseKey(hDeviceKey);
+         }
+    }
+    else if (ulAction == PNP_SET_HWPROFFLAGS)
+    {
+        /* FIXME: not implemented yet */
+        ret = CR_CALL_NOT_IMPLEMENTED;
+    }
+
+    RegCloseKey(hKey);
 
     return ret;
 }
 
 
+/* Function 41 */
+DWORD PNP_GetHwProfInfo(
+    handle_t hBinding,
+    DWORD ulIndex,
+    HWPROFILEINFO *pHWProfileInfo,
+    DWORD ulProfileInfoSize,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
 /* Function 42 */
-CONFIGRET
-PNP_AddEmptyLogConf(handle_t BindingHandle,
-                    wchar_t *DeviceInstance,
-                    unsigned long ulPriority,
-                    unsigned long *pulLogConfTag,
-                    unsigned long ulFlags)
+DWORD PNP_AddEmptyLogConf(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulPriority,
+    DWORD *pulLogConfTag,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceInstance);
-    UNREFERENCED_PARAMETER(ulPriority);
-    UNREFERENCED_PARAMETER(ulFlags);
 
-    DPRINT1("PNP_AddEmptyLogConf() called\n");
+/* Function 43 */
+DWORD PNP_FreeLogConf(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfType,
+    DWORD ulLogConfTag,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
 
-    *pulLogConfTag = 0; /* FIXME */
+/* Function 44 */
+DWORD PNP_GetFirstLogConf(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfType,
+    DWORD *pulLogConfTag,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    DPRINT1("PNP_AddEmptyLogConf() done (returns %lx)\n", ret);
 
-    return ret;
+/* Function 45 */
+DWORD PNP_GetNextLogConf(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfType,
+    DWORD ulCurrentTag,
+    DWORD *pulNextTag,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
-/* Function 43 */
-CONFIGRET
-PNP_FreeLogConf(handle_t BindingHandle,
-                wchar_t *DeviceInstance,
-                unsigned long ulType,
-                unsigned long ulLogConfTag,
-                unsigned long ulFlags)
+/* Function 46 */
+DWORD PNP_GetLogConfPriority(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulType,
+    DWORD ulTag,
+    DWORD *pPriority,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceInstance);
-    UNREFERENCED_PARAMETER(ulType);
-    UNREFERENCED_PARAMETER(ulLogConfTag);
-    UNREFERENCED_PARAMETER(ulFlags);
 
-    DPRINT1("PNP_FreeLogConf() called\n");
+/* Function 47 */
+DWORD PNP_AddResDes(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfTag,
+    DWORD ulLogConfType,
+    RESOURCEID ResourceID,
+    DWORD *pulResourceTag,
+    BYTE *ResourceData,
+    PNP_RPC_BUFFER_SIZE ResourceLen,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
 
-    DPRINT1("PNP_FreeLogConf() done (returns %lx)\n", ret);
+/* Function 48 */
+DWORD PNP_FreeResDes(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfTag,
+    DWORD ulLogConfType,
+    RESOURCEID ResourceID,
+    DWORD ulResourceTag,
+    DWORD *pulPreviousResType,
+    DWORD *pulPreviousResTag,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    return ret;
+
+/* Function 49 */
+DWORD PNP_GetNextResDes(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfTag,
+    DWORD ulLogConfType,
+    RESOURCEID ResourceID,
+    DWORD ulResourceTag,
+    DWORD *pulNextResType,
+    DWORD *pulNextResTag,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
-/* Function 44 */
-CONFIGRET
-PNP_GetFirstLogConf(handle_t BindingHandle,
-                    wchar_t *DeviceInstance,
-                    unsigned long ulPriority,
-                    unsigned long *pulLogConfTag,
-                    unsigned long ulFlags)
+/* Function 50 */
+DWORD PNP_GetResDesData(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfTag,
+    DWORD ulLogConfType,
+    RESOURCEID ResourceID,
+    DWORD ulResourceTag,
+    BYTE *Buffer,
+    PNP_RPC_BUFFER_SIZE BufferLen,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceInstance);
-    UNREFERENCED_PARAMETER(ulPriority);
-    UNREFERENCED_PARAMETER(ulFlags);
 
-    DPRINT1("PNP_GetFirstLogConf() called\n");
+/* Function 51 */
+DWORD PNP_GetResDesDataSize(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfTag,
+    DWORD ulLogConfType,
+    RESOURCEID ResourceID,
+    DWORD ulResourceTag,
+    DWORD *pulSize,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    *pulLogConfTag = 0; /* FIXME */
 
-    DPRINT1("PNP_GetFirstLogConf() done (returns %lx)\n", ret);
+/* Function 52 */
+DWORD PNP_ModifyResDes(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    DWORD ulLogConfTag,
+    DWORD ulLogConfType,
+    RESOURCEID CurrentResourceID,
+    RESOURCEID NewResourceID,
+    DWORD ulResourceTag,
+    BYTE *ResourceData,
+    PNP_RPC_BUFFER_SIZE ResourceLen,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    return ret;
+
+/* Function 53 */
+DWORD PNP_DetectResourceConflict(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    RESOURCEID ResourceID,
+    BYTE *ResourceData,
+    PNP_RPC_BUFFER_SIZE ResourceLen,
+    BOOL *pbConflictDetected,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
-/* Function 45 */
-CONFIGRET
-PNP_GetNextLogConf(handle_t BindingHandle,
-                   wchar_t *DeviceInstance,
-                   unsigned long ulLogConfType,
-                   unsigned long ulCurrentTag,
-                   unsigned long *pulNextTag,
-                   unsigned long ulFlags)
+/* Function 54 */
+DWORD PNP_QueryResConfList(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    RESOURCEID ResourceID,
+    BYTE *ResourceData,
+    PNP_RPC_BUFFER_SIZE ResourceLen,
+    BYTE *Buffer,
+    PNP_RPC_BUFFER_SIZE BufferLen,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceInstance);
-    UNREFERENCED_PARAMETER(ulLogConfType);
-    UNREFERENCED_PARAMETER(ulCurrentTag);
-    UNREFERENCED_PARAMETER(ulFlags);
 
-    DPRINT1("PNP_GetNextLogConf() called\n");
+/* Function 55 */
+DWORD PNP_SetHwProf(
+    handle_t hBinding,
+    DWORD ulHardwareProfile,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    *pulNextTag = 0; /* FIXME */
 
-    DPRINT1("PNP_GetNextLogConf() done (returns %lx)\n", ret);
+/* Function 56 */
+DWORD PNP_QueryArbitratorFreeData(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    return ret;
+
+/* Function 57 */
+DWORD PNP_QueryArbitratorFreeSize(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
-/* Function 46 */
+/* Function 58 */
 CONFIGRET
-PNP_GetLogConfPriority(handle_t BindingHandle,
-                       wchar_t *DeviceInstance,
-                       unsigned long ulLogConfType,
-                       unsigned long ulCurrentTag,
-                       unsigned long *pPriority,
-                       unsigned long ulFlags)
+PNP_RunDetection(
+    handle_t hBinding,
+    DWORD ulFlags)
 {
-    CONFIGRET ret = CR_SUCCESS;
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(DeviceInstance);
-    UNREFERENCED_PARAMETER(ulLogConfType);
-    UNREFERENCED_PARAMETER(ulCurrentTag);
-    UNREFERENCED_PARAMETER(ulFlags);
 
-    DPRINT1("PNP_GetLogConfPriority() called\n");
+/* Function 59 */
+DWORD PNP_RegisterNotification(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
 
-    *pPriority = 0; /* FIXME */
+/* Function 60 */
+DWORD PNP_UnregisterNotification(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
 
-    DPRINT1("PNP_GetLogConfPriority() done (returns %lx)\n", ret);
 
-    return ret;
+/* Function 61 */
+DWORD PNP_GetCustomDevProp(
+    handle_t hBinding,
+    LPWSTR pDeviceID,
+    LPWSTR CustomPropName,
+    DWORD *pulRegDataType,
+    BYTE *Buffer,
+    PNP_RPC_STRING_LEN *pulTransferLen,
+    PNP_RPC_STRING_LEN *pulLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
-/* Function 58 */
-CONFIGRET
-PNP_RunDetection(handle_t BindingHandle,
-                 unsigned long Flags)
+/* Function 62 */
+DWORD PNP_GetVersionInternal(
+    handle_t hBinding,
+    WORD *pwVersion)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 63 */
+DWORD PNP_GetBlockedDriverInfo(
+    handle_t hBinding,
+    BYTE *Buffer,
+    PNP_RPC_BUFFER_SIZE *pulTransferLen,
+    PNP_RPC_BUFFER_SIZE *pulLength,
+    DWORD ulFlags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 64 */
+DWORD PNP_GetServerSideDeviceInstallFlags(
+    handle_t hBinding,
+    DWORD *pulSSDIFlags,
+    DWORD ulFlags)
 {
-    UNREFERENCED_PARAMETER(BindingHandle);
-    UNREFERENCED_PARAMETER(Flags);
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
 
-    DPRINT("PNP_RunDetection() called\n");
+/* Function 65 */
+DWORD PNP_GetObjectPropKeys(
+    handle_t hBinding,
+    LPWSTR ObjectName,
+    DWORD ObjectType,
+    LPWSTR PropertyCultureName,
+    PNP_PROP_COUNT *PropertyCount,
+    PNP_PROP_COUNT *TransferLen,
+    DEVPROPKEY *PropertyKeys,
+    DWORD Flags)
+{
+    UNIMPLEMENTED;
     return CR_CALL_NOT_IMPLEMENTED;
 }
 
 
-typedef BOOL (WINAPI *PDEV_INSTALL_W)(HWND, HINSTANCE, LPCWSTR, INT);
+/* Function 66 */
+DWORD PNP_GetObjectProp(
+    handle_t hBinding,
+    LPWSTR ObjectName,
+    DWORD ObjectType,
+    LPWSTR PropertyCultureName,
+    const DEVPROPKEY *PropertyKey,
+    DEVPROPTYPE *PropertyType,
+    PNP_PROP_SIZE *PropertySize,
+    PNP_PROP_SIZE *TransferLen,
+    BYTE *PropertyBuffer,
+    DWORD Flags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 67 */
+DWORD PNP_SetObjectProp(
+    handle_t hBinding,
+    LPWSTR ObjectName,
+    DWORD ObjectType,
+    LPWSTR PropertyCultureName,
+    const DEVPROPKEY *PropertyKey,
+    DEVPROPTYPE PropertyType,
+    PNP_PROP_SIZE PropertySize,
+    BYTE *PropertyBuffer,
+    DWORD Flags)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 68 */
+DWORD PNP_InstallDevInst(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 69 */
+DWORD PNP_ApplyPowerSettings(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 70 */
+DWORD PNP_DriverStoreAddDriverPackage(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 71 */
+DWORD PNP_DriverStoreDeleteDriverPackage(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 72 */
+DWORD PNP_RegisterServiceNotification(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 73 */
+DWORD PNP_SetActiveService(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+/* Function 74 */
+DWORD PNP_DeleteServiceDevices(
+    handle_t hBinding)
+{
+    UNIMPLEMENTED;
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
 
 static BOOL
 InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
 {
     PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
-    HMODULE hNewDev = NULL;
-    PDEV_INSTALL_W DevInstallW;
     NTSTATUS Status;
     BOOL DeviceInstalled = FALSE;
+    DWORD BytesWritten;
+    DWORD Value;
+    HANDLE hPipe = INVALID_HANDLE_VALUE;
+    LPVOID Environment = NULL;
+    PROCESS_INFORMATION ProcessInfo;
+    STARTUPINFOW StartupInfo;
+    UUID RandomUuid;
+
+    /* The following lengths are constant (see below), they cannot overflow */
+    WCHAR CommandLine[116];
+    WCHAR InstallEventName[73];
+    WCHAR PipeName[74];
+    WCHAR UuidString[39];
+
+    DPRINT("InstallDevice(%S, %d)\n", DeviceInstance, ShowWizard);
+
+    ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
 
     RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
                          DeviceInstance);
@@ -1503,31 +2077,121 @@ InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
                                (PVOID)&PlugPlayData,
                                sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
     if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("NtPlugPlayControl('%S') failed with status 0x%08lx\n", DeviceInstance, Status);
         return FALSE;
+    }
 
     if ((PlugPlayData.DeviceStatus & (DNF_STARTED | DNF_START_FAILED)) != 0)
+    {
         /* Device is already started, or disabled due to some problem. Don't install it */
+        DPRINT("No need to install '%S'\n", DeviceInstance);
         return TRUE;
+    }
 
-    /* Install device */
-    SetEnvironmentVariableW(L"USERPROFILE", L"."); /* FIXME: why is it needed? */
+    /* Create a random UUID for the named pipe */
+    UuidCreate(&RandomUuid);
+    swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
+        RandomUuid.Data1, RandomUuid.Data2, RandomUuid.Data3,
+        RandomUuid.Data4[0], RandomUuid.Data4[1], RandomUuid.Data4[2],
+        RandomUuid.Data4[3], RandomUuid.Data4[4], RandomUuid.Data4[5],
+        RandomUuid.Data4[6], RandomUuid.Data4[7]);
 
-    hNewDev = LoadLibraryW(L"newdev.dll");
-    if (!hNewDev)
+    /* Create the named pipe */
+    wcscpy(PipeName, L"\\\\.\\pipe\\PNP_Device_Install_Pipe_0.");
+    wcscat(PipeName, UuidString);
+    hPipe = CreateNamedPipeW(PipeName, PIPE_ACCESS_OUTBOUND, PIPE_TYPE_BYTE, 1, 512, 512, 0, NULL);
+
+    if(hPipe == INVALID_HANDLE_VALUE)
+    {
+        DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
         goto cleanup;
+    }
+
+    /* Launch rundll32 to call ClientSideInstallW */
+    wcscpy(CommandLine, L"rundll32.exe newdev.dll,ClientSideInstall ");
+    wcscat(CommandLine, PipeName);
+
+    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
+    StartupInfo.cb = sizeof(StartupInfo);
+
+    if(hUserToken)
+    {
+        /* newdev has to run under the environment of the current user */
+        if(!CreateEnvironmentBlock(&Environment, hUserToken, FALSE))
+        {
+            DPRINT1("CreateEnvironmentBlock failed with error %d\n", GetLastError());
+            goto cleanup;
+        }
+
+        if(!CreateProcessAsUserW(hUserToken, NULL, CommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT, Environment, NULL, &StartupInfo, &ProcessInfo))
+        {
+            DPRINT1("CreateProcessAsUserW failed with error %u\n", GetLastError());
+            goto cleanup;
+        }
+    }
+    else
+    {
+        /* FIXME: This is probably not correct, I guess newdev should never be run with SYSTEM privileges.
+
+           Still, we currently do that in 2nd stage setup and probably Console mode as well, so allow it here.
+           (ShowWizard is only set to FALSE for these two modes) */
+        ASSERT(!ShowWizard);
+
+        if(!CreateProcessW(NULL, CommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo))
+        {
+            DPRINT1("CreateProcessW failed with error %u\n", GetLastError());
+            goto cleanup;
+        }
+    }
 
-    DevInstallW = (PDEV_INSTALL_W)GetProcAddress(hNewDev, (LPCSTR)"DevInstallW");
-    if (!DevInstallW)
+    /* Wait for the function to connect to our pipe */
+    if(!ConnectNamedPipe(hPipe, NULL))
+    {
+        DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
         goto cleanup;
+    }
 
-    if (!DevInstallW(NULL, NULL, DeviceInstance, ShowWizard ? SW_SHOWNOACTIVATE : SW_HIDE))
+    /* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
+    wcscpy(InstallEventName, L"Global\\PNP_Device_Install_Event_0.");
+    wcscat(InstallEventName, UuidString);
+
+    Value = sizeof(InstallEventName);
+    WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
+    WriteFile(hPipe, InstallEventName, Value, &BytesWritten, NULL);
+
+    /* I couldn't figure out what the following value means under WinXP. It's usually 0 in my tests, but was also 5 once.
+       Therefore the following line is entirely ReactOS-specific. We use the value here to pass the ShowWizard variable. */
+    WriteFile(hPipe, &ShowWizard, sizeof(ShowWizard), &BytesWritten, NULL);
+
+    Value = (wcslen(DeviceInstance) + 1) * sizeof(WCHAR);
+    WriteFile(hPipe, &Value, sizeof(Value), &BytesWritten, NULL);
+    WriteFile(hPipe, DeviceInstance, Value, &BytesWritten, NULL);
+
+    /* Wait for newdev.dll to finish processing */
+    WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
+
+    /* The following check for success is probably not compatible to Windows, but should do its job */
+    if(!GetExitCodeProcess(ProcessInfo.hProcess, &Value))
+    {
+        DPRINT1("GetExitCodeProcess failed with error %u\n", GetLastError());
         goto cleanup;
+    }
 
-    DeviceInstalled = TRUE;
+    DeviceInstalled = Value;
 
 cleanup:
-    if (hNewDev != NULL)
-        FreeLibrary(hNewDev);
+    if(hPipe != INVALID_HANDLE_VALUE)
+        CloseHandle(hPipe);
+
+    if(Environment)
+        DestroyEnvironmentBlock(Environment);
+
+    if(ProcessInfo.hProcess)
+        CloseHandle(ProcessInfo.hProcess);
+
+    if(ProcessInfo.hThread)
+        CloseHandle(ProcessInfo.hThread);
 
     return DeviceInstalled;
 }
@@ -1628,7 +2292,7 @@ IsConsoleBoot(VOID)
         NextOption = wcschr(CurrentOption, L' ');
         if (NextOption)
             *NextOption = L'\0';
-        if (wcsicmp(CurrentOption, L"CONSOLE") == 0)
+        if (_wcsicmp(CurrentOption, L"CONSOLE") == 0)
         {
             DPRINT("Found %S. Switching to console boot\n", CurrentOption);
             ConsoleBoot = TRUE;
@@ -1659,9 +2323,9 @@ DeviceInstallThread(LPVOID lpParameter)
 
     UNREFERENCED_PARAMETER(lpParameter);
 
-    showWizard = !SetupIsActive() && !IsConsoleBoot();
+    WaitForSingleObject(hInstallEvent, INFINITE);
 
-    SetEnvironmentVariable(L"USERPROFILE", L"."); /* FIXME: why is it needed? */
+    showWizard = !SetupIsActive() && !IsConsoleBoot();
 
     while (TRUE)
     {
@@ -1716,7 +2380,8 @@ PnpEventThread(LPVOID lpParameter)
         if (Status == STATUS_BUFFER_TOO_SMALL)
         {
             PnpEventSize += 0x400;
-            PnpEvent = HeapReAlloc(GetProcessHeap(), 0, PnpEvent, PnpEventSize);
+            HeapFree(GetProcessHeap(), 0, PnpEvent);
+            PnpEvent = HeapAlloc(GetProcessHeap(), 0, PnpEventSize);
             if (PnpEvent == NULL)
                 return ERROR_OUTOFMEMORY;
             continue;
@@ -1730,31 +2395,44 @@ PnpEventThread(LPVOID lpParameter)
 
         /* Process the pnp event */
         DPRINT("Received PnP Event\n");
-        if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
+        if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ENUMERATED, &RpcStatus))
         {
             DeviceInstallParams* Params;
             DWORD len;
+            DWORD DeviceIdLength;
 
-            DPRINT("Device arrival event: %S\n", PnpEvent->TargetDevice.DeviceIds);
+            DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
 
-            /* Queue device install (will be dequeued by DeviceInstallThread */
-            len = FIELD_OFFSET(DeviceInstallParams, DeviceIds)
-                + wcslen(PnpEvent->TargetDevice.DeviceIds) * sizeof(WCHAR) + sizeof(UNICODE_NULL);
-            Params = HeapAlloc(GetProcessHeap(), 0, len);
-            if (Params)
+            DeviceIdLength = lstrlenW(PnpEvent->TargetDevice.DeviceIds);
+            if (DeviceIdLength)
             {
-                wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds);
+                /* Queue device install (will be dequeued by DeviceInstallThread */
+                len = FIELD_OFFSET(DeviceInstallParams, DeviceIds) + (DeviceIdLength + 1) * sizeof(WCHAR);
+                Params = HeapAlloc(GetProcessHeap(), 0, len);
+                if (Params)
+                {
+                    wcscpy(Params->DeviceIds, PnpEvent->TargetDevice.DeviceIds);
 #ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
-                InterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry);
+                    InterlockedPushEntrySList(&DeviceInstallListHead, &Params->ListEntry);
 #else
-                InsertTailList(&DeviceInstallListHead, &Params->ListEntry);
+                    InsertTailList(&DeviceInstallListHead, &Params->ListEntry);
 #endif
-                SetEvent(hDeviceInstallListNotEmpty);
+                    SetEvent(hDeviceInstallListNotEmpty);
+                }
             }
         }
+        else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
+        {
+            DPRINT("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
+            /* FIXME: ? */
+        }
         else
         {
-            DPRINT1("Unknown event\n");
+            DPRINT1("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
+                PnpEvent->EventGuid.Data1, PnpEvent->EventGuid.Data2, PnpEvent->EventGuid.Data3,
+                PnpEvent->EventGuid.Data4[0], PnpEvent->EventGuid.Data4[1], PnpEvent->EventGuid.Data4[2],
+                PnpEvent->EventGuid.Data4[3], PnpEvent->EventGuid.Data4[4], PnpEvent->EventGuid.Data4[5],
+                PnpEvent->EventGuid.Data4[6], PnpEvent->EventGuid.Data4[7]);
         }
 
         /* Dequeue the current pnp event and signal the next one */
@@ -1767,21 +2445,92 @@ PnpEventThread(LPVOID lpParameter)
 }
 
 
-static VOID CALLBACK
-ServiceMain(DWORD argc, LPTSTR *argv)
+static DWORD WINAPI
+ServiceControlHandler(DWORD dwControl,
+                      DWORD dwEventType,
+                      LPVOID lpEventData,
+                      LPVOID lpContext)
+{
+    /* FIXME */
+    DPRINT1("ServiceControlHandler() called (control code %lu)\n", dwControl);
+    return ERROR_SUCCESS;
+}
+
+
+static DWORD
+ServiceInit(VOID)
 {
     HANDLE hThread;
     DWORD dwThreadId;
+    DWORD dwError;
+    BOOLEAN OldValue;
+
+    /* We need this privilege for using CreateProcessAsUserW */
+    RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,
+                       TRUE,
+                       FALSE,
+                       &OldValue);
+
+    hInstallEvent = CreateEvent(NULL,
+                                TRUE,
+                                SetupIsActive()/*FALSE*/,
+                                NULL);
+    if (hInstallEvent == NULL)
+    {
+        dwError = GetLastError();
+        DPRINT1("Could not create the Install Event! (Error %lu)\n", dwError);
+        return dwError;
+    }
 
-    UNREFERENCED_PARAMETER(argc);
-    UNREFERENCED_PARAMETER(argv);
-
-    DPRINT("ServiceMain() called\n");
+    hDeviceInstallListNotEmpty = CreateEvent(NULL,
+                                             FALSE,
+                                             FALSE,
+                                             NULL);
+    if (hDeviceInstallListNotEmpty == NULL)
+    {
+        dwError = GetLastError();
+        DPRINT1("Could not create the Event! (Error %lu)\n", dwError);
+        return dwError;
+    }
 
     hNoPendingInstalls = CreateEventW(NULL,
                                       TRUE,
                                       FALSE,
                                       L"Global\\PnP_No_Pending_Install_Events");
+    if (hNoPendingInstalls == NULL)
+    {
+        dwError = GetLastError();
+        DPRINT1("Could not create the Event! (Error %lu)\n", dwError);
+        return dwError;
+    }
+
+#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
+    InitializeSListHead(&DeviceInstallListHead);
+#else
+    InitializeListHead(&DeviceInstallListHead);
+#endif
+
+    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                            L"System\\CurrentControlSet\\Enum",
+                            0,
+                            KEY_ALL_ACCESS,
+                            &hEnumKey);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError);
+        return dwError;
+    }
+
+    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                            L"System\\CurrentControlSet\\Control\\Class",
+                            0,
+                            KEY_ALL_ACCESS,
+                            &hClassKey);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError);
+        return dwError;
+    }
 
     hThread = CreateThread(NULL,
                            0,
@@ -1789,90 +2538,104 @@ ServiceMain(DWORD argc, LPTSTR *argv)
                            NULL,
                            0,
                            &dwThreadId);
-    if (hThread != NULL)
-        CloseHandle(hThread);
+    if (hThread == NULL)
+    {
+        return GetLastError();
+    }
+    CloseHandle(hThread);
 
     hThread = CreateThread(NULL,
                            0,
-                           DeviceInstallThread,
+                           RpcServerThread,
                            NULL,
                            0,
                            &dwThreadId);
-    if (hThread != NULL)
-        CloseHandle(hThread);
+    if (hThread == NULL)
+    {
+        return GetLastError();
+    }
+    CloseHandle(hThread);
 
     hThread = CreateThread(NULL,
                            0,
-                           RpcServerThread,
+                           DeviceInstallThread,
                            NULL,
                            0,
                            &dwThreadId);
-    if (hThread != NULL)
-        CloseHandle(hThread);
+    if (hThread == NULL)
+    {
+        return GetLastError();
+    }
+    CloseHandle(hThread);
 
-    DPRINT("ServiceMain() done\n");
+    return ERROR_SUCCESS;
 }
 
 
-int
-main(int argc, char *argv[])
+static VOID CALLBACK
+ServiceMain(DWORD argc,
+            LPWSTR *argv)
 {
+    SERVICE_STATUS ServiceStatus;
+    SERVICE_STATUS_HANDLE ServiceStatusHandle;
     DWORD dwError;
 
     UNREFERENCED_PARAMETER(argc);
     UNREFERENCED_PARAMETER(argv);
 
-    DPRINT("Umpnpmgr: main() started\n");
+    DPRINT("ServiceMain() called\n");
 
-    hInstallEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
-    if (hInstallEvent == NULL)
+    ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
+                                                        ServiceControlHandler,
+                                                        NULL);
+    if (!ServiceStatusHandle)
     {
         dwError = GetLastError();
-        DPRINT1("Could not create the Install Event! (Error %lu)\n", dwError);
-        return dwError;
+        DPRINT1("RegisterServiceCtrlHandlerW() failed! (Error %lu)\n", dwError);
+        return;
     }
 
-    hDeviceInstallListNotEmpty = CreateEvent(NULL, FALSE, FALSE, NULL);
-    if (hDeviceInstallListNotEmpty == NULL)
-    {
-        dwError = GetLastError();
-        DPRINT1("Could not create the Event! (Error %lu)\n", dwError);
-        return dwError;
-    }
+    ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+    ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
+    ServiceStatus.dwControlsAccepted = 0;
+    ServiceStatus.dwWin32ExitCode = NO_ERROR;
+    ServiceStatus.dwServiceSpecificExitCode = 0;
+    ServiceStatus.dwCheckPoint = 0;
+    ServiceStatus.dwWaitHint = 2000;
 
-#ifdef HAVE_SLIST_ENTRY_IMPLEMENTED
-    InitializeSListHead(&DeviceInstallListHead);
-#else
-    InitializeListHead(&DeviceInstallListHead);
-#endif
+    SetServiceStatus(ServiceStatusHandle,
+                     &ServiceStatus);
 
-    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-                            L"System\\CurrentControlSet\\Enum",
-                            0,
-                            KEY_ALL_ACCESS,
-                            &hEnumKey);
+    dwError = ServiceInit();
     if (dwError != ERROR_SUCCESS)
     {
-        DPRINT1("Could not open the Enum Key! (Error %lu)\n", dwError);
-        return dwError;
+        DPRINT1("Service stopped\n");
+        ServiceStatus.dwCurrentState = SERVICE_STOPPED;
     }
-
-    dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
-                            L"System\\CurrentControlSet\\Control\\Class",
-                            0,
-                            KEY_ALL_ACCESS,
-                            &hClassKey);
-    if (dwError != ERROR_SUCCESS)
+    else
     {
-        DPRINT1("Could not open the Class Key! (Error %lu)\n", dwError);
-        return dwError;
+        ServiceStatus.dwCurrentState = SERVICE_RUNNING;
     }
 
-    StartServiceCtrlDispatcher(ServiceTable);
+    SetServiceStatus(ServiceStatusHandle,
+                     &ServiceStatus);
+
+    DPRINT("ServiceMain() done\n");
+}
+
+
+int
+wmain(int argc,
+      WCHAR *argv[])
+{
+    UNREFERENCED_PARAMETER(argc);
+    UNREFERENCED_PARAMETER(argv);
+
+    DPRINT1("Umpnpmgr: main() started\n");
 
-    DPRINT("Umpnpmgr: main() done\n");
+    StartServiceCtrlDispatcherW(ServiceTable);
 
-    ExitThread(0);
+    DPRINT1("Umpnpmgr: main() done\n");
 
     return 0;
 }