[UMPNPMGR]
[reactos.git] / reactos / base / services / umpnpmgr / umpnpmgr.c
index fb04757..86da35e 100644 (file)
  */
 
 /* INCLUDES *****************************************************************/
+
 //#define HAVE_SLIST_ENTRY_IMPLEMENTED
 #define WIN32_NO_STATUS
-#include <windows.h>
+#define _INC_WINDOWS
+#define COM_NO_WINDOWS_H
+#include <stdarg.h>
+#include <windef.h>
+#include <winbase.h>
+#include <winreg.h>
+#include <winsvc.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_s.h"
+#include <shlwapi.h>
+#include <pnp_s.h>
 
 #define NDEBUG
 #include <debug.h>
 
 /* GLOBALS ******************************************************************/
 
-static VOID CALLBACK ServiceMain(DWORD argc, LPWSTR *argv);
 static WCHAR ServiceName[] = L"PlugPlay";
-static SERVICE_TABLE_ENTRYW ServiceTable[] =
-{
-    {ServiceName, ServiceMain},
-    {NULL, NULL}
-};
 
 static SERVICE_STATUS_HANDLE ServiceStatusHandle;
 static SERVICE_STATUS ServiceStatus;
@@ -101,7 +97,7 @@ RpcServerThread(LPVOID lpParameter)
     DPRINT("RpcServerThread() called\n");
 
 #if 0
-    /* XP-compatible protocol sequence/endpoint */
+    /* 2k/XP/2k3-compatible protocol sequence/endpoint */
     Status = RpcServerUseProtseqEpW(L"ncacn_np",
                                     20,
                                     L"\\pipe\\ntsvcs",
@@ -112,7 +108,7 @@ RpcServerThread(LPVOID lpParameter)
         DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
 #endif
 
-    /* Vista-compatible protocol sequence/endpoint */
+    /* Vista/7-compatible protocol sequence/endpoint */
     Status = RpcServerUseProtseqEpW(L"ncacn_np",
                                     20,
                                     L"\\pipe\\plugplay",
@@ -730,14 +726,17 @@ DWORD PNP_GetDeviceRegProp(
                                   pulRegDataType,
                                   Buffer,
                                   pulLength);
-        if (lError == ERROR_MORE_DATA)
-        {
-            ret = CR_BUFFER_SMALL;
-        }
-        else
+        if (lError != ERROR_SUCCESS)
         {
-            *pulLength = 0;
-            ret = CR_NO_SUCH_VALUE;
+            if (lError == ERROR_MORE_DATA)
+            {
+                ret = CR_BUFFER_SMALL;
+            }
+            else
+            {
+                *pulLength = 0;
+                ret = CR_NO_SUCH_VALUE;
+            }
         }
     }
     else
@@ -746,7 +745,7 @@ DWORD PNP_GetDeviceRegProp(
         RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
                              pDeviceID);
         PlugPlayData.Buffer = Buffer;
-        PlugPlayData.BufferSize = *pulTransferLen;
+        PlugPlayData.BufferSize = *pulLength;
 
         switch (ulProperty)
         {
@@ -826,8 +825,8 @@ DWORD PNP_GetDeviceRegProp(
         }
     }
 
-done:;
-    *pulTransferLen = (ret != CR_SUCCESS) ? 0 : *pulLength;
+done:
+    *pulTransferLen = (ret == CR_SUCCESS) ? *pulLength : 0;
 
     if (hKey != NULL)
         RegCloseKey(hKey);
@@ -1139,7 +1138,7 @@ DWORD PNP_DeleteClassKey(
 
     if (ulFlags & CM_DELETE_CLASS_SUBKEYS)
     {
-        if (RegDeleteTreeW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
+        if (SHDeleteKeyW(hClassKey, pszClassGuid) != ERROR_SUCCESS)
             ret = CR_REGISTRY_ERROR;
     }
     else
@@ -1234,8 +1233,114 @@ DWORD PNP_GetClassRegProp(
     PNP_RPC_STRING_LEN *pulLength,
     DWORD ulFlags)
 {
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
+    CONFIGRET ret = CR_SUCCESS;
+    LPWSTR lpValueName = NULL;
+    HKEY hInstKey = NULL;
+    HKEY hPropKey = NULL;
+    LONG lError;
+
+    UNREFERENCED_PARAMETER(hBinding);
+
+    DPRINT("PNP_GetClassRegProp() called\n");
+
+    if (pulTransferLen == NULL || pulLength == NULL)
+    {
+        ret = CR_INVALID_POINTER;
+        goto done;
+    }
+
+    if (ulFlags != 0)
+    {
+        ret = CR_INVALID_FLAG;
+        goto done;
+    }
+
+    if (*pulLength < *pulTransferLen)
+        *pulLength = *pulTransferLen;
+
+    *pulTransferLen = 0;
+
+    switch (ulProperty)
+    {
+        case CM_CRP_SECURITY:
+            lpValueName = L"Security";
+            break;
+
+        case CM_CRP_DEVTYPE:
+            lpValueName = L"DeviceType";
+            break;
+
+        case CM_CRP_EXCLUSIVE:
+            lpValueName = L"Exclusive";
+            break;
+
+        case CM_CRP_CHARACTERISTICS:
+            lpValueName = L"DeviceCharacteristics";
+            break;
+
+        default:
+            ret = CR_INVALID_PROPERTY;
+            goto done;
+    }
+
+    DPRINT("Value name: %S\n", lpValueName);
+
+    lError = RegOpenKeyExW(hClassKey,
+                           pszClassGuid,
+                           0,
+                           KEY_READ,
+                           &hInstKey);
+    if (lError != ERROR_SUCCESS)
+    {
+        *pulLength = 0;
+        ret = CR_NO_SUCH_REGISTRY_KEY;
+        goto done;
+    }
+
+    lError = RegOpenKeyExW(hInstKey,
+                           L"Properties",
+                           0,
+                           KEY_READ,
+                           &hPropKey);
+    if (lError != ERROR_SUCCESS)
+    {
+        *pulLength = 0;
+        ret = CR_NO_SUCH_REGISTRY_KEY;
+        goto done;
+    }
+
+    lError = RegQueryValueExW(hPropKey,
+                              lpValueName,
+                              NULL,
+                              pulRegDataType,
+                              Buffer,
+                              pulLength);
+    if (lError != ERROR_SUCCESS)
+    {
+        if (lError == ERROR_MORE_DATA)
+        {
+            ret = CR_BUFFER_SMALL;
+        }
+        else
+        {
+            *pulLength = 0;
+            ret = CR_NO_SUCH_VALUE;
+        }
+    }
+
+done:
+    if (ret == CR_SUCCESS)
+        *pulTransferLen = *pulLength;
+
+    if (hPropKey != NULL)
+        RegCloseKey(hPropKey);
+
+    if (hInstKey != NULL)
+        RegCloseKey(hInstKey);
+
+    DPRINT("PNP_GetClassRegProp() done (returns %lx)\n", ret);
+
+    return ret;
 }
 
 
@@ -1264,19 +1369,19 @@ DWORD PNP_SetClassRegProp(
 
     switch (ulProperty)
     {
-        case CM_DRP_SECURITY:
+        case CM_CRP_SECURITY:
             lpValueName = L"Security";
             break;
 
-        case CM_DRP_DEVTYPE:
+        case CM_CRP_DEVTYPE:
             lpValueName = L"DeviceType";
             break;
 
-        case CM_DRP_EXCLUSIVE:
+        case CM_CRP_EXCLUSIVE:
             lpValueName = L"Exclusive";
             break;
 
-        case CM_DRP_CHARACTERISTICS:
+        case CM_CRP_CHARACTERISTICS:
             lpValueName = L"DeviceCharacteristics";
             break;
 
@@ -1328,7 +1433,7 @@ DWORD PNP_SetClassRegProp(
             ret = CR_REGISTRY_ERROR;
     }
 
-done:;
+done:
     if (hPropKey != NULL)
         RegCloseKey(hPropKey);
 
@@ -1504,16 +1609,42 @@ DWORD PNP_CreateDevInst(
 
     if (ulFlags & CM_CREATE_DEVNODE_GENERATE_ID)
     {
-        /* FIXME */
-        DPRINT1("CM_CREATE_DEVNODE_GENERATE_ID support not implemented yet!\n", ret);
-        ret = CR_CALL_NOT_IMPLEMENTED;
-        goto done;
-    }
+        WCHAR szGeneratedInstance[MAX_DEVICE_ID_LEN];
+        DWORD dwInstanceNumber;
+
+        /* Generated ID is: Root\<Device ID>\<Instance number> */
+        dwInstanceNumber = 0;
+        do
+        {
+            swprintf(szGeneratedInstance, L"Root\\%ls\\%04lu",
+                     pszDeviceID, dwInstanceNumber);
 
-    /* Create the device instance */
-    ret = CreateDeviceInstance(pszDeviceID);
+            /* Try to create a device instance with this ID */
+            ret = CreateDeviceInstance(szGeneratedInstance);
+
+            dwInstanceNumber++;
+        }
+        while (ret == CR_ALREADY_SUCH_DEVINST);
+        
+        if (ret == CR_SUCCESS)
+        {
+            /* pszDeviceID is an out parameter too for generated IDs */
+            if (wcslen(szGeneratedInstance) > ulLength)
+            {
+                ret = CR_BUFFER_SMALL;
+            }
+            else
+            {
+                wcscpy(pszDeviceID, szGeneratedInstance);
+            }
+        }
+    }
+    else
+    {
+        /* Create the device instance */
+        ret = CreateDeviceInstance(pszDeviceID);
+    }
 
-done:;
     DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret);
 
     return ret;
@@ -1980,7 +2111,7 @@ DWORD PNP_HwProfFlags(
     else
     {
         swprintf(szKeyName,
-                 L"System\\CurrentControlSet\\HardwareProfiles\\%04u\\System\\CurrentControlSet\\Enum",
+                 L"System\\CurrentControlSet\\HardwareProfiles\\%04lu\\System\\CurrentControlSet\\Enum",
                  ulConfig);
     }
 
@@ -2037,8 +2168,128 @@ DWORD PNP_GetHwProfInfo(
     DWORD ulProfileInfoSize,
     DWORD ulFlags)
 {
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
+    WCHAR szProfileName[5];
+    HKEY hKeyConfig = NULL;
+    HKEY hKeyProfiles = NULL;
+    HKEY hKeyProfile = NULL;
+    DWORD dwDisposition;
+    DWORD dwSize;
+    LONG lError;
+    CONFIGRET ret = CR_SUCCESS;
+
+    UNREFERENCED_PARAMETER(hBinding);
+
+    DPRINT("PNP_GetHwProfInfo() called\n");
+
+    if (ulProfileInfoSize == 0)
+    {
+        ret = CR_INVALID_DATA;
+        goto done;
+    }
+
+    if (ulFlags != 0)
+    {
+        ret = CR_INVALID_FLAG;
+        goto done;
+    }
+
+    /* Initialize the profile information */
+    pHWProfileInfo->HWPI_ulHWProfile = 0;
+    pHWProfileInfo->HWPI_szFriendlyName[0] = 0;
+    pHWProfileInfo->HWPI_dwFlags = 0;
+
+    /* Open the 'IDConfigDB' key */
+    lError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+                             L"System\\CurrentControlSet\\Control\\IDConfigDB",
+                             0,
+                             NULL,
+                             REG_OPTION_NON_VOLATILE,
+                             KEY_QUERY_VALUE,
+                             NULL,
+                             &hKeyConfig,
+                             &dwDisposition);
+    if (lError != ERROR_SUCCESS)
+    {
+        ret = CR_REGISTRY_ERROR;
+        goto done;
+    }
+
+    /* Open the 'Hardware Profiles' subkey */
+    lError = RegCreateKeyExW(hKeyConfig,
+                             L"Hardware Profiles",
+                             0,
+                             NULL,
+                             REG_OPTION_NON_VOLATILE,
+                             KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE,
+                             NULL,
+                             &hKeyProfiles,
+                             &dwDisposition);
+    if (lError != ERROR_SUCCESS)
+    {
+        ret = CR_REGISTRY_ERROR;
+        goto done;
+    }
+
+    if (ulIndex == (ULONG)-1)
+    {
+        dwSize = sizeof(ULONG);
+        lError = RegQueryValueExW(hKeyConfig,
+                                  L"CurrentConfig",
+                                  NULL,
+                                  NULL,
+                                  (LPBYTE)&pHWProfileInfo->HWPI_ulHWProfile,
+                                  &dwSize);
+        if (lError != ERROR_SUCCESS)
+        {
+            pHWProfileInfo->HWPI_ulHWProfile = 0;
+            ret = CR_REGISTRY_ERROR;
+            goto done;
+        }
+    }
+    else
+    {
+        /* FIXME: not implemented yet */
+        ret = CR_CALL_NOT_IMPLEMENTED;
+        goto done;
+    }
+
+    swprintf(szProfileName, L"%04lu", pHWProfileInfo->HWPI_ulHWProfile);
+
+    lError = RegOpenKeyExW(hKeyProfiles,
+                           szProfileName,
+                           0,
+                           KEY_QUERY_VALUE,
+                           &hKeyProfile);
+    if (lError != ERROR_SUCCESS)
+    {
+        ret = CR_REGISTRY_ERROR;
+        goto done;
+    }
+
+    dwSize = sizeof(pHWProfileInfo->HWPI_szFriendlyName);
+    lError = RegQueryValueExW(hKeyProfile,
+                              L"FriendlyName",
+                              NULL,
+                              NULL,
+                              (LPBYTE)&pHWProfileInfo->HWPI_szFriendlyName,
+                              &dwSize);
+    if (lError != ERROR_SUCCESS)
+    {
+        ret = CR_REGISTRY_ERROR;
+        goto done;
+    }
+
+done:
+    if (hKeyProfile != NULL)
+        RegCloseKey(hKeyProfile);
+
+    if (hKeyProfiles != NULL)
+        RegCloseKey(hKeyProfiles);
+
+    if (hKeyConfig != NULL)
+        RegCloseKey(hKeyConfig);
+
+    return ret;
 }
 
 
@@ -2319,8 +2570,86 @@ DWORD PNP_GetCustomDevProp(
     PNP_RPC_STRING_LEN *pulLength,
     DWORD ulFlags)
 {
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
+    HKEY hDeviceKey = NULL;
+    HKEY hParamKey = NULL;
+    LONG lError;
+    CONFIGRET ret = CR_SUCCESS;
+
+    UNREFERENCED_PARAMETER(hBinding);
+
+    DPRINT("PNP_GetCustomDevProp() called\n");
+
+    if (pulTransferLen == NULL || pulLength == NULL)
+    {
+        ret = CR_INVALID_POINTER;
+        goto done;
+    }
+
+    if (ulFlags & ~CM_CUSTOMDEVPROP_BITS)
+    {
+        ret = CR_INVALID_FLAG;
+        goto done;
+    }
+
+    if (*pulLength < *pulTransferLen)
+        *pulLength = *pulTransferLen;
+
+    *pulTransferLen = 0;
+
+    lError = RegOpenKeyExW(hEnumKey,
+                           pDeviceID,
+                           0,
+                           KEY_READ,
+                           &hDeviceKey);
+    if (lError != ERROR_SUCCESS)
+    {
+        ret = CR_REGISTRY_ERROR;
+        goto done;
+    }
+
+    lError = RegOpenKeyExW(hDeviceKey,
+                           L"Device Parameters",
+                           0,
+                           KEY_READ,
+                           &hParamKey);
+    if (lError != ERROR_SUCCESS)
+    {
+        ret = CR_REGISTRY_ERROR;
+        goto done;
+    }
+
+    lError = RegQueryValueExW(hParamKey,
+                              CustomPropName,
+                              NULL,
+                              pulRegDataType,
+                              Buffer,
+                              pulLength);
+    if (lError != ERROR_SUCCESS)
+    {
+        if (lError == ERROR_MORE_DATA)
+        {
+            ret = CR_BUFFER_SMALL;
+        }
+        else
+        {
+            *pulLength = 0;
+            ret = CR_NO_SUCH_VALUE;
+        }
+    }
+
+done:
+    if (ret == CR_SUCCESS)
+        *pulTransferLen = *pulLength;
+
+    if (hParamKey != NULL)
+        RegCloseKey(hParamKey);
+
+    if (hDeviceKey != NULL)
+        RegCloseKey(hDeviceKey);
+
+    DPRINT("PNP_GetCustomDevProp() done (returns %lx)\n", ret);
+
+    return ret;
 }
 
 
@@ -2329,6 +2658,8 @@ DWORD PNP_GetVersionInternal(
     handle_t hBinding,
     WORD *pwVersion)
 {
+    *pwVersion = 0x501;
+    return CR_SUCCESS;
     UNIMPLEMENTED;
     return CR_CALL_NOT_IMPLEMENTED;
 }
@@ -2456,7 +2787,9 @@ DWORD PNP_RegisterServiceNotification(
 
 /* Function 73 */
 DWORD PNP_SetActiveService(
-    handle_t hBinding)
+    handle_t hBinding,
+    LPWSTR pszFilter,
+    DWORD ulFlags)
 {
     UNIMPLEMENTED;
     return CR_CALL_NOT_IMPLEMENTED;
@@ -2502,7 +2835,7 @@ InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
                       &DeviceKey) == ERROR_SUCCESS)
     {
         if (RegQueryValueExW(DeviceKey,
-                             L"ClassGUID",
+                             L"Class",
                              NULL,
                              NULL,
                              NULL,
@@ -2577,8 +2910,11 @@ InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
     /* Wait for the function to connect to our pipe */
     if(!ConnectNamedPipe(hPipe, NULL))
     {
-        DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
-        goto cleanup;
+        if (GetLastError() != ERROR_PIPE_CONNECTED)
+        {
+            DPRINT1("ConnectNamedPipe failed with error %u\n", GetLastError());
+            goto cleanup;
+        }
     }
 
     /* Pass the data. The following output is partly compatible to Windows XP SP2 (researched using a modified newdev.dll to log this stuff) */
@@ -2716,7 +3052,7 @@ IsConsoleBoot(VOID)
     if (rc != ERROR_SUCCESS)
         goto cleanup;
 
-    /* Check for CMDCONS in SystemStartOptions */
+    /* Check for CONSOLE switch in SystemStartOptions */
     CurrentOption = SystemStartOptions;
     while (CurrentOption)
     {
@@ -2832,7 +3168,7 @@ PnpEventThread(LPVOID lpParameter)
             DWORD len;
             DWORD DeviceIdLength;
 
-            DPRINT1("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
+            DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
 
             DeviceIdLength = lstrlenW(PnpEvent->TargetDevice.DeviceIds);
             if (DeviceIdLength)
@@ -2854,9 +3190,33 @@ PnpEventThread(LPVOID lpParameter)
         }
         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
         {
-            DPRINT1("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
+            DPRINT("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
             /* FIXME: ? */
         }
+        else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_EJECT_VETOED, &RpcStatus))
+        {
+            DPRINT1("Eject vetoed: %S\n", PnpEvent->TargetDevice.DeviceIds);
+        }
+        else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_KERNEL_INITIATED_EJECT, &RpcStatus))
+        {
+            DPRINT1("Kernel initiated eject: %S\n", PnpEvent->TargetDevice.DeviceIds);
+        }
+        else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_SAFE_REMOVAL, &RpcStatus))
+        {
+            DPRINT1("Safe removal: %S\n", PnpEvent->TargetDevice.DeviceIds);
+        }
+        else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_SURPRISE_REMOVAL, &RpcStatus))
+        {
+            DPRINT1("Surprise removal: %S\n", PnpEvent->TargetDevice.DeviceIds);
+        }
+        else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_REMOVAL_VETOED, &RpcStatus))
+        {
+            DPRINT1("Removal vetoed: %S\n", PnpEvent->TargetDevice.DeviceIds);
+        }
+        else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_REMOVE_PENDING, &RpcStatus))
+        {
+            DPRINT1("Removal pending: %S\n", PnpEvent->TargetDevice.DeviceIds);
+        }
         else
         {
             DPRINT1("Unknown event, GUID {%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}\n",
@@ -2911,6 +3271,8 @@ ServiceControlHandler(DWORD dwControl,
     {
         case SERVICE_CONTROL_STOP:
             DPRINT1("  SERVICE_CONTROL_STOP received\n");
+            /* Stop listening to RPC Messages */
+            RpcMgmtStopServerListening(NULL);
             UpdateServiceStatus(SERVICE_STOPPED);
             return ERROR_SUCCESS;
 
@@ -2932,6 +3294,8 @@ ServiceControlHandler(DWORD dwControl,
 
         case SERVICE_CONTROL_SHUTDOWN:
             DPRINT1("  SERVICE_CONTROL_SHUTDOWN received\n");
+            /* Stop listening to RPC Messages */
+            RpcMgmtStopServerListening(NULL);
             UpdateServiceStatus(SERVICE_STOPPED);
             return ERROR_SUCCESS;
 
@@ -2942,7 +3306,7 @@ ServiceControlHandler(DWORD dwControl,
 }
 
 
-static VOID CALLBACK
+VOID WINAPI
 ServiceMain(DWORD argc, LPTSTR *argv)
 {
     HANDLE hThread;
@@ -2996,22 +3360,18 @@ ServiceMain(DWORD argc, LPTSTR *argv)
     DPRINT("ServiceMain() done\n");
 }
 
-
-int
-wmain(int argc, WCHAR *argv[])
+static DWORD
+InitializePnPManager(VOID)
 {
     BOOLEAN OldValue;
     DWORD dwError;
 
-    UNREFERENCED_PARAMETER(argc);
-    UNREFERENCED_PARAMETER(argv);
-
-    DPRINT("Umpnpmgr: main() started\n");
+    DPRINT("UMPNPMGR: InitializePnPManager() started\n");
 
     /* We need this privilege for using CreateProcessAsUserW */
     RtlAdjustPrivilege(SE_ASSIGNPRIMARYTOKEN_PRIVILEGE, TRUE, FALSE, &OldValue);
 
-    hInstallEvent = CreateEvent(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
+    hInstallEvent = CreateEventW(NULL, TRUE, SetupIsActive()/*FALSE*/, NULL);
     if (hInstallEvent == NULL)
     {
         dwError = GetLastError();
@@ -3019,7 +3379,7 @@ wmain(int argc, WCHAR *argv[])
         return dwError;
     }
 
-    hDeviceInstallListNotEmpty = CreateEvent(NULL, FALSE, FALSE, NULL);
+    hDeviceInstallListNotEmpty = CreateEventW(NULL, FALSE, FALSE, NULL);
     if (hDeviceInstallListNotEmpty == NULL)
     {
         dwError = GetLastError();
@@ -3066,13 +3426,28 @@ wmain(int argc, WCHAR *argv[])
         return dwError;
     }
 
-    StartServiceCtrlDispatcher(ServiceTable);
+    DPRINT("UMPNPMGR: InitializePnPManager() done\n");
 
-    DPRINT("Umpnpmgr: main() done\n");
+    return 0;
+}
 
-    ExitThread(0);
+BOOL WINAPI
+DllMain(HINSTANCE hinstDLL,
+        DWORD fdwReason,
+        LPVOID lpvReserved)
+{
+    switch (fdwReason)
+    {
+        case DLL_PROCESS_ATTACH:
+            DisableThreadLibraryCalls(hinstDLL);
+            InitializePnPManager();
+            break;
 
-    return 0;
+        case DLL_PROCESS_DETACH:
+            break;
+    }
+
+    return TRUE;
 }
 
 /* EOF */