advapi32/service.c; patch 6/7: Implemented RegisterServiceCtrlHandler,
ControlService
Alexander Yaworsky
yaworsky at migusoft.ru
Thu Nov 11 21:36:50 CST 2004
ChangeLog:
Implemented RegisterServiceCtrlHandler, ControlService.
diff -urN out1/dlls/advapi32/service.c out2/dlls/advapi32/service.c
--- out1/dlls/advapi32/service.c 2004-11-12 02:14:33.000000000 +0600
+++ out2/dlls/advapi32/service.c 2004-11-12 02:18:48.000000000 +0600
@@ -44,9 +44,13 @@
'D','I','S','P','_','%','s',0};
static const WCHAR szServiceMutexNameFmtW[] = {'A','D','V','A','P','I','_',
'M','U','X','_','%','s',0};
+static const WCHAR szServiceAckEventNameFmtW[] = {'A','D','V','A','P','I','_',
+ 'A','C','K','_','%','s',0};
struct SEB /* service environment block */
{ /* resides in service's shared memory object */
+ DWORD control_code; /* service control code */
+ DWORD dispatcher_error; /* set by dispatcher if it fails to invoke control handler */
SERVICE_STATUS status;
DWORD argc;
/* variable part of SEB contains service arguments */
@@ -332,6 +336,8 @@
struct SEB *seb;
HANDLE thread_handle;
HANDLE mutex; /* provides serialization of control request */
+ HANDLE ack_event; /* request handling completion acknowledgement */
+ LPHANDLER_FUNCTION ctrl_handler;
BOOL terminated;
};
@@ -353,6 +359,7 @@
static void dispose_service_thread_data( struct service_thread_data* thread_data )
{
if( thread_data->mutex ) CloseHandle( thread_data->mutex );
+ if( thread_data->ack_event ) CloseHandle( thread_data->ack_event );
if( thread_data->argv ) HeapFree( GetProcessHeap(), 0, thread_data->argv );
if( thread_data->seb ) UnmapViewOfFile( thread_data->seb );
if( thread_data->hServiceShmem ) CloseHandle( thread_data->hServiceShmem );
@@ -439,6 +446,18 @@
goto error;
}
+ /* create service event */
+ snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, thread_data->service_name );
+ thread_data->ack_event = CreateEventW( NULL, FALSE, FALSE, object_name );
+ if( NULL == thread_data->ack_event )
+ goto error;
+
+ if( ERROR_ALREADY_EXISTS == GetLastError() )
+ {
+ SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
+ goto error;
+ }
+
/* create service thread in suspended state
* to avoid race while caller handles return value */
thread_data->service_main = service_main;
@@ -471,6 +490,7 @@
/* create dispatcher event object */
/* FIXME: object name should be based on executable image path because
* this object is a dispatcher's entity; it is common for all services in the process */
+ /* But what if own and shared services have the same executable? */
snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, service->service_name );
dispatcher_event = CreateEventW( NULL, FALSE, FALSE, object_name );
if( NULL == dispatcher_event )
@@ -505,7 +525,19 @@
break;
}
- /* FIXME: look for control requests */
+ /* look for control requests */
+ if( service->seb->control_code )
+ {
+ if( NULL == service->ctrl_handler )
+ service->seb->dispatcher_error = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
+ else
+ {
+ service->ctrl_handler( service->seb->control_code );
+ service->seb->dispatcher_error = 0;
+ }
+ service->seb->control_code = 0;
+ SetEvent( service->ack_event );
+ }
/* FIXME: if shared service, check SCM lock object;
* if exists, a new service should be started */
@@ -604,8 +636,14 @@
SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
LPHANDLER_FUNCTION lpfHandler )
-{ FIXME("%s %p\n", lpServiceName, lpfHandler);
- return 0xcacacafe;
+{
+ UNICODE_STRING lpServiceNameW;
+ SERVICE_STATUS_HANDLE ret;
+
+ RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
+ ret = RegisterServiceCtrlHandlerW( lpServiceNameW.Buffer, lpfHandler );
+ RtlFreeUnicodeString(&lpServiceNameW);
+ return ret;
}
/******************************************************************************
@@ -618,8 +656,11 @@
SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
LPHANDLER_FUNCTION lpfHandler )
-{ FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
- return 0xcacacafe;
+{
+ /* FIXME: find service thread data by service name */
+
+ service->ctrl_handler = lpfHandler;
+ return 0xcacacafe;
}
/******************************************************************************
@@ -741,14 +782,94 @@
* RETURNS
* Success: TRUE.
* Failure: FALSE.
+ *
+ * BUGS
+ * Unlike M$' implementation, control requests are not seralized and may be
+ * processed asynchronously.
*/
BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
LPSERVICE_STATUS lpServiceStatus )
{
- FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
- return TRUE;
-}
+ struct sc_handle *hsvc = hService;
+ WCHAR object_name[ MAX_PATH ];
+ HANDLE mutex = NULL, shmem = NULL;
+ HANDLE disp_event = NULL, ack_event = NULL;
+ struct SEB *seb = NULL;
+ DWORD r;
+ BOOL ret = FALSE, mutex_owned = FALSE;
+
+ /* open and hold mutex */
+ snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->u.service.name );
+ mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
+ if( NULL == mutex )
+ {
+ SetLastError( ERROR_SERVICE_NOT_ACTIVE );
+ return FALSE;
+ }
+
+ r = WaitForSingleObject( mutex, 30000 );
+ if( WAIT_FAILED == r )
+ goto done;
+ if( WAIT_TIMEOUT == r )
+ {
+ SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
+ goto done;
+ }
+ mutex_owned = TRUE;
+
+ /* open event objects */
+ snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, hsvc->u.service.name );
+ disp_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
+ if( NULL == disp_event )
+ goto done;
+
+ snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, hsvc->u.service.name );
+ ack_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
+ if( NULL == ack_event )
+ goto done;
+
+ /* get service environment block */
+ seb = open_seb_shmem( hsvc->u.service.name, &shmem );
+ if( NULL == seb )
+ goto done;
+
+ /* send request */
+ /* FIXME: check dwControl against controls accepted */
+ seb->control_code = dwControl;
+ SetEvent( disp_event );
+
+ /* wait for acknowledgement */
+ r = WaitForSingleObject( ack_event, 30000 );
+ if( WAIT_FAILED == r )
+ goto done;
+
+ if( WAIT_TIMEOUT == r )
+ {
+ SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
+ goto done;
+ }
+
+ if( seb->dispatcher_error )
+ {
+ SetLastError( seb->dispatcher_error );
+ goto done;
+ }
+
+ /* get status */
+ if( lpServiceStatus )
+ memcpy( lpServiceStatus, &seb->status, sizeof(SERVICE_STATUS) );
+ ret = TRUE;
+
+done:
+ if( seb ) UnmapViewOfFile( seb );
+ if( shmem ) CloseHandle( shmem );
+ if( ack_event ) CloseHandle( ack_event );
+ if( disp_event ) CloseHandle( disp_event );
+ if( mutex_owned ) ReleaseMutex( mutex );
+ if( mutex ) CloseHandle( mutex );
+ return ret;
+}
/******************************************************************************
* CloseServiceHandle [ADVAPI32.@]
More information about the wine-patches
mailing list