Implement basic version of PNP_CreateKey.
[reactos.git] / reactos / base / services / umpnpmgr / umpnpmgr.c
index 23366e7..8dc8a16 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>
@@ -131,7 +135,7 @@ RpcServerThread(LPVOID lpParameter)
 }
 
 
-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);
 }
@@ -160,7 +164,7 @@ NtStatusToCrError(NTSTATUS Status)
 
 
 /* Function 0 */
-DWORD PNP_Function0(
+DWORD PNP_Disconnect(
     handle_t hBinding)
 {
     UNREFERENCED_PARAMETER(hBinding);
@@ -170,7 +174,7 @@ DWORD PNP_Function0(
 
 
 /* Function 1 */
-DWORD PNP_Function1(
+DWORD PNP_Connect(
     handle_t hBinding)
 {
     UNREFERENCED_PARAMETER(hBinding);
@@ -222,6 +226,7 @@ DWORD PNP_ReportLogOn(
     BOOL Admin,
     DWORD ProcessId)
 {
+    DWORD ReturnValue = CR_FAILURE;
     HANDLE hProcess;
 
     UNREFERENCED_PARAMETER(hBinding);
@@ -229,32 +234,38 @@ DWORD PNP_ReportLogOn(
 
     DPRINT("PNP_ReportLogOn(%u, %u) called\n", Admin, ProcessId);
 
-    if (hInstallEvent != NULL)
-        SetEvent(hInstallEvent);
-
     /* 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)
-        SetEvent(hInstallEvent);*/
+    if (hInstallEvent)
+        SetEvent(hInstallEvent);
 
-    return CR_SUCCESS;
+    ReturnValue = CR_SUCCESS;
+
+cleanup:
+    if(hProcess)
+        CloseHandle(hProcess);
+
+    return ReturnValue;
 }
 
 
@@ -308,6 +319,11 @@ DWORD PNP_GetRootDeviceInstance(
 
     DPRINT("PNP_GetRootDeviceInstance() called\n");
 
+    if (!pDeviceID)
+    {
+        ret = CR_INVALID_POINTER;
+        goto Done;
+    }
     if (ulLength < lstrlenW(szRootDeviceId) + 1)
     {
         ret = CR_BUFFER_SMALL;
@@ -651,11 +667,11 @@ DWORD PNP_GetDeviceRegProp(
             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;
@@ -815,8 +831,24 @@ DWORD PNP_CreateKey(
     DWORD samDesired,
     DWORD ulFlags)
 {
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
+    HKEY hKey = 0;
+
+    if (RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                        pszSubKey,
+                        0,
+                        NULL,
+                        0,
+                        KEY_ALL_ACCESS,
+                        NULL,
+                        &hKey,
+                        NULL))
+        return CR_REGISTRY_ERROR;
+
+    /* FIXME: Set security key */
+
+    RegCloseKey(hKey);
+
+    return CR_SUCCESS;
 }
 
 
@@ -891,9 +923,8 @@ DWORD PNP_GetClassName(
 
     DPRINT("PNP_GetClassName() called\n");
 
-    lstrcpyW(szKeyName, L"System\\CurrentControlSet\\Control\\Class");
-    lstrcatW(szKeyName, L"\\");
-    if(lstrlenW(pszClassGuid) < sizeof(szKeyName)/sizeof(WCHAR)-lstrlenW(szKeyName))
+    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;
 
@@ -1070,48 +1101,102 @@ DWORD PNP_CreateDevInst(
 }
 
 
+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)
+{
+    DPRINT("SetupDeviceInstance: not implemented\n");
+    /* FIXME */
+    return CR_CALL_NOT_IMPLEMENTED;
+}
+
+
+static CONFIGRET
+EnableDeviceInstance(LPWSTR pszDeviceInstance)
+{
+    PLUGPLAY_CONTROL_RESET_DEVICE_DATA ResetDeviceData;
+    CONFIGRET ret = CR_SUCCESS;
+    NTSTATUS Status;
+
+    DPRINT("Enable device instance\n");
+
+    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 */
-#define PNP_DEVINST_SETUP       0x3
-#define PNP_DEVINST_ENABLE      0x4
-#define PNP_DEVINST_REENUMERATE 0x7
 DWORD PNP_DeviceInstanceAction(
     handle_t hBinding,
-    DWORD ulMajorAction,
-    DWORD ulMinorAction,
+    DWORD ulAction,
+    DWORD ulFlags,
     LPWSTR pszDeviceInstance1,
     LPWSTR pszDeviceInstance2)
 {
     CONFIGRET ret = CR_SUCCESS;
 
     UNREFERENCED_PARAMETER(hBinding);
-    UNREFERENCED_PARAMETER(ulMinorAction);
-    UNREFERENCED_PARAMETER(pszDeviceInstance1);
-    UNREFERENCED_PARAMETER(pszDeviceInstance2);
 
     DPRINT("PNP_DeviceInstanceAction() called\n");
 
-    switch (ulMajorAction)
+    switch (ulAction)
     {
+        case PNP_DEVINST_MOVE:
+            ret = MoveDeviceInstance(pszDeviceInstance1,
+                                     pszDeviceInstance2);
+            break;
+
         case PNP_DEVINST_SETUP:
-            DPRINT("Setup device instance\n");
-            /* FIXME */
-            ret = CR_CALL_NOT_IMPLEMENTED;
+            ret = SetupDeviceInstance(pszDeviceInstance1,
+                                      ulFlags);
             break;
 
         case PNP_DEVINST_ENABLE:
-            DPRINT("Enable device instance\n");
-            /* FIXME */
-            ret = CR_CALL_NOT_IMPLEMENTED;
+            ret = EnableDeviceInstance(pszDeviceInstance1);
+            break;
+
+        case PNP_DEVINST_DISABLE:
+            ret = DisableDeviceInstance(pszDeviceInstance1);
             break;
 
         case PNP_DEVINST_REENUMERATE:
-            DPRINT("Reenumerate device instance\n");
-            /* FIXME */
-            ret = CR_CALL_NOT_IMPLEMENTED;
+            ret = ReenumerateDeviceInstance(pszDeviceInstance1);
             break;
 
         default:
-            DPRINT1("Unknown function %lu\n", ulMajorAction);
+            DPRINT1("Unknown device action %lu: not implemented\n", ulAction);
             ret = CR_CALL_NOT_IMPLEMENTED;
     }
 
@@ -1250,7 +1335,8 @@ DWORD PNP_AddID(
     HKEY hDeviceKey;
     LPWSTR pszSubKey;
     DWORD dwDeviceIdListSize;
-    WCHAR szDeviceIdList[512];
+    DWORD dwNewDeviceIdSize;
+    WCHAR * pszDeviceIdList = NULL;
 
     UNREFERENCED_PARAMETER(hBinding);
 
@@ -1271,12 +1357,40 @@ DWORD PNP_AddID(
 
     pszSubKey = (ulFlags & CM_ADD_ID_COMPATIBLE) ? L"CompatibleIDs" : L"HardwareID";
 
-    dwDeviceIdListSize = 512 * sizeof(WCHAR);
     if (RegQueryValueExW(hDeviceKey,
                          pszSubKey,
                          NULL,
                          NULL,
-                         (LPBYTE)szDeviceIdList,
+                         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;
+    }
+
+    if (RegQueryValueExW(hDeviceKey,
+                         pszSubKey,
+                         NULL,
+                         NULL,
+                         (LPBYTE)pszDeviceIdList,
                          &dwDeviceIdListSize) != ERROR_SUCCESS)
     {
         DPRINT("Failed to query the desired ID string!\n");
@@ -1285,7 +1399,7 @@ DWORD PNP_AddID(
     }
 
     /* Check whether the device ID is already in use */
-    if (CheckForDeviceId(szDeviceIdList, pszDeviceID))
+    if (CheckForDeviceId(pszDeviceIdList, pszDeviceID))
     {
         DPRINT("Device ID was found in the ID string!\n");
         ret = CR_SUCCESS;
@@ -1293,13 +1407,13 @@ DWORD PNP_AddID(
     }
 
     /* Append the Device ID */
-    AppendDeviceId(szDeviceIdList, &dwDeviceIdListSize, pszID);
+    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");
@@ -1308,6 +1422,8 @@ DWORD PNP_AddID(
 
 Done:
     RegCloseKey(hDeviceKey);
+    if (pszDeviceIdList)
+        HeapFree(GetProcessHeap(), 0, pszDeviceIdList);
 
     DPRINT("PNP_AddID() done (returns %lx)\n", ret);
 
@@ -1427,8 +1543,70 @@ DWORD PNP_HwProfFlags(
     DWORD ulNameLength,
     DWORD ulFlags)
 {
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
+    CONFIGRET ret = CR_SUCCESS;
+    WCHAR szKeyName[MAX_PATH];
+    HKEY hKey;
+    HKEY hDeviceKey;
+    DWORD dwSize;
+
+    UNREFERENCED_PARAMETER(hBinding);
+
+    DPRINT("PNP_HwProfFlags() called\n");
+
+    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);
+    }
+
+    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;
 }
 
 
@@ -1646,8 +1824,10 @@ DWORD PNP_QueryResConfList(
 
 
 /* Function 55 */
-DWORD PNP_Function55(
-    handle_t hBinding)
+DWORD PNP_SetHwProf(
+    handle_t hBinding,
+    DWORD ulHardwareProfile,
+    DWORD ulFlags)
 {
     UNIMPLEMENTED;
     return CR_CALL_NOT_IMPLEMENTED;
@@ -1655,7 +1835,7 @@ DWORD PNP_Function55(
 
 
 /* Function 56 */
-DWORD PNP_Function56(
+DWORD PNP_QueryArbitratorFreeData(
     handle_t hBinding)
 {
     UNIMPLEMENTED;
@@ -1664,7 +1844,7 @@ DWORD PNP_Function56(
 
 
 /* Function 57 */
-DWORD PNP_Function57(
+DWORD PNP_QueryArbitratorFreeSize(
     handle_t hBinding)
 {
     UNIMPLEMENTED;
@@ -1675,7 +1855,7 @@ DWORD PNP_Function57(
 /* Function 58 */
 CONFIGRET
 PNP_RunDetection(
-    handle_t BindingHandle,
+    handle_t hBinding,
     DWORD ulFlags)
 {
     UNIMPLEMENTED;
@@ -1684,7 +1864,7 @@ PNP_RunDetection(
 
 
 /* Function 59 */
-DWORD PNP_Function59(
+DWORD PNP_RegisterNotification(
     handle_t hBinding)
 {
     UNIMPLEMENTED;
@@ -1693,7 +1873,7 @@ DWORD PNP_Function59(
 
 
 /* Function 60 */
-DWORD PNP_Function60(
+DWORD PNP_UnregisterNotification(
     handle_t hBinding)
 {
     UNIMPLEMENTED;
@@ -1802,19 +1982,93 @@ DWORD PNP_SetObjectProp(
 }
 
 
-typedef BOOL (WINAPI *PDEV_INSTALL_W)(HWND, HINSTANCE, LPCWSTR, INT);
+/* 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);
     PlugPlayData.Operation = 0; /* Get status */
@@ -1836,34 +2090,109 @@ InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
         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]);
+
+    /* 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);
 
-    hNewDev = LoadLibraryW(L"newdev.dll");
-    if (!hNewDev)
+    if(hPipe == INVALID_HANDLE_VALUE)
     {
-        DPRINT1("Unable to load newdev.dll\n");
+        DPRINT1("CreateNamedPipeW failed with error %u\n", GetLastError());
         goto cleanup;
     }
 
-    DevInstallW = (PDEV_INSTALL_W)GetProcAddress(hNewDev, (LPCSTR)"DevInstallW");
-    if (!DevInstallW)
+    /* 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)
     {
-        DPRINT1("'DevInstallW' not found in newdev.dll\n");
+        /* 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;
+        }
+    }
+
+    /* 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("DevInstallW('%S') failed\n", DeviceInstance);
+        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;
 }
@@ -1964,7 +2293,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;
@@ -2067,31 +2396,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 */
@@ -2115,11 +2457,6 @@ ServiceMain(DWORD argc, LPTSTR *argv)
 
     DPRINT("ServiceMain() called\n");
 
-    hNoPendingInstalls = CreateEventW(NULL,
-                                      TRUE,
-                                      FALSE,
-                                      L"Global\\PnP_No_Pending_Install_Events");
-
     hThread = CreateThread(NULL,
                            0,
                            PnpEventThread,
@@ -2131,7 +2468,7 @@ ServiceMain(DWORD argc, LPTSTR *argv)
 
     hThread = CreateThread(NULL,
                            0,
-                           DeviceInstallThread,
+                           RpcServerThread,
                            NULL,
                            0,
                            &dwThreadId);
@@ -2140,7 +2477,7 @@ ServiceMain(DWORD argc, LPTSTR *argv)
 
     hThread = CreateThread(NULL,
                            0,
-                           RpcServerThread,
+                           DeviceInstallThread,
                            NULL,
                            0,
                            &dwThreadId);
@@ -2152,8 +2489,9 @@ ServiceMain(DWORD argc, LPTSTR *argv)
 
 
 int
-main(int argc, char *argv[])
+wmain(int argc, WCHAR *argv[])
 {
+    BOOLEAN OldValue;
     DWORD dwError;
 
     UNREFERENCED_PARAMETER(argc);
@@ -2161,6 +2499,9 @@ main(int argc, char *argv[])
 
     DPRINT("Umpnpmgr: main() started\n");
 
+    /* We need this privilege for using CreateProcessAsUserW */
+    RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue);
+
     hInstallEvent = CreateEvent(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
     if (hInstallEvent == NULL)
     {
@@ -2177,6 +2518,17 @@ main(int argc, char *argv[])
         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