Forward StartServiceA/W to services.exe
[reactos.git] / reactos / lib / advapi32 / service / scm.c
index 16f798d..eb50852 100644 (file)
@@ -12,8 +12,8 @@
 
 /* INCLUDES ******************************************************************/
 
-#include "advapi32.h"
-#include "svcctl.h"
+#include <advapi32.h>
+#include "svcctl_c.h"
 
 #define NDEBUG
 #include <debug.h>
@@ -25,37 +25,37 @@ handle_t BindingHandle = NULL;
 static VOID
 HandleBind(VOID)
 {
-  LPWSTR pszStringBinding;
-  RPC_STATUS status;
+    LPWSTR pszStringBinding;
+    RPC_STATUS status;
 
-  if (BindingHandle != NULL)
-    return;
+    if (BindingHandle != NULL)
+        return;
 
-  status = RpcStringBindingComposeW(NULL,
-                                    L"ncacn_np",
-                                    NULL,
-                                    L"\\pipe\\ntsvcs",
-                                    NULL,
-                                    &pszStringBinding);
-  if (status)
-  {
-    DPRINT1("RpcStringBindingCompose returned 0x%x\n", status);
-    return;
-  }
+    status = RpcStringBindingComposeW(NULL,
+                                      L"ncacn_np",
+                                      NULL,
+                                      L"\\pipe\\ntsvcs",
+                                      NULL,
+                                      &pszStringBinding);
+    if (status)
+    {
+        DPRINT1("RpcStringBindingCompose returned 0x%x\n", status);
+        return;
+    }
 
-  /* Set the binding handle that will be used to bind to the server. */
-  status = RpcBindingFromStringBindingW(pszStringBinding,
-                                        &BindingHandle);
-  if (status)
-  {
-    DPRINT1("RpcBindingFromStringBinding returned 0x%x\n", status);
-  }
+    /* Set the binding handle that will be used to bind to the server. */
+    status = RpcBindingFromStringBindingW(pszStringBinding,
+                                          &BindingHandle);
+    if (status)
+    {
+        DPRINT1("RpcBindingFromStringBinding returned 0x%x\n", status);
+    }
 
-  status = RpcStringFreeW(&pszStringBinding);
-  if (status)
-  {
-    DPRINT1("RpcStringFree returned 0x%x\n", status);
-  }
+    status = RpcStringFreeW(&pszStringBinding);
+    if (status)
+    {
+        DPRINT1("RpcStringFree returned 0x%x\n", status);
+    }
 }
 
 
@@ -63,69 +63,204 @@ HandleBind(VOID)
 static VOID
 HandleUnbind(VOID)
 {
-  RPC_STATUS status;
+    RPC_STATUS status;
 
-  if (BindingHandle == NULL)
-    return;
+    if (BindingHandle == NULL)
+        return;
 
-  status = RpcBindingFree(&BindingHandle);
-  if (status)
-  {
-    DPRINT1("RpcBindingFree returned 0x%x\n", status);
-  }
+    status = RpcBindingFree(&BindingHandle);
+    if (status)
+    {
+        DPRINT1("RpcBindingFree returned 0x%x\n", status);
+    }
 }
 #endif
 
 
+/**********************************************************************
+ *  ChangeServiceConfig2W
+ *
+ * @implemented
+ */
+BOOL WINAPI
+ChangeServiceConfig2W(SC_HANDLE hService,
+                      DWORD dwInfoLevel,
+                      LPVOID lpInfo)
+{
+    DWORD lpInfoSize;
+    DWORD dwError;
+
+    DPRINT("ChangeServiceConfig2W() called\n");
+
+    /* Determine the length of the lpInfo parameter */
+    switch (dwInfoLevel)
+    {
+        case SERVICE_CONFIG_DESCRIPTION:
+            lpInfoSize = sizeof(SERVICE_DESCRIPTION);
+            break;
+        case SERVICE_CONFIG_FAILURE_ACTIONS:
+            lpInfoSize = sizeof(SERVICE_FAILURE_ACTIONS);
+            break;
+        default:
+            DPRINT1("Unknown info level 0x%lx\n", dwInfoLevel);
+            SetLastError(ERROR_INVALID_PARAMETER);
+            return FALSE;
+    }
+
+    if (lpInfo == NULL)
+        return TRUE;
+
+    HandleBind();
+
+    dwError = ScmrChangeServiceConfig2W(BindingHandle,
+                                        (unsigned int)hService,
+                                        dwInfoLevel,
+                                        lpInfo,
+                                        lpInfoSize);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrChangeServiceConfig2W() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
+}
+
+
 /**********************************************************************
  *  ChangeServiceConfigA
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-ChangeServiceConfigA(
-    SC_HANDLE   hService,
-    DWORD       dwServiceType,
-    DWORD       dwStartType,
-    DWORD       dwErrorControl,
-    LPCSTR      lpBinaryPathName,
-    LPCSTR      lpLoadOrderGroup,
-    LPDWORD     lpdwTagId,
-    LPCSTR      lpDependencies,
-    LPCSTR      lpServiceStartName,
-    LPCSTR      lpPassword,
-    LPCSTR      lpDisplayName)
-{
-    DPRINT1("ChangeServiceConfigA is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+BOOL STDCALL
+ChangeServiceConfigA(SC_HANDLE hService,
+                     DWORD dwServiceType,
+                     DWORD dwStartType,
+                     DWORD dwErrorControl,
+                     LPCSTR lpBinaryPathName,
+                     LPCSTR lpLoadOrderGroup,
+                     LPDWORD lpdwTagId,
+                     LPCSTR lpDependencies,
+                     LPCSTR lpServiceStartName,
+                     LPCSTR lpPassword,
+                     LPCSTR lpDisplayName)
+{
+    DWORD dwError;
+    DWORD dwDependenciesLength = 0;
+    DWORD dwLength;
+    LPSTR lpStr;
+
+    DPRINT("ChangeServiceConfigA() called\n");
+
+    /* Calculate the Dependencies length*/
+    if (lpDependencies != NULL)
+    {
+        lpStr = (LPSTR)lpDependencies;
+        while (*lpStr)
+        {
+            dwLength = strlen(lpStr) + 1;
+            dwDependenciesLength += dwLength;
+            lpStr = lpStr + dwLength;
+        }
+        dwDependenciesLength++;
+    }
+
+    /* FIXME: Encrypt the password */
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrChangeServiceConfigA(BindingHandle,
+                                       (unsigned int)hService,
+                                       dwServiceType,
+                                       dwStartType,
+                                       dwErrorControl,
+                                       (LPSTR)lpBinaryPathName,
+                                       (LPSTR)lpLoadOrderGroup,
+                                       lpdwTagId,
+                                       (LPSTR)lpDependencies,
+                                       dwDependenciesLength,
+                                       (LPSTR)lpServiceStartName,
+                                       NULL,              /* FIXME: lpPassword */
+                                       0,                 /* FIXME: dwPasswordLength */
+                                       (LPSTR)lpDisplayName);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrChangeServiceConfigA() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  ChangeServiceConfigW
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-ChangeServiceConfigW(
-    SC_HANDLE   hService,
-    DWORD       dwServiceType,
-    DWORD       dwStartType,
-    DWORD       dwErrorControl,
-    LPCWSTR     lpBinaryPathName,
-    LPCWSTR     lpLoadOrderGroup,
-    LPDWORD     lpdwTagId,
-    LPCWSTR     lpDependencies,
-    LPCWSTR     lpServiceStartName,
-    LPCWSTR     lpPassword,
-    LPCWSTR     lpDisplayName)
-{
-    DPRINT1("ChangeServiceConfigW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+BOOL STDCALL
+ChangeServiceConfigW(SC_HANDLE hService,
+                     DWORD dwServiceType,
+                     DWORD dwStartType,
+                     DWORD dwErrorControl,
+                     LPCWSTR lpBinaryPathName,
+                     LPCWSTR lpLoadOrderGroup,
+                     LPDWORD lpdwTagId,
+                     LPCWSTR lpDependencies,
+                     LPCWSTR lpServiceStartName,
+                     LPCWSTR lpPassword,
+                     LPCWSTR lpDisplayName)
+{
+    DWORD dwError;
+    DWORD dwDependenciesLength = 0;
+    DWORD dwLength;
+    LPWSTR lpStr;
+
+    DPRINT("ChangeServiceConfigW() called\n");
+
+    /* Calculate the Dependencies length*/
+    if (lpDependencies != NULL)
+    {
+        lpStr = (LPWSTR)lpDependencies;
+        while (*lpStr)
+        {
+            dwLength = wcslen(lpStr) + 1;
+            dwDependenciesLength += dwLength;
+            lpStr = lpStr + dwLength;
+        }
+        dwDependenciesLength++;
+    }
+
+    /* FIXME: Encrypt the password */
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrChangeServiceConfigW(BindingHandle,
+                                       (unsigned int)hService,
+                                       dwServiceType,
+                                       dwStartType,
+                                       dwErrorControl,
+                                       (LPWSTR)lpBinaryPathName,
+                                       (LPWSTR)lpLoadOrderGroup,
+                                       lpdwTagId,
+                                       (LPWSTR)lpDependencies,
+                                       dwDependenciesLength,
+                                       (LPWSTR)lpServiceStartName,
+                                       NULL,              /* FIXME: lpPassword */
+                                       0,                 /* FIXME: dwPasswordLength */
+                                       (LPWSTR)lpDisplayName);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrChangeServiceConfigW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
@@ -137,116 +272,287 @@ ChangeServiceConfigW(
 BOOL STDCALL
 CloseServiceHandle(SC_HANDLE hSCObject)
 {
-  DWORD dwError;
+    DWORD dwError;
 
-  DPRINT1("CloseServiceHandle() called\n");
+    DPRINT("CloseServiceHandle() called\n");
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrCloseServiceHandle(BindingHandle,
-                                   (unsigned int)hSCObject);
-  DPRINT1("dwError %lu\n", dwError);
+    /* Call to services.exe using RPC */
+    dwError = ScmrCloseServiceHandle(BindingHandle,
+                                     (unsigned int)hSCObject);
+    if (dwError)
+    {
+        DPRINT1("ScmrCloseServiceHandle() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
 
-  if (dwError)
-  {
-    SetLastError(dwError);
-    return FALSE;
-  }
+    DPRINT("CloseServiceHandle() done\n");
 
-  return TRUE;
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  ControlService
  *
- * @unimplemented
+ * @implemented
  */
 BOOL STDCALL
-ControlService(SC_HANDLE        hService,
-               DWORD            dwControl,
+ControlService(SC_HANDLE hService,
+               DWORD dwControl,
                LPSERVICE_STATUS lpServiceStatus)
 {
-#if 0
-  DWORD dwError;
+    DWORD dwError;
 
-  DPRINT1("ControlService(%x, %x, %p)\n",
-          hService, dwControl, lpServiceStatus);
+    DPRINT("ControlService(%x, %x, %p)\n",
+           hService, dwControl, lpServiceStatus);
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrControlService(BindingHandle,
-                               (unsigned int)hService,
-                               dwControl,
-                               lpServiceStatus);
-  if (dwError != ERROR_SUCCESS)
-  {
-    SetLastError(dwError);
-    return FALSE;
-  }
+    /* Call to services.exe using RPC */
+    dwError = ScmrControlService(BindingHandle,
+                                 (unsigned int)hService,
+                                 dwControl,
+                                 lpServiceStatus);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrControlService() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
 
-  return TRUE;
-#endif
+    DPRINT("ControlService() done\n");
 
-  DPRINT1("ControlService is unimplemented\n");
-  SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-  return FALSE;
+    return TRUE;
 }
 
 
 /**********************************************************************
- *  CreateServiceA
+ *  ControlServiceEx
  *
  * @unimplemented
  */
+BOOL STDCALL
+ControlServiceEx(IN SC_HANDLE hService,
+                 IN DWORD dwControl,
+                 IN DWORD dwInfoLevel,
+                 IN OUT PVOID pControlParams)
+{
+    DPRINT1("ControlServiceEx(0x%p, 0x%x, 0x%x, 0x%p) UNIMPLEMENTED!\n",
+            hService, dwControl, dwInfoLevel, pControlParams);
+    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    return FALSE;
+}
+
+
+
+/**********************************************************************
+ *  CreateServiceA
+ *
+ * @implemented
+ */
 SC_HANDLE
 STDCALL
-CreateServiceA(
-    SC_HANDLE   hSCManager,
-    LPCSTR      lpServiceName,
-    LPCSTR      lpDisplayName,
-    DWORD       dwDesiredAccess,
-    DWORD       dwServiceType,
-    DWORD       dwStartType,
-    DWORD       dwErrorControl,
-    LPCSTR      lpBinaryPathName,
-    LPCSTR      lpLoadOrderGroup,
-    LPDWORD     lpdwTagId,
-    LPCSTR      lpDependencies,
-    LPCSTR      lpServiceStartName,
-    LPCSTR      lpPassword)
+CreateServiceA(SC_HANDLE hSCManager,
+               LPCSTR lpServiceName,
+               LPCSTR lpDisplayName,
+               DWORD dwDesiredAccess,
+               DWORD dwServiceType,
+               DWORD dwStartType,
+               DWORD dwErrorControl,
+               LPCSTR lpBinaryPathName,
+               LPCSTR lpLoadOrderGroup,
+               LPDWORD lpdwTagId,
+               LPCSTR lpDependencies,
+               LPCSTR lpServiceStartName,
+               LPCSTR lpPassword)
 {
-    DPRINT1("CreateServiceA is unimplemented, but returning INVALID_HANDLE_VALUE instead of NULL\n");
-    return INVALID_HANDLE_VALUE;
+    SC_HANDLE RetVal = NULL;
+    LPWSTR lpServiceNameW = NULL;
+    LPWSTR lpDisplayNameW = NULL;
+    LPWSTR lpBinaryPathNameW = NULL;
+    LPWSTR lpLoadOrderGroupW = NULL;
+    LPWSTR lpDependenciesW = NULL;
+    LPWSTR lpServiceStartNameW = NULL;
+    LPWSTR lpPasswordW = NULL;
+    DWORD dwDependenciesLength = 0;
+    DWORD dwLength;
+    LPSTR lpStr;
+
+    int len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
+    lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!lpServiceNameW)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
+
+    len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
+    lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!lpDisplayNameW)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
+
+    len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
+    lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!lpBinaryPathNameW)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpBinaryPathNameW, len);
+
+    len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
+    lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!lpLoadOrderGroupW)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
+
+    if (lpDependencies != NULL)
+    {
+        lpStr = (LPSTR)lpDependencies;
+        while (*lpStr)
+        {
+            dwLength = strlen(lpStr) + 1;
+            dwDependenciesLength += dwLength;
+            lpStr = lpStr + dwLength;
+        }
+        dwDependenciesLength++;
+    }
+
+    lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
+    if (!lpDependenciesW)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    MultiByteToWideChar(CP_ACP, 0, lpDependencies, -1, lpDependenciesW, dwDependenciesLength);
+
+    len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
+    lpServiceStartName = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!lpServiceStartNameW)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
+
+    len = MultiByteToWideChar(CP_ACP, 0, lpPassword, -1, NULL, 0);
+    lpPasswordW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
+    if (!lpPasswordW)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        goto cleanup;
+    }
+    MultiByteToWideChar(CP_ACP, 0, lpPassword, -1, lpPasswordW, len);
+
+    RetVal = CreateServiceW(hSCManager,
+                            lpServiceNameW,
+                            lpDisplayNameW,
+                            dwDesiredAccess,
+                            dwServiceType,
+                            dwStartType,
+                            dwErrorControl,
+                            lpBinaryPathNameW,
+                            lpLoadOrderGroupW,
+                            lpdwTagId,
+                            lpDependenciesW,
+                            lpServiceStartNameW,
+                            lpPasswordW);
+
+cleanup:
+    HeapFree(GetProcessHeap(), 0, lpServiceNameW);
+    HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
+    HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
+    HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
+    HeapFree(GetProcessHeap(), 0, lpDependenciesW);
+    HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
+    HeapFree(GetProcessHeap(), 0, lpPasswordW);
+
+    return RetVal;
 }
 
 
 /**********************************************************************
  *  CreateServiceW
  *
- * @unimplemented
+ * @implemented
  */
-SC_HANDLE
-STDCALL
-CreateServiceW(
-    SC_HANDLE   hSCManager,
-    LPCWSTR     lpServiceName,
-    LPCWSTR     lpDisplayName,
-    DWORD       dwDesiredAccess,
-    DWORD       dwServiceType,
-    DWORD       dwStartType,
-    DWORD       dwErrorControl,
-    LPCWSTR     lpBinaryPathName,
-    LPCWSTR     lpLoadOrderGroup,
-    LPDWORD     lpdwTagId,
-    LPCWSTR     lpDependencies,
-    LPCWSTR     lpServiceStartName,
-    LPCWSTR     lpPassword)
+SC_HANDLE STDCALL
+CreateServiceW(SC_HANDLE hSCManager,
+               LPCWSTR lpServiceName,
+               LPCWSTR lpDisplayName,
+               DWORD dwDesiredAccess,
+               DWORD dwServiceType,
+               DWORD dwStartType,
+               DWORD dwErrorControl,
+               LPCWSTR lpBinaryPathName,
+               LPCWSTR lpLoadOrderGroup,
+               LPDWORD lpdwTagId,
+               LPCWSTR lpDependencies,
+               LPCWSTR lpServiceStartName,
+               LPCWSTR lpPassword)
 {
-    DPRINT1("CreateServiceW is unimplemented, but returning INVALID_HANDLE_VALUE instead of NULL\n");
-    return INVALID_HANDLE_VALUE;
+    SC_HANDLE hService = NULL;
+    DWORD dwError;
+    DWORD dwDependenciesLength = 0;
+    DWORD dwLength;
+    LPWSTR lpStr;
+
+    DPRINT1("CreateServiceW() called\n");
+
+    /* Calculate the Dependencies length*/
+    if (lpDependencies != NULL)
+    {
+        lpStr = (LPWSTR)lpDependencies;
+        while (*lpStr)
+        {
+            dwLength = wcslen(lpStr) + 1;
+            dwDependenciesLength += dwLength;
+            lpStr = lpStr + dwLength;
+        }
+        dwDependenciesLength++;
+    }
+
+    /* FIXME: Encrypt the password */
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrCreateServiceW(BindingHandle,
+                                 (unsigned int)hSCManager,
+                                 (LPWSTR)lpServiceName,
+                                 (LPWSTR)lpDisplayName,
+                                 dwDesiredAccess,
+                                 dwServiceType,
+                                 dwStartType,
+                                 dwErrorControl,
+                                 (LPWSTR)lpBinaryPathName,
+                                 (LPWSTR)lpLoadOrderGroup,
+                                 lpdwTagId,
+                                 (LPWSTR)lpDependencies,
+                                 dwDependenciesLength,
+                                 (LPWSTR)lpServiceStartName,
+                                 NULL,              /* FIXME: lpPassword */
+                                 0,                 /* FIXME: dwPasswordLength */
+                                 (unsigned int *)&hService);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrCreateServiceW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return NULL;
+    }
+
+    return hService;
 }
 
 
@@ -258,22 +564,23 @@ CreateServiceW(
 BOOL STDCALL
 DeleteService(SC_HANDLE hService)
 {
-  DWORD dwError;
+    DWORD dwError;
 
-  DPRINT1("DeleteService(%x)\n", hService);
+    DPRINT("DeleteService(%x)\n", hService);
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrDeleteService(BindingHandle,
-                              (unsigned int)hService);
-  if (dwError != ERROR_SUCCESS)
-  {
-    SetLastError(dwError);
-    return FALSE;
-  }
+    /* Call to services.exe using RPC */
+    dwError = ScmrDeleteService(BindingHandle,
+                                (unsigned int)hService);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrDeleteService() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
 
-  return TRUE;
+    return TRUE;
 }
 
 
@@ -305,13 +612,12 @@ EnumDependentServicesA(
  */
 BOOL
 STDCALL
-EnumDependentServicesW(
-    SC_HANDLE       hService,
-    DWORD           dwServiceState,
-    LPENUM_SERVICE_STATUSW  lpServices,
-    DWORD           cbBufSize,
-    LPDWORD         pcbBytesNeeded,
-    LPDWORD         lpServicesReturned)
+EnumDependentServicesW(SC_HANDLE hService,
+                       DWORD dwServiceState,
+                       LPENUM_SERVICE_STATUSW lpServices,
+                       DWORD cbBufSize,
+                       LPDWORD pcbBytesNeeded,
+                       LPDWORD lpServicesReturned)
 {
     DPRINT1("EnumDependentServicesW is unimplemented\n");
     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
@@ -326,16 +632,16 @@ EnumDependentServicesW(
  */
 BOOL
 STDCALL
-EnumServiceGroupW (
-    DWORD   Unknown0,
-    DWORD   Unknown1,
-    DWORD   Unknown2,
-    DWORD   Unknown3,
-    DWORD   Unknown4,
-    DWORD   Unknown5,
-    DWORD   Unknown6,
-    DWORD   Unknown7,
-    DWORD   Unknown8)
+EnumServiceGroupW(
+    SC_HANDLE               hSCManager,
+    DWORD                   dwServiceType,
+    DWORD                   dwServiceState,
+    LPENUM_SERVICE_STATUSA  lpServices,
+    DWORD                   cbBufSize,
+    LPDWORD                 pcbBytesNeeded,
+    LPDWORD                 lpServicesReturned,
+    LPDWORD                 lpResumeHandle,
+    LPCWSTR                 lpGroup)
 {
     DPRINT1("EnumServiceGroupW is unimplemented\n");
     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
@@ -350,7 +656,7 @@ EnumServiceGroupW (
  */
 BOOL
 STDCALL
-EnumServicesStatusA (
+EnumServicesStatusA(
     SC_HANDLE               hSCManager,
     DWORD                   dwServiceType,
     DWORD                   dwServiceState,
@@ -367,37 +673,73 @@ EnumServicesStatusA (
 
 
 /**********************************************************************
- *  EnumServicesStatusExA
+ *  EnumServicesStatusW
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-EnumServicesStatusExA(SC_HANDLE  hSCManager,
-  SC_ENUM_TYPE  InfoLevel,
-  DWORD  dwServiceType,
-  DWORD  dwServiceState,
-  LPBYTE  lpServices,
-  DWORD  cbBufSize,
-  LPDWORD  pcbBytesNeeded,
-  LPDWORD  lpServicesReturned,
-  LPDWORD  lpResumeHandle,
-  LPCSTR  pszGroupName)
+BOOL STDCALL
+EnumServicesStatusW(SC_HANDLE hSCManager,
+                    DWORD dwServiceType,
+                    DWORD dwServiceState,
+                    LPENUM_SERVICE_STATUSW lpServices,
+                    DWORD cbBufSize,
+                    LPDWORD pcbBytesNeeded,
+                    LPDWORD lpServicesReturned,
+                    LPDWORD lpResumeHandle)
 {
-    DPRINT1("EnumServicesStatusExA is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    LPENUM_SERVICE_STATUSW lpStatusPtr;
+    DWORD dwError = ERROR_SUCCESS;
+    DWORD dwCount;
+
+    DPRINT("EnumServicesStatusW() called\n");
+
+    HandleBind();
+
+    dwError = ScmrEnumServicesStatusW(BindingHandle,
+                                      (unsigned int)hSCManager,
+                                      dwServiceType,
+                                      dwServiceState,
+                                      (unsigned char *)lpServices,
+                                      cbBufSize,
+                                      pcbBytesNeeded,
+                                      lpServicesReturned,
+                                      lpResumeHandle);
+
+    lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpServices;
+    for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
+    {
+        if (lpStatusPtr->lpServiceName)
+            lpStatusPtr->lpServiceName =
+                (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
+
+        if (lpStatusPtr->lpDisplayName)
+            lpStatusPtr->lpDisplayName =
+                (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
+
+        lpStatusPtr++;
+    }
+
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT("ScmrEnumServicesStatusW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    DPRINT("ScmrEnumServicesStatusW() done\n");
+
+    return TRUE;
 }
 
 
 /**********************************************************************
- *  EnumServicesStatusExW
+ *  EnumServicesStatusExA
  *
  * @unimplemented
  */
 BOOL
 STDCALL
-EnumServicesStatusExW(SC_HANDLE  hSCManager,
+EnumServicesStatusExA(SC_HANDLE  hSCManager,
   SC_ENUM_TYPE  InfoLevel,
   DWORD  dwServiceType,
   DWORD  dwServiceState,
@@ -406,110 +748,215 @@ EnumServicesStatusExW(SC_HANDLE  hSCManager,
   LPDWORD  pcbBytesNeeded,
   LPDWORD  lpServicesReturned,
   LPDWORD  lpResumeHandle,
-  LPCWSTR  pszGroupName)
+  LPCSTR  pszGroupName)
 {
-    DPRINT1("EnumServicesStatusExW is unimplemented\n");
+    DPRINT1("EnumServicesStatusExA is unimplemented\n");
     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
     return FALSE;
 }
 
 
 /**********************************************************************
- *  EnumServicesStatusW
+ *  EnumServicesStatusExW
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-EnumServicesStatusW(
-    SC_HANDLE               hSCManager,
-    DWORD                   dwServiceType,
-    DWORD                   dwServiceState,
-    LPENUM_SERVICE_STATUSW  lpServices,
-    DWORD                   cbBufSize,
-    LPDWORD                 pcbBytesNeeded,
-    LPDWORD                 lpServicesReturned,
-    LPDWORD                 lpResumeHandle)
+BOOL STDCALL
+EnumServicesStatusExW(SC_HANDLE hSCManager,
+                      SC_ENUM_TYPE InfoLevel,
+                      DWORD dwServiceType,
+                      DWORD dwServiceState,
+                      LPBYTE lpServices,
+                      DWORD cbBufSize,
+                      LPDWORD pcbBytesNeeded,
+                      LPDWORD lpServicesReturned,
+                      LPDWORD lpResumeHandle,
+                      LPCWSTR pszGroupName)
 {
-    DPRINT1("EnumServicesStatusW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
+    DWORD dwError = ERROR_SUCCESS;
+    DWORD dwCount;
+
+    DPRINT1("EnumServicesStatusExW() called\n");
+
+    HandleBind();
+
+    dwError = ScmrEnumServicesStatusExW(BindingHandle,
+                                        (unsigned int)hSCManager,
+                                        (unsigned long)InfoLevel,
+                                        dwServiceType,
+                                        dwServiceState,
+                                        (unsigned char *)lpServices,
+                                        cbBufSize,
+                                        pcbBytesNeeded,
+                                        lpServicesReturned,
+                                        lpResumeHandle,
+                                        (wchar_t *)pszGroupName);
+
+    lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpServices;
+    for (dwCount = 0; dwCount < *lpServicesReturned; dwCount++)
+    {
+        if (lpStatusPtr->lpServiceName)
+            lpStatusPtr->lpServiceName =
+                (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpServiceName);
+
+        if (lpStatusPtr->lpDisplayName)
+            lpStatusPtr->lpDisplayName =
+                (LPWSTR)((ULONG_PTR)lpServices + (ULONG_PTR)lpStatusPtr->lpDisplayName);
+
+        lpStatusPtr++;
+    }
+
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrEnumServicesStatusExW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    DPRINT1("ScmrEnumServicesStatusExW() done\n");
+
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  GetServiceDisplayNameA
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-GetServiceDisplayNameA(
-    SC_HANDLE   hSCManager,
-    LPCSTR      lpServiceName,
-    LPSTR       lpDisplayName,
-    LPDWORD     lpcchBuffer)
+BOOL STDCALL
+GetServiceDisplayNameA(SC_HANDLE hSCManager,
+                       LPCSTR lpServiceName,
+                       LPSTR lpDisplayName,
+                       LPDWORD lpcchBuffer)
 {
-    DPRINT1("GetServiceDisplayNameA is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("GetServiceDisplayNameA() called\n");
+
+    HandleBind();
+
+    dwError = ScmrGetServiceDisplayNameA(BindingHandle,
+                                         (unsigned int)hSCManager,
+                                         (LPSTR)lpServiceName,
+                                         lpDisplayName,
+                                         lpcchBuffer);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrGetServiceDisplayNameA() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    (*lpcchBuffer)--;
+
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  GetServiceDisplayNameW
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-GetServiceDisplayNameW(
-    SC_HANDLE   hSCManager,
-    LPCWSTR     lpServiceName,
-    LPWSTR      lpDisplayName,
-    LPDWORD     lpcchBuffer)
+BOOL STDCALL
+GetServiceDisplayNameW(SC_HANDLE hSCManager,
+                       LPCWSTR lpServiceName,
+                       LPWSTR lpDisplayName,
+                       LPDWORD lpcchBuffer)
 {
-    DPRINT1("GetServiceDisplayNameW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("GetServiceDisplayNameW() called\n");
+
+    HandleBind();
+
+    dwError = ScmrGetServiceDisplayNameW(BindingHandle,
+                                         (unsigned int)hSCManager,
+                                         (LPWSTR)lpServiceName,
+                                         lpDisplayName,
+                                         lpcchBuffer);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrGetServiceDisplayNameW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    (*lpcchBuffer)--;
+
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  GetServiceKeyNameA
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-GetServiceKeyNameA(
-    SC_HANDLE   hSCManager,
-    LPCSTR      lpDisplayName,
-    LPSTR       lpServiceName,
-    LPDWORD     lpcchBuffer)
+BOOL STDCALL
+GetServiceKeyNameA(SC_HANDLE hSCManager,
+                   LPCSTR lpDisplayName,
+                   LPSTR lpServiceName,
+                   LPDWORD lpcchBuffer)
 {
-    DPRINT1("GetServiceKeyNameA is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("GetServiceKeyNameA() called\n");
+
+    HandleBind();
+
+    dwError = ScmrGetServiceKeyNameA(BindingHandle,
+                                     (unsigned int)hSCManager,
+                                     (LPSTR)lpDisplayName,
+                                     lpServiceName,
+                                     lpcchBuffer);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrGetServiceKeyNameA() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    (*lpcchBuffer)--;
+
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  GetServiceKeyNameW
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-GetServiceKeyNameW(
-    SC_HANDLE   hSCManager,
-    LPCWSTR     lpDisplayName,
-    LPWSTR      lpServiceName,
-    LPDWORD     lpcchBuffer)
+BOOL STDCALL
+GetServiceKeyNameW(SC_HANDLE hSCManager,
+                   LPCWSTR lpDisplayName,
+                   LPWSTR lpServiceName,
+                   LPDWORD lpcchBuffer)
 {
-    DPRINT1("GetServiceKeyNameW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("GetServiceKeyNameW() called\n");
+
+    HandleBind();
+
+    dwError = ScmrGetServiceKeyNameW(BindingHandle,
+                                     (unsigned int)hSCManager,
+                                     (LPWSTR)lpDisplayName,
+                                     lpServiceName,
+                                     lpcchBuffer);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrGetServiceKeyNameW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    (*lpcchBuffer)--;
+
+    return TRUE;
 }
 
 
@@ -521,67 +968,67 @@ GetServiceKeyNameW(
 SC_LOCK STDCALL
 LockServiceDatabase(SC_HANDLE hSCManager)
 {
-  SC_LOCK hLock;
-  DWORD dwError;
+    SC_LOCK hLock;
+    DWORD dwError;
 
-  DPRINT("LockServiceDatabase(%x)\n", hSCManager);
+    DPRINT("LockServiceDatabase(%x)\n", hSCManager);
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrLockServiceDatabase(BindingHandle,
-                                    (unsigned int)hSCManager,
-                                    (unsigned int *)&hLock);
-  if (dwError != ERROR_SUCCESS)
-  {
-    DPRINT("ScmrLockServiceDatabase() failed (Error %lu)\n", dwError);
-    SetLastError(dwError);
-    return NULL;
-  }
+    /* Call to services.exe using RPC */
+    dwError = ScmrLockServiceDatabase(BindingHandle,
+                                      (unsigned int)hSCManager,
+                                      (unsigned int *)&hLock);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrLockServiceDatabase() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return NULL;
+    }
 
-  DPRINT("hLock = %p\n", hLock);
+    DPRINT("hLock = %p\n", hLock);
 
-  return hLock;
+    return hLock;
 }
 
 
 static VOID
 WaitForSCManager(VOID)
 {
-  HANDLE hEvent;
+    HANDLE hEvent;
 
-  DPRINT("WaitForSCManager() called\n");
+    DPRINT("WaitForSCManager() called\n");
 
-  /* Try to open the existing event */
-  hEvent = OpenEventW(SYNCHRONIZE,
-                      FALSE,
-                      L"SvcctrlStartEvent_A3725DX");
-  if (hEvent == NULL)
-  {
-    if (GetLastError() != ERROR_FILE_NOT_FOUND)
-      return;
-
-    /* Try to create a new event */
-    hEvent = CreateEventW(NULL,
-                          TRUE,
-                          FALSE,
-                          L"SvcctrlStartEvent_A3725DX");
+    /* Try to open the existing event */
+    hEvent = OpenEventW(SYNCHRONIZE,
+                        FALSE,
+                        L"SvcctrlStartEvent_A3725DX");
     if (hEvent == NULL)
     {
-      /* Try to open the existing event again */
-      hEvent = OpenEventW(SYNCHRONIZE,
-                          FALSE,
-                          L"SvcctrlStartEvent_A3725DX");
-      if (hEvent == NULL)
-        return;
+        if (GetLastError() != ERROR_FILE_NOT_FOUND)
+            return;
+
+        /* Try to create a new event */
+        hEvent = CreateEventW(NULL,
+                              TRUE,
+                              FALSE,
+                              L"SvcctrlStartEvent_A3725DX");
+        if (hEvent == NULL)
+        {
+            /* Try to open the existing event again */
+            hEvent = OpenEventW(SYNCHRONIZE,
+                                FALSE,
+                                L"SvcctrlStartEvent_A3725DX");
+            if (hEvent == NULL)
+                return;
+        }
     }
-  }
 
-  /* Wait for 3 minutes */
-  WaitForSingleObject(hEvent, 180000);
-  CloseHandle(hEvent);
+    /* Wait for 3 minutes */
+    WaitForSingleObject(hEvent, 180000);
+    CloseHandle(hEvent);
 
-  DPRINT("ScmWaitForSCManager() done\n");
+    DPRINT("ScmWaitForSCManager() done\n");
 }
 
 
@@ -595,32 +1042,32 @@ OpenSCManagerA(LPCSTR lpMachineName,
                LPCSTR lpDatabaseName,
                DWORD dwDesiredAccess)
 {
-  SC_HANDLE hScm = NULL;
-  DWORD dwError;
+    SC_HANDLE hScm = NULL;
+    DWORD dwError;
 
-  DPRINT("OpenSCManagerA(%s, %s, %lx)\n",
-         lpMachineName, lpDatabaseName, dwDesiredAccess);
+    DPRINT("OpenSCManagerA(%s, %s, %lx)\n",
+           lpMachineName, lpDatabaseName, dwDesiredAccess);
 
-  WaitForSCManager();
+    WaitForSCManager();
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrOpenSCManagerA(BindingHandle,
-                               (LPSTR)lpMachineName,
-                               (LPSTR)lpDatabaseName,
-                               dwDesiredAccess,
-                               (unsigned int*)&hScm);
-  if (dwError)
-  {
-    DPRINT("ScmrOpenSCManagerA() failed (Error %lu)\n", dwError);
-    SetLastError(dwError);
-    return NULL;
-  }
+    /* Call to services.exe using RPC */
+    dwError = ScmrOpenSCManagerA(BindingHandle,
+                                 (LPSTR)lpMachineName,
+                                 (LPSTR)lpDatabaseName,
+                                 dwDesiredAccess,
+                                 (unsigned int*)&hScm);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrOpenSCManagerA() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return NULL;
+    }
 
-  DPRINT("hScm = %p\n", hScm);
+    DPRINT("hScm = %p\n", hScm);
 
-  return hScm;
+    return hScm;
 }
 
 
@@ -634,32 +1081,32 @@ OpenSCManagerW(LPCWSTR lpMachineName,
                LPCWSTR lpDatabaseName,
                DWORD dwDesiredAccess)
 {
-  SC_HANDLE hScm = NULL;
-  DWORD dwError;
+    SC_HANDLE hScm = NULL;
+    DWORD dwError;
 
-  DPRINT("OpenSCManagerW(%S, %S, %lx)\n",
-         lpMachineName, lpDatabaseName, dwDesiredAccess);
+    DPRINT("OpenSCManagerW(%S, %S, %lx)\n",
+           lpMachineName, lpDatabaseName, dwDesiredAccess);
 
-  WaitForSCManager();
+    WaitForSCManager();
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrOpenSCManagerW(BindingHandle,
-                               (LPWSTR)lpMachineName,
-                               (LPWSTR)lpDatabaseName,
-                               dwDesiredAccess,
-                               (unsigned int*)&hScm);
-  if (dwError != ERROR_SUCCESS)
-  {
-    DPRINT1("ScmrOpenSCManagerW() failed (Error %lu)\n", dwError);
-    SetLastError(dwError);
-    return NULL;
-  }
+    /* Call to services.exe using RPC */
+    dwError = ScmrOpenSCManagerW(BindingHandle,
+                                 (LPWSTR)lpMachineName,
+                                 (LPWSTR)lpDatabaseName,
+                                 dwDesiredAccess,
+                                 (unsigned int*)&hScm);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrOpenSCManagerW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return NULL;
+    }
 
-  DPRINT("hScm = %p\n", hScm);
+    DPRINT("hScm = %p\n", hScm);
 
-  return hScm;
+    return hScm;
 }
 
 
@@ -673,30 +1120,30 @@ OpenServiceA(SC_HANDLE hSCManager,
              LPCSTR lpServiceName,
              DWORD dwDesiredAccess)
 {
-  SC_HANDLE hService = NULL;
-  DWORD dwError;
+    SC_HANDLE hService = NULL;
+    DWORD dwError;
 
-  DPRINT("OpenServiceA(%p, %s, %lx)\n",
-         hSCManager, lpServiceName, dwDesiredAccess);
+    DPRINT("OpenServiceA(%p, %s, %lx)\n",
+           hSCManager, lpServiceName, dwDesiredAccess);
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrOpenServiceA(BindingHandle,
-                             (unsigned int)hSCManager,
-                             (LPSTR)lpServiceName,
-                             dwDesiredAccess,
-                             (unsigned int*)&hService);
-  if (dwError != ERROR_SUCCESS)
-  {
-    DPRINT1("ScmrOpenServiceA() failed (Error %lu)\n", dwError);
-    SetLastError(dwError);
-    return NULL;
-  }
+    /* Call to services.exe using RPC */
+    dwError = ScmrOpenServiceA(BindingHandle,
+                               (unsigned int)hSCManager,
+                               (LPSTR)lpServiceName,
+                               dwDesiredAccess,
+                               (unsigned int*)&hService);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrOpenServiceA() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return NULL;
+    }
 
-  DPRINT("hService = %p\n", hService);
+    DPRINT("hService = %p\n", hService);
 
-  return hService;
+    return hService;
 }
 
 
@@ -710,67 +1157,193 @@ OpenServiceW(SC_HANDLE hSCManager,
              LPCWSTR lpServiceName,
              DWORD dwDesiredAccess)
 {
-  SC_HANDLE hService = NULL;
-  DWORD dwError;
+    SC_HANDLE hService = NULL;
+    DWORD dwError;
 
-  DPRINT("OpenServiceW(%p, %S, %lx)\n",
-         hSCManager, lpServiceName, dwDesiredAccess);
+    DPRINT("OpenServiceW(%p, %S, %lx)\n",
+           hSCManager, lpServiceName, dwDesiredAccess);
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrOpenServiceW(BindingHandle,
-                             (unsigned int)hSCManager,
-                             (LPWSTR)lpServiceName,
-                             dwDesiredAccess,
-                             (unsigned int*)&hService);
-  if (dwError != ERROR_SUCCESS)
-  {
-    DPRINT1("ScmrOpenServiceW() failed (Error %lu)\n", dwError);
-    SetLastError(dwError);
-    return NULL;
-  }
+    /* Call to services.exe using RPC */
+    dwError = ScmrOpenServiceW(BindingHandle,
+                               (unsigned int)hSCManager,
+                               (LPWSTR)lpServiceName,
+                               dwDesiredAccess,
+                               (unsigned int*)&hService);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrOpenServiceW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return NULL;
+    }
 
-  DPRINT("hService = %p\n", hService);
+    DPRINT("hService = %p\n", hService);
 
-  return hService;
+    return hService;
 }
 
 
 /**********************************************************************
  *  QueryServiceConfigA
  *
+ * @implemented
+ */
+BOOL STDCALL
+QueryServiceConfigA(SC_HANDLE hService,
+                    LPQUERY_SERVICE_CONFIGA lpServiceConfig,
+                    DWORD cbBufSize,
+                    LPDWORD pcbBytesNeeded)
+{
+    DWORD dwError;
+
+    DPRINT("QueryServiceConfigA(%p, %p, %lu, %p)\n",
+           hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrQueryServiceConfigA(BindingHandle,
+                                      (unsigned int)hService,
+                                      (unsigned char *)lpServiceConfig,
+                                      cbBufSize,
+                                      pcbBytesNeeded);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT("ScmrQueryServiceConfigA() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    /* Adjust the pointers */
+    if (lpServiceConfig->lpBinaryPathName)
+        lpServiceConfig->lpBinaryPathName =
+            (LPSTR)((ULONG_PTR)lpServiceConfig +
+                    (ULONG_PTR)lpServiceConfig->lpBinaryPathName);
+
+    if (lpServiceConfig->lpLoadOrderGroup)
+        lpServiceConfig->lpLoadOrderGroup =
+            (LPSTR)((ULONG_PTR)lpServiceConfig +
+                    (ULONG_PTR)lpServiceConfig->lpLoadOrderGroup);
+
+    if (lpServiceConfig->lpDependencies)
+        lpServiceConfig->lpDependencies =
+            (LPSTR)((ULONG_PTR)lpServiceConfig +
+                    (ULONG_PTR)lpServiceConfig->lpDependencies);
+
+    if (lpServiceConfig->lpServiceStartName)
+        lpServiceConfig->lpServiceStartName =
+            (LPSTR)((ULONG_PTR)lpServiceConfig +
+                    (ULONG_PTR)lpServiceConfig->lpServiceStartName);
+
+    if (lpServiceConfig->lpDisplayName)
+        lpServiceConfig->lpDisplayName =
+           (LPSTR)((ULONG_PTR)lpServiceConfig +
+                   (ULONG_PTR)lpServiceConfig->lpDisplayName);
+
+    DPRINT("QueryServiceConfigA() done\n");
+
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *  QueryServiceConfigW
+ *
+ * @implemented
+ */
+BOOL STDCALL
+QueryServiceConfigW(SC_HANDLE hService,
+                    LPQUERY_SERVICE_CONFIGW lpServiceConfig,
+                    DWORD cbBufSize,
+                    LPDWORD pcbBytesNeeded)
+{
+    DWORD dwError;
+
+    DPRINT("QueryServiceConfigW(%p, %p, %lu, %p)\n",
+           hService, lpServiceConfig, cbBufSize, pcbBytesNeeded);
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrQueryServiceConfigW(BindingHandle,
+                                      (unsigned int)hService,
+                                      (unsigned char *)lpServiceConfig,
+                                      cbBufSize,
+                                      pcbBytesNeeded);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT("ScmrQueryServiceConfigW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    /* Adjust the pointers */
+    if (lpServiceConfig->lpBinaryPathName)
+        lpServiceConfig->lpBinaryPathName =
+            (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                     (ULONG_PTR)lpServiceConfig->lpBinaryPathName);
+
+    if (lpServiceConfig->lpLoadOrderGroup)
+        lpServiceConfig->lpLoadOrderGroup =
+            (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                     (ULONG_PTR)lpServiceConfig->lpLoadOrderGroup);
+
+    if (lpServiceConfig->lpDependencies)
+        lpServiceConfig->lpDependencies =
+            (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                     (ULONG_PTR)lpServiceConfig->lpDependencies);
+
+    if (lpServiceConfig->lpServiceStartName)
+        lpServiceConfig->lpServiceStartName =
+            (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                     (ULONG_PTR)lpServiceConfig->lpServiceStartName);
+
+    if (lpServiceConfig->lpDisplayName)
+        lpServiceConfig->lpDisplayName =
+           (LPWSTR)((ULONG_PTR)lpServiceConfig +
+                    (ULONG_PTR)lpServiceConfig->lpDisplayName);
+
+    DPRINT("QueryServiceConfigW() done\n");
+
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *  QueryServiceConfig2A
+ *
  * @unimplemented
  */
 BOOL
 STDCALL
-QueryServiceConfigA(
+QueryServiceConfig2A(
     SC_HANDLE       hService,
-    LPQUERY_SERVICE_CONFIGA lpServiceConfig,
+    DWORD           dwInfo,
+    LPBYTE          lpBuffer,
     DWORD           cbBufSize,
     LPDWORD         pcbBytesNeeded)
 {
-    DPRINT1("QueryServiceConfigA is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    DPRINT1("QueryServiceConfig2A is unimplemented\n");
     return FALSE;
 }
 
 
 /**********************************************************************
- *  QueryServiceConfigW
+ *  QueryServiceConfig2W
  *
  * @unimplemented
  */
 BOOL
 STDCALL
-QueryServiceConfigW(
+QueryServiceConfig2W(
     SC_HANDLE       hService,
-    LPQUERY_SERVICE_CONFIGW lpServiceConfig,
-    DWORD                   cbBufSize,
-    LPDWORD                 pcbBytesNeeded)
+    DWORD           dwInfo,
+    LPBYTE          lpBuffer,
+    DWORD           cbBufSize,
+    LPDWORD         pcbBytesNeeded)
 {
-    DPRINT1("QueryServiceConfigW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    DPRINT1("QueryServiceConfig2W is unimplemented\n");
     return FALSE;
 }
 
@@ -816,94 +1389,322 @@ QueryServiceLockStatusW(
 /**********************************************************************
  *  QueryServiceObjectSecurity
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-QueryServiceObjectSecurity(
-    SC_HANDLE       hService,
-    SECURITY_INFORMATION    dwSecurityInformation,
-    PSECURITY_DESCRIPTOR    lpSecurityDescriptor,
-    DWORD           cbBufSize,
-    LPDWORD         pcbBytesNeeded)
+BOOL STDCALL
+QueryServiceObjectSecurity(SC_HANDLE hService,
+                           SECURITY_INFORMATION dwSecurityInformation,
+                           PSECURITY_DESCRIPTOR lpSecurityDescriptor,
+                           DWORD cbBufSize,
+                           LPDWORD pcbBytesNeeded)
 {
-    DPRINT1("QueryServiceObjectSecurity is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("QueryServiceObjectSecurity(%p, %lu, %p)\n",
+           hService, dwSecurityInformation, lpSecurityDescriptor);
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrQueryServiceObjectSecurity(BindingHandle,
+                                             (unsigned int)hService,
+                                             dwSecurityInformation,
+                                             (unsigned char *)lpSecurityDescriptor,
+                                             cbBufSize,
+                                             pcbBytesNeeded);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("QueryServiceObjectSecurity() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  QueryServiceStatus
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-QueryServiceStatus(
-    SC_HANDLE       hService,
-    LPSERVICE_STATUS    lpServiceStatus)
+BOOL STDCALL
+QueryServiceStatus(SC_HANDLE hService,
+                   LPSERVICE_STATUS lpServiceStatus)
 {
-    DPRINT1("QueryServiceStatus is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("QueryServiceStatus(%p, %p)\n",
+           hService, lpServiceStatus);
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrQueryServiceStatus(BindingHandle,
+                                     (unsigned int)hService,
+                                     lpServiceStatus);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrQueryServiceStatus() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  QueryServiceStatusEx
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-QueryServiceStatusEx(SC_HANDLE  hService,
-  SC_STATUS_TYPE  InfoLevel,
-  LPBYTE  lpBuffer,
-  DWORD  cbBufSize,
-  LPDWORD  pcbBytesNeeded)
+BOOL STDCALL
+QueryServiceStatusEx(SC_HANDLE hService,
+                     SC_STATUS_TYPE InfoLevel,
+                     LPBYTE lpBuffer,
+                     DWORD cbBufSize,
+                     LPDWORD pcbBytesNeeded)
 {
-    DPRINT1("QueryServiceStatusEx is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("QueryServiceStatusEx() called\n");
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrQueryServiceStatusEx(BindingHandle,
+                                       (unsigned int)hService,
+                                       InfoLevel,
+                                       lpBuffer,
+                                       cbBufSize,
+                                       pcbBytesNeeded);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT("ScmrQueryServiceStatusEx() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
 /**********************************************************************
- *  StartServiceA
+ *  SetServiceObjectSecurity
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-StartServiceA(
-    SC_HANDLE   hService,
-    DWORD       dwNumServiceArgs,
-    LPCSTR      *lpServiceArgVectors)
+BOOL STDCALL
+SetServiceObjectSecurity(SC_HANDLE hService,
+                         SECURITY_INFORMATION dwSecurityInformation,
+                         PSECURITY_DESCRIPTOR lpSecurityDescriptor)
 {
-    DPRINT1("StartServiceA is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    PSECURITY_DESCRIPTOR SelfRelativeSD = NULL;
+    ULONG Length;
+    NTSTATUS Status;
+    DWORD dwError;
+
+    Length = 0;
+    Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
+                                   SelfRelativeSD,
+                                   &Length);
+    if (Status != STATUS_BUFFER_TOO_SMALL)
+    {
+        SetLastError(ERROR_INVALID_PARAMETER);
+        return FALSE;
+    }
+
+    SelfRelativeSD = HeapAlloc(GetProcessHeap(), 0, Length);
+    if (SelfRelativeSD == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
+    }
+
+    Status = RtlMakeSelfRelativeSD(lpSecurityDescriptor,
+                                   SelfRelativeSD,
+                                   &Length);
+    if (!NT_SUCCESS(Status))
+    {
+        HeapFree(GetProcessHeap(), 0, SelfRelativeSD);
+        SetLastError(RtlNtStatusToDosError(Status));
+        return FALSE;
+    }
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrSetServiceObjectSecurity(BindingHandle,
+                                           (unsigned int)hService,
+                                           dwSecurityInformation,
+                                           (unsigned char *)SelfRelativeSD,
+                                           Length);
+
+    HeapFree(GetProcessHeap(), 0, SelfRelativeSD);
+
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrServiceObjectSecurity() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
+/**********************************************************************
+ *  StartServiceA
+ *
+ * @implemented
+ */
+BOOL STDCALL
+StartServiceA(SC_HANDLE hService,
+              DWORD dwNumServiceArgs,
+              LPCSTR *lpServiceArgVectors)
+{
+#if 0
+    DWORD dwError;
+
+    DPRINT("StartServiceA()\n");
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrStartServiceA(BindingHandle,
+                                hService,
+                                dwNumServiceArgs,
+                                lpServiceArgVectors);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrStartServiceA() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
+#endif
+    LPSTR lpBuffer;
+    LPSTR lpStr;
+    DWORD dwError;
+    DWORD dwBufSize;
+    DWORD i;
+
+    dwBufSize = 0;
+    for (i = 0; i < dwNumServiceArgs; i++)
+    {
+        dwBufSize += (strlen(lpServiceArgVectors[i]) + 1);
+    }
+    DPRINT1("dwBufSize: %lu\n", dwBufSize);
+
+    lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwBufSize);
+    if (lpBuffer == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
+    }
+
+    lpStr = lpBuffer;
+    for (i = 0; i < dwNumServiceArgs; i++)
+    {
+        strcpy(lpStr, lpServiceArgVectors[i]);
+        lpStr += (strlen(lpServiceArgVectors[i]) + 1);
+    }
+
+    dwError = ScmrStartServiceA(BindingHandle,
+                                (unsigned int)hService,
+                                dwNumServiceArgs,
+                                (unsigned char *)lpBuffer,
+                                dwBufSize);
+
+    HeapFree(GetProcessHeap(), 0, lpBuffer);
+
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrStartServiceA() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
+}
 
 
 /**********************************************************************
  *  StartServiceW
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-StartServiceW(
-    SC_HANDLE   hService,
-    DWORD       dwNumServiceArgs,
-    LPCWSTR     *lpServiceArgVectors)
+BOOL STDCALL
+StartServiceW(SC_HANDLE hService,
+              DWORD dwNumServiceArgs,
+              LPCWSTR *lpServiceArgVectors)
 {
-    DPRINT1("StartServiceW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+#if 0
+    DWORD dwError;
+
+    DPRINT("StartServiceW()\n");
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrStartServiceW(BindingHandle,
+                                hService,
+                                dwNumServiceArgs,
+                                lpServiceArgVectors);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrStartServiceW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
+#endif
+    LPWSTR lpBuffer;
+    LPWSTR lpStr;
+    DWORD dwError;
+    DWORD dwBufSize;
+    DWORD i;
+
+    dwBufSize = 0;
+    for (i = 0; i < dwNumServiceArgs; i++)
+    {
+        dwBufSize += ((wcslen(lpServiceArgVectors[i]) + 1) * sizeof(WCHAR));
+    }
+    DPRINT1("dwBufSize: %lu\n", dwBufSize);
+
+    lpBuffer = HeapAlloc(GetProcessHeap(), 0, dwBufSize);
+    if (lpBuffer == NULL)
+    {
+        SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+        return FALSE;
+    }
+
+    lpStr = lpBuffer;
+    for (i = 0; i < dwNumServiceArgs; i++)
+    {
+        wcscpy(lpStr, lpServiceArgVectors[i]);
+        lpStr += (wcslen(lpServiceArgVectors[i]) + 1);
+    }
+
+    dwError = ScmrStartServiceW(BindingHandle,
+                                (unsigned int)hService,
+                                dwNumServiceArgs,
+                                (unsigned char *)lpBuffer,
+                                dwBufSize);
+
+    HeapFree(GetProcessHeap(), 0, lpBuffer);
+
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrStartServiceW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
@@ -915,34 +1716,63 @@ StartServiceW(
 BOOL STDCALL
 UnlockServiceDatabase(SC_LOCK ScLock)
 {
-  DWORD dwError;
+    DWORD dwError;
 
-  DPRINT("UnlockServiceDatabase(%x)\n", hSCManager);
+    DPRINT("UnlockServiceDatabase(%x)\n", ScLock);
 
-  HandleBind();
+    HandleBind();
 
-  /* Call to services.exe using RPC */
-  dwError = ScmrUnlockServiceDatabase(BindingHandle,
-                                      (unsigned int)ScLock);
-  if (dwError != ERROR_SUCCESS)
-  {
-    DPRINT("ScmrUnlockServiceDatabase() failed (Error %lu)\n", dwError);
-    SetLastError(dwError);
-    return FALSE;
-  }
+    /* Call to services.exe using RPC */
+    dwError = ScmrUnlockServiceDatabase(BindingHandle,
+                                        (unsigned int)ScLock);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("ScmrUnlockServiceDatabase() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
+}
 
-  return TRUE;
+
+/**********************************************************************
+ *  NotifyBootConfigStatus
+ *
+ * @implemented
+ */
+BOOL STDCALL
+NotifyBootConfigStatus(BOOL BootAcceptable)
+{
+    DWORD dwError;
+
+    DPRINT1("NotifyBootConfigStatus()\n");
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrNotifyBootConfigStatus(BindingHandle,
+                                         BootAcceptable);
+    if (dwError != ERROR_SUCCESS)
+    {
+        DPRINT1("NotifyBootConfigStatus() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return FALSE;
+    }
+
+    return TRUE;
 }
 
 
 void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
 {
-  return GlobalAlloc(GPTR,len);
+    return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
 }
 
+
 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
 {
-  GlobalFree(ptr);
+    HeapFree(GetProcessHeap(), 0, ptr);
 }
 
 /* EOF */