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