[COMCTL32] Pt.rc: Place accelerator FIXMEs
[reactos.git] / dll / win32 / advapi32 / service / scm.c
index 0e80fc2..aee23c5 100644 (file)
@@ -5,9 +5,7 @@
  * PURPOSE:         Service control manager functions
  * PROGRAMMER:      Emanuele Aliberti
  *                  Eric Kohl
- * UPDATE HISTORY:
- *  19990413 EA created
- *  19990515 EA
+ *                  Pierre Schweitzer
  */
 
 /* INCLUDES ******************************************************************/
 #include <advapi32.h>
 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
 
+NTSTATUS
+WINAPI
+SystemFunction004(
+    const struct ustring *in,
+    const struct ustring *key,
+    struct ustring *out);
+
+NTSTATUS
+WINAPI
+SystemFunction028(
+    IN PVOID ContextHandle,
+    OUT LPBYTE SessionKey);
 
 /* FUNCTIONS *****************************************************************/
 
@@ -22,17 +32,18 @@ handle_t __RPC_USER
 SVCCTL_HANDLEA_bind(SVCCTL_HANDLEA szMachineName)
 {
     handle_t hBinding = NULL;
-    UCHAR *pszStringBinding;
+    RPC_CSTR pszStringBinding;
     RPC_STATUS status;
 
-    TRACE("SVCCTL_HANDLEA_bind() called\n");
+    TRACE("SVCCTL_HANDLEA_bind(%s)\n",
+          debugstr_a(szMachineName));
 
     status = RpcStringBindingComposeA(NULL,
-                                      (UCHAR *)"ncacn_np",
-                                      (UCHAR *)szMachineName,
-                                      (UCHAR *)"\\pipe\\ntsvcs",
+                                      (RPC_CSTR)"ncacn_np",
+                                      (RPC_CSTR)szMachineName,
+                                      (RPC_CSTR)"\\pipe\\ntsvcs",
                                       NULL,
-                                      (UCHAR **)&pszStringBinding);
+                                      &pszStringBinding);
     if (status != RPC_S_OK)
     {
         ERR("RpcStringBindingCompose returned 0x%x\n", status);
@@ -63,7 +74,8 @@ SVCCTL_HANDLEA_unbind(SVCCTL_HANDLEA szMachineName,
 {
     RPC_STATUS status;
 
-    TRACE("SVCCTL_HANDLEA_unbind() called\n");
+    TRACE("SVCCTL_HANDLEA_unbind(%s %p)\n",
+          debugstr_a(szMachineName), hBinding);
 
     status = RpcBindingFree(&hBinding);
     if (status != RPC_S_OK)
@@ -77,10 +89,11 @@ handle_t __RPC_USER
 SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW szMachineName)
 {
     handle_t hBinding = NULL;
-    LPWSTR pszStringBinding;
+    RPC_WSTR pszStringBinding;
     RPC_STATUS status;
 
-    TRACE("SVCCTL_HANDLEW_bind() called\n");
+    TRACE("SVCCTL_HANDLEW_bind(%s)\n",
+          debugstr_w(szMachineName));
 
     status = RpcStringBindingComposeW(NULL,
                                       L"ncacn_np",
@@ -118,7 +131,8 @@ SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW szMachineName,
 {
     RPC_STATUS status;
 
-    TRACE("SVCCTL_HANDLEW_unbind() called\n");
+    TRACE("SVCCTL_HANDLEW_unbind(%s %p)\n",
+          debugstr_w(szMachineName), hBinding);
 
     status = RpcBindingFree(&hBinding);
     if (status != RPC_S_OK)
@@ -131,8 +145,12 @@ SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW szMachineName,
 DWORD
 ScmRpcStatusToWinError(RPC_STATUS Status)
 {
+    TRACE("ScmRpcStatusToWinError(%lx)\n",
+          Status);
+
     switch (Status)
     {
+        case STATUS_ACCESS_VIOLATION:
         case RPC_S_INVALID_BINDING:
         case RPC_X_SS_IN_NULL_CONTEXT:
             return ERROR_INVALID_HANDLE;
@@ -150,6 +168,76 @@ ScmRpcStatusToWinError(RPC_STATUS Status)
 }
 
 
+static
+DWORD
+ScmEncryptPassword(
+    _In_ PVOID ContextHandle,
+    _In_ PCWSTR pClearTextPassword,
+    _Out_ PBYTE *pEncryptedPassword,
+    _Out_ PDWORD pEncryptedPasswordSize)
+{
+    struct ustring inData, keyData, outData;
+    BYTE SessionKey[16];
+    PBYTE pBuffer;
+    NTSTATUS Status;
+
+    /* Get the session key */
+    Status = SystemFunction028(ContextHandle,
+                               SessionKey);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("SystemFunction028 failed (Status 0x%08lx)\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    inData.Length = (wcslen(pClearTextPassword) + 1) * sizeof(WCHAR);
+    inData.MaximumLength = inData.Length;
+    inData.Buffer = (unsigned char *)pClearTextPassword;
+
+    keyData.Length = sizeof(SessionKey);
+    keyData.MaximumLength = keyData.Length;
+    keyData.Buffer = SessionKey;
+
+    outData.Length = 0;
+    outData.MaximumLength = 0;
+    outData.Buffer = NULL;
+
+    /* Get the required buffer size */
+    Status = SystemFunction004(&inData,
+                               &keyData,
+                               &outData);
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+        ERR("SystemFunction004 failed (Status 0x%08lx)\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    /* Allocate a buffer for the encrypted password */
+    pBuffer = HeapAlloc(GetProcessHeap(), 0, outData.Length);
+    if (pBuffer == NULL)
+        return ERROR_OUTOFMEMORY;
+
+    outData.MaximumLength = outData.Length;
+    outData.Buffer = pBuffer;
+
+    /* Encrypt the password */
+    Status = SystemFunction004(&inData,
+                               &keyData,
+                               &outData);
+    if (!NT_SUCCESS(Status))
+    {
+        ERR("SystemFunction004 failed (Status 0x%08lx)\n", Status);
+        HeapFree(GetProcessHeap(), 0, pBuffer);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    *pEncryptedPassword = outData.Buffer;
+    *pEncryptedPasswordSize = outData.Length;
+
+    return ERROR_SUCCESS;
+}
+
+
 /**********************************************************************
  *  ChangeServiceConfig2A
  *
@@ -163,21 +251,21 @@ ChangeServiceConfig2A(SC_HANDLE hService,
     SC_RPC_CONFIG_INFOA Info;
     DWORD dwError;
 
-    TRACE("ChangeServiceConfig2A() called\n");
+    TRACE("ChangeServiceConfig2A(%p %lu %p)\n",
+          hService, dwInfoLevel, lpInfo);
 
     if (lpInfo == NULL) return TRUE;
 
-    /* Fill relevent field of the Info structure */
+    /* Fill relevant field of the Info structure */
     Info.dwInfoLevel = dwInfoLevel;
     switch (dwInfoLevel)
     {
         case SERVICE_CONFIG_DESCRIPTION:
-            Info.psd = (LPSERVICE_DESCRIPTIONA)&lpInfo;
-            Info.lpDescription = ((LPSERVICE_DESCRIPTIONA)lpInfo)->lpDescription; //HACK
+            Info.psd = lpInfo;
             break;
 
         case SERVICE_CONFIG_FAILURE_ACTIONS:
-            Info.psfa = (LPSERVICE_FAILURE_ACTIONSA)lpInfo;
+            Info.psfa = lpInfo;
             break;
 
         default:
@@ -221,20 +309,21 @@ ChangeServiceConfig2W(SC_HANDLE hService,
     SC_RPC_CONFIG_INFOW Info;
     DWORD dwError;
 
-    TRACE("ChangeServiceConfig2W() called\n");
+    TRACE("ChangeServiceConfig2W(%p %lu %p)\n",
+          hService, dwInfoLevel, lpInfo);
 
     if (lpInfo == NULL) return TRUE;
 
-    /* Fill relevent field of the Info structure */
+    /* Fill relevant field of the Info structure */
     Info.dwInfoLevel = dwInfoLevel;
     switch (dwInfoLevel)
     {
         case SERVICE_CONFIG_DESCRIPTION:
-            Info.psd = (LPSERVICE_DESCRIPTIONW)lpInfo;
+            Info.psd = lpInfo;
             break;
 
         case SERVICE_CONFIG_FAILURE_ACTIONS:
-            Info.psfa = (LPSERVICE_FAILURE_ACTIONSW)lpInfo;
+            Info.psfa = lpInfo;
             break;
 
         default:
@@ -287,10 +376,14 @@ ChangeServiceConfigA(SC_HANDLE hService,
     DWORD dwDependenciesLength = 0;
     SIZE_T cchLength;
     LPCSTR lpStr;
-    DWORD dwPasswordLength = 0;
+    DWORD dwPasswordSize = 0;
+    LPWSTR lpPasswordW = NULL;
     LPBYTE lpEncryptedPassword = NULL;
 
-    TRACE("ChangeServiceConfigA() called\n");
+    TRACE("ChangeServiceConfigA(%p %lu %lu %lu %s %s %p %s %s %s %s)\n",
+          hService, dwServiceType, dwStartType, dwErrorControl, debugstr_a(lpBinaryPathName),
+          debugstr_a(lpLoadOrderGroup), lpdwTagId, debugstr_a(lpDependencies),
+          debugstr_a(lpServiceStartName), debugstr_a(lpPassword), debugstr_a(lpDisplayName));
 
     /* Calculate the Dependencies length*/
     if (lpDependencies != NULL)
@@ -305,13 +398,36 @@ ChangeServiceConfigA(SC_HANDLE hService,
         dwDependenciesLength++;
     }
 
-    /* FIXME: Encrypt the password */
-    lpEncryptedPassword = (LPBYTE)lpPassword;
-    dwPasswordLength = (DWORD)(lpPassword ? (strlen(lpPassword) + 1) * sizeof(CHAR) : 0);
+    if (lpPassword != NULL)
+    {
+        /* Convert the password to unicode */
+        lpPasswordW = HeapAlloc(GetProcessHeap(),
+                                HEAP_ZERO_MEMORY,
+                                (strlen(lpPassword) + 1) * sizeof(WCHAR));
+        if (lpPasswordW == NULL)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
+
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            lpPassword,
+                            -1,
+                            lpPasswordW,
+                            (int)(strlen(lpPassword) + 1));
+
+        /* Encrypt the unicode password */
+        dwError = ScmEncryptPassword(hService,
+                                     lpPasswordW,
+                                     &lpEncryptedPassword,
+                                     &dwPasswordSize);
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+    }
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RChangeServiceConfigA((SC_RPC_HANDLE)hService,
                                         dwServiceType,
                                         dwStartType,
@@ -323,7 +439,7 @@ ChangeServiceConfigA(SC_HANDLE hService,
                                         dwDependenciesLength,
                                         (LPSTR)lpServiceStartName,
                                         lpEncryptedPassword,
-                                        dwPasswordLength,
+                                        dwPasswordSize,
                                         (LPSTR)lpDisplayName);
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
@@ -332,6 +448,20 @@ ChangeServiceConfigA(SC_HANDLE hService,
     }
     RpcEndExcept;
 
+done:
+    if (lpPasswordW != NULL)
+    {
+        /* Wipe and release the password buffers */
+        SecureZeroMemory(lpPasswordW, (wcslen(lpPasswordW) + 1) * sizeof(WCHAR));
+        HeapFree(GetProcessHeap(), 0, lpPasswordW);
+
+        if (lpEncryptedPassword != NULL)
+        {
+            SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
+            HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
+        }
+    }
+
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("RChangeServiceConfigA() failed (Error %lu)\n", dwError);
@@ -365,10 +495,13 @@ ChangeServiceConfigW(SC_HANDLE hService,
     DWORD dwDependenciesLength = 0;
     SIZE_T cchLength;
     LPCWSTR lpStr;
-    DWORD dwPasswordLength = 0;
+    DWORD dwPasswordSize = 0;
     LPBYTE lpEncryptedPassword = NULL;
 
-    TRACE("ChangeServiceConfigW() called\n");
+    TRACE("ChangeServiceConfigW(%p %lu %lu %lu %s %s %p %s %s %s %s)\n",
+          hService, dwServiceType, dwStartType, dwErrorControl, debugstr_w(lpBinaryPathName),
+          debugstr_w(lpLoadOrderGroup), lpdwTagId, debugstr_w(lpDependencies),
+          debugstr_w(lpServiceStartName), debugstr_w(lpPassword), debugstr_w(lpDisplayName));
 
     /* Calculate the Dependencies length*/
     if (lpDependencies != NULL)
@@ -384,13 +517,21 @@ ChangeServiceConfigW(SC_HANDLE hService,
         dwDependenciesLength *= sizeof(WCHAR);
     }
 
-    /* FIXME: Encrypt the password */
-    lpEncryptedPassword = (LPBYTE)lpPassword;
-    dwPasswordLength = (lpPassword ? (wcslen(lpPassword) + 1) * sizeof(WCHAR) : 0);
+    if (lpPassword != NULL)
+    {
+        dwError = ScmEncryptPassword(hService,
+                                     lpPassword,
+                                     &lpEncryptedPassword,
+                                     &dwPasswordSize);
+        if (dwError != ERROR_SUCCESS)
+        {
+            ERR("ScmEncryptPassword failed (Error %lu)\n", dwError);
+            goto done;
+        }
+    }
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RChangeServiceConfigW((SC_RPC_HANDLE)hService,
                                         dwServiceType,
                                         dwStartType,
@@ -402,7 +543,7 @@ ChangeServiceConfigW(SC_HANDLE hService,
                                         dwDependenciesLength,
                                         (LPWSTR)lpServiceStartName,
                                         lpEncryptedPassword,
-                                        dwPasswordLength,
+                                        dwPasswordSize,
                                         (LPWSTR)lpDisplayName);
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
@@ -411,6 +552,14 @@ ChangeServiceConfigW(SC_HANDLE hService,
     }
     RpcEndExcept;
 
+done:
+    if (lpEncryptedPassword != NULL)
+    {
+        /* Wipe and release the password buffer */
+        SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
+        HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
+    }
+
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("RChangeServiceConfigW() failed (Error %lu)\n", dwError);
@@ -432,7 +581,8 @@ CloseServiceHandle(SC_HANDLE hSCObject)
 {
     DWORD dwError;
 
-    TRACE("CloseServiceHandle() called\n");
+    TRACE("CloseServiceHandle(%p)\n",
+          hSCObject);
 
     if (!hSCObject)
     {
@@ -442,7 +592,6 @@ CloseServiceHandle(SC_HANDLE hSCObject)
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RCloseServiceHandle((LPSC_RPC_HANDLE)&hSCObject);
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
@@ -476,12 +625,11 @@ ControlService(SC_HANDLE hService,
 {
     DWORD dwError;
 
-    TRACE("ControlService(%x, %x, %p)\n",
-           hService, dwControl, lpServiceStatus);
+    TRACE("ControlService(%p %lu %p)\n",
+          hService, dwControl, lpServiceStatus);
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RControlService((SC_RPC_HANDLE)hService,
                                   dwControl,
                                   lpServiceStatus);
@@ -516,8 +664,8 @@ ControlServiceEx(IN SC_HANDLE hService,
                  IN DWORD dwInfoLevel,
                  IN OUT PVOID pControlParams)
 {
-    FIXME("ControlServiceEx(0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
-            hService, dwControl, dwInfoLevel, pControlParams);
+    FIXME("ControlServiceEx(%p %lu %lu %p)\n",
+          hService, dwControl, dwInfoLevel, pControlParams);
     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
     return FALSE;
 }
@@ -548,12 +696,15 @@ CreateServiceA(SC_HANDLE hSCManager,
     DWORD dwError;
     SIZE_T cchLength;
     LPCSTR lpStr;
-    DWORD dwPasswordLength = 0;
+    DWORD dwPasswordSize = 0;
+    LPWSTR lpPasswordW = NULL;
     LPBYTE lpEncryptedPassword = NULL;
 
-    TRACE("CreateServiceA() called\n");
-    TRACE("%p %s %s\n", hSCManager,
-          lpServiceName, lpDisplayName);
+    TRACE("CreateServiceA(%p %s %s %lx %lu %lu %lu %s %s %p %s %s %s)\n",
+          hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName),
+          dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
+          debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup), lpdwTagId,
+          debugstr_a(lpDependencies), debugstr_a(lpServiceStartName), debugstr_a(lpPassword));
 
     if (!hSCManager)
     {
@@ -574,13 +725,36 @@ CreateServiceA(SC_HANDLE hSCManager,
         dwDependenciesLength++;
     }
 
-    /* FIXME: Encrypt the password */
-    lpEncryptedPassword = (LPBYTE)lpPassword;
-    dwPasswordLength = (DWORD)(lpPassword ? (strlen(lpPassword) + 1) * sizeof(CHAR) : 0);
+    if (lpPassword != NULL)
+    {
+        /* Convert the password to unicode */
+        lpPasswordW = HeapAlloc(GetProcessHeap(),
+                                HEAP_ZERO_MEMORY,
+                                (strlen(lpPassword) + 1) * sizeof(WCHAR));
+        if (lpPasswordW == NULL)
+        {
+            SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+            return FALSE;
+        }
+
+        MultiByteToWideChar(CP_ACP,
+                            0,
+                            lpPassword,
+                            -1,
+                            lpPasswordW,
+                            (int)(strlen(lpPassword) + 1));
+
+        /* Encrypt the password */
+        dwError = ScmEncryptPassword(hSCManager,
+                                     lpPasswordW,
+                                     &lpEncryptedPassword,
+                                     &dwPasswordSize);
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+    }
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RCreateServiceA((SC_RPC_HANDLE)hSCManager,
                                   (LPSTR)lpServiceName,
                                   (LPSTR)lpDisplayName,
@@ -595,7 +769,7 @@ CreateServiceA(SC_HANDLE hSCManager,
                                   dwDependenciesLength,
                                   (LPSTR)lpServiceStartName,
                                   lpEncryptedPassword,
-                                  dwPasswordLength,
+                                  dwPasswordSize,
                                   (SC_RPC_HANDLE *)&hService);
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
@@ -604,10 +778,24 @@ CreateServiceA(SC_HANDLE hSCManager,
     }
     RpcEndExcept;
 
+done:
+    if (lpPasswordW != NULL)
+    {
+        /* Wipe and release the password buffers */
+        SecureZeroMemory(lpPasswordW, (wcslen(lpPasswordW) + 1) * sizeof(WCHAR));
+        HeapFree(GetProcessHeap(), 0, lpPasswordW);
+
+        if (lpEncryptedPassword != NULL)
+        {
+            SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
+            HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
+        }
+    }
+
+    SetLastError(dwError);
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("RCreateServiceA() failed (Error %lu)\n", dwError);
-        SetLastError(dwError);
         return NULL;
     }
 
@@ -640,12 +828,14 @@ CreateServiceW(SC_HANDLE hSCManager,
     DWORD dwError;
     SIZE_T cchLength;
     LPCWSTR lpStr;
-    DWORD dwPasswordLength = 0;
+    DWORD dwPasswordSize = 0;
     LPBYTE lpEncryptedPassword = NULL;
 
-    TRACE("CreateServiceW() called\n");
-    TRACE("%p %S %S\n", hSCManager,
-          lpServiceName, lpDisplayName);
+    TRACE("CreateServiceW(%p %s %s %lx %lu %lu %lu %s %s %p %s %s %s)\n",
+          hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName),
+          dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
+          debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup), lpdwTagId,
+          debugstr_w(lpDependencies), debugstr_w(lpServiceStartName), debugstr_w(lpPassword));
 
     if (!hSCManager)
     {
@@ -667,13 +857,19 @@ CreateServiceW(SC_HANDLE hSCManager,
         dwDependenciesLength *= sizeof(WCHAR);
     }
 
-    /* FIXME: Encrypt the password */
-    lpEncryptedPassword = (LPBYTE)lpPassword;
-    dwPasswordLength = (DWORD)(lpPassword ? (wcslen(lpPassword) + 1) * sizeof(WCHAR) : 0);
+    if (lpPassword != NULL)
+    {
+        /* Encrypt the password */
+        dwError = ScmEncryptPassword(hSCManager,
+                                     lpPassword,
+                                     &lpEncryptedPassword,
+                                     &dwPasswordSize);
+        if (dwError != ERROR_SUCCESS)
+            goto done;
+    }
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RCreateServiceW((SC_RPC_HANDLE)hSCManager,
                                   lpServiceName,
                                   lpDisplayName,
@@ -688,7 +884,7 @@ CreateServiceW(SC_HANDLE hSCManager,
                                   dwDependenciesLength,
                                   lpServiceStartName,
                                   lpEncryptedPassword,
-                                  dwPasswordLength,
+                                  dwPasswordSize,
                                   (SC_RPC_HANDLE *)&hService);
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
@@ -697,10 +893,18 @@ CreateServiceW(SC_HANDLE hSCManager,
     }
     RpcEndExcept;
 
+done:
+    if (lpEncryptedPassword != NULL)
+    {
+        /* Wipe and release the password buffers */
+        SecureZeroMemory(lpEncryptedPassword, dwPasswordSize);
+        HeapFree(GetProcessHeap(), 0, lpEncryptedPassword);
+    }
+
+    SetLastError(dwError);
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("RCreateServiceW() failed (Error %lu)\n", dwError);
-        SetLastError(dwError);
         return NULL;
     }
 
@@ -718,11 +922,11 @@ DeleteService(SC_HANDLE hService)
 {
     DWORD dwError;
 
-    TRACE("DeleteService(%x)\n", hService);
+    TRACE("DeleteService(%p)\n",
+          hService);
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RDeleteService((SC_RPC_HANDLE)hService);
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
@@ -761,7 +965,9 @@ EnumDependentServicesA(SC_HANDLE hService,
     DWORD dwError;
     DWORD dwCount;
 
-    TRACE("EnumDependentServicesA() called\n");
+    TRACE("EnumDependentServicesA(%p %lu %p %lu %p %p)\n",
+          hService, dwServiceState, lpServices, cbBufSize,
+          pcbBytesNeeded, lpServicesReturned);
 
     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSA))
     {
@@ -837,7 +1043,9 @@ EnumDependentServicesW(SC_HANDLE hService,
     DWORD dwError;
     DWORD dwCount;
 
-    TRACE("EnumDependentServicesW() called\n");
+    TRACE("EnumDependentServicesW(%p %lu %p %lu %p %p)\n",
+          hService, dwServiceState, lpServices, cbBufSize,
+          pcbBytesNeeded, lpServicesReturned);
 
     if (lpServices == NULL || cbBufSize < sizeof(ENUM_SERVICE_STATUSW))
     {
@@ -916,7 +1124,10 @@ EnumServiceGroupW(SC_HANDLE hSCManager,
     DWORD dwError;
     DWORD dwCount;
 
-    TRACE("EnumServiceGroupW() called\n");
+    TRACE("EnumServiceGroupW(%p %lu %lu %p %lu %p %p %p %s)\n",
+          hSCManager, dwServiceType, dwServiceState, lpServices,
+          cbBufSize, pcbBytesNeeded, lpServicesReturned,
+          lpResumeHandle, debugstr_w(lpGroup));
 
     if (!hSCManager)
     {
@@ -1023,7 +1234,9 @@ EnumServicesStatusA(SC_HANDLE hSCManager,
     DWORD dwError;
     DWORD dwCount;
 
-    TRACE("EnumServicesStatusA() called\n");
+    TRACE("EnumServicesStatusA(%p %lu %lu %p %lu %p %p %p)\n",
+          hSCManager, dwServiceType, dwServiceState, lpServices,
+          cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
 
     if (!hSCManager)
     {
@@ -1115,7 +1328,9 @@ EnumServicesStatusW(SC_HANDLE hSCManager,
     DWORD dwError;
     DWORD dwCount;
 
-    TRACE("EnumServicesStatusW() called\n");
+    TRACE("EnumServicesStatusW(%p %lu %lu %p %lu %p %p %p)\n",
+          hSCManager, dwServiceType, dwServiceState, lpServices,
+          cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
 
     if (!hSCManager)
     {
@@ -1209,7 +1424,10 @@ EnumServicesStatusExA(SC_HANDLE hSCManager,
     DWORD dwError;
     DWORD dwCount;
 
-    TRACE("EnumServicesStatusExA() called\n");
+    TRACE("EnumServicesStatusExA(%p %lu %lu %p %lu %p %p %p %s)\n",
+          hSCManager, dwServiceType, dwServiceState, lpServices,
+          cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle,
+          debugstr_a(pszGroupName));
 
     if (InfoLevel != SC_ENUM_PROCESS_INFO)
     {
@@ -1314,7 +1532,10 @@ EnumServicesStatusExW(SC_HANDLE hSCManager,
     DWORD dwError;
     DWORD dwCount;
 
-    TRACE("EnumServicesStatusExW() called\n");
+    TRACE("EnumServicesStatusExW(%p %lu %lu %p %lu %p %p %p %s)\n",
+          hSCManager, dwServiceType, dwServiceState, lpServices,
+          cbBufSize, pcbBytesNeeded, lpServicesReturned, lpResumeHandle,
+          debugstr_w(pszGroupName));
 
     if (InfoLevel != SC_ENUM_PROCESS_INFO)
     {
@@ -1411,9 +1632,8 @@ GetServiceDisplayNameA(SC_HANDLE hSCManager,
     LPSTR lpNameBuffer;
     CHAR szEmptyName[] = "";
 
-    TRACE("GetServiceDisplayNameA() called\n");
-    TRACE("%p %s %p %p\n", hSCManager,
-          debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
+    TRACE("GetServiceDisplayNameA(%p %s %p %p)\n",
+          hSCManager, debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
 
     if (!hSCManager)
     {
@@ -1440,7 +1660,6 @@ GetServiceDisplayNameA(SC_HANDLE hSCManager,
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
     {
-        /* HACK: because of a problem with rpcrt4, rpcserver is hacked to return 6 for ERROR_SERVICE_DOES_NOT_EXIST */
         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
     }
     RpcEndExcept;
@@ -1471,7 +1690,8 @@ GetServiceDisplayNameW(SC_HANDLE hSCManager,
     LPWSTR lpNameBuffer;
     WCHAR szEmptyName[] = L"";
 
-    TRACE("GetServiceDisplayNameW() called\n");
+    TRACE("GetServiceDisplayNameW(%p %s %p %p)\n",
+          hSCManager, debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
 
     if (!hSCManager)
     {
@@ -1479,6 +1699,11 @@ GetServiceDisplayNameW(SC_HANDLE hSCManager,
         return FALSE;
     }
 
+    /*
+     * NOTE: A size of 1 character would be enough, but tests show that
+     * Windows returns 2 characters instead, certainly due to a WCHAR/bytes
+     * mismatch in their code.
+     */
     if (!lpDisplayName || *lpcchBuffer < sizeof(WCHAR))
     {
         lpNameBuffer = szEmptyName;
@@ -1528,7 +1753,8 @@ GetServiceKeyNameA(SC_HANDLE hSCManager,
     LPSTR lpNameBuffer;
     CHAR szEmptyName[] = "";
 
-    TRACE("GetServiceKeyNameA() called\n");
+    TRACE("GetServiceKeyNameA(%p %s %p %p)\n",
+          hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
 
     if (!hSCManager)
     {
@@ -1555,6 +1781,7 @@ GetServiceKeyNameA(SC_HANDLE hSCManager,
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
     {
+        /* HACK: because of a problem with rpcrt4, rpcserver is hacked to return 6 for ERROR_SERVICE_DOES_NOT_EXIST */
         dwError = ScmRpcStatusToWinError(RpcExceptionCode());
     }
     RpcEndExcept;
@@ -1585,7 +1812,8 @@ GetServiceKeyNameW(SC_HANDLE hSCManager,
     LPWSTR lpNameBuffer;
     WCHAR szEmptyName[] = L"";
 
-    TRACE("GetServiceKeyNameW() called\n");
+    TRACE("GetServiceKeyNameW(%p %s %p %p)\n",
+          hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
 
     if (!hSCManager)
     {
@@ -1593,6 +1821,11 @@ GetServiceKeyNameW(SC_HANDLE hSCManager,
         return FALSE;
     }
 
+    /*
+     * NOTE: A size of 1 character would be enough, but tests show that
+     * Windows returns 2 characters instead, certainly due to a WCHAR/bytes
+     * mismatch in their code.
+     */
     if (!lpServiceName || *lpcchBuffer < sizeof(WCHAR))
     {
         lpNameBuffer = szEmptyName;
@@ -1627,6 +1860,95 @@ GetServiceKeyNameW(SC_HANDLE hSCManager,
 }
 
 
+/**********************************************************************
+ *  I_ScGetCurrentGroupStateW
+ *
+ * @implemented
+ */
+DWORD WINAPI
+I_ScGetCurrentGroupStateW(SC_HANDLE hSCManager,
+                          LPWSTR pszGroupName,
+                          LPDWORD pdwGroupState)
+{
+    DWORD dwError;
+
+    TRACE("I_ScGetCurrentGroupStateW(%p %s %p)\n",
+          hSCManager, debugstr_w(pszGroupName), pdwGroupState);
+
+    RpcTryExcept
+    {
+        dwError = RI_ScGetCurrentGroupStateW((SC_RPC_HANDLE)hSCManager,
+                                             pszGroupName,
+                                             pdwGroupState);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwError = ScmRpcStatusToWinError(RpcExceptionCode());
+    }
+    RpcEndExcept
+
+    if (dwError != ERROR_SUCCESS)
+    {
+        TRACE("RI_ScGetCurrentGroupStateW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+    }
+
+    return dwError;
+}
+
+
+/**********************************************************************
+ *  I_ScValidatePnpService
+ *
+ * Undocumented
+ *
+ * @implemented
+ */
+DWORD
+WINAPI
+I_ScValidatePnpService(
+    _In_ LPCWSTR pszMachineName,
+    _In_ LPCWSTR pszServiceName,
+    _Out_ SERVICE_STATUS_HANDLE *phServiceStatus)
+{
+    SC_RPC_HANDLE hSCManager = NULL;
+    SERVICE_STATUS_HANDLE hServiceStatus = NULL;
+    DWORD dwError;
+
+    TRACE("I_ScValidatePnpService(%S %S %p)\n",
+         pszMachineName, pszServiceName, phServiceStatus);
+
+    hSCManager = OpenSCManagerW(pszMachineName,
+                                SERVICES_ACTIVE_DATABASEW,
+                                SC_MANAGER_CONNECT);
+    if (hSCManager == NULL)
+    {
+        dwError = GetLastError();
+        goto done;
+    }
+
+    RpcTryExcept
+    {
+        dwError = RI_ScValidatePnPService(hSCManager,
+                                          (LPWSTR)pszServiceName,
+                                          (RPC_SERVICE_STATUS_HANDLE *)&hServiceStatus);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwError = ScmRpcStatusToWinError(RpcExceptionCode());
+    }
+    RpcEndExcept
+
+    *phServiceStatus = hServiceStatus;
+
+done:
+    if (hSCManager != NULL)
+        CloseServiceHandle(hSCManager);
+
+    return dwError;
+}
+
+
 /**********************************************************************
  *  LockServiceDatabase
  *
@@ -1638,11 +1960,11 @@ LockServiceDatabase(SC_HANDLE hSCManager)
     SC_LOCK hLock;
     DWORD dwError;
 
-    TRACE("LockServiceDatabase(%x)\n", hSCManager);
+    TRACE("LockServiceDatabase(%p)\n",
+          hSCManager);
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RLockServiceDatabase((SC_RPC_HANDLE)hSCManager,
                                        (SC_RPC_LOCK *)&hLock);
     }
@@ -1670,17 +1992,19 @@ WaitForSCManager(VOID)
 {
     HANDLE hEvent;
 
-    TRACE("WaitForSCManager() called\n");
+    TRACE("WaitForSCManager()\n");
 
     /* Try to open the existing event */
     hEvent = OpenEventW(SYNCHRONIZE, FALSE, SCM_START_EVENT);
     if (hEvent == NULL)
     {
-        if (GetLastError() != ERROR_FILE_NOT_FOUND) return;
+        if (GetLastError() != ERROR_FILE_NOT_FOUND)
+            return;
 
         /* Try to create a new event */
         hEvent = CreateEventW(NULL, TRUE, FALSE, SCM_START_EVENT);
-        if (hEvent == NULL) return;
+        if (hEvent == NULL)
+            return;
     }
 
     /* Wait for 3 minutes */
@@ -1704,14 +2028,13 @@ OpenSCManagerA(LPCSTR lpMachineName,
     SC_HANDLE hScm = NULL;
     DWORD dwError;
 
-    TRACE("OpenSCManagerA(%s, %s, %lx)\n",
-           lpMachineName, lpDatabaseName, dwDesiredAccess);
+    TRACE("OpenSCManagerA(%s %s %lx)\n",
+          debugstr_a(lpMachineName), debugstr_a(lpDatabaseName), dwDesiredAccess);
 
     WaitForSCManager();
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = ROpenSCManagerA((LPSTR)lpMachineName,
                                   (LPSTR)lpDatabaseName,
                                   dwDesiredAccess,
@@ -1723,10 +2046,10 @@ OpenSCManagerA(LPCSTR lpMachineName,
     }
     RpcEndExcept;
 
+    SetLastError(dwError);
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("ROpenSCManagerA() failed (Error %lu)\n", dwError);
-        SetLastError(dwError);
         return NULL;
     }
 
@@ -1749,14 +2072,13 @@ OpenSCManagerW(LPCWSTR lpMachineName,
     SC_HANDLE hScm = NULL;
     DWORD dwError;
 
-    TRACE("OpenSCManagerW(%S, %S, %lx)\n",
-           lpMachineName, lpDatabaseName, dwDesiredAccess);
+    TRACE("OpenSCManagerW(%s %s %lx)\n",
+          debugstr_w(lpMachineName), debugstr_w(lpDatabaseName), dwDesiredAccess);
 
     WaitForSCManager();
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = ROpenSCManagerW((LPWSTR)lpMachineName,
                                   (LPWSTR)lpDatabaseName,
                                   dwDesiredAccess,
@@ -1768,10 +2090,10 @@ OpenSCManagerW(LPCWSTR lpMachineName,
     }
     RpcEndExcept;
 
+    SetLastError(dwError);
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("ROpenSCManagerW() failed (Error %lu)\n", dwError);
-        SetLastError(dwError);
         return NULL;
     }
 
@@ -1794,8 +2116,8 @@ OpenServiceA(SC_HANDLE hSCManager,
     SC_HANDLE hService = NULL;
     DWORD dwError;
 
-    TRACE("OpenServiceA(%p, %s, %lx)\n",
-           hSCManager, lpServiceName, dwDesiredAccess);
+    TRACE("OpenServiceA(%p %s %lx)\n",
+           hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
 
     if (!hSCManager)
     {
@@ -1805,7 +2127,6 @@ OpenServiceA(SC_HANDLE hSCManager,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = ROpenServiceA((SC_RPC_HANDLE)hSCManager,
                                 (LPSTR)lpServiceName,
                                 dwDesiredAccess,
@@ -1817,10 +2138,10 @@ OpenServiceA(SC_HANDLE hSCManager,
     }
     RpcEndExcept;
 
+    SetLastError(dwError);
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("ROpenServiceA() failed (Error %lu)\n", dwError);
-        SetLastError(dwError);
         return NULL;
     }
 
@@ -1843,8 +2164,8 @@ OpenServiceW(SC_HANDLE hSCManager,
     SC_HANDLE hService = NULL;
     DWORD dwError;
 
-    TRACE("OpenServiceW(%p, %S, %lx)\n",
-           hSCManager, lpServiceName, dwDesiredAccess);
+    TRACE("OpenServiceW(%p %s %lx)\n",
+           hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
 
     if (!hSCManager)
     {
@@ -1854,7 +2175,6 @@ OpenServiceW(SC_HANDLE hSCManager,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = ROpenServiceW((SC_RPC_HANDLE)hSCManager,
                                 (LPWSTR)lpServiceName,
                                 dwDesiredAccess,
@@ -1866,10 +2186,10 @@ OpenServiceW(SC_HANDLE hSCManager,
     }
     RpcEndExcept;
 
+    SetLastError(dwError);
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("ROpenServiceW() failed (Error %lu)\n", dwError);
-        SetLastError(dwError);
         return NULL;
     }
 
@@ -1895,7 +2215,7 @@ QueryServiceConfigA(SC_HANDLE hService,
     DWORD dwBufferSize;
     DWORD dwError;
 
-    TRACE("QueryServiceConfigA(%p, %p, %lu, %p)\n",
+    TRACE("QueryServiceConfigA(%p %p %lu %p)\n",
            hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
 
     if (lpServiceConfig == NULL ||
@@ -1912,7 +2232,6 @@ QueryServiceConfigA(SC_HANDLE hService,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceConfigA((SC_RPC_HANDLE)hService,
                                        (LPBYTE)lpConfigPtr,
                                        dwBufferSize,
@@ -1979,7 +2298,7 @@ QueryServiceConfigW(SC_HANDLE hService,
     DWORD dwBufferSize;
     DWORD dwError;
 
-    TRACE("QueryServiceConfigW(%p, %p, %lu, %p)\n",
+    TRACE("QueryServiceConfigW(%p %p %lu %p)\n",
            hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
 
     if (lpServiceConfig == NULL ||
@@ -1996,7 +2315,6 @@ QueryServiceConfigW(SC_HANDLE hService,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceConfigW((SC_RPC_HANDLE)hService,
                                        (LPBYTE)lpConfigPtr,
                                        dwBufferSize,
@@ -2066,7 +2384,7 @@ QueryServiceConfig2A(SC_HANDLE hService,
     DWORD dwBufferSize;
     DWORD dwError;
 
-    TRACE("QueryServiceConfig2A(hService %p, dwInfoLevel %lu, lpBuffer %p, cbBufSize %lu, pcbBytesNeeded %p)\n",
+    TRACE("QueryServiceConfig2A(%p %lu %p %lu %p)\n",
           hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
 
     lpTempBuffer = lpBuffer;
@@ -2100,7 +2418,6 @@ QueryServiceConfig2A(SC_HANDLE hService,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceConfig2A((SC_RPC_HANDLE)hService,
                                         dwInfoLevel,
                                         lpTempBuffer,
@@ -2120,7 +2437,7 @@ QueryServiceConfig2A(SC_HANDLE hService,
         return FALSE;
     }
 
-    if (bUseTempBuffer == TRUE)
+    if (bUseTempBuffer != FALSE)
     {
         TRACE("RQueryServiceConfig2A() returns ERROR_INSUFFICIENT_BUFFER\n");
         *pcbBytesNeeded = dwBufferSize;
@@ -2184,8 +2501,8 @@ QueryServiceConfig2W(SC_HANDLE hService,
     DWORD dwBufferSize;
     DWORD dwError;
 
-    TRACE("QueryServiceConfig2W(%p, %lu, %p, %lu, %p)\n",
-           hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
+    TRACE("QueryServiceConfig2W(%p %lu %p %lu %p)\n",
+          hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
 
     lpTempBuffer = lpBuffer;
     dwBufferSize = cbBufSize;
@@ -2218,7 +2535,6 @@ QueryServiceConfig2W(SC_HANDLE hService,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceConfig2W((SC_RPC_HANDLE)hService,
                                         dwInfoLevel,
                                         lpTempBuffer,
@@ -2238,7 +2554,7 @@ QueryServiceConfig2W(SC_HANDLE hService,
         return FALSE;
     }
 
-    if (bUseTempBuffer == TRUE)
+    if (bUseTempBuffer != FALSE)
     {
         TRACE("RQueryServiceConfig2W() returns ERROR_INSUFFICIENT_BUFFER\n");
         *pcbBytesNeeded = dwBufferSize;
@@ -2299,7 +2615,8 @@ QueryServiceLockStatusA(SC_HANDLE hSCManager,
     DWORD dwBufferSize;
     DWORD dwError;
 
-    TRACE("QueryServiceLockStatusA() called\n");
+    TRACE("QueryServiceLockStatusA(%p %p %lu %p)\n",
+          hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
 
     if (lpLockStatus == NULL || cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSA))
     {
@@ -2314,7 +2631,6 @@ QueryServiceLockStatusA(SC_HANDLE hSCManager,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceLockStatusA((SC_RPC_HANDLE)hSCManager,
                                            (LPBYTE)lpStatusPtr,
                                            dwBufferSize,
@@ -2361,7 +2677,8 @@ QueryServiceLockStatusW(SC_HANDLE hSCManager,
     DWORD dwBufferSize;
     DWORD dwError;
 
-    TRACE("QueryServiceLockStatusW() called\n");
+    TRACE("QueryServiceLockStatusW(%p %p %lu %p)\n",
+          hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
 
     if (lpLockStatus == NULL || cbBufSize < sizeof(QUERY_SERVICE_LOCK_STATUSW))
     {
@@ -2376,7 +2693,6 @@ QueryServiceLockStatusW(SC_HANDLE hSCManager,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceLockStatusW((SC_RPC_HANDLE)hSCManager,
                                            (LPBYTE)lpStatusPtr,
                                            dwBufferSize,
@@ -2421,12 +2737,11 @@ QueryServiceObjectSecurity(SC_HANDLE hService,
 {
     DWORD dwError;
 
-    TRACE("QueryServiceObjectSecurity(%p, %lu, %p)\n",
+    TRACE("QueryServiceObjectSecurity(%p %lu %p)\n",
            hService, dwSecurityInformation, lpSecurityDescriptor);
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceObjectSecurity((SC_RPC_HANDLE)hService,
                                               dwSecurityInformation,
                                               (LPBYTE)lpSecurityDescriptor,
@@ -2449,6 +2764,7 @@ QueryServiceObjectSecurity(SC_HANDLE hService,
     return TRUE;
 }
 
+
 /**********************************************************************
  *  SetServiceObjectSecurity
  *
@@ -2464,6 +2780,9 @@ SetServiceObjectSecurity(SC_HANDLE hService,
     NTSTATUS Status;
     DWORD dwError;
 
+    TRACE("SetServiceObjectSecurity(%p %lu %p)\n",
+          hService, dwSecurityInformation, lpSecurityDescriptor);
+
     Length = 0;
     Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
                                    SelfRelativeSD,
@@ -2493,7 +2812,6 @@ SetServiceObjectSecurity(SC_HANDLE hService,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RSetServiceObjectSecurity((SC_RPC_HANDLE)hService,
                                             dwSecurityInformation,
                                             (LPBYTE)SelfRelativeSD,
@@ -2529,8 +2847,8 @@ QueryServiceStatus(SC_HANDLE hService,
 {
     DWORD dwError;
 
-    TRACE("QueryServiceStatus(%p, %p)\n",
-           hService, lpServiceStatus);
+    TRACE("QueryServiceStatus(%p %p)\n",
+          hService, lpServiceStatus);
 
     if (!hService)
     {
@@ -2540,7 +2858,6 @@ QueryServiceStatus(SC_HANDLE hService,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceStatus((SC_RPC_HANDLE)hService,
                                       lpServiceStatus);
     }
@@ -2575,7 +2892,8 @@ QueryServiceStatusEx(SC_HANDLE hService,
 {
     DWORD dwError;
 
-    TRACE("QueryServiceStatusEx() called\n");
+    TRACE("QueryServiceStatusEx(%p %lu %p %lu %p)\n",
+          hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
 
     if (InfoLevel != SC_STATUS_PROCESS_INFO)
     {
@@ -2592,7 +2910,6 @@ QueryServiceStatusEx(SC_HANDLE hService,
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RQueryServiceStatusEx((SC_RPC_HANDLE)hService,
                                         InfoLevel,
                                         lpBuffer,
@@ -2628,6 +2945,9 @@ StartServiceA(SC_HANDLE hService,
 {
     DWORD dwError;
 
+    TRACE("StartServiceA(%p %lu %p)\n",
+          hService, dwNumServiceArgs, lpServiceArgVectors);
+
     RpcTryExcept
     {
         dwError = RStartServiceA((SC_RPC_HANDLE)hService,
@@ -2663,6 +2983,9 @@ StartServiceW(SC_HANDLE hService,
 {
     DWORD dwError;
 
+    TRACE("StartServiceW(%p %lu %p)\n",
+          hService, dwNumServiceArgs, lpServiceArgVectors);
+
     RpcTryExcept
     {
         dwError = RStartServiceW((SC_RPC_HANDLE)hService,
@@ -2696,11 +3019,11 @@ UnlockServiceDatabase(SC_LOCK ScLock)
 {
     DWORD dwError;
 
-    TRACE("UnlockServiceDatabase(%x)\n", ScLock);
+    TRACE("UnlockServiceDatabase(%x)\n",
+          ScLock);
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RUnlockServiceDatabase((LPSC_RPC_LOCK)&ScLock);
     }
     RpcExcept(EXCEPTION_EXECUTE_HANDLER)
@@ -2709,6 +3032,9 @@ UnlockServiceDatabase(SC_LOCK ScLock)
     }
     RpcEndExcept;
 
+    if (dwError == ERROR_INVALID_HANDLE)
+        dwError = ERROR_INVALID_SERVICE_LOCK;
+
     if (dwError != ERROR_SUCCESS)
     {
         TRACE("RUnlockServiceDatabase() failed (Error %lu)\n", dwError);
@@ -2730,11 +3056,11 @@ NotifyBootConfigStatus(BOOL BootAcceptable)
 {
     DWORD dwError;
 
-    TRACE("NotifyBootConfigStatus()\n");
+    TRACE("NotifyBootConfigStatus(%u)\n",
+          BootAcceptable);
 
     RpcTryExcept
     {
-        /* Call to services.exe using RPC */
         dwError = RNotifyBootConfigStatus(NULL,
                                           BootAcceptable);
     }
@@ -2754,4 +3080,135 @@ NotifyBootConfigStatus(BOOL BootAcceptable)
     return TRUE;
 }
 
+DWORD
+I_ScQueryServiceTagInfo(PVOID Unused,
+                        TAG_INFO_LEVEL dwInfoLevel,
+                        PTAG_INFO_NAME_FROM_TAG InOutParams)
+{
+    SC_HANDLE hScm;
+    DWORD dwError;
+    PTAG_INFO_NAME_FROM_TAG_IN_PARAMS InParams;
+    PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS OutParams;
+    LPWSTR lpszName;
+
+    /* We only support one class */
+    if (dwInfoLevel != TagInfoLevelNameFromTag)
+    {
+        return ERROR_RETRY;
+    }
+
+    /* Validate input structure */
+    if (InOutParams->InParams.dwPid == 0 || InOutParams->InParams.dwTag == 0)
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    /* Validate output structure */
+    if (InOutParams->OutParams.pszName != NULL)
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    /* Open service manager */
+    hScm = OpenSCManagerW(NULL, NULL, SC_MANAGER_ENUMERATE_SERVICE);
+    if (hScm == NULL)
+    {
+        return GetLastError();
+    }
+
+    /* Setup call parameters */
+    InParams = &InOutParams->InParams;
+    OutParams = NULL;
+
+    /* Call SCM to query tag information */
+    RpcTryExcept
+    {
+        dwError = RI_ScQueryServiceTagInfo(hScm, TagInfoLevelNameFromTag, &InParams, &OutParams);
+    }
+    RpcExcept(EXCEPTION_EXECUTE_HANDLER)
+    {
+        dwError = ScmRpcStatusToWinError(RpcExceptionCode());
+    }
+    RpcEndExcept;
+
+    /* Quit if not a success */
+    if (dwError != ERROR_SUCCESS)
+    {
+        goto Cleanup;
+    }
+
+    /* OutParams must be set now and we must have a name */
+    if (OutParams == NULL ||
+        OutParams->pszName == NULL)
+    {
+        dwError = ERROR_INVALID_DATA;
+        goto Cleanup;
+    }
+
+    /* Copy back what SCM returned */
+    lpszName = LocalAlloc(LPTR,
+                          sizeof(WCHAR) * wcslen(OutParams->pszName) + sizeof(UNICODE_NULL));
+    if (lpszName == NULL)
+    {
+        dwError = GetLastError();
+        goto Cleanup;
+    }
+
+    wcscpy(lpszName, OutParams->pszName);
+    InOutParams->OutParams.pszName = lpszName;
+    InOutParams->OutParams.TagType = OutParams->TagType;
+
+Cleanup:
+    CloseServiceHandle(hScm);
+
+    /* Free memory allocated by SCM */
+    if (OutParams != NULL)
+    {
+        if (OutParams->pszName != NULL)
+        {
+            midl_user_free(OutParams->pszName);
+        }
+
+        midl_user_free(OutParams);
+    }
+
+    return dwError;
+}
+
+/**********************************************************************
+ *  I_QueryTagInformation
+ *
+ * @implemented
+ */
+DWORD WINAPI
+I_QueryTagInformation(PVOID Unused,
+                      TAG_INFO_LEVEL dwInfoLevel,
+                      PTAG_INFO_NAME_FROM_TAG InOutParams)
+{
+    /*
+     * We only support one information class and it
+     * needs parameters
+     */
+    if (dwInfoLevel != TagInfoLevelNameFromTag ||
+        InOutParams == NULL)
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    /* Validate input structure */
+    if (InOutParams->InParams.dwPid == 0 || InOutParams->InParams.dwTag == 0)
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    /* Validate output structure */
+    if (InOutParams->OutParams.pszName != NULL)
+    {
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    /* Call internal function for the RPC call */
+    return I_ScQueryServiceTagInfo(Unused, TagInfoLevelNameFromTag, InOutParams);
+}
+
 /* EOF */