advapi32/service.c; patch 6/7: Implemented
RegisterServiceCtrlHandler, ControlService
Alexander Yaworsky
yaworsky at migusoft.ru
Tue Dec 7 00:25:01 CST 2004
ChangeLog:
Implemented RegisterServiceCtrlHandler, ControlService.
Index: dlls/advapi32/service.c
===================================================================
RCS file: /home/wine/wine/dlls/advapi32/service.c,v
retrieving revision 1.71
diff -u -r1.71 service.c
--- dlls/advapi32/service.c 6 Dec 2004 16:17:08 -0000 1.71
+++ dlls/advapi32/service.c 7 Dec 2004 07:17:11 -0000
@@ -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 */
@@ -329,6 +333,8 @@
struct SEB *seb;
HANDLE thread_handle;
HANDLE mutex; /* provides serialization of control request */
+ HANDLE ack_event; /* control handler completion acknowledgement */
+ LPHANDLER_FUNCTION ctrl_handler;
};
static DWORD WINAPI service_thread( LPVOID arg )
@@ -348,6 +354,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 );
@@ -434,6 +441,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;
@@ -466,6 +485,7 @@
/* create dispatcher event object */
/* FIXME: object_name should be based on executable image path because
* this object 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 )
@@ -502,7 +522,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 */
@@ -601,8 +633,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;
}
/******************************************************************************
@@ -615,8 +653,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;
}
/******************************************************************************
@@ -738,14 +779,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