sorry, forgot to change one var
[reactos.git] / reactos / lib / advapi32 / service / scm.c
index 20faa01..60dc0cf 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id$
- * 
+/*
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS system libraries
  * FILE:            lib/advapi32/service/scm.c
  * PURPOSE:         Service control manager functions
  * PROGRAMMER:      Emanuele Aliberti
+ *                  Eric Kohl
  * UPDATE HISTORY:
  *  19990413 EA created
  *  19990515 EA
 
 /* INCLUDES ******************************************************************/
 
-#include "advapi32.h"
+#include <advapi32.h>
+#include "svcctl_c.h"
+
 #define NDEBUG
 #include <debug.h>
 
 /* FUNCTIONS *****************************************************************/
 
+handle_t BindingHandle = NULL;
+
+static VOID
+HandleBind(VOID)
+{
+    LPWSTR pszStringBinding;
+    RPC_STATUS status;
+
+    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;
+    }
+
+    /* 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);
+    }
+}
+
+
+#if 0
+static VOID
+HandleUnbind(VOID)
+{
+    RPC_STATUS status;
+
+    if (BindingHandle == NULL)
+        return;
+
+    status = RpcBindingFree(&BindingHandle);
+    if (status)
+    {
+        DPRINT1("RpcBindingFree returned 0x%x\n", status);
+    }
+}
+#endif
+
+
 /**********************************************************************
  *  ChangeServiceConfigA
  *
@@ -47,26 +106,68 @@ ChangeServiceConfigA(
 /**********************************************************************
  *  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)
+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;
+    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;
 }
 
 
@@ -75,16 +176,27 @@ ChangeServiceConfigW(
  *
  * @implemented
  */
-BOOL 
-STDCALL
+BOOL STDCALL
 CloseServiceHandle(SC_HANDLE hSCObject)
 {
-    DPRINT("CloseServiceHandle() - called.\n");
+    DWORD dwError;
 
-    if (!CloseHandle(hSCObject)) {
-        SetLastError(ERROR_INVALID_HANDLE);
+    DPRINT("CloseServiceHandle() called\n");
+
+    HandleBind();
+
+    /* 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;
     }
+
+    DPRINT("CloseServiceHandle() done\n");
+
     return TRUE;
 }
 
@@ -94,22 +206,59 @@ CloseServiceHandle(SC_HANDLE hSCObject)
  *
  * @unimplemented
  */
-BOOL
-STDCALL
-ControlService(SC_HANDLE        hService,
-               DWORD            dwControl,
+BOOL STDCALL
+ControlService(SC_HANDLE hService,
+               DWORD dwControl,
                LPSERVICE_STATUS lpServiceStatus)
 {
-    DPRINT1("ControlService is unimplemented\n");
+    DWORD dwError;
+
+    DPRINT("ControlService(%x, %x, %p)\n",
+           hService, dwControl, lpServiceStatus);
+
+    HandleBind();
+
+    /* 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;
+    }
+
+    DPRINT("ControlService() done\n");
+
+    return TRUE;
+}
+
+
+/**********************************************************************
+ *  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
  *
- * @unimplemented
+ * @implemented
  */
 SC_HANDLE
 STDCALL
@@ -128,50 +277,219 @@ CreateServiceA(
     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 INVALID_HANDLE_VALUE;
+    }
+
+    return hService;
 }
 
 
 /**********************************************************************
  *  DeleteService
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
+BOOL STDCALL
 DeleteService(SC_HANDLE hService)
 {
-    DPRINT1("DeleteService is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("DeleteService(%x)\n", hService);
+
+    HandleBind();
+
+    /* 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;
 }
 
 
@@ -357,19 +675,35 @@ GetServiceDisplayNameA(
 /**********************************************************************
  *  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;
 }
 
 
@@ -395,283 +729,259 @@ GetServiceKeyNameA(
 /**********************************************************************
  *  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;
 }
 
+
 /**********************************************************************
  *  LockServiceDatabase
  *
- * @unimplemented
+ * @implemented
  */
-SC_LOCK
-STDCALL
-LockServiceDatabase(SC_HANDLE   hSCManager)
+SC_LOCK STDCALL
+LockServiceDatabase(SC_HANDLE hSCManager)
 {
-    DPRINT1("LockServiceDatabase is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return NULL;
+    SC_LOCK hLock;
+    DWORD dwError;
+
+    DPRINT("LockServiceDatabase(%x)\n", hSCManager);
+
+    HandleBind();
+
+    /* 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);
+
+    return hLock;
+}
+
+
+static VOID
+WaitForSCManager(VOID)
+{
+    HANDLE hEvent;
+
+    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");
+        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);
+
+    DPRINT("ScmWaitForSCManager() done\n");
 }
 
 
 /**********************************************************************
  *  OpenSCManagerA
  *
- * @unplemented
+ * @implemented
  */
 SC_HANDLE STDCALL
 OpenSCManagerA(LPCSTR lpMachineName,
-           LPCSTR lpDatabaseName,
-           DWORD dwDesiredAccess)
+               LPCSTR lpDatabaseName,
+               DWORD dwDesiredAccess)
 {
-  SC_HANDLE Handle;
-  UNICODE_STRING MachineNameW;
-  UNICODE_STRING DatabaseNameW;
-  ANSI_STRING MachineNameA;
-  ANSI_STRING DatabaseNameA;
+    SC_HANDLE hScm = NULL;
+    DWORD dwError;
 
-  DPRINT("OpenSCManagerA(%x, %x, %d)\n", lpMachineName, lpDatabaseName, dwDesiredAccess);
+    DPRINT("OpenSCManagerA(%s, %s, %lx)\n",
+           lpMachineName, lpDatabaseName, dwDesiredAccess);
 
-  RtlInitAnsiString(&MachineNameA, (LPSTR)lpMachineName);
-  RtlAnsiStringToUnicodeString(&MachineNameW, &MachineNameA, TRUE);
-  RtlInitAnsiString(&DatabaseNameA, (LPSTR)lpDatabaseName);
-  RtlAnsiStringToUnicodeString(&DatabaseNameW, &DatabaseNameA, TRUE);
+    WaitForSCManager();
+
+    HandleBind();
+
+    /* 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;
+    }
 
-  Handle = OpenSCManagerW(lpMachineName ? MachineNameW.Buffer : NULL,
-              lpDatabaseName ? DatabaseNameW.Buffer : NULL,
-              dwDesiredAccess);
+    DPRINT("hScm = %p\n", hScm);
 
-  RtlFreeHeap(GetProcessHeap(), 0, MachineNameW.Buffer);
-  RtlFreeHeap(GetProcessHeap(), 0, DatabaseNameW.Buffer);
-  return Handle;
+    return hScm;
 }
 
 
 /**********************************************************************
  *  OpenSCManagerW
  *
- * @unimplemented
+ * @implemented
  */
-SC_HANDLE STDCALL OpenSCManagerW(LPCWSTR lpMachineName,
-                                 LPCWSTR lpDatabaseName,
-                                 DWORD dwDesiredAccess)
-{
-  HANDLE hPipe;
-  DWORD dwMode;
-  DWORD dwWait;
-  BOOL fSuccess;
-  HANDLE hStartEvent;
-  LPWSTR lpszPipeName = L"\\\\.\\pipe\\Ntsvcs";
-
-  DPRINT("OpenSCManagerW(%x, %x, %d)\n", lpMachineName, lpDatabaseName, dwDesiredAccess);
-
-  if (lpMachineName == NULL || wcslen(lpMachineName) == 0)
-    {
-      if (lpDatabaseName != NULL && wcscmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
-       {
-         DPRINT("OpenSCManagerW() - Invalid parameters.\n");
-         return NULL; 
-       }
-
-      DPRINT("OpenSCManagerW() - OpenEvent(\"SvcctrlStartEvent_A3725DX\")\n");
-
-      // Only connect to scm when event "SvcctrlStartEvent_A3725DX" is signaled
-      hStartEvent = OpenEventW(SYNCHRONIZE, FALSE, L"SvcctrlStartEvent_A3725DX");
-      if (hStartEvent == NULL)
-       {
-         SetLastError(ERROR_DATABASE_DOES_NOT_EXIST);
-         DPRINT("OpenSCManagerW() - Failed to Open Event \"SvcctrlStartEvent_A3725DX\".\n");
-         return NULL;
-       }
-
-      DPRINT("OpenSCManagerW() - Waiting forever on event handle: %x\n", hStartEvent);
-
-#if 1
-      dwWait = WaitForSingleObject(hStartEvent, INFINITE);
-      if (dwWait == WAIT_FAILED)
-       {
-         DPRINT("OpenSCManagerW() - Wait For Start Event failed.\n");
-         SetLastError(ERROR_ACCESS_DENIED);
-         return NULL;
-       }
-#else
-       {
-          DWORD Count;
-
-         /* wait for event creation (by SCM) for max. 20 seconds */
-         for (Count = 0; Count < 20; Count++)
-           {
-             dwWait = WaitForSingleObject(hStartEvent, 1000);
-             if (dwWait == WAIT_FAILED)
-               {
-                 DPRINT("OpenSCManagerW() - Wait For Start Event failed.\n");
-                 Sleep(1000);
-               }
-             else
-               {
-                 break;
-               }
-           }
-
-         if (dwWait == WAIT_FAILED)
-           {
-             DbgPrint("WL: Failed to wait on event \"SvcctrlStartEvent_A3725DX\"\n");
-           }
-
-       }
-#endif
+SC_HANDLE STDCALL
+OpenSCManagerW(LPCWSTR lpMachineName,
+               LPCWSTR lpDatabaseName,
+               DWORD dwDesiredAccess)
+{
+    SC_HANDLE hScm = NULL;
+    DWORD dwError;
 
-      DPRINT("OpenSCManagerW() - Closing handle to event...\n");
-      
-      CloseHandle(hStartEvent);
-      
-      // Try to open a named pipe; wait for it, if necessary
-      while (1)
-      {
-       DWORD dwLastError;
-       DPRINT("OpenSCManagerW() - attempting to open named pipe to SCM.\n");
-       hPipe = CreateFileW(lpszPipeName,     // pipe name
-           dwDesiredAccess,
-           0,                // no sharing
-           NULL,             // no security attributes
-           OPEN_EXISTING,    // opens existing pipe
-           0,                // default attributes
-           NULL);            // no template file
-       
-       DPRINT("OpenSCManagerW() - handle to named pipe: %x\n", hPipe);
-       // Break if the pipe handle is valid
-       if (hPipe != INVALID_HANDLE_VALUE)
-         {
-           break;
-         }
-       
-       // Exit if an error other than ERROR_PIPE_BUSY occurs
-       dwLastError = GetLastError();
-       if (dwLastError != ERROR_PIPE_BUSY)
-         {
-           DPRINT("OpenSCManagerW() - returning at 4, dwLastError %d\n", dwLastError);
-           return NULL;
-         }
-       
-       // All pipe instances are busy, so wait for 20 seconds
-       if (!WaitNamedPipeW(lpszPipeName, 20000))
-         {
-           DPRINT("OpenSCManagerW() - Failed on WaitNamedPipeW(...).\n");
-           return NULL;
-         }
-      }
-    
-      // The pipe connected; change to message-read mode
-      dwMode = PIPE_READMODE_MESSAGE;
-      fSuccess = SetNamedPipeHandleState(
-         hPipe,    // pipe handle
-         &dwMode,  // new pipe mode
-         NULL,     // don't set maximum bytes
-         NULL);    // don't set maximum time
-      if (!fSuccess)
-       {
-         CloseHandle(hPipe);
-         DPRINT("OpenSCManagerW() - Failed on SetNamedPipeHandleState(...).\n");
-         return NULL;
-       }
-#if 0
-      // Send a message to the pipe server
-      lpvMessage = (argc > 1) ? argv[1] : "default message";
-      
-      fSuccess = WriteFile(
-         hPipe,                  // pipe handle
-         lpvMessage,             // message
-         strlen(lpvMessage) + 1, // message length
-         &cbWritten,             // bytes written
-         NULL);                  // not overlapped
-      if (!fSuccess)
-       {
-         CloseHandle(hPipe);
-         DPRINT("OpenSCManagerW() - Failed to write to pipe.\n");
-         return NULL;
-       }
-      
-      do
-       {
-         DPRINT("OpenSCManagerW() - in I/O loop to SCM...\n");
-         // Read from the pipe
-         fSuccess = ReadFile(
-             hPipe,    // pipe handle
-             chBuf,    // buffer to receive reply
-             512,      // size of buffer
-             &cbRead,  // number of bytes read
-             NULL);    // not overlapped
-         
-         if (!fSuccess && GetLastError() != ERROR_MORE_DATA)
-           {
-             break;
-           }
-         
-         // Reply from the pipe is written to STDOUT.
-         if (!WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), chBuf, cbRead, &cbWritten, NULL))
-           {
-             break;
-           }
-       } while(!fSuccess);  // repeat loop if ERROR_MORE_DATA
-      
-      DPRINT("OpenSCManagerW() - I/O loop completed.\n");
-      //CloseHandle(hPipe);
-#endif
-      DPRINT("OpenSCManagerW() - success, returning handle to pipe %x\n", hPipe);
-      return hPipe;
-    }
-  else
+    DPRINT("OpenSCManagerW(%S, %S, %lx)\n",
+           lpMachineName, lpDatabaseName, dwDesiredAccess);
+
+    WaitForSCManager();
+
+    HandleBind();
+
+    /* Call to services.exe using RPC */
+    dwError = ScmrOpenSCManagerW(BindingHandle,
+                                 (LPWSTR)lpMachineName,
+                                 (LPWSTR)lpDatabaseName,
+                                 dwDesiredAccess,
+                                 (unsigned int*)&hScm);
+    if (dwError != ERROR_SUCCESS)
     {
-      /* FIXME: Connect to remote SCM */
-      DPRINT("OpenSCManagerW() - FIXME: Connect to remote SCM is unimplemented.\n");
-      return NULL;
+        DPRINT1("ScmrOpenSCManagerW() failed (Error %lu)\n", dwError);
+        SetLastError(dwError);
+        return NULL;
     }
+
+    DPRINT("hScm = %p\n", hScm);
+
+    return hScm;
 }
 
 
 /**********************************************************************
  *  OpenServiceA
  *
- * @unimplemented
+ * @implemented
  */
 SC_HANDLE STDCALL
 OpenServiceA(SC_HANDLE hSCManager,
-         LPCSTR  lpServiceName,
-         DWORD dwDesiredAccess)
+             LPCSTR lpServiceName,
+             DWORD dwDesiredAccess)
 {
-  DPRINT1("OpenServiceA is unimplemented, returning ERROR_SERVICE_DOES_NOT_EXIST for %s\n", lpServiceName);
-  SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
-  return NULL;
+    SC_HANDLE hService = NULL;
+    DWORD dwError;
+
+    DPRINT("OpenServiceA(%p, %s, %lx)\n",
+           hSCManager, lpServiceName, dwDesiredAccess);
+
+    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;
+    }
+
+    DPRINT("hService = %p\n", hService);
+
+    return hService;
 }
 
 
 /**********************************************************************
  *  OpenServiceW
  *
- * @unimplemented
+ * @implemented
  */
-SC_HANDLE
-STDCALL
-OpenServiceW(
-    SC_HANDLE   hSCManager,
-    LPCWSTR     lpServiceName,
-    DWORD       dwDesiredAccess
-    )
+SC_HANDLE STDCALL
+OpenServiceW(SC_HANDLE hSCManager,
+             LPCWSTR lpServiceName,
+             DWORD dwDesiredAccess)
 {
-  DPRINT1("OpenServiceW is unimplemented, returning ERROR_SERVICE_DOES_NOT_EXIST for %S\n", lpServiceName);
-  SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
-  return NULL;
+    SC_HANDLE hService = NULL;
+    DWORD dwError;
+
+    DPRINT("OpenServiceW(%p, %S, %lx)\n",
+           hSCManager, lpServiceName, dwDesiredAccess);
+
+    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;
+    }
+
+    DPRINT("hService = %p\n", hService);
+
+    return hService;
 }
 
 
@@ -708,8 +1018,17 @@ QueryServiceConfigW(
     LPDWORD                 pcbBytesNeeded)
 {
     DPRINT1("QueryServiceConfigW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    if (lpServiceConfig && cbBufSize >= sizeof(QUERY_SERVICE_CONFIGW))
+    {
+        memset(lpServiceConfig, 0, *pcbBytesNeeded);
+        return TRUE;
+    }
+    else
+    {
+        *pcbBytesNeeded = sizeof(QUERY_SERVICE_CONFIGW);
+        SetLastError(ERROR_INSUFFICIENT_BUFFER);
+        return FALSE;
+    }
 }
 
 
@@ -774,17 +1093,31 @@ QueryServiceObjectSecurity(
 /**********************************************************************
  *  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;
 }
 
 
@@ -825,8 +1158,6 @@ StartServiceA(
 }
 
 
-
-
 /**********************************************************************
  *  StartServiceW
  *
@@ -839,25 +1170,78 @@ StartServiceW(
     DWORD       dwNumServiceArgs,
     LPCWSTR     *lpServiceArgVectors)
 {
-    DPRINT1("StartServiceW is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DPRINT1("StartServiceW is unimplemented, but returns success...\n");
+    //SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+    //return FALSE;
+    return TRUE;
 }
 
 
 /**********************************************************************
  *  UnlockServiceDatabase
  *
- * @unimplemented
+ * @implemented
  */
-BOOL
-STDCALL
-UnlockServiceDatabase(SC_LOCK   ScLock)
+BOOL STDCALL
+UnlockServiceDatabase(SC_LOCK ScLock)
 {
-    DPRINT1("UnlockServiceDatabase is unimplemented\n");
-    SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
-    return FALSE;
+    DWORD dwError;
+
+    DPRINT("UnlockServiceDatabase(%x)\n", ScLock);
+
+    HandleBind();
+
+    /* 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;
+}
+
+
+/**********************************************************************
+ *  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 HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
+}
+
+
+void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
+{
+    HeapFree(GetProcessHeap(), 0, ptr);
+}
+
 /* EOF */