[PATCH] services.exe: start a local RPC server, make advapi32 connect to it

Mikołaj Zalewski mikolaj at zalewski.pl
Sun Sep 23 00:21:17 CDT 2007


---
 .gitignore                    |    4 +
 dlls/advapi32/Makefile.in     |    3 +
 dlls/advapi32/service.c       |  154 +++++++++++++++++++++++----
 dlls/advapi32/svcctl.idl      |    1 +
 dlls/advapi32/tests/service.c |    3 -
 include/wine/svcctl.idl       |   67 ++++++++++++
 programs/services/Makefile.in |    9 +-
 programs/services/rpc.c       |  240 +++++++++++++++++++++++++++++++++++++++++
 programs/services/services.c  |    7 +-
 programs/services/services.h  |    4 +
 programs/services/svcctl.idl  |    1 +
 11 files changed, 467 insertions(+), 26 deletions(-)

diff --git a/.gitignore b/.gitignore
index f444e0c..9f7c636 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,6 +18,8 @@ dlls/advapi32/libadvapi32.def
 dlls/advapi32/tests/*.ok
 dlls/advapi32/tests/advapi32_crosstest.exe
 dlls/advapi32/tests/testlist.c
+dlls/advapi32/svcctl.h
+dlls/advapi32/svcctl_c.c
 dlls/advapi32/version.res
 dlls/advpack/libadvpack.def
 dlls/advpack/tests/*.ok
@@ -641,6 +643,8 @@ programs/rpcss/irot_s.c
 programs/rpcss/rpcss
 programs/rundll32/rundll32
 programs/services/services
+programs/services/svcctl.h
+programs/services/svcctl_s.c
 programs/spoolsv/spoolsv
 programs/start/rsrc.res
 programs/start/start
diff --git a/dlls/advapi32/Makefile.in b/dlls/advapi32/Makefile.in
index 8f6fe33..788c695 100644
--- a/dlls/advapi32/Makefile.in
+++ b/dlls/advapi32/Makefile.in
@@ -6,6 +6,7 @@ VPATH     = @srcdir@
 MODULE    = advapi32.dll
 IMPORTLIB = libadvapi32.$(IMPLIBEXT)
 IMPORTS   = kernel32 ntdll
+DELAYIMPORTS = rpcrt4
 
 C_SRCS = \
 	advapi.c \
@@ -22,6 +23,8 @@ C_SRCS = \
 	security.c \
 	service.c
 
+IDL_C_SRCS = svcctl.idl
+
 RC_SRCS = version.rc
 
 @MAKE_DLL_RULES@
diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index ce031ab..7575558 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -37,8 +37,20 @@
 #include "lmserver.h"
 #include "wine/list.h"
 
+#include "svcctl.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
 
+void  __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
+{
+    return HeapAlloc(GetProcessHeap(), 0, len);
+}
+
+void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
+{
+    HeapFree(GetProcessHeap(), 0, ptr);
+}
+
 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
       'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
       'S','e','r','v','i','c','e','s',0 };
@@ -120,6 +132,8 @@ struct sc_handle
     SC_HANDLE_TYPE htype;
     DWORD ref_count;
     sc_handle_destructor destroy;
+    SvcCtlRpcHandle rpc_handle;      /* RPC connection handle */
+    POLICY_HANDLE server_handle;     /* server-side handle */
 };
 
 struct sc_manager       /* service control manager handle */
@@ -180,6 +194,8 @@ static void sc_handle_destroy_manager(struct sc_handle *handle)
     struct sc_manager *mgr = (struct sc_manager*) handle;
 
     TRACE("destroying SC Manager %p\n", mgr);
+    if (mgr->hdr.rpc_handle)
+        RpcBindingFree(&mgr->hdr.rpc_handle);
     if (mgr->hkey)
         RegCloseKey(mgr->hkey);
 }
@@ -234,6 +250,95 @@ static inline LPWSTR SERV_dupmulti(LPCSTR str)
 }
 
 /******************************************************************************
+ * RPC connection with servies.exe
+ */
+
+BOOL check_services_exe()
+{
+    HANDLE hEvent = OpenEventW(SYNCHRONIZE, FALSE, SVCCTL_STARTED_EVENT);
+    if (hEvent == NULL)
+    {
+        static const WCHAR services[] = {'\\','s','e','r','v','i','c','e','s','.','e','x','e',0};
+        PROCESS_INFORMATION out;
+        STARTUPINFOW si;
+        HANDLE wait_handles[2];
+        WCHAR path[MAX_PATH];
+
+        if (!GetSystemDirectoryW(path, MAX_PATH - strlenW(services)))
+            return FALSE;
+        strcatW(path, services);
+        ZeroMemory(&si, sizeof(si));
+        si.cb = sizeof(si);
+        if (!CreateProcessW(path, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &out))
+        {
+            ERR("Couldn't start services.exe: error %u\n", GetLastError());
+            return FALSE;
+        }
+        CloseHandle(out.hThread);
+
+        hEvent = CreateEventW(NULL, TRUE, FALSE, SVCCTL_STARTED_EVENT);
+        wait_handles[0] = hEvent;
+        wait_handles[1] = out.hProcess;
+        /* wait for the event to become available or the process to exit */
+        if (WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE) == WAIT_OBJECT_0 + 1)
+        {
+            DWORD exit_code;
+            GetExitCodeProcess(out.hProcess, &exit_code);
+            CloseHandle(out.hProcess);
+            ERR("Unexpected termination of services.exe - exit code %d\n", exit_code);
+            return FALSE;
+        }
+        CloseHandle(out.hProcess);
+    }
+
+    TRACE("Waiting for services.exe to be available\n");
+    WaitForSingleObject(hEvent, INFINITE);
+    TRACE("Services.exe are available\n");
+    CloseHandle(hEvent);
+
+    return TRUE;
+}
+
+SvcCtlRpcHandle connect_to_server(LPCWSTR server)
+{
+    WCHAR transport[] = SVCCTL_TRANSPORT;
+    WCHAR endpoint[] = SVCCTL_ENDPOINT;
+    LPWSTR server_copy = NULL;
+    RPC_WSTR binding_str;
+    RPC_STATUS status;
+    SvcCtlRpcHandle rpc_handle;
+
+    /* unlike Windows we start services.exe on demand. We start it always as
+     * checking if this is our address can be tricky */
+    if (!check_services_exe())
+        return NULL;
+
+    if (server) /* parameters of RpcStringBindingComposeW are not const */
+    {
+        server_copy = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR)*(strlenW(server) + 1));
+        strcpyW(server_copy, server);
+    }
+    status = RpcStringBindingComposeW(NULL, transport, server_copy, endpoint, NULL, &binding_str);
+    HeapFree(GetProcessHeap(), 0, server_copy);
+    if (status != RPC_S_OK)
+    {
+        ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
+        return NULL;
+    }
+
+    status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
+    RpcStringFreeW(&binding_str);
+
+    if (status != RPC_S_OK)
+    {
+        ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
+        return NULL;
+    }
+
+    return rpc_handle;
+}
+
+/******************************************************************************
  * registry access functions and data
  */
 static const WCHAR szDisplayName[] = {
@@ -1029,29 +1134,22 @@ SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
     TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
           debugstr_w(lpDatabaseName), dwDesiredAccess);
 
-    if( lpDatabaseName && lpDatabaseName[0] )
-    {
-        if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
-        {
-            /* noop, all right */
-        }
-        else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
-        {
-            SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
-            return NULL;
-        }
-        else
-        {
-            SetLastError( ERROR_INVALID_NAME );
-            return NULL;
-        }
-    }
-
     manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
                                sc_handle_destroy_manager );
     if (!manager)
          return NULL;
 
+    manager->hdr.rpc_handle = connect_to_server(lpMachineName);
+    if (manager->hdr.rpc_handle == NULL)
+    {
+        r = GetLastError();
+        goto error;
+    }
+
+    r = svcctl_OpenSCManagerW(manager->hdr.rpc_handle, NULL, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
+    if (r!=ERROR_SUCCESS)
+        goto error;
+
     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
     if (r!=ERROR_SUCCESS)
         goto error;
@@ -1160,10 +1258,28 @@ BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
 BOOL WINAPI
 CloseServiceHandle( SC_HANDLE hSCObject )
 {
+    struct sc_handle *obj;
+    DWORD err;
+
     TRACE("%p\n", hSCObject);
+    if (hSCObject == NULL)
+    {
+        SetLastError(ERROR_INVALID_HANDLE);
+        return FALSE;
+    }
 
-    sc_handle_free( (struct sc_handle*) hSCObject );
+    obj = (struct sc_handle *)hSCObject;
+    if (obj->rpc_handle)   /* service handles currently don't have RPC connections */
+        err = svcctl_CloseServiceHandle(obj->rpc_handle, &obj->server_handle);
+    else
+        err = ERROR_SUCCESS;
+    sc_handle_free( obj );
 
+    if (err != ERROR_SUCCESS)
+    {
+        SetLastError(err);
+        return FALSE;
+    }
     return TRUE;
 }
 
diff --git a/dlls/advapi32/svcctl.idl b/dlls/advapi32/svcctl.idl
new file mode 100644
index 0000000..101e0f2
--- /dev/null
+++ b/dlls/advapi32/svcctl.idl
@@ -0,0 +1 @@
+#include "wine/svcctl.idl"
diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c
index 7aea906..7b93df8 100644
--- a/dlls/advapi32/tests/service.c
+++ b/dlls/advapi32/tests/service.c
@@ -699,11 +699,8 @@ static void test_close(void)
     /* NULL handle */
     SetLastError(0xdeadbeef);
     ret = CloseServiceHandle(NULL);
-    todo_wine
-    {
     ok(!ret, "Expected failure\n");
     ok(GetLastError() == ERROR_INVALID_HANDLE, "Expected ERROR_INVALID_HANDLE, got %d\n", GetLastError());
-    }
 
     /* TODO: Add some tests with invalid handles. These produce errors on Windows but crash on Wine */
 
diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl
new file mode 100644
index 0000000..123349b
--- /dev/null
+++ b/include/wine/svcctl.idl
@@ -0,0 +1,67 @@
+/*
+ * svcctl interface definitions - exported by services.exe to access the
+ * services database
+ *
+ * Copyright 2007 Google (Mikolaj Zalewski)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+import "wtypes.idl";
+
+/*
+ * some defined for the C code
+ */
+cpp_quote("#define SVCCTL_TRANSPORT {'n','c','a','c','n','_','n','p',0}");
+cpp_quote("#define SVCCTL_ENDPOINT {'\\\\','p','i','p','e','\\\\','s','v','c','c','t','l',0}");
+
+/* Not the Windows event name - if needed the true one can be found in Inside Windows */
+cpp_quote("#define SVCCTL_STARTED_EVENT (const WCHAR[]){'_','_','w','i','n','e','_','S','v','c','c','t','l','S','t','a','r','t','e','d',0}");
+
+
+/* Based on the Samba IDL. Some functions are compatible with Windows but some
+ * aren't and many are missing (thus function numbers are different) so we
+ * don't use the Windows uuid which is 367abb81-9844-35f1-ad32-98f038001003 .
+ */
+[ uuid(78e2d9e8-d2a8-40d8-9bbe-7328cc5a9c32),
+  version(2.0),
+  pointer_default(unique),
+  endpoint("ncacn_np:[\\pipe\\svcctl]"),
+  helpstring("Service Control")
+] interface svcctl
+{
+    typedef handle_t SvcCtlRpcHandle;
+
+    typedef struct _POLICY_HANDLE
+    {
+        DWORD dwHandleType;
+	GUID uuid;
+    } POLICY_HANDLE;
+
+    /* Compatible with Windows function 0x00 */
+    DWORD svcctl_CloseServiceHandle(
+        [in] SvcCtlRpcHandle rpc_handle,
+        [in,out] POLICY_HANDLE *handle
+    );
+
+    /* Compatible with Windows function 0x0f */
+    DWORD svcctl_OpenSCManagerW(
+        SvcCtlRpcHandle rpc_handle,
+        [in,unique] LPCWSTR MachineName,
+        [in,unique] LPCWSTR DatabaseName,
+        [in] DWORD dwAccessMask,
+        [out] POLICY_HANDLE *handle
+    );
+
+}
diff --git a/programs/services/Makefile.in b/programs/services/Makefile.in
index 0aa642c..bd05be8 100644
--- a/programs/services/Makefile.in
+++ b/programs/services/Makefile.in
@@ -4,10 +4,13 @@ SRCDIR    = @srcdir@
 VPATH     = @srcdir@
 MODULE    = services.exe
 APPMODE   = -mwindows
-IMPORTS   = advapi32 kernel32
+IMPORTS   = rpcrt4 advapi32 kernel32 ntdll
 
-C_SRCS = services.c \
-	utils.c
+C_SRCS = rpc.c \
+    services.c \
+    utils.c
+
+IDL_S_SRCS = svcctl.idl
 
 @MAKE_PROG_RULES@
 
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
new file mode 100644
index 0000000..c112062
--- /dev/null
+++ b/programs/services/rpc.c
@@ -0,0 +1,240 @@
+/*
+ * Services.exe - RPC functions
+ *
+ * Copyright 2007 Google (Mikolaj Zalewski)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#define WIN32_LEAN_AND_MEAN
+
+#include <stdarg.h>
+#include <windows.h>
+#include <winternl.h>
+#include <winsvc.h>
+#include <ntsecapi.h>
+#include <rpc.h>
+
+#include "wine/list.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+#include "services.h"
+#include "svcctl.h"
+
+extern HANDLE __wine_make_process_system(void);
+
+WINE_DEFAULT_DEBUG_CHANNEL(services);
+
+static CRITICAL_SECTION g_handle_table_cs;
+static CRITICAL_SECTION_DEBUG g_handle_table_cs_debug =
+{
+    0, 0, &g_handle_table_cs,
+    { &g_handle_table_cs_debug.ProcessLocksList,
+      &g_handle_table_cs_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": g_handle_table_cs") }
+};
+static CRITICAL_SECTION g_handle_table_cs = { &g_handle_table_cs_debug, -1, 0, 0, 0, 0 };
+
+static const GENERIC_MAPPING g_scm_generic = {
+    (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
+    (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
+    (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
+    SC_MANAGER_ALL_ACCESS
+};
+
+typedef struct _handle_uuid   /* we interpret the uuid field of the POLICY_HANDLE as such a structure */
+{
+    ULONG index;
+    DWORD padding;
+    LONGLONG dwHandleKey;
+} handle_uuid;
+
+RTL_HANDLE_TABLE g_handle_table;
+
+#define HANDLE_TYPE_DONT_CARE 0
+#define HANDLE_TYPE_MANAGER   1
+#define HANDLE_TYPE_SERVICE   2
+
+typedef struct _handle_data
+{
+    ULONG_PTR ulHandleFlags;       /* bit #0 used by handle table */
+    DWORD dwType;
+    DWORD dwAccess;
+    LONGLONG dwHandleKey;
+} handle_data;
+
+static void init_policy_handle(POLICY_HANDLE *handle, ULONG index, handle_data *data)
+{
+    handle_uuid *uuid;
+
+    RtlGenRandom(&data->dwHandleKey, sizeof(data->dwHandleKey));
+
+    handle->dwHandleType = 0;
+    uuid = (handle_uuid *)&handle->uuid;
+    uuid->index = index;
+    uuid->padding = 0;
+    uuid->dwHandleKey = data->dwHandleKey;
+}
+
+/* Check if the given handle is valid, of a good type and allows the requested access. Note that as this
+ * function returns on success a pointer to handle data so in such a case the handle table lock is held.
+ */
+static DWORD validate_policy_handle(POLICY_HANDLE *handle, DWORD dwType, DWORD dwNeededAccess, handle_data **outData)
+{
+    handle_data *data;
+    handle_uuid *uuid;
+    /* FIXME: should we check if the handle is created by the current session? */
+    if (handle->dwHandleType != 0)
+    {
+        WINE_ERR("Invalid handle passed - invalid dwType\n");
+        return ERROR_INVALID_HANDLE;
+    }
+
+    uuid = (handle_uuid *)&handle->uuid;
+    EnterCriticalSection(&g_handle_table_cs);
+    if (!RtlIsValidIndexHandle(&g_handle_table, uuid->index, (RTL_HANDLE **)&data))
+    {
+        WINE_ERR("Invalid handle passed - invalid index %d\n", uuid->index);
+        LeaveCriticalSection(&g_handle_table_cs);
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if (uuid->dwHandleKey != data->dwHandleKey || uuid->padding != 0)
+    {
+        WINE_ERR("Invalid handle passed - invalid key\n");
+        LeaveCriticalSection(&g_handle_table_cs);
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if (dwType != HANDLE_TYPE_DONT_CARE && data->dwType != dwType)
+    {
+        WINE_ERR("Handle is of an invalid type\n");
+        LeaveCriticalSection(&g_handle_table_cs);
+        return ERROR_INVALID_HANDLE;
+    }
+
+    if ((dwNeededAccess & data->dwAccess) != dwNeededAccess)
+    {
+        WINE_ERR("Access denied - handle created with access %x, needed %x\n", data->dwAccess, dwNeededAccess);
+        LeaveCriticalSection(&g_handle_table_cs);
+        return ERROR_ACCESS_DENIED;
+    }
+
+    *outData = data;
+    return ERROR_SUCCESS;
+}
+
+DWORD svcctl_OpenSCManagerW(
+    SvcCtlRpcHandle rpc_handle,
+    LPCWSTR MachineName,      /* Note: this parameter is ignored */
+    LPCWSTR DatabaseName,
+    DWORD dwAccessMask,
+    POLICY_HANDLE *handle)
+{
+    handle_data *data;
+    ULONG index;
+    WINE_TRACE("conn=%p (%s, %s, %x)\n", rpc_handle, wine_dbgstr_w(MachineName), wine_dbgstr_w(DatabaseName), dwAccessMask);
+    if (DatabaseName != NULL && DatabaseName[0])
+    {
+        if (strcmpW(DatabaseName, SERVICES_FAILED_DATABASEW) == 0)
+            return ERROR_DATABASE_DOES_NOT_EXIST;
+        if (strcmpW(DatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
+            return ERROR_INVALID_NAME;
+    }
+
+    if (!(data = (handle_data *)RtlAllocateHandle(&g_handle_table, &index)))
+        return ERROR_NOT_ENOUGH_SERVER_MEMORY;
+    ZeroMemory(data, sizeof(data));
+    data->ulHandleFlags |= 1;  /* mark handle as used */
+    data->dwType = HANDLE_TYPE_MANAGER;
+
+    if (dwAccessMask & MAXIMUM_ALLOWED)
+        dwAccessMask |= SC_MANAGER_ALL_ACCESS;
+    data->dwAccess = dwAccessMask;
+    RtlMapGenericMask(&data->dwAccess, &g_scm_generic);
+
+    init_policy_handle(handle, index, data);
+    return ERROR_SUCCESS;
+}
+
+DWORD svcctl_CloseServiceHandle(
+    SvcCtlRpcHandle rpc_handle,
+    POLICY_HANDLE *handle)
+{
+    handle_data *data;
+    DWORD err;
+
+    WINE_TRACE("conn=%p (%s)\n", rpc_handle, wine_dbgstr_guid(&handle->uuid));
+    if ((err = validate_policy_handle(handle, HANDLE_TYPE_DONT_CARE, 0, &data)) != ERROR_SUCCESS)
+        return err;
+
+    RtlFreeHandle(&g_handle_table, (RTL_HANDLE *)data);
+    ZeroMemory(handle, sizeof(*handle));
+    LeaveCriticalSection(&g_handle_table_cs);
+    return ERROR_SUCCESS;
+}
+
+DWORD RPC_MainLoop(void)
+{
+    WCHAR transport[] = SVCCTL_TRANSPORT;
+    WCHAR endpoint[] = SVCCTL_ENDPOINT;
+    HANDLE hSleepHandle;
+    DWORD handle_size = 1;
+    DWORD err;
+
+    while (handle_size < sizeof(handle_data))
+        handle_size *= 2;       /* handle size must be a power of 2 */
+    RtlInitializeHandleTable(1048576, handle_size, &g_handle_table);
+
+    if ((err = RpcServerUseProtseqEpW(transport, 0, endpoint, NULL)) != ERROR_SUCCESS)
+    {
+        WINE_ERR("RpcServerUseProtseq failed with error %u\n", err);
+        return err;
+    }
+
+    if ((err = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 0, 0)) != ERROR_SUCCESS)
+    {
+        WINE_ERR("RpcServerRegisterIf failed with error %u", err);
+        return err;
+    }
+
+    if ((err = RpcServerListen(1, RPC_C_LISTEN_MAX_CALLS_DEFAULT, TRUE)) != ERROR_SUCCESS)
+    {
+        WINE_ERR("RpcServerListen failed with error %u\n", err);
+        return err;
+    }
+
+    WINE_TRACE("Entered main loop\n");
+    hSleepHandle = __wine_make_process_system();
+    SetEvent(g_hStartedEvent);
+    do {
+        err = WaitForSingleObjectEx(hSleepHandle, INFINITE, TRUE);
+        WINE_TRACE("Wait returned %d\n", err);
+    } while (err != WAIT_OBJECT_0);
+
+    WINE_TRACE("Object signaled - wine shutdown\n");
+    return ERROR_SUCCESS;
+}
+
+void  __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
+{
+    return HeapAlloc(GetProcessHeap(), 0, len);
+}
+
+void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
+{
+    HeapFree(GetProcessHeap(), 0, ptr);
+}
diff --git a/programs/services/services.c b/programs/services/services.c
index 1bb6769..49a07b6 100644
--- a/programs/services/services.c
+++ b/programs/services/services.c
@@ -23,10 +23,12 @@
 #include <stdarg.h>
 #include <windows.h>
 #include <winsvc.h>
+#include <rpc.h>
 
 #include "wine/list.h"
 #include "wine/unicode.h"
 #include "wine/debug.h"
+#include "svcctl.h"
 
 #include "services.h"
 
@@ -34,6 +36,8 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(services);
 
+HANDLE g_hStartedEvent;
+
 struct list g_services;
 
 /* Registry constants */
@@ -195,8 +199,9 @@ DWORD load_services()
 int main(int argc, char *argv[])
 {
     DWORD err;
+    g_hStartedEvent = CreateEventW(NULL, TRUE, FALSE, SVCCTL_STARTED_EVENT);
     list_init(&g_services);
     if ((err = load_services()) != 0)
         return err;
-    return 0;
+    return RPC_MainLoop();
 }
diff --git a/programs/services/services.h b/programs/services/services.h
index 2756342..a59bbe2 100644
--- a/programs/services/services.h
+++ b/programs/services/services.h
@@ -34,6 +34,10 @@ typedef struct _service_entry
     LPWSTR dependOnGroups;
 } service_entry;
 
+extern HANDLE g_hStartedEvent;
+
+DWORD RPC_MainLoop(void);
+
 /* from utils.c */
 LPWSTR strdupW(LPWSTR str);
 
diff --git a/programs/services/svcctl.idl b/programs/services/svcctl.idl
new file mode 100644
index 0000000..101e0f2
--- /dev/null
+++ b/programs/services/svcctl.idl
@@ -0,0 +1 @@
+#include "wine/svcctl.idl"
-- 
1.4.4.2


--------------090301030503030601070308--



More information about the wine-patches mailing list