Commit 76d4eeeb authored by Mikołaj Zalewski's avatar Mikołaj Zalewski Committed by Alexandre Julliard

services: Move ChangeServiceConfigW implementation from advapi32.dll to services.exe.

parent a363b9a0
......@@ -243,6 +243,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
*/
......@@ -1322,7 +1334,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));
......@@ -1340,16 +1352,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
......@@ -1370,8 +1372,9 @@ CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
err = svcctl_CreateServiceW(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)
{
......@@ -2299,11 +2302,9 @@ 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,
......@@ -2317,37 +2318,18 @@ BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
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 );
cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
if( lpLoadOrderGroup )
service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
(const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
(const BYTE *)lpPassword, cb_pwd, lpDisplayName);
/* 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 );
if( lpPassword )
FIXME("ignoring password\n");
if( lpServiceStartName )
service_set_string( &val[n++], szObjectName, lpServiceStartName );
r = service_write_values( hsvc->hkey, val, n );
if (err != ERROR_SUCCESS)
SetLastError(err);
return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
return err == ERROR_SUCCESS;
}
/******************************************************************************
......
......@@ -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,24 @@ 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());
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);
SetLastError(0xdeadbeef);
ret = DeleteService(svc_handle);
ok(ret, "Expected success\n");
......
......@@ -69,6 +69,23 @@ cpp_quote("#endif")
[in] SC_RPC_HANDLE hService
);
/* Compatible with Windows function 0x0b */
DWORD svcctl_ChangeServiceConfigW(
[in] SC_RPC_HANDLE hService,
[in] DWORD dwServiceType,
[in] DWORD dwStartType,
[in] DWORD dwErrorControl,
[in,unique] LPCWSTR lpBinaryPathName,
[in,unique] LPCWSTR lpLoadOrderGroupKey,
[in,out,unique] DWORD *lpdwTagId,
[in,unique,size_is(dwDependenciesSize)] const BYTE *lpDependencies,
[in] DWORD dwDependenciesSize,
[in,unique] LPCWSTR lpServiceStartName,
[in,unique,size_is(dwPasswordSize)] const BYTE *lpPassword,
[in] DWORD dwPasswordSize,
[in,unique] LPCWSTR lpDisplayName
);
/* Compatible with Windows function 0x0c */
DWORD svcctl_CreateServiceW(
[in] SC_RPC_HANDLE hSCManager,
......
......@@ -370,6 +370,119 @@ DWORD svcctl_QueryServiceConfigW(
return ERROR_SUCCESS;
}
DWORD svcctl_ChangeServiceConfigW(
SC_RPC_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)
{
struct service_entry new_entry;
struct sc_service *service;
DWORD err;
WINE_TRACE("\n");
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->service_entry))
{
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->service_entry;
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->service_entry->config.lpBinaryPathName);
new_entry.config.lpBinaryPathName = strdupW(lpBinaryPathName);
}
if (lpLoadOrderGroup != NULL)
{
HeapFree(GetProcessHeap(), 0, service->service_entry->config.lpLoadOrderGroup);
new_entry.config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup);
}
if (lpServiceStartName != NULL)
{
HeapFree(GetProcessHeap(), 0, service->service_entry->config.lpServiceStartName);
new_entry.config.lpServiceStartName = strdupW(lpServiceStartName);
}
if (lpDisplayName != NULL)
{
HeapFree(GetProcessHeap(), 0, service->service_entry->config.lpDisplayName);
new_entry.config.lpDisplayName = strdupW(lpDisplayName);
}
*service->service_entry = new_entry;
save_service_config(service->service_entry);
unlock_services();
return ERROR_SUCCESS;
}
DWORD svcctl_CloseServiceHandle(
SC_RPC_HANDLE *handle)
{
......
......@@ -140,7 +140,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(struct service_entry *entry)
DWORD save_service_config(struct service_entry *entry)
{
HKEY hServicesRootKey;
DWORD err;
......
......@@ -41,6 +41,7 @@ struct service_entry *find_service(LPCWSTR name);
struct service_entry *find_service_by_displayname(LPCWSTR name);
DWORD add_service(struct service_entry *entry);
DWORD remove_service(struct service_entry *entry);
DWORD save_service_config(struct service_entry *entry);
void free_service_entry(struct service_entry *entry);
void release_service(struct service_entry *service);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment