advapi32: Do not terminate a regular program if it calls StartServiceCtrlDispatcher.

This commit is contained in:
Alexander Morozov 2013-04-01 22:43:33 +04:00 committed by Alexandre Julliard
parent 59c0c5fb2d
commit a792a5b486
1 changed files with 38 additions and 32 deletions

View File

@ -75,6 +75,12 @@ typedef struct service_data_t
WCHAR name[1]; WCHAR name[1];
} service_data; } service_data;
typedef struct dispatcher_data_t
{
SC_HANDLE manager;
HANDLE pipe;
} dispatcher_data;
static CRITICAL_SECTION service_cs; static CRITICAL_SECTION service_cs;
static CRITICAL_SECTION_DEBUG service_cs_debug = static CRITICAL_SECTION_DEBUG service_cs_debug =
{ {
@ -358,22 +364,7 @@ static DWORD service_handle_control(const service_data *service, DWORD dwControl
*/ */
static DWORD WINAPI service_control_dispatcher(LPVOID arg) static DWORD WINAPI service_control_dispatcher(LPVOID arg)
{ {
SC_HANDLE manager; dispatcher_data *disp = arg;
HANDLE pipe;
if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
{
ERR("failed to open service manager error %u\n", GetLastError());
return 0;
}
pipe = service_open_pipe();
if (pipe==INVALID_HANDLE_VALUE)
{
WARN("failed to create control pipe error = %d\n", GetLastError());
return 0;
}
/* dispatcher loop */ /* dispatcher loop */
while (1) while (1)
@ -384,7 +375,7 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg)
BOOL r; BOOL r;
DWORD data_size = 0, count, result; DWORD data_size = 0, count, result;
r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL ); r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
if (!r) if (!r)
{ {
if (GetLastError() != ERROR_BROKEN_PIPE) if (GetLastError() != ERROR_BROKEN_PIPE)
@ -400,7 +391,7 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg)
{ {
data_size = info.total_size - FIELD_OFFSET(service_start_info,data); data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
data = HeapAlloc( GetProcessHeap(), 0, data_size ); data = HeapAlloc( GetProcessHeap(), 0, data_size );
r = ReadFile( pipe, data, data_size, &count, NULL ); r = ReadFile( disp->pipe, data, data_size, &count, NULL );
if (!r) if (!r)
{ {
if (GetLastError() != ERROR_BROKEN_PIPE) if (GetLastError() != ERROR_BROKEN_PIPE)
@ -433,8 +424,9 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg)
case WINESERV_STARTINFO: case WINESERV_STARTINFO:
if (!service->handle) if (!service->handle)
{ {
if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )) || if (!(service->handle = OpenServiceW( disp->manager, data, SERVICE_SET_STATUS )) ||
!(service->full_access_handle = OpenServiceW( manager, data, GENERIC_READ|GENERIC_WRITE ))) !(service->full_access_handle = OpenServiceW( disp->manager, data,
GENERIC_READ|GENERIC_WRITE )))
FIXME( "failed to open service %s\n", debugstr_w(data) ); FIXME( "failed to open service %s\n", debugstr_w(data) );
} }
result = service_handle_start(service, data, data_size / sizeof(WCHAR)); result = service_handle_start(service, data, data_size / sizeof(WCHAR));
@ -449,12 +441,13 @@ static DWORD WINAPI service_control_dispatcher(LPVOID arg)
} }
done: done:
WriteFile(pipe, &result, sizeof(result), &count, NULL); WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
HeapFree( GetProcessHeap(), 0, data ); HeapFree( GetProcessHeap(), 0, data );
} }
CloseHandle(pipe); CloseHandle( disp->pipe );
CloseServiceHandle( manager ); CloseServiceHandle( disp->manager );
HeapFree( GetProcessHeap(), 0, disp );
return 1; return 1;
} }
@ -466,13 +459,32 @@ static BOOL service_run_main_thread(void)
DWORD i, n, ret; DWORD i, n, ret;
HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS]; HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
UINT wait_services[MAXIMUM_WAIT_OBJECTS]; UINT wait_services[MAXIMUM_WAIT_OBJECTS];
dispatcher_data *disp = HeapAlloc( GetProcessHeap(), 0, sizeof(*disp) );
disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
if (!disp->manager)
{
ERR("failed to open service manager error %u\n", GetLastError());
HeapFree( GetProcessHeap(), 0, disp );
return FALSE;
}
disp->pipe = service_open_pipe();
if (disp->pipe == INVALID_HANDLE_VALUE)
{
WARN("failed to create control pipe error %u\n", GetLastError());
CloseServiceHandle( disp->manager );
HeapFree( GetProcessHeap(), 0, disp );
SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
return FALSE;
}
service_event = CreateEventW( NULL, FALSE, FALSE, NULL ); service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
stop_event = CreateEventW( NULL, FALSE, FALSE, NULL ); stop_event = CreateEventW( NULL, FALSE, FALSE, NULL );
/* FIXME: service_control_dispatcher should be merged into the main thread */ /* FIXME: service_control_dispatcher should be merged into the main thread */
wait_handles[0] = __wine_make_process_system(); wait_handles[0] = __wine_make_process_system();
wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL ); wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
wait_handles[2] = service_event; wait_handles[2] = service_event;
wait_handles[3] = stop_event; wait_handles[3] = stop_event;
@ -563,7 +575,6 @@ BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
{ {
service_data *info; service_data *info;
unsigned int i; unsigned int i;
BOOL ret = TRUE;
TRACE("%p\n", servent); TRACE("%p\n", servent);
@ -592,9 +603,7 @@ BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
services[i] = info; services[i] = info;
} }
service_run_main_thread(); return service_run_main_thread();
return ret;
} }
/****************************************************************************** /******************************************************************************
@ -614,7 +623,6 @@ BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
{ {
service_data *info; service_data *info;
unsigned int i; unsigned int i;
BOOL ret = TRUE;
TRACE("%p\n", servent); TRACE("%p\n", servent);
@ -643,9 +651,7 @@ BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
services[i] = info; services[i] = info;
} }
service_run_main_thread(); return service_run_main_thread();
return ret;
} }
/****************************************************************************** /******************************************************************************