[UMPNPMGR]
[reactos.git] / reactos / base / services / umpnpmgr / umpnpmgr.c
index 8dc8a16..4704927 100644 (file)
 
 /* GLOBALS ******************************************************************/
 
-static VOID CALLBACK
-ServiceMain(DWORD argc, LPTSTR *argv);
-
-static SERVICE_TABLE_ENTRY ServiceTable[2] =
+static VOID CALLBACK ServiceMain(DWORD argc, LPWSTR *argv);
+static WCHAR ServiceName[] = L"PlugPlay";
+static SERVICE_TABLE_ENTRYW ServiceTable[] =
 {
-    {TEXT("PlugPlay"), ServiceMain},
+    {ServiceName, ServiceMain},
     {NULL, NULL}
 };
 
+static SERVICE_STATUS_HANDLE ServiceStatusHandle;
+static SERVICE_STATUS ServiceStatus;
+
 static WCHAR szRootDeviceId[] = L"HTREE\\ROOT\\0";
 
 static HKEY hEnumKey = NULL;
@@ -92,20 +94,37 @@ static DWORD WINAPI
 RpcServerThread(LPVOID lpParameter)
 {
     RPC_STATUS Status;
+    BOOLEAN RegisteredProtSeq = FALSE;
 
     UNREFERENCED_PARAMETER(lpParameter);
 
     DPRINT("RpcServerThread() called\n");
 
+#if 0
+    /* XP-compatible protocol sequence/endpoint */
     Status = RpcServerUseProtseqEpW(L"ncacn_np",
                                     20,
-                                    L"\\pipe\\umpnpmgr",
+                                    L"\\pipe\\ntsvcs",
                                     NULL);  // Security descriptor
-    if (Status != RPC_S_OK)
-    {
+    if (Status == RPC_S_OK)
+        RegisteredProtSeq = TRUE;
+    else
         DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
+#endif
+
+    /* Vista-compatible protocol sequence/endpoint */
+    Status = RpcServerUseProtseqEpW(L"ncacn_np",
+                                    20,
+                                    L"\\pipe\\plugplay",
+                                    NULL);  // Security descriptor
+    if (Status == RPC_S_OK)
+        RegisteredProtSeq = TRUE;
+    else
+        DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
+
+    /* Make sure there's a usable endpoint */
+    if (RegisteredProtSeq == FALSE)
         return 0;
-    }
 
     Status = RpcServerRegisterIf(pnp_v1_0_s_ifspec,
                                  NULL,
@@ -168,8 +187,7 @@ DWORD PNP_Disconnect(
     handle_t hBinding)
 {
     UNREFERENCED_PARAMETER(hBinding);
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
+    return CR_SUCCESS;
 }
 
 
@@ -178,8 +196,7 @@ DWORD PNP_Connect(
     handle_t hBinding)
 {
     UNREFERENCED_PARAMETER(hBinding);
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
+    return CR_SUCCESS;
 }
 
 
@@ -519,14 +536,33 @@ DWORD PNP_GetDeviceRegProp(
     PLUGPLAY_CONTROL_PROPERTY_DATA PlugPlayData;
     CONFIGRET ret = CR_SUCCESS;
     LPWSTR lpValueName = NULL;
-    HKEY hKey = 0;
+    HKEY hKey = NULL;
+    LONG lError;
     NTSTATUS Status;
 
     UNREFERENCED_PARAMETER(hBinding);
-    UNREFERENCED_PARAMETER(ulFlags);
 
     DPRINT("PNP_GetDeviceRegProp() called\n");
 
+    if (pulTransferLen == NULL || pulLength == NULL)
+    {
+        ret = CR_INVALID_POINTER;
+        goto done;
+    }
+
+    if (ulFlags != 0)
+    {
+        ret = CR_INVALID_FLAG;
+        goto done;
+    }
+
+    /* FIXME: Check pDeviceID */
+
+    if (*pulLength < *pulTransferLen)
+        *pulLength = *pulTransferLen;
+
+    *pulTransferLen = 0;
+
     switch (ulProperty)
     {
         case CM_DRP_DEVICEDESC:
@@ -609,8 +645,65 @@ DWORD PNP_GetDeviceRegProp(
             lpValueName = NULL;
             break;
 
+        case CM_DRP_SECURITY:
+            lpValueName = L"Security";
+            break;
+
+        case CM_DRP_DEVTYPE:
+            lpValueName = L"DeviceType";
+            break;
+
+        case CM_DRP_EXCLUSIVE:
+            lpValueName = L"Exclusive";
+            break;
+
+        case CM_DRP_CHARACTERISTICS:
+            lpValueName = L"DeviceCharacteristics";
+            break;
+
+        case CM_DRP_ADDRESS:
+            lpValueName = NULL;
+            break;
+
+        case CM_DRP_UI_NUMBER_DESC_FORMAT:
+            lpValueName = L"UINumberDescFormat";
+            break;
+
+        case CM_DRP_DEVICE_POWER_DATA:
+            lpValueName = NULL;
+            break;
+
+        case CM_DRP_REMOVAL_POLICY:
+            lpValueName = NULL;
+            break;
+
+        case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
+            lpValueName = NULL;
+            break;
+
+        case CM_DRP_REMOVAL_POLICY_OVERRIDE:
+            lpValueName = L"RemovalPolicy";
+            break;
+
+        case CM_DRP_INSTALL_STATE:
+            lpValueName = NULL;
+            break;
+
+#if (WINVER >= _WIN32_WINNT_WS03)
+        case CM_DRP_LOCATION_PATHS:
+            lpValueName = NULL;
+            break;
+#endif
+
+#if (WINVER >= _WIN32_WINNT_WIN7)
+        case CM_DRP_BASE_CONTAINERID:
+            lpValueName = NULL;
+            break;
+#endif
+
         default:
-            return CR_INVALID_PROPERTY;
+            ret = CR_INVALID_PROPERTY;
+            goto done;
     }
 
     DPRINT("Value name: %S\n", lpValueName);
@@ -618,24 +711,34 @@ DWORD PNP_GetDeviceRegProp(
     if (lpValueName)
     {
         /* Retrieve information from the Registry */
-        if (RegOpenKeyExW(hEnumKey,
-                          pDeviceID,
-                          0,
-                          KEY_ALL_ACCESS,
-                          &hKey))
-            return CR_INVALID_DEVNODE;
-
-        if (RegQueryValueExW(hKey,
-                             lpValueName,
-                             NULL,
-                             pulRegDataType,
-                             Buffer,
-                             pulLength))
-            ret = CR_REGISTRY_ERROR;
-
-        /* FIXME: Check buffer size */
+        lError = RegOpenKeyExW(hEnumKey,
+                               pDeviceID,
+                               0,
+                               KEY_QUERY_VALUE,
+                               &hKey);
+        if (lError != ERROR_SUCCESS)
+        {
+            hKey = NULL;
+            *pulLength = 0;
+            ret = CR_INVALID_DEVNODE;
+            goto done;
+        }
 
-        RegCloseKey(hKey);
+        lError = RegQueryValueExW(hKey,
+                                  lpValueName,
+                                  NULL,
+                                  pulRegDataType,
+                                  Buffer,
+                                  pulLength);
+        if (lError == ERROR_MORE_DATA)
+        {
+            ret = CR_BUFFER_SMALL;
+        }
+        else
+        {
+            *pulLength = 0;
+            ret = CR_NO_SUCH_VALUE;
+        }
     }
     else
     {
@@ -647,32 +750,65 @@ DWORD PNP_GetDeviceRegProp(
 
         switch (ulProperty)
         {
-#if 0
             case CM_DRP_PHYSICAL_DEVICE_OBJECT_NAME:
-                PlugPlayData.Property = DevicePropertyPhysicalDeviceObjectName;
+                PlugPlayData.Property = 0xb; // DevicePropertyPhysicalDeviceObjectName;
                 break;
 
             case CM_DRP_UI_NUMBER:
-                PlugPlayData.Property = DevicePropertyUINumber;
+                PlugPlayData.Property = 0x11; // DevicePropertyUINumber;
                 break;
 
             case CM_DRP_BUSTYPEGUID:
-                PlugPlayData.Property = DevicePropertyBusTypeGuid;
+                PlugPlayData.Property = 0xc; // DevicePropertyBusTypeGuid;
                 break;
 
             case CM_DRP_LEGACYBUSTYPE:
-                PlugPlayData.Property = DevicePropertyLegacyBusType;
+                PlugPlayData.Property = 0xd; // DevicePropertyLegacyBusType;
                 break;
 
             case CM_DRP_BUSNUMBER:
-                PlugPlayData.Property = DevicePropertyBusNumber;
+                PlugPlayData.Property = 0xe; // DevicePropertyBusNumber;
                 break;
-#endif
 
             case CM_DRP_ENUMERATOR_NAME:
-                PlugPlayData.Property = 15; //DevicePropertyEnumeratorName;
+                PlugPlayData.Property = 0xf; // DevicePropertyEnumeratorName;
+                break;
+
+            case CM_DRP_ADDRESS:
+                PlugPlayData.Property = 0x10; // DevicePropertyAddress;
                 break;
 
+#if 0
+            /* FIXME: This property is not supported by IoGetDeviceProperty */
+            case CM_DRP_DEVICE_POWER_DATA:
+#endif
+
+            case CM_DRP_REMOVAL_POLICY:
+                PlugPlayData.Property = 0x12; // DevicePropertyRemovalPolicy
+                break;
+
+#if 0
+            /* FIXME: This property is not supported by IoGetDeviceProperty */
+            case CM_DRP_REMOVAL_POLICY_HW_DEFAULT:
+#endif
+
+            case CM_DRP_INSTALL_STATE:
+                PlugPlayData.Property = 0x12; // DevicePropertyInstallState;
+                break;
+
+#if 0
+            /* FIXME: This property is not supported by IoGetDeviceProperty */
+#if (WINVER >= _WIN32_WINNT_WS03)
+            case CM_DRP_LOCATION_PATHS:
+#endif
+#endif
+
+#if (WINVER >= _WIN32_WINNT_WIN7)
+            case CM_DRP_BASE_CONTAINERID:
+                PlugPlayData.Property = 0x16; // DevicePropertyContainerID;
+                break;
+#endif
+
             default:
                 return CR_INVALID_PROPERTY;
         }
@@ -690,6 +826,12 @@ DWORD PNP_GetDeviceRegProp(
         }
     }
 
+done:;
+    *pulTransferLen = (ret != CR_SUCCESS) ? 0 : *pulLength;
+
+    if (hKey != NULL)
+        RegCloseKey(hKey);
+
     DPRINT("PNP_GetDeviceRegProp() done (returns %lx)\n", ret);
 
     return ret;
@@ -774,6 +916,30 @@ DWORD PNP_SetDeviceRegProp(
             lpValueName = L"LowerFilters";
             break;
 
+        case CM_DRP_SECURITY:
+            lpValueName = L"Security";
+            break;
+
+        case CM_DRP_DEVTYPE:
+            lpValueName = L"DeviceType";
+            break;
+
+        case CM_DRP_EXCLUSIVE:
+            lpValueName = L"Exclusive";
+            break;
+
+        case CM_DRP_CHARACTERISTICS:
+            lpValueName = L"DeviceCharacteristics";
+            break;
+
+        case CM_DRP_UI_NUMBER_DESC_FORMAT:
+            lpValueName = L"UINumberDescFormat";
+            break;
+
+        case CM_DRP_REMOVAL_POLICY_OVERRIDE:
+            lpValueName = L"RemovalPolicy";
+            break;
+
         default:
             return CR_INVALID_PROPERTY;
     }
@@ -783,7 +949,7 @@ DWORD PNP_SetDeviceRegProp(
     if (RegOpenKeyExW(hEnumKey,
                       pDeviceId,
                       0,
-                      KEY_ALL_ACCESS, /* FIXME: so much? */
+                      KEY_SET_VALUE,
                       &hKey))
         return CR_INVALID_DEVNODE;
 
@@ -1088,6 +1254,157 @@ DWORD PNP_SetClassRegProp(
 }
 
 
+static VOID
+SplitDeviceInstanceID(IN LPWSTR pszDeviceInstanceID,
+                      OUT LPWSTR pszEnumerator,
+                      OUT LPWSTR pszDevice,
+                      OUT LPWSTR pszInstance)
+{
+    WCHAR szLocalDeviceInstanceID[MAX_DEVICE_ID_LEN];
+    LPWSTR lpEnumerator = NULL;
+    LPWSTR lpDevice = NULL;
+    LPWSTR lpInstance = NULL;
+    LPWSTR ptr;
+
+    wcscpy(szLocalDeviceInstanceID, pszDeviceInstanceID);
+
+    *pszEnumerator = 0;
+    *pszDevice = 0;
+    *pszInstance = 0;
+
+    lpEnumerator = szLocalDeviceInstanceID;
+
+    ptr = wcschr(lpEnumerator, L'\\');
+    if (ptr != NULL)
+    {
+        *ptr = 0;
+        lpDevice = ++ptr;
+
+        ptr = wcschr(lpDevice, L'\\');
+        if (ptr != NULL)
+        {
+            *ptr = 0;
+            lpInstance = ++ptr;
+        }
+    }
+
+    if (lpEnumerator != NULL)
+        wcscpy(pszEnumerator, lpEnumerator);
+
+    if (lpDevice != NULL)
+        wcscpy(pszDevice, lpDevice);
+
+    if (lpInstance != NULL)
+        wcscpy(pszInstance, lpInstance);
+}
+
+
+static CONFIGRET
+CreateDeviceInstance(LPWSTR pszDeviceID)
+{
+    WCHAR szEnumerator[MAX_DEVICE_ID_LEN];
+    WCHAR szDevice[MAX_DEVICE_ID_LEN];
+    WCHAR szInstance[MAX_DEVICE_ID_LEN];
+    HKEY hKeyEnumerator;
+    HKEY hKeyDevice;
+    HKEY hKeyInstance;
+    HKEY hKeyControl;
+    LONG lError;
+
+    /* Split the instance ID */
+    SplitDeviceInstanceID(pszDeviceID,
+                          szEnumerator,
+                          szDevice,
+                          szInstance);
+
+    /* Open or create the enumerator key */
+    lError = RegCreateKeyExW(hEnumKey,
+                             szEnumerator,
+                             0,
+                             NULL,
+                             REG_OPTION_NON_VOLATILE,
+                             KEY_ALL_ACCESS,
+                             NULL,
+                             &hKeyEnumerator,
+                             NULL);
+    if (lError != ERROR_SUCCESS)
+    {
+        return CR_REGISTRY_ERROR;
+    }
+
+    /* Open or create the device key */
+    lError = RegCreateKeyExW(hKeyEnumerator,
+                             szDevice,
+                             0,
+                             NULL,
+                             REG_OPTION_NON_VOLATILE,
+                             KEY_ALL_ACCESS,
+                             NULL,
+                             &hKeyDevice,
+                             NULL);
+
+    /* Close the enumerator key */
+    RegCloseKey(hKeyEnumerator);
+
+    if (lError != ERROR_SUCCESS)
+    {
+        return CR_REGISTRY_ERROR;
+    }
+
+    /* Try to open the instance key and fail if it exists */
+    lError = RegOpenKeyExW(hKeyDevice,
+                           szInstance,
+                           0,
+                           KEY_SET_VALUE,
+                           &hKeyInstance);
+    if (lError == ERROR_SUCCESS)
+    {
+        DPRINT1("Instance %S already exists!\n", szInstance);
+        RegCloseKey(hKeyInstance);
+        RegCloseKey(hKeyDevice);
+        return CR_ALREADY_SUCH_DEVINST;
+    }
+
+    /* Create a new instance key */
+    lError = RegCreateKeyExW(hKeyDevice,
+                             szInstance,
+                             0,
+                             NULL,
+                             REG_OPTION_NON_VOLATILE,
+                             KEY_ALL_ACCESS,
+                             NULL,
+                             &hKeyInstance,
+                             NULL);
+
+    /* Close the device key */
+    RegCloseKey(hKeyDevice);
+
+    if (lError != ERROR_SUCCESS)
+    {
+        return CR_REGISTRY_ERROR;
+    }
+
+    /* Create the 'Control' sub key */
+    lError = RegCreateKeyExW(hKeyInstance,
+                             L"Control",
+                             0,
+                             NULL,
+                             REG_OPTION_NON_VOLATILE,
+                             KEY_ALL_ACCESS,
+                             NULL,
+                             &hKeyControl,
+                             NULL);
+    if (lError == ERROR_SUCCESS)
+    {
+        RegCloseKey(hKeyControl);
+    }
+
+    RegCloseKey(hKeyInstance);
+
+    return (lError == ERROR_SUCCESS) ? CR_SUCCESS : CR_REGISTRY_ERROR;
+}
+
+
 /* Function 28 */
 DWORD PNP_CreateDevInst(
     handle_t hBinding,
@@ -1096,8 +1413,25 @@ DWORD PNP_CreateDevInst(
     PNP_RPC_STRING_LEN ulLength,
     DWORD ulFlags)
 {
-    UNIMPLEMENTED;
-    return CR_CALL_NOT_IMPLEMENTED;
+    CONFIGRET ret = CR_SUCCESS;
+
+    DPRINT("PNP_CreateDevInst: %S\n", pszDeviceID);
+
+    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;
+    }
+
+    /* Create the device instance */
+    ret = CreateDeviceInstance(pszDeviceID);
+
+done:;
+    DPRINT("PNP_CreateDevInst() done (returns %lx)\n", ret);
+
+    return ret;
 }
 
 
@@ -1836,7 +2170,12 @@ DWORD PNP_SetHwProf(
 
 /* Function 56 */
 DWORD PNP_QueryArbitratorFreeData(
-    handle_t hBinding)
+    handle_t hBinding,
+    BYTE *pData,
+    DWORD DataLen,
+    LPWSTR pDeviceID,
+    RESOURCEID ResourceID,
+    DWORD ulFlags)
 {
     UNIMPLEMENTED;
     return CR_CALL_NOT_IMPLEMENTED;
@@ -1845,7 +2184,11 @@ DWORD PNP_QueryArbitratorFreeData(
 
 /* Function 57 */
 DWORD PNP_QueryArbitratorFreeSize(
-    handle_t hBinding)
+    handle_t hBinding,
+    DWORD *pulSize,
+    LPWSTR pDeviceID,
+    RESOURCEID ResourceID,
+    DWORD ulFlags)
 {
     UNIMPLEMENTED;
     return CR_CALL_NOT_IMPLEMENTED;
@@ -1858,7 +2201,6 @@ PNP_RunDetection(
     handle_t hBinding,
     DWORD ulFlags)
 {
-    UNIMPLEMENTED;
     return CR_CALL_NOT_IMPLEMENTED;
 }
 
@@ -2048,8 +2390,6 @@ DWORD PNP_DeleteServiceDevices(
 static BOOL
 InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
 {
-    PLUGPLAY_CONTROL_STATUS_DATA PlugPlayData;
-    NTSTATUS Status;
     BOOL DeviceInstalled = FALSE;
     DWORD BytesWritten;
     DWORD Value;
@@ -2058,6 +2398,7 @@ InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
     PROCESS_INFORMATION ProcessInfo;
     STARTUPINFOW StartupInfo;
     UUID RandomUuid;
+    HKEY DeviceKey;
 
     /* The following lengths are constant (see below), they cannot overflow */
     WCHAR CommandLine[116];
@@ -2069,27 +2410,29 @@ InstallDevice(PCWSTR DeviceInstance, BOOL ShowWizard)
 
     ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
 
-    RtlInitUnicodeString(&PlugPlayData.DeviceInstance,
-                         DeviceInstance);
-    PlugPlayData.Operation = 0; /* Get status */
-
-    /* Get device status */
-    Status = NtPlugPlayControl(PlugPlayControlDeviceStatus,
-                               (PVOID)&PlugPlayData,
-                               sizeof(PLUGPLAY_CONTROL_STATUS_DATA));
-    if (!NT_SUCCESS(Status))
+    if (RegOpenKeyExW(hEnumKey,
+                      DeviceInstance,
+                      0,
+                      KEY_QUERY_VALUE,
+                      &DeviceKey) == ERROR_SUCCESS)
     {
-        DPRINT1("NtPlugPlayControl('%S') failed with status 0x%08lx\n", DeviceInstance, Status);
-        return FALSE;
-    }
+        if (RegQueryValueExW(DeviceKey,
+                             L"ClassGUID",
+                             NULL,
+                             NULL,
+                             NULL,
+                             NULL) == ERROR_SUCCESS)
+        {
+            DPRINT("No need to install: %S\n", DeviceInstance);
+            RegCloseKey(DeviceKey);
+            return TRUE;
+        }
 
-    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;
+        RegCloseKey(DeviceKey);
     }
 
+    DPRINT1("Installing: %S\n", DeviceInstance);
+
     /* Create a random UUID for the named pipe */
     UuidCreate(&RandomUuid);
     swprintf(UuidString, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
@@ -2194,6 +2537,8 @@ cleanup:
     if(ProcessInfo.hThread)
         CloseHandle(ProcessInfo.hThread);
 
+    DPRINT1("Success? %d\n", DeviceInstalled);
+
     return DeviceInstalled;
 }
 
@@ -2402,7 +2747,7 @@ PnpEventThread(LPVOID lpParameter)
             DWORD len;
             DWORD DeviceIdLength;
 
-            DPRINT("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
+            DPRINT1("Device enumerated: %S\n", PnpEvent->TargetDevice.DeviceIds);
 
             DeviceIdLength = lstrlenW(PnpEvent->TargetDevice.DeviceIds);
             if (DeviceIdLength)
@@ -2424,7 +2769,7 @@ PnpEventThread(LPVOID lpParameter)
         }
         else if (UuidEqual(&PnpEvent->EventGuid, (UUID*)&GUID_DEVICE_ARRIVAL, &RpcStatus))
         {
-            DPRINT("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
+            DPRINT1("Device arrival: %S\n", PnpEvent->TargetDevice.DeviceIds);
             /* FIXME: ? */
         }
         else
@@ -2446,6 +2791,72 @@ PnpEventThread(LPVOID lpParameter)
 }
 
 
+static VOID
+UpdateServiceStatus(DWORD dwState)
+{
+    ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+    ServiceStatus.dwCurrentState = dwState;
+    ServiceStatus.dwControlsAccepted = 0;
+    ServiceStatus.dwWin32ExitCode = 0;
+    ServiceStatus.dwServiceSpecificExitCode = 0;
+    ServiceStatus.dwCheckPoint = 0;
+
+    if (dwState == SERVICE_START_PENDING ||
+        dwState == SERVICE_STOP_PENDING ||
+        dwState == SERVICE_PAUSE_PENDING ||
+        dwState == SERVICE_CONTINUE_PENDING)
+        ServiceStatus.dwWaitHint = 10000;
+    else
+        ServiceStatus.dwWaitHint = 0;
+
+    SetServiceStatus(ServiceStatusHandle,
+                     &ServiceStatus);
+}
+
+
+static DWORD WINAPI
+ServiceControlHandler(DWORD dwControl,
+                      DWORD dwEventType,
+                      LPVOID lpEventData,
+                      LPVOID lpContext)
+{
+    DPRINT1("ServiceControlHandler() called\n");
+
+    switch (dwControl)
+    {
+        case SERVICE_CONTROL_STOP:
+            DPRINT1("  SERVICE_CONTROL_STOP received\n");
+            UpdateServiceStatus(SERVICE_STOPPED);
+            return ERROR_SUCCESS;
+
+        case SERVICE_CONTROL_PAUSE:
+            DPRINT1("  SERVICE_CONTROL_PAUSE received\n");
+            UpdateServiceStatus(SERVICE_PAUSED);
+            return ERROR_SUCCESS;
+
+        case SERVICE_CONTROL_CONTINUE:
+            DPRINT1("  SERVICE_CONTROL_CONTINUE received\n");
+            UpdateServiceStatus(SERVICE_RUNNING);
+            return ERROR_SUCCESS;
+
+        case SERVICE_CONTROL_INTERROGATE:
+            DPRINT1("  SERVICE_CONTROL_INTERROGATE received\n");
+            SetServiceStatus(ServiceStatusHandle,
+                             &ServiceStatus);
+            return ERROR_SUCCESS;
+
+        case SERVICE_CONTROL_SHUTDOWN:
+            DPRINT1("  SERVICE_CONTROL_SHUTDOWN received\n");
+            UpdateServiceStatus(SERVICE_STOPPED);
+            return ERROR_SUCCESS;
+
+        default :
+            DPRINT1("  Control %lu received\n");
+            return ERROR_CALL_NOT_IMPLEMENTED;
+    }
+}
+
+
 static VOID CALLBACK
 ServiceMain(DWORD argc, LPTSTR *argv)
 {
@@ -2457,6 +2868,17 @@ ServiceMain(DWORD argc, LPTSTR *argv)
 
     DPRINT("ServiceMain() called\n");
 
+    ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
+                                                        ServiceControlHandler,
+                                                        NULL);
+    if (!ServiceStatusHandle)
+    {
+        DPRINT1("RegisterServiceCtrlHandlerExW() failed! (Error %lu)\n", GetLastError());
+        return;
+    }
+
+    UpdateServiceStatus(SERVICE_START_PENDING);
+
     hThread = CreateThread(NULL,
                            0,
                            PnpEventThread,
@@ -2484,6 +2906,8 @@ ServiceMain(DWORD argc, LPTSTR *argv)
     if (hThread != NULL)
         CloseHandle(hThread);
 
+    UpdateServiceStatus(SERVICE_RUNNING);
+
     DPRINT("ServiceMain() done\n");
 }