services: Move ChangeServiceConfigW implementation from advapi32.dll to services.exe.
This commit is contained in:
parent
a363b9a066
commit
76d4eeebff
|
@ -243,6 +243,18 @@ static inline LPWSTR SERV_dupmulti(LPCSTR str)
|
||||||
return wstr;
|
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
|
* RPC connection with servies.exe
|
||||||
*/
|
*/
|
||||||
|
@ -1322,7 +1334,7 @@ CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
|
||||||
struct sc_service *hsvc = NULL;
|
struct sc_service *hsvc = NULL;
|
||||||
DWORD new_mask = dwDesiredAccess;
|
DWORD new_mask = dwDesiredAccess;
|
||||||
DWORD len, err;
|
DWORD len, err;
|
||||||
SIZE_T depslen = 0, passwdlen;
|
SIZE_T passwdlen;
|
||||||
|
|
||||||
TRACE("%p %s %s\n", hSCManager,
|
TRACE("%p %s %s\n", hSCManager,
|
||||||
debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
|
debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
|
||||||
|
@ -1340,16 +1352,6 @@ CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
|
||||||
return NULL;
|
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)
|
if (lpPassword)
|
||||||
passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
|
passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
|
||||||
else
|
else
|
||||||
|
@ -1370,8 +1372,9 @@ CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
|
||||||
|
|
||||||
err = svcctl_CreateServiceW(hscm->hdr.server_handle, lpServiceName,
|
err = svcctl_CreateServiceW(hscm->hdr.server_handle, lpServiceName,
|
||||||
lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
|
lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
|
||||||
lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies, depslen,
|
lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies,
|
||||||
lpServiceStartName, (LPBYTE)lpPassword, passwdlen, &hsvc->hdr.server_handle);
|
multisz_cb(lpDependencies), lpServiceStartName, (LPBYTE)lpPassword, passwdlen,
|
||||||
|
&hsvc->hdr.server_handle);
|
||||||
|
|
||||||
if (err != ERROR_SUCCESS)
|
if (err != ERROR_SUCCESS)
|
||||||
{
|
{
|
||||||
|
@ -2299,11 +2302,9 @@ BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
|
||||||
LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
|
LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
|
||||||
LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
|
LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
|
||||||
{
|
{
|
||||||
struct reg_value val[10];
|
|
||||||
struct sc_service *hsvc;
|
struct sc_service *hsvc;
|
||||||
DWORD r = ERROR_SUCCESS;
|
DWORD cb_pwd;
|
||||||
HKEY hKey;
|
DWORD err;
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
|
TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
|
||||||
hService, dwServiceType, dwStartType, dwErrorControl,
|
hService, dwServiceType, dwStartType, dwErrorControl,
|
||||||
|
@ -2317,37 +2318,18 @@ BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
|
||||||
SetLastError( ERROR_INVALID_HANDLE );
|
SetLastError( ERROR_INVALID_HANDLE );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
hKey = hsvc->hkey;
|
|
||||||
|
|
||||||
if( dwServiceType != SERVICE_NO_CHANGE )
|
cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
|
||||||
service_set_dword( &val[n++], szType, &dwServiceType );
|
|
||||||
|
|
||||||
if( dwStartType != SERVICE_NO_CHANGE )
|
err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
|
||||||
service_set_dword( &val[n++], szStart, &dwStartType );
|
dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
|
||||||
|
(const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
|
||||||
|
(const BYTE *)lpPassword, cb_pwd, lpDisplayName);
|
||||||
|
|
||||||
if( dwErrorControl != SERVICE_NO_CHANGE )
|
if (err != ERROR_SUCCESS)
|
||||||
service_set_dword( &val[n++], szError, &dwErrorControl );
|
SetLastError(err);
|
||||||
|
|
||||||
if( lpBinaryPathName )
|
return err == ERROR_SUCCESS;
|
||||||
service_set_string( &val[n++], szImagePath, lpBinaryPathName );
|
|
||||||
|
|
||||||
if( lpLoadOrderGroup )
|
|
||||||
service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
|
|
||||||
|
|
||||||
/* 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 );
|
|
||||||
|
|
||||||
return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
|
|
@ -730,6 +730,7 @@ static void test_sequence(void)
|
||||||
DWORD given, needed;
|
DWORD given, needed;
|
||||||
static const CHAR servicename [] = "Winetest";
|
static const CHAR servicename [] = "Winetest";
|
||||||
static const CHAR displayname [] = "Winetest dummy service";
|
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 pathname [] = "we_dont_care.exe";
|
||||||
static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0";
|
static const CHAR dependencies[] = "Master1\0Master2\0+MasterGroup1\0";
|
||||||
static const CHAR password [] = "";
|
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->lpServiceStartName, localsystem), "Expected 'LocalSystem', got '%s'\n", config->lpServiceStartName);
|
||||||
ok(!strcmp(config->lpDisplayName, displayname), "Expected '%s', got '%s'\n", displayname, config->lpDisplayName);
|
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);
|
SetLastError(0xdeadbeef);
|
||||||
ret = DeleteService(svc_handle);
|
ret = DeleteService(svc_handle);
|
||||||
ok(ret, "Expected success\n");
|
ok(ret, "Expected success\n");
|
||||||
|
|
|
@ -69,6 +69,23 @@ cpp_quote("#endif")
|
||||||
[in] SC_RPC_HANDLE hService
|
[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 */
|
/* Compatible with Windows function 0x0c */
|
||||||
DWORD svcctl_CreateServiceW(
|
DWORD svcctl_CreateServiceW(
|
||||||
[in] SC_RPC_HANDLE hSCManager,
|
[in] SC_RPC_HANDLE hSCManager,
|
||||||
|
|
|
@ -370,6 +370,119 @@ DWORD svcctl_QueryServiceConfigW(
|
||||||
return ERROR_SUCCESS;
|
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(
|
DWORD svcctl_CloseServiceHandle(
|
||||||
SC_RPC_HANDLE *handle)
|
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));
|
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;
|
HKEY hServicesRootKey;
|
||||||
DWORD err;
|
DWORD err;
|
||||||
|
|
|
@ -41,6 +41,7 @@ struct service_entry *find_service(LPCWSTR name);
|
||||||
struct service_entry *find_service_by_displayname(LPCWSTR name);
|
struct service_entry *find_service_by_displayname(LPCWSTR name);
|
||||||
DWORD add_service(struct service_entry *entry);
|
DWORD add_service(struct service_entry *entry);
|
||||||
DWORD remove_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 free_service_entry(struct service_entry *entry);
|
||||||
void release_service(struct service_entry *service);
|
void release_service(struct service_entry *service);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue