[PATCH] services.exe/advapi32: move ChangeServiceConfigW to services.exe

Mikołaj Zalewski mikolaj at zalewski.pl
Sat Mar 15 13:11:12 CDT 2008


---
 dlls/advapi32/service.c       |   74 ++++++++++-----------------
 dlls/advapi32/tests/service.c |   21 ++++++++
 include/wine/svcctl.idl       |   18 +++++++
 programs/services/rpc.c       |  113 +++++++++++++++++++++++++++++++++++++++++
 programs/services/services.c  |    2 +-
 programs/services/services.h  |    1 +
 6 files changed, 182 insertions(+), 47 deletions(-)

diff --git a/dlls/advapi32/service.c b/dlls/advapi32/service.c
index b9892c1..5fc73c9 100644
--- a/dlls/advapi32/service.c
+++ b/dlls/advapi32/service.c
@@ -246,6 +246,18 @@ static inline LPWSTR SERV_dupmulti(LPCSTR str)
     return wstr;
 }
 
+static inline DWORD multisz_cb(LPCWSTR wmultisz)
+{
+    const WCHAR *wptr = wmultisz;
+
+    if (wmultisz == NULL)
+        return 0;
+
+    while (*wptr)
+        wptr += lstrlenW(wptr)+1;
+    return (wptr - wmultisz + 1)*sizeof(WCHAR);
+}
+
 /******************************************************************************
  * RPC connection with servies.exe
  */
@@ -1333,7 +1345,7 @@ CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
     struct sc_service *hsvc = NULL;
     DWORD new_mask = dwDesiredAccess;
     DWORD len, err;
-    SIZE_T depslen = 0, passwdlen;
+    SIZE_T passwdlen;
 
     TRACE("%p %s %s\n", hSCManager, 
           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
@@ -1351,16 +1363,6 @@ CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
         return NULL;
     }
 
-    if (lpDependencies)
-    {
-        const WCHAR *wptr = lpDependencies;
-        while (*wptr)
-            wptr += strlenW(wptr)+1;
-        depslen = (wptr - lpDependencies + 1)*sizeof(WCHAR);
-    }
-    else
-        depslen = 0;
-
     if (lpPassword)
         passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
     else
@@ -1382,8 +1384,9 @@ CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
 
     err = svcctl_CreateServiceW(hscm->hdr.rpc_handle, &hscm->hdr.server_handle, lpServiceName,
             lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
-            lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies, depslen,
-            lpServiceStartName, (LPBYTE)lpPassword, passwdlen, &hsvc->hdr.server_handle);
+            lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies,
+            multisz_cb(lpDependencies), lpServiceStartName, (LPBYTE)lpPassword, passwdlen,
+            &hsvc->hdr.server_handle);
 
     if (err != ERROR_SUCCESS)
     {
@@ -2194,55 +2197,34 @@ BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
 {
-    struct reg_value val[10];
     struct sc_service *hsvc;
-    DWORD r = ERROR_SUCCESS;
-    HKEY hKey;
-    int n = 0;
+    DWORD cb_pwd;
+    DWORD err;
 
     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
           hService, dwServiceType, dwStartType, dwErrorControl, 
           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
-
+    
     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
     if (!hsvc)
     {
         SetLastError( ERROR_INVALID_HANDLE );
         return FALSE;
     }
-    hKey = hsvc->hkey;
-
-    if( dwServiceType != SERVICE_NO_CHANGE )
-        service_set_dword( &val[n++], szType, &dwServiceType );
-
-    if( dwStartType != SERVICE_NO_CHANGE )
-        service_set_dword( &val[n++], szStart, &dwStartType );
-
-    if( dwErrorControl != SERVICE_NO_CHANGE )
-        service_set_dword( &val[n++], szError, &dwErrorControl );
-
-    if( lpBinaryPathName )
-        service_set_string( &val[n++], szImagePath, lpBinaryPathName );
 
-    if( lpLoadOrderGroup )
-        service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
+    cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
 
-    /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
-     * There is no such key as what szDependencies refers to */
-    if( lpDependencies )
-        service_set_multi_string( &val[n++], szDependencies, lpDependencies );
+    err = svcctl_ChangeServiceConfigW(hsvc->hdr.rpc_handle, &hsvc->hdr.server_handle, dwServiceType,
+            dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
+            (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
+            (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
 
-    if( lpPassword )
-        FIXME("ignoring password\n");
-
-    if( lpServiceStartName )
-        service_set_string( &val[n++], szObjectName, lpServiceStartName );
-
-    r = service_write_values( hsvc->hkey, val, n );
-
-    return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
+    if (err != ERROR_SUCCESS)
+        SetLastError(err);
+    
+    return err == ERROR_SUCCESS;
 }
 
 /******************************************************************************
diff --git a/dlls/advapi32/tests/service.c b/dlls/advapi32/tests/service.c
index 27bad34..be6bd79 100644
--- a/dlls/advapi32/tests/service.c
+++ b/dlls/advapi32/tests/service.c
@@ -730,6 +730,7 @@ static void test_sequence(void)
     DWORD given, needed;
     static const CHAR servicename [] = "Winetest";
     static const CHAR displayname [] = "Winetest dummy service";
+    static const CHAR displayname2[] = "Winetest dummy service (2)";
     static const CHAR pathname    [] = "we_dont_care.exe";
     static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0";
     static const CHAR password    [] = "";
@@ -823,6 +824,26 @@ static void test_sequence(void)
     ok(!strcmp(config->lpServiceStartName, localsystem), "Expected 'LocalSystem', got '%s'\n", config->lpServiceStartName);
     ok(!strcmp(config->lpDisplayName, displayname), "Expected '%s', got '%s'\n", displayname, config->lpDisplayName);
     
+    ok(ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_ERROR_NORMAL, NULL, "TestGroup2", NULL, NULL, NULL, NULL, displayname2),
+        "ChangeServiceConfig failed (err=%d)\n", GetLastError());
+
+#if 0 /* for some reason (rpcrt4 bug?) QueryServiceConfig for a non-NULL lpLoadOrder crashes Wine */
+    QueryServiceConfigA(svc_handle, NULL, 0, &needed);
+    config = HeapReAlloc(GetProcessHeap(), 0, config, needed);
+    ok(QueryServiceConfigA(svc_handle, config, needed, &needed), "QueryServiceConfig failed\n");
+    ok(config->lpBinaryPathName && config->lpLoadOrderGroup && config->lpDependencies && config->lpServiceStartName &&
+        config->lpDisplayName, "Expected all string struct members to be non-NULL\n");
+    ok(config->dwServiceType == (SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS),
+        "Expected SERVICE_INTERACTIVE_PROCESS | SERVICE_WIN32_OWN_PROCESS, got %d\n", config->dwServiceType);
+    ok(config->dwStartType == SERVICE_DISABLED, "Expected SERVICE_DISABLED, got %d\n", config->dwStartType);
+    ok(config->dwErrorControl == SERVICE_ERROR_NORMAL, "Expected SERVICE_ERROR_NORMAL, got %d\n", config->dwErrorControl);
+    ok(!strcmp(config->lpBinaryPathName, pathname), "Expected '%s', got '%s'\n", pathname, config->lpBinaryPathName);
+    ok(!strcmp(config->lpLoadOrderGroup, "TestGroup2"), "Expected 'TestGroup2', got '%s'\n", config->lpLoadOrderGroup);
+    ok(config->dwTagId == 0, "Expected 0, got %d\n", config->dwTagId);
+    ok(!strcmp(config->lpServiceStartName, localsystem), "Expected 'LocalSystem', got '%s'\n", config->lpServiceStartName);
+    ok(!strcmp(config->lpDisplayName, displayname2), "Expected '%s', got '%s'\n", displayname2, config->lpDisplayName);
+#endif
+
     SetLastError(0xdeadbeef);
     ret = DeleteService(svc_handle);
     ok(ret, "Expected success\n");
diff --git a/include/wine/svcctl.idl b/include/wine/svcctl.idl
index f7ce1d9..fa94315 100644
--- a/include/wine/svcctl.idl
+++ b/include/wine/svcctl.idl
@@ -79,6 +79,24 @@ cpp_quote("#endif")
         [in,ref] POLICY_HANDLE *hService
     );
 
+    /* Compatible with Windows function 0x0b */
+    DWORD svcctl_ChangeServiceConfigW(
+        SvcCtlRpcHandle rpc_handle,
+        [in,ref] POLICY_HANDLE *hService,
+        [in] DWORD dwServiceType,
+        [in] DWORD dwStartType,
+        [in] DWORD dwErrorControl,
+        [in,unique,string] LPCWSTR lpBinaryPathName,
+        [in,unique,string] LPCWSTR lpLoadOrderGroupKey,
+        [in,out,unique] DWORD *lpdwTagId,
+        [in,unique,size_is(dwDependenciesSize)] const BYTE *lpDependencies,
+        [in] DWORD dwDependenciesSize,
+        [in,unique,string] LPCWSTR lpServiceStartName,
+        [in,unique,size_is(dwPasswordSize)] const BYTE *lpPassword,
+        [in] DWORD dwPasswordSize,
+        [in,unique,string] LPCWSTR lpDisplayName
+    );
+
     /* Compatible with Windows function 0x0c */
     DWORD svcctl_CreateServiceW(
         SvcCtlRpcHandle rpc_handle,
diff --git a/programs/services/rpc.c b/programs/services/rpc.c
index 1fe474f..b2bb1f9 100644
--- a/programs/services/rpc.c
+++ b/programs/services/rpc.c
@@ -388,6 +388,119 @@ DWORD svcctl_QueryServiceConfigW(
     return ERROR_SUCCESS;
 }
 
+DWORD svcctl_ChangeServiceConfigW(
+        SvcCtlRpcHandle rpc_handle,
+        POLICY_HANDLE *hService,
+        DWORD dwServiceType,
+        DWORD dwStartType,
+        DWORD dwErrorControl,
+        LPCWSTR lpBinaryPathName,
+        LPCWSTR lpLoadOrderGroup,
+        DWORD *lpdwTagId,
+        const BYTE *lpDependencies,
+        DWORD dwDependenciesSize,
+        LPCWSTR lpServiceStartName,
+        const BYTE *lpPassword,
+        DWORD dwPasswordSize,
+        LPCWSTR lpDisplayName)
+{
+    service_entry new_entry;
+    service_entry *service;
+    DWORD err;
+
+    WINE_TRACE("conn=%p (%s)\n", rpc_handle, wine_dbgstr_guid(&hService->uuid));
+    if ((err = validate_service_handle(hService, SERVICE_CHANGE_CONFIG, &service)) != 0)
+        return err;
+    
+    if (!check_multisz((LPCWSTR)lpDependencies, dwDependenciesSize))
+        return ERROR_INVALID_PARAMETER;
+    
+    /* first check if the new configuration is correct */
+    lock_services();
+
+    if (is_marked_for_delete(service))
+    {
+        unlock_services();
+        return ERROR_SERVICE_MARKED_FOR_DELETE;
+    }
+
+    if (lpDisplayName != NULL && find_service_by_displayname(lpDisplayName))
+    {
+        unlock_services();
+        return ERROR_DUPLICATE_SERVICE_NAME;
+    }
+
+    new_entry = *service;
+
+    if (dwServiceType != SERVICE_NO_CHANGE)
+        new_entry.config.dwServiceType = dwServiceType;
+
+    if (dwStartType != SERVICE_NO_CHANGE)
+        new_entry.config.dwStartType = dwStartType;
+
+    if (dwErrorControl != SERVICE_NO_CHANGE)
+        new_entry.config.dwErrorControl = dwErrorControl;
+
+    if (lpBinaryPathName != NULL)
+        new_entry.config.lpBinaryPathName = (LPWSTR)lpBinaryPathName;
+
+    if (lpLoadOrderGroup != NULL)
+        new_entry.config.lpLoadOrderGroup = (LPWSTR)lpLoadOrderGroup;
+
+    if (lpdwTagId != NULL)
+        WINE_FIXME("Changing tag id not supported\n");
+
+    if (lpDependencies != NULL)
+        WINE_FIXME("Chainging dependencies not supported\n");
+
+    if (lpServiceStartName != NULL)
+        new_entry.config.lpServiceStartName = (LPWSTR)lpServiceStartName;
+
+    if (lpPassword != NULL)
+        WINE_FIXME("Setting password not supported\n");
+
+    if (lpDisplayName != NULL)
+        new_entry.config.lpDisplayName = (LPWSTR)lpDisplayName;
+
+    if (!validate_service_config(&new_entry))
+    {
+        WINE_ERR("The configuration after the change wouldn't be valid");
+        unlock_services();
+        return ERROR_INVALID_PARAMETER;
+    }
+
+    /* configuration OK. The strings needs to be duplicated */
+    if (lpBinaryPathName != NULL)
+    {
+        HeapFree(GetProcessHeap(), 0, service->config.lpBinaryPathName);
+        new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName);
+    }
+
+    if (lpLoadOrderGroup != NULL)
+    {
+        HeapFree(GetProcessHeap(), 0, service->config.lpLoadOrderGroup);
+        new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
+    }
+
+    if (lpServiceStartName != NULL)
+    {
+        HeapFree(GetProcessHeap(), 0, service->config.lpServiceStartName);
+        new_entry.config.lpServiceStartName = strdupW(lpServiceStartName);
+    }
+
+    if (lpDisplayName != NULL)
+    {
+        HeapFree(GetProcessHeap(), 0, service->config.lpDisplayName);
+        new_entry.config.lpDisplayName = strdupW(lpDisplayName);
+    }
+
+    *service = new_entry;
+    save_service_config(service);
+    unlock_services();
+
+    return ERROR_SUCCESS;
+}
+
 DWORD svcctl_CloseServiceHandle(
     SvcCtlRpcHandle rpc_handle,
     POLICY_HANDLE *handle)
diff --git a/programs/services/services.c b/programs/services/services.c
index b78fc5f..3ab8690 100644
--- a/programs/services/services.c
+++ b/programs/services/services.c
@@ -141,7 +141,7 @@ static DWORD reg_set_string_value(HKEY hKey, LPCWSTR value_name, LPCWSTR string)
     return RegSetValueExW(hKey, value_name, 0, REG_SZ, (LPBYTE)string, sizeof(WCHAR)*(strlenW(string) + 1));
 }
 
-static DWORD save_service_config(service_entry *entry)
+DWORD save_service_config(service_entry *entry)
 {
     HKEY hServicesRootKey;
     DWORD err;
diff --git a/programs/services/services.h b/programs/services/services.h
index 5dfca89..b8cf458 100644
--- a/programs/services/services.h
+++ b/programs/services/services.h
@@ -41,6 +41,7 @@ service_entry *find_service(LPCWSTR name);
 service_entry *find_service_by_displayname(LPCWSTR name);
 DWORD add_service(service_entry *entry);
 DWORD remove_service(service_entry *entry);
+DWORD save_service_config(service_entry *entry);
 void free_service_entry(service_entry *entry);
 void release_service(service_entry *service);
 
-- 
1.5.4


--------------000309080705090404040605--



More information about the wine-patches mailing list