advapi32: Unify service startup and control handling.
Signed-off-by: Sebastian Lackner <sebastian@fds-team.de> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
328fbb6880
commit
1c5affa205
|
@ -379,9 +379,9 @@ static DWORD WINAPI service_thread(LPVOID arg)
|
|||
/******************************************************************************
|
||||
* service_handle_start
|
||||
*/
|
||||
static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
|
||||
static DWORD service_handle_start(service_data *service, const void *data, DWORD data_size)
|
||||
{
|
||||
TRACE("%s argsize %u\n", debugstr_w(service->name), count);
|
||||
DWORD count = data_size / sizeof(WCHAR);
|
||||
|
||||
if (service->thread)
|
||||
{
|
||||
|
@ -390,8 +390,11 @@ static DWORD service_handle_start(service_data *service, const WCHAR *data, DWOR
|
|||
}
|
||||
|
||||
heap_free(service->args);
|
||||
service->args = heap_alloc(count * sizeof(WCHAR));
|
||||
memcpy( service->args, data, count * sizeof(WCHAR) );
|
||||
service->args = heap_alloc((count + 2) * sizeof(WCHAR));
|
||||
if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
|
||||
service->args[count++] = 0;
|
||||
service->args[count++] = 0;
|
||||
|
||||
service->thread = CreateThread( NULL, 0, service_thread,
|
||||
service, 0, NULL );
|
||||
SetEvent( service_event ); /* notify the main loop */
|
||||
|
@ -401,14 +404,16 @@ static DWORD service_handle_start(service_data *service, const WCHAR *data, DWOR
|
|||
/******************************************************************************
|
||||
* service_handle_control
|
||||
*/
|
||||
static DWORD service_handle_control(const service_data *service, DWORD control, void *data)
|
||||
static DWORD service_handle_control(service_data *service, DWORD control, const void *data, DWORD data_size)
|
||||
{
|
||||
DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
|
||||
|
||||
TRACE("%s control %u data %p\n", debugstr_w(service->name), control, data);
|
||||
TRACE("%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size);
|
||||
|
||||
if (service->handler)
|
||||
ret = service->handler(control, 0, data, service->context);
|
||||
if (control == SERVICE_CONTROL_START)
|
||||
ret = service_handle_start(service, data, data_size);
|
||||
else if (service->handler)
|
||||
ret = service->handler(control, 0, (void *)data, service->context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -472,39 +477,33 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg)
|
|||
goto done;
|
||||
}
|
||||
|
||||
/* find the service */
|
||||
if (!(service = find_service_by_name( name )))
|
||||
if (info.magic != SERVICE_PROTOCOL_MAGIC)
|
||||
{
|
||||
FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(name));
|
||||
ERR( "received invalid request for service %s\n", debugstr_w(name) );
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
goto done;
|
||||
}
|
||||
|
||||
TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(name) );
|
||||
|
||||
/* handle the request */
|
||||
switch (info.cmd)
|
||||
/* find the service */
|
||||
if (!(service = find_service_by_name( name )))
|
||||
{
|
||||
case WINESERV_STARTINFO:
|
||||
if (!service->handle)
|
||||
{
|
||||
if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
|
||||
!(service->full_access_handle = OpenServiceW( disp->manager, name,
|
||||
GENERIC_READ|GENERIC_WRITE )))
|
||||
FIXME( "failed to open service %s\n", debugstr_w(name) );
|
||||
}
|
||||
result = service_handle_start(service, (WCHAR *)data, data_size / sizeof(WCHAR));
|
||||
break;
|
||||
case WINESERV_SENDCONTROL:
|
||||
result = service_handle_control(service, info.control, (data_size > info.name_size * sizeof(WCHAR)) ?
|
||||
&data[info.name_size * sizeof(WCHAR)] : NULL);
|
||||
break;
|
||||
default:
|
||||
ERR("received invalid command %u\n", info.cmd);
|
||||
FIXME( "got request for unknown service %s\n", debugstr_w(name) );
|
||||
result = ERROR_INVALID_PARAMETER;
|
||||
break;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!service->handle)
|
||||
{
|
||||
if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
|
||||
!(service->full_access_handle = OpenServiceW( disp->manager, name,
|
||||
GENERIC_READ|GENERIC_WRITE )))
|
||||
FIXME( "failed to open service %s\n", debugstr_w(name) );
|
||||
}
|
||||
|
||||
data_size -= info.name_size * sizeof(WCHAR);
|
||||
result = service_handle_control(service, info.control, data_size ?
|
||||
&data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
|
||||
|
||||
done:
|
||||
LeaveCriticalSection( &service_cs );
|
||||
WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
|
||||
|
@ -592,13 +591,13 @@ static BOOL service_run_main_thread(void)
|
|||
{
|
||||
FIXME("service should be able to delay shutdown\n");
|
||||
timeout += spi.dwPreshutdownTimeout;
|
||||
ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL );
|
||||
ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN, NULL, 0 );
|
||||
wait_handles[n++] = services[i]->thread;
|
||||
}
|
||||
}
|
||||
else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
|
||||
{
|
||||
ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL );
|
||||
ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN, NULL, 0 );
|
||||
wait_handles[n++] = services[i]->thread;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,15 +34,12 @@ cpp_quote("#define SVCCTL_ENDPOINTA \"\\\\pipe\\\\svcctl\"")
|
|||
cpp_quote("#define SVCCTL_STARTED_EVENT {'_','_','w','i','n','e','_','S','v','c','c','t','l','S','t','a','r','t','e','d',0}")
|
||||
|
||||
/* Service startup protocol over control pipe - not compatible with Windows */
|
||||
enum service_pipe_command
|
||||
{
|
||||
WINESERV_STARTINFO = 1,
|
||||
WINESERV_SENDCONTROL = 2
|
||||
};
|
||||
cpp_quote("#define SERVICE_PROTOCOL_MAGIC 0x57494e45")
|
||||
cpp_quote("#define SERVICE_CONTROL_START 0")
|
||||
|
||||
typedef struct service_start_info_t
|
||||
{
|
||||
enum service_pipe_command cmd; /* request code */
|
||||
DWORD magic; /* protocol magic */
|
||||
DWORD total_size; /* total request size */
|
||||
DWORD name_size; /* size of name in data buffer */
|
||||
DWORD control; /* control code */
|
||||
|
|
|
@ -979,7 +979,7 @@ static BOOL service_accepts_control(const struct service_entry *service, DWORD d
|
|||
/******************************************************************************
|
||||
* process_send_command
|
||||
*/
|
||||
BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
|
||||
static BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result)
|
||||
{
|
||||
OVERLAPPED overlapped;
|
||||
DWORD count, ret;
|
||||
|
@ -1030,8 +1030,8 @@ BOOL process_send_command(struct process_entry *process, const void *data, DWORD
|
|||
/******************************************************************************
|
||||
* process_send_control
|
||||
*/
|
||||
static BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control,
|
||||
const BYTE *data, DWORD data_size, DWORD *result)
|
||||
BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control,
|
||||
const BYTE *data, DWORD data_size, DWORD *result)
|
||||
{
|
||||
service_start_info *ssi;
|
||||
DWORD len;
|
||||
|
@ -1041,7 +1041,7 @@ static BOOL process_send_control(struct process_entry *process, const WCHAR *nam
|
|||
len = (strlenW(name) + 1) * sizeof(WCHAR) + data_size;
|
||||
|
||||
ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
|
||||
ssi->cmd = WINESERV_SENDCONTROL;
|
||||
ssi->magic = SERVICE_PROTOCOL_MAGIC;
|
||||
ssi->control = control;
|
||||
ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
|
||||
ssi->name_size = strlenW(name) + 1;
|
||||
|
|
|
@ -844,8 +844,7 @@ static DWORD process_send_start_message(struct process_entry *process, const WCH
|
|||
{
|
||||
OVERLAPPED overlapped;
|
||||
DWORD i, len, result;
|
||||
service_start_info *ssi;
|
||||
LPWSTR p;
|
||||
WCHAR *str, *p;
|
||||
|
||||
WINE_TRACE("%p %s %p %d\n", process, wine_dbgstr_w(name), argv, argc);
|
||||
|
||||
|
@ -872,32 +871,28 @@ static DWORD process_send_start_message(struct process_entry *process, const WCH
|
|||
}
|
||||
}
|
||||
|
||||
/* calculate how much space do we need to send the startup info */
|
||||
len = strlenW(name) + 1;
|
||||
for (i=0; i<argc; i++)
|
||||
for (i = 0; i < argc; i++)
|
||||
len += strlenW(argv[i])+1;
|
||||
len = (len + 1) * sizeof(WCHAR);
|
||||
|
||||
ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len]));
|
||||
ssi->cmd = WINESERV_STARTINFO;
|
||||
ssi->control = 0;
|
||||
ssi->total_size = FIELD_OFFSET(service_start_info, data[len]);
|
||||
ssi->name_size = strlenW(name) + 1;
|
||||
strcpyW((WCHAR *)ssi->data, name);
|
||||
if (!(str = HeapAlloc(GetProcessHeap(), 0, len)))
|
||||
return ERROR_NOT_ENOUGH_SERVER_MEMORY;
|
||||
|
||||
/* copy service args into a single buffer*/
|
||||
p = (WCHAR *)&ssi->data[ssi->name_size * sizeof(WCHAR)];
|
||||
for (i=0; i<argc; i++)
|
||||
p = str;
|
||||
strcpyW(p, name);
|
||||
p += strlenW(name) + 1;
|
||||
for (i = 0; i < argc; i++)
|
||||
{
|
||||
strcpyW(p, argv[i]);
|
||||
p += strlenW(p) + 1;
|
||||
}
|
||||
*p=0;
|
||||
*p = 0;
|
||||
|
||||
if (!process_send_command(process, ssi, ssi->total_size, &result))
|
||||
if (!process_send_control(process, name, SERVICE_CONTROL_START, (const BYTE *)str, len, &result))
|
||||
result = ERROR_SERVICE_REQUEST_TIMEOUT;
|
||||
|
||||
HeapFree(GetProcessHeap(), 0, ssi);
|
||||
HeapFree(GetProcessHeap(), 0, str);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,7 +95,8 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *
|
|||
|
||||
struct process_entry *grab_process(struct process_entry *process);
|
||||
void release_process(struct process_entry *process);
|
||||
BOOL process_send_command(struct process_entry *process, const void *data, DWORD size, DWORD *result);
|
||||
BOOL process_send_control(struct process_entry *process, const WCHAR *name, DWORD control,
|
||||
const BYTE *data, DWORD data_size, DWORD *result);
|
||||
void process_terminate(struct process_entry *process);
|
||||
|
||||
extern DWORD service_pipe_timeout;
|
||||
|
|
Loading…
Reference in New Issue