resend: advapi32 service functions
Alexander Yaworsky
yaworsky at migusoft.ru
Sat Jun 19 02:48:59 CDT 2004
Hello
my apologize for incorrect prev. post
ChangeLog:
Improved functionality of service functions.
Index: dlls/advapi32/service.c
===================================================================
RCS file: /home/wine/wine/dlls/advapi32/service.c,v
retrieving revision 1.45
diff -u -r1.45 service.c
--- dlls/advapi32/service.c 23 Apr 2004 21:32:34 -0000 1.45
+++ dlls/advapi32/service.c 19 Jun 2004 07:21:29 -0000
@@ -34,16 +34,130 @@
WINE_DEFAULT_DEBUG_CHANNEL(advapi);
-static DWORD start_dwNumServiceArgs;
-static LPWSTR *start_lpServiceArgVectors;
+#define LOCK_OBJECT_SIZE 256 * sizeof(WCHAR) /* max service name length */
+
+/* structure of shared memory of service */
+typedef struct
+{
+ DWORD code; /* request code on enter and reply error code on exit */
+ SERVICE_STATUS status;
+ DWORD argc;
+ WCHAR argdata[4000];
+} SERVICE_SHMEM;
-static const WCHAR _ServiceStartDataW[] = {'A','D','V','A','P','I','_','S',
- 'e','r','v','i','c','e','S','t',
- 'a','r','t','D','a','t','a',0};
static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
'S','e','r','v','i','c','e','s','\\',0 };
+static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
+ 'L','O','C','K',0};
+static const WCHAR szWaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
+ 'a','i','t','S','e','r','v','i',
+ 'c','e','S','t','a','r','t',0};
+/* shared object names */
+static const WCHAR szServiceObjectNameFmtW[] = {'A','D','V','A','P','I','_',
+ '%','s','_','%','s',0};
+static const WCHAR szShMemNameW[] = {'S','H','M','E','M',0};
+static const WCHAR szMutexNameW[] = {'M','U','X',0};
+static const WCHAR szRequestEventNameW[] = {'R','E','Q','E','V','T',0};
+static const WCHAR szReplyEventNameW[] = {'R','E','P','L','Y','E','V','T',0};
+
+/******************************************************************************
+ * SC_HANDLEs
+ * they just keep service name
+ */
+
+typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
+struct sc_handle;
+
+struct sc_manager
+{
+ /* paranoidal error handling for insane applications:
+ * if SCM handle has been closed before any related service handle,
+ * leave SCM handle alive
+ */
+ LONG ref_count;
+};
+
+struct sc_service
+{
+ struct sc_handle *sc_manager;
+ WCHAR service_name[256];
+};
+
+struct sc_handle
+{
+ SC_HANDLE_TYPE htype;
+ HKEY hKey;
+ union
+ {
+ struct sc_manager manager;
+ struct sc_service service;
+ } hdata;
+};
+
+static
+struct sc_handle*
+alloc_sc_handle( SC_HANDLE_TYPE htype, LPCWSTR lpServiceName )
+{
+ struct sc_handle *retval;
+
+ retval = HeapAlloc( GetProcessHeap(), 0, sizeof(struct sc_handle) );
+ if( retval != NULL )
+ {
+ retval->htype = htype;
+ retval->hKey = NULL;
+ if( SC_HTYPE_SERVICE == htype )
+ {
+ strncpyW( retval->hdata.service.service_name, lpServiceName, 256 );
+ retval->hdata.service.service_name[ 255 ] = 0;
+ }
+ }
+ return retval;
+}
+
+static
+void
+free_sc_handle( struct sc_handle* handle )
+{
+ if( SC_HTYPE_MANAGER == handle->htype )
+ {
+ if( 0 != InterlockedDecrement( &handle->hdata.manager.ref_count ) )
+ /* let it be */
+ return;
+ }
+ if( SC_HTYPE_SERVICE == handle->htype )
+ {
+ struct sc_handle *h = handle->hdata.service.sc_manager;
+ if( 0 == InterlockedDecrement( &h->hdata.manager.ref_count ) )
+ {
+ /* it's time to really close SCM handle */
+ if( h->hKey != NULL )
+ RegCloseKey( h->hKey );
+ HeapFree( GetProcessHeap(), 0, h );
+ }
+ }
+ if( handle->hKey != NULL )
+ RegCloseKey( handle->hKey );
+ HeapFree( GetProcessHeap(), 0, handle );
+}
+
+static
+void
+init_sc_manager( struct sc_handle* handle, HKEY hKey )
+{
+ handle->hKey = hKey;
+ handle->hdata.manager.ref_count = 1;
+}
+
+static
+void
+init_sc_service( struct sc_handle* handle, HKEY hKey, struct sc_handle* sc_manager )
+{
+ handle->hKey = hKey;
+ InterlockedIncrement( &sc_manager->hdata.manager.ref_count );
+ handle->hdata.service.sc_manager = sc_manager;
+}
/******************************************************************************
* EnumServicesStatusA [ADVAPI32.@]
@@ -76,62 +190,277 @@
}
/******************************************************************************
- * StartServiceCtrlDispatcherA [ADVAPI32.@]
+ * service thread params; service_thread_func for StartServiceCtrlDispatcher
*/
-BOOL WINAPI
-StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
+
+typedef struct
{
- LPSERVICE_MAIN_FUNCTIONA fpMain;
- HANDLE wait;
- DWORD dwNumServiceArgs ;
- LPWSTR *lpArgVecW;
- LPSTR *lpArgVecA;
- int i;
+ WCHAR service_name[ 256 ];
+ HANDLE shmem, mutex, request_event, reply_event;
+ SERVICE_SHMEM *shmem_ptr;
+ LPSERVICE_MAIN_FUNCTIONW func;
+ LPHANDLER_FUNCTION handler;
+ LONG terminated;
+ LPWSTR argv[ 64 ]; /* FIXME: use dynamic allocation */
+ CHAR argv0_a[ 256 ];
+} SERVICE_THREAD_PARAMS;
+
+/* FIXME: use service thread list for SERVICE_WIN32_SHARE_PROCESS
+ * instead of single global variable?
+ */
+static SERVICE_THREAD_PARAMS *service_thread_params;
+
+static DWORD WINAPI
+service_thread_func( LPVOID arg )
+{
+ SERVICE_THREAD_PARAMS *params = arg;
+
+ params->func( params->shmem_ptr->argc, params->argv );
+
+ /* signal to request handler in StartServiceCtrlDispatcher */
+ params->terminated = 1;
+ SetEvent( params->request_event );
+
+ return 0;
+}
+
+/******************************************************************************
+ * _StartServiceCtrlDispatcher
+ */
+static BOOL WINAPI
+do_StartServiceCtrlDispatcher( LPSERVICE_TABLE_ENTRYW servent, int unicode )
+{
+ SERVICE_THREAD_PARAMS *params;
+ WCHAR object_name[ MAX_PATH ];
+ LPWSTR argptr;
+ HANDLE ss_wait;
+ LPSERVICE_MAIN_FUNCTIONW fpMain;
+ HANDLE service_thread;
+ DWORD lasterr, i;
+ BOOL ret = FALSE;
TRACE("(%p)\n", servent);
- wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
- if(wait == 0)
+
+ params = HeapAlloc( GetProcessHeap(),
+ HEAP_ZERO_MEMORY, sizeof(SERVICE_THREAD_PARAMS) );
+ if( NULL == params )
+ return FALSE;
+
+ /* open locking shared memory object and read service name */
+ params->shmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
+ if( NULL == params->shmem )
{
- ERR("Couldn't find wait semaphore\n");
- ERR("perhaps you need to start services using StartService\n");
- return FALSE;
+ lasterr = ERROR_FAILED_SERVICE_CONTROLLER_CONNECT;
+ goto done;
+ }
+ argptr = MapViewOfFile( params->shmem, FILE_MAP_ALL_ACCESS,
+ 0, 0, LOCK_OBJECT_SIZE );
+ if( NULL == argptr )
+ {
+ lasterr = GetLastError();
+ goto done;
}
+ strcpyW( params->service_name, argptr );
+ UnmapViewOfFile( argptr );
+ CloseHandle( params->shmem );
+ params->shmem = NULL;
- dwNumServiceArgs = start_dwNumServiceArgs;
- lpArgVecW = start_lpServiceArgVectors;
+ /* create events and mutex; mutex is initially owned */
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szRequestEventNameW, params->service_name );
+ params->request_event = CreateEventW( NULL, FALSE, FALSE, object_name );
+ if( NULL == params->request_event )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ if( ERROR_ALREADY_EXISTS == GetLastError() )
+ {
+ lasterr = ERROR_SERVICE_ALREADY_RUNNING;
+ goto done;
+ }
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szReplyEventNameW, params->service_name );
+ params->reply_event = CreateEventW( NULL, FALSE, FALSE, object_name );
+ if( NULL == params->reply_event )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szMutexNameW, params->service_name );
+ params->mutex = CreateMutexW( NULL, TRUE, object_name );
+ if( NULL == params->mutex )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
- ReleaseSemaphore(wait, 1, NULL);
+ /* open service shared memory */
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szShMemNameW, params->service_name );
+ params->shmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
+ if( NULL == params->shmem )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ params->shmem_ptr = MapViewOfFile( params->shmem, FILE_MAP_ALL_ACCESS,
+ 0, 0, sizeof(SERVICE_SHMEM) );
+ if( NULL == params->shmem_ptr )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
- /* Convert the Unicode arg vectors back to ASCII */
- if(dwNumServiceArgs)
- lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
- dwNumServiceArgs*sizeof(LPSTR) );
+ /* init argvectors */
+ if( unicode )
+ {
+ LPWSTR argptr = ¶ms->shmem_ptr->argdata[0];
+ for( i = 1; i <= params->shmem_ptr->argc; i++ )
+ {
+ if( i == sizeof(params->argv) / sizeof(params->argv[0]) - 1 )
+ {
+ /* FIXME: use dynamic allocation */
+ params->shmem_ptr->argc = i;
+ break;
+ }
+ params->argv[ i ] = argptr;
+ argptr += strlenW( argptr ) + 1;
+ }
+ params->argv[ 0 ] = ¶ms->service_name[0];
+ params->argv[ i ] = NULL;
+ }
else
- lpArgVecA = NULL;
+ {
+ LPSTR argptr = (LPSTR) ¶ms->shmem_ptr->argdata[0];
+ LPSTR buf;
- for(i=0; i<dwNumServiceArgs; i++)
- lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
+ buf = HeapAlloc( GetProcessHeap(), 0,
+ sizeof(params->shmem_ptr->argdata) );
+ if( NULL == buf )
+ {
+ params->shmem_ptr->argc = 0;
+ i = 1;
+ }
+ else
+ {
+ DWORD n = sizeof(params->shmem_ptr->argdata);
+ LPWSTR src = params->shmem_ptr->argdata;
+ LPSTR dest = buf;
+ for( i = 0; i < params->shmem_ptr->argc; i++ )
+ {
+ DWORD len = strlenW( src ) + 1;
+ WideCharToMultiByte( CP_ACP, 0, src, -1, dest, n, NULL, NULL );
+ src += len;
+ n -= len;
+ dest += strlen( dest ) + 1;
+ }
+ memcpy( params->shmem_ptr->argdata, buf,
+ sizeof(params->shmem_ptr->argdata) );
+ HeapFree( GetProcessHeap(), 0, buf );
+ for( i = 1; i <= params->shmem_ptr->argc; i++ )
+ {
+ if( i == sizeof(params->argv) / sizeof(params->argv[0]) - 1 )
+ {
+ /* FIXME: use dynamic allocation */
+ params->shmem_ptr->argc = i;
+ break;
+ }
+ params->argv[ i ] = (LPWSTR) argptr;
+ argptr += strlen( argptr ) + 1;
+ }
+ }
+ WideCharToMultiByte( CP_ACP, 0, params->service_name, -1,
+ params->argv0_a, 256, NULL, NULL );
+ params->argv[ 0 ] = (LPWSTR) ¶ms->argv0_a[0];
+ params->argv[ i ] = NULL;
+ TRACE("argc=%d argv[0]=%s\n", (int) params->shmem_ptr->argc, (LPSTR) params->argv[0]);
+ }
+ params->shmem_ptr->argc++;
+
+ /* init status according to docs for StartService */
+ params->shmem_ptr->status.dwCurrentState = SERVICE_START_PENDING;
+ params->shmem_ptr->status.dwControlsAccepted = 0;
+ params->shmem_ptr->status.dwCheckPoint = 0;
+ params->shmem_ptr->status.dwWaitHint = 2000;
- /* FIXME: should we blindly start all services? */
- while (servent->lpServiceName) {
- TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
- fpMain = servent->lpServiceProc;
+ /* try to start the service */
- /* try to start the service */
- fpMain( dwNumServiceArgs, lpArgVecA);
+ /* FIXME: find entry by name for SERVICE_WIN32_SHARE_PROCESS */
+ fpMain = servent->lpServiceProc;
- servent++;
+ params->func = fpMain;
+ params->handler = NULL;
+ params->terminated = 0;
+ service_thread = CreateThread( NULL, 0, service_thread_func, params, 0, &i );
+ if( NULL == service_thread )
+ {
+ lasterr = GetLastError();
+ goto done;
}
- if(dwNumServiceArgs)
+ /* signal event for StartService */
+ ss_wait = OpenEventW( EVENT_ALL_ACCESS, FALSE, szWaitServiceStartW );
+ if( NULL != ss_wait )
{
- /* free arg strings */
- for(i=0; i<dwNumServiceArgs; i++)
- HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
- HeapFree(GetProcessHeap(), 0, lpArgVecA);
+ SetEvent( ss_wait );
+ CloseHandle( ss_wait );
}
- return TRUE;
+ /* ready to accept requests */
+ ReleaseMutex( params->mutex );
+
+ /* FIXME: multiple service threads in SERVICE_WIN32_SHARE_PROCESS */
+ service_thread_params = params;
+ for(;;)
+ {
+ WaitForSingleObject( params->request_event, INFINITE );
+
+ if( params->terminated )
+ {
+ break;
+ }
+
+ if( NULL == params->handler )
+ {
+ params->shmem_ptr->code = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
+ }
+ else
+ {
+ params->handler( params->shmem_ptr->code );
+ params->shmem_ptr->code = 0;
+ }
+
+ SetEvent( params->reply_event );
+ }
+
+ CloseHandle( service_thread );
+ lasterr = 0;
+ ret = TRUE;
+
+ /* close mutex first to make it abandoned for status requests
+ * that may occur in parallel
+ */
+done:
+ if( params->mutex != NULL ) CloseHandle( params->mutex );
+ if( params->shmem_ptr != NULL ) UnmapViewOfFile( params->shmem_ptr );
+ if( params->shmem != NULL ) CloseHandle( params->shmem );
+ if( params->reply_event != NULL ) CloseHandle( params->reply_event );
+ if( params->request_event != NULL ) CloseHandle( params->request_event );
+ HeapFree( GetProcessHeap(), 0, params );
+ SetLastError( lasterr );
+ return ret;
+}
+
+/******************************************************************************
+ * StartServiceCtrlDispatcherA [ADVAPI32.@]
+ */
+BOOL WINAPI
+StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
+{
+ return do_StartServiceCtrlDispatcher( (LPSERVICE_TABLE_ENTRYW) servent,
+ 0 /* not unicode */ );
}
/******************************************************************************
@@ -143,37 +472,7 @@
BOOL WINAPI
StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
{
- LPSERVICE_MAIN_FUNCTIONW fpMain;
- HANDLE wait;
- DWORD dwNumServiceArgs ;
- LPWSTR *lpServiceArgVectors ;
-
- TRACE("(%p)\n", servent);
- wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
- if(wait == 0)
- {
- ERR("Couldn't find wait semaphore\n");
- ERR("perhaps you need to start services using StartService\n");
- return FALSE;
- }
-
- dwNumServiceArgs = start_dwNumServiceArgs;
- lpServiceArgVectors = start_lpServiceArgVectors;
-
- ReleaseSemaphore(wait, 1, NULL);
-
- /* FIXME: should we blindly start all services? */
- while (servent->lpServiceName) {
- TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
- fpMain = servent->lpServiceProc;
-
- /* try to start the service */
- fpMain( dwNumServiceArgs, lpServiceArgVectors);
-
- servent++;
- }
-
- return TRUE;
+ return do_StartServiceCtrlDispatcher( servent, 1 /* unicode */ );
}
/******************************************************************************
@@ -181,8 +480,29 @@
*/
LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
{
- FIXME("%p\n",hSCManager);
- return (SC_HANDLE)0xcacacafe;
+ HANDLE hLock;
+
+ TRACE("%p\n",hSCManager);
+
+ /* FIXME: what to do with hSCManager?
+ * local SCM is always assumed here
+ */
+ hLock = CreateFileMappingW( INVALID_HANDLE_VALUE,
+ NULL,
+ PAGE_READWRITE,
+ 0, LOCK_OBJECT_SIZE,
+ szSCMLock );
+ if( hLock != NULL
+ && GetLastError() == ERROR_ALREADY_EXISTS )
+ {
+ CloseHandle( hLock );
+ hLock = NULL;
+ SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
+ }
+
+ TRACE("returning %p\n", hLock);
+
+ return hLock;
}
/******************************************************************************
@@ -190,8 +510,9 @@
*/
BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
{
- FIXME(": %p\n",ScLock);
- return TRUE;
+ TRACE("%p\n",ScLock);
+
+ return CloseHandle( (HANDLE) ScLock );
}
/******************************************************************************
@@ -200,8 +521,14 @@
SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
LPHANDLER_FUNCTION lpfHandler )
-{ FIXME("%s %p\n", lpServiceName, lpfHandler);
- return 0xcacacafe;
+{
+ SERVICE_STATUS_HANDLE ret;
+ UNICODE_STRING lpServiceNameW;
+
+ RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
+ ret = RegisterServiceCtrlHandlerW( lpServiceNameW.Buffer, lpfHandler );
+ RtlFreeUnicodeString(&lpServiceNameW);
+ return ret;
}
/******************************************************************************
@@ -214,8 +541,14 @@
SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
LPHANDLER_FUNCTION lpfHandler )
-{ FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
- return 0xcacacafe;
+{
+ TRACE("%s, %p\n",debugstr_w(lpServiceName),lpfHandler);
+
+ /* FIXME: find service thread by service name
+ * (implement SERVICE_WIN32_SHARE_PROCESS)
+ */
+ service_thread_params->handler = lpfHandler;
+ return 0xcacacafe;
}
/******************************************************************************
@@ -226,16 +559,32 @@
* lpStatus []
*/
BOOL WINAPI
-SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
-{ FIXME("0x%lx %p\n",hService, lpStatus);
- TRACE("\tType:%lx\n",lpStatus->dwServiceType);
- TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
- TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
- TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
- TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
- TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
- TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
- return TRUE;
+SetServiceStatus( SERVICE_STATUS_HANDLE hStatus, LPSERVICE_STATUS lpStatus )
+{
+ DWORD r;
+
+ TRACE("\tType:%lx\n",lpStatus->dwServiceType);
+ TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
+ TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
+ TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
+ TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
+ TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
+ TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
+
+ /* FIXME: find service thread data by status handle
+ * (implement SERVICE_WIN32_SHARE_PROCESS)
+ */
+
+ /* acquire mutex; note that mutex may already be owned
+ * when service handles control request
+ */
+ r = WaitForSingleObject( service_thread_params->mutex, 0 );
+ memcpy( &service_thread_params->shmem_ptr->status,
+ lpStatus, sizeof(SERVICE_STATUS) );
+ if( WAIT_OBJECT_0 == r || WAIT_ABANDONED == r )
+ ReleaseMutex( service_thread_params->mutex );
+
+ return TRUE;
}
/******************************************************************************
@@ -275,6 +624,7 @@
SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
DWORD dwDesiredAccess )
{
+ struct sc_handle *retval;
HKEY hReg, hKey = NULL;
LONG r;
@@ -287,16 +637,22 @@
* docs, but what if it isn't?
*/
+ retval = alloc_sc_handle( SC_HTYPE_MANAGER, NULL );
+ if( NULL == retval )
+ return NULL;
+
r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
if (r==ERROR_SUCCESS)
{
- r = RegOpenKeyExW(hReg, szServiceManagerKey,0, dwDesiredAccess, &hKey );
+ r = RegOpenKeyExW(hReg, szServiceManagerKey,0, KEY_ALL_ACCESS, &hKey );
RegCloseKey( hReg );
}
+
+ init_sc_manager( retval, hKey );
- TRACE("returning %p\n", hKey);
+ TRACE("returning %p\n", retval);
- return hKey;
+ return (SC_HANDLE) retval;
}
@@ -332,8 +688,112 @@
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 shmem = NULL, mutex = NULL;
+ HANDLE request_event = NULL, reply_event = NULL;
+ SERVICE_SHMEM *shmem_ptr = NULL;
+ DWORD lasterr, r;
+ BOOL ret = FALSE, mutex_acquired = FALSE;
+
+ /* open and acquire mutex */
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szMutexNameW, hsvc->hdata.service.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 )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ if( WAIT_TIMEOUT == r )
+ {
+ lasterr = ERROR_SERVICE_REQUEST_TIMEOUT;
+ goto done;
+ }
+ if( WAIT_ABANDONED == r )
+ {
+ lasterr = ERROR_SERVICE_NOT_ACTIVE;
+ goto done;
+ }
+ mutex_acquired = TRUE;
+
+ /* open events and shared memory */
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szRequestEventNameW, hsvc->hdata.service.service_name );
+ request_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
+ if( NULL == request_event )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szReplyEventNameW, hsvc->hdata.service.service_name );
+ reply_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
+ if( NULL == reply_event )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szShMemNameW, hsvc->hdata.service.service_name );
+ shmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
+ if( NULL == shmem )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ shmem_ptr = MapViewOfFile( shmem, FILE_MAP_ALL_ACCESS,
+ 0, 0, sizeof(SERVICE_SHMEM) );
+ if( NULL == shmem_ptr )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+
+ /* send request */
+ /* FIXME: check dwControl against controls accepted */
+ shmem_ptr->code = dwControl;
+ SetEvent( request_event );
+
+ /* wait for reply */
+ r = WaitForSingleObject( reply_event, 30000 );
+ if( WAIT_FAILED == r )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ if( WAIT_TIMEOUT == r )
+ {
+ lasterr = ERROR_SERVICE_REQUEST_TIMEOUT;
+ goto done;
+ }
+
+ if( shmem_ptr->code != 0 )
+ {
+ lasterr = shmem_ptr->code;
+ goto done;
+ }
+
+ /* allright */
+ memcpy( lpServiceStatus, &shmem_ptr->status, sizeof(SERVICE_STATUS) );
+ ret = TRUE;
+ lasterr = 0;
+
+done:
+ if( shmem_ptr != NULL ) UnmapViewOfFile( shmem_ptr );
+ if( shmem != NULL ) CloseHandle( shmem );
+ if( reply_event != NULL ) CloseHandle( reply_event );
+ if( request_event != NULL ) CloseHandle( request_event );
+ if( mutex_acquired ) ReleaseMutex( mutex );
+ if( mutex != NULL ) CloseHandle( mutex );
+ SetLastError( lasterr );
+ return ret;
}
@@ -349,12 +809,13 @@
* Success: TRUE
* Failure: FALSE
*/
+
BOOL WINAPI
CloseServiceHandle( SC_HANDLE hSCObject )
{
TRACE("(%p)\n", hSCObject);
- RegCloseKey(hSCObject);
+ free_sc_handle( (struct sc_handle*) hSCObject );
return TRUE;
}
@@ -389,7 +850,6 @@
return ret;
}
-
/******************************************************************************
* OpenServiceW [ADVAPI32.@]
*
@@ -398,19 +858,30 @@
SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
DWORD dwDesiredAccess)
{
+ struct sc_handle *hscm = hSCManager;
+ struct sc_handle *retval;
HKEY hKey;
long r;
TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
dwDesiredAccess);
- r = RegOpenKeyExW(hSCManager, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
+ retval = alloc_sc_handle( SC_HTYPE_SERVICE, lpServiceName );
+ if( NULL == retval )
+ return NULL;
+
+ r = RegOpenKeyExW( hscm->hKey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
if (r!=ERROR_SUCCESS)
- return 0;
+ {
+ free_sc_handle( retval );
+ return NULL;
+ }
+
+ init_sc_service( retval, hKey, hscm );
- TRACE("returning %p\n",hKey);
+ TRACE("returning %p\n",retval);
- return hKey;
+ return (SC_HANDLE) retval;
}
/******************************************************************************
@@ -425,6 +896,8 @@
LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
LPCWSTR lpPassword )
{
+ struct sc_handle *hscm = hSCManager;
+ struct sc_handle *retval;
HKEY hKey;
LONG r;
DWORD dp;
@@ -439,41 +912,47 @@
FIXME("%p %s %s\n", hSCManager,
debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
- r = RegCreateKeyExW(hSCManager, lpServiceName, 0, NULL,
+ retval = alloc_sc_handle( SC_HTYPE_SERVICE, lpServiceName );
+ if( NULL == retval )
+ return NULL;
+
+ r = RegCreateKeyExW(hscm->hKey, lpServiceName, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
if (r!=ERROR_SUCCESS)
- return 0;
+ goto failure;
if (dp != REG_CREATED_NEW_KEY)
- return 0;
+ goto failure;
+
+ init_sc_service( retval, hKey, hscm );
if(lpDisplayName)
{
r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
(strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
if (r!=ERROR_SUCCESS)
- return 0;
+ goto failure;
}
r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
if (r!=ERROR_SUCCESS)
- return 0;
+ goto failure;
r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
if (r!=ERROR_SUCCESS)
- return 0;
+ goto failure;
r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
(LPVOID)&dwErrorControl, sizeof (DWORD) );
if (r!=ERROR_SUCCESS)
- return 0;
+ goto failure;
if(lpBinaryPathName)
{
r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
(strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
if (r!=ERROR_SUCCESS)
- return 0;
+ goto failure;
}
if(lpLoadOrderGroup)
@@ -481,7 +960,7 @@
r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
(strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
if (r!=ERROR_SUCCESS)
- return 0;
+ goto failure;
}
if(lpDependencies)
@@ -496,7 +975,7 @@
r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
(LPBYTE)lpDependencies, len );
if (r!=ERROR_SUCCESS)
- return 0;
+ goto failure;
}
if(lpPassword)
@@ -509,7 +988,11 @@
FIXME("Don't know how to add a ServiceStartName for a service.\n");
}
- return hKey;
+ return (SC_HANDLE) retval;
+
+failure:
+ free_sc_handle( retval );
+ return NULL;
}
@@ -608,63 +1091,31 @@
*/
BOOL WINAPI DeleteService( SC_HANDLE hService )
{
+ struct sc_handle *hsvc = hService;
WCHAR valname[MAX_PATH+1];
INT index = 0;
LONG rc;
- DWORD value = 0x1;
DWORD size;
- HKEY hKey;
-
- static const WCHAR szDeleted[] = {'D','e','l','e','t','e','d',0};
FIXME("(%p): stub\n",hService);
size = MAX_PATH+1;
/* Clean out the values */
- rc = RegEnumValueW(hService, index, valname,&size,0,0,0,0);
+ rc = RegEnumValueW(hsvc->hKey, index, valname,&size,0,0,0,0);
while (rc == ERROR_SUCCESS)
{
- RegDeleteValueW(hService,valname);
+ RegDeleteValueW(hsvc->hKey,valname);
index++;
size = MAX_PATH+1;
- rc = RegEnumValueW(hService, index, valname, &size,0,0,0,0);
+ rc = RegEnumValueW(hsvc->hKey, index, valname, &size,0,0,0,0);
}
- /* tag for deletion */
- RegSetValueExW(hService, szDeleted, 0, REG_DWORD, (LPVOID)&value,
- sizeof (DWORD) );
+ RegCloseKey(hsvc->hKey);
+ hsvc->hKey = NULL;
- RegCloseKey(hService);
-
- /* find and delete the key */
- rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, szServiceManagerKey,0,
- KEY_ALL_ACCESS, &hKey );
- index = 0;
- size = MAX_PATH+1;
- rc = RegEnumKeyExW(hKey,0, valname, &size, 0, 0, 0, 0);
- while (rc == ERROR_SUCCESS)
- {
- HKEY checking;
- rc = RegOpenKeyExW(hKey,valname,0,KEY_ALL_ACCESS,&checking);
- if (rc == ERROR_SUCCESS)
- {
- DWORD deleted = 0;
- DWORD size = sizeof(DWORD);
- rc = RegQueryValueExW(checking, szDeleted , NULL, NULL,
- (LPVOID)&deleted, &size);
- if (deleted)
- {
- RegDeleteValueW(checking,szDeleted);
- RegDeleteKeyW(hKey,valname);
- }
- else
- index ++;
- RegCloseKey(checking);
- }
- size = MAX_PATH+1;
- rc = RegEnumKeyExW(hKey, index, valname, &size, 0, 0, 0, 0);
- }
- RegCloseKey(hKey);
+ /* delete the key */
+ RegDeleteKeyW(hsvc->hdata.service.sc_manager->hKey,
+ hsvc->hdata.service.service_name);
return TRUE;
}
@@ -684,8 +1135,6 @@
* - NT implements this function using an obscure RPC call.
* - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
* to get things like "%SystemRoot%\\System32\\service.exe" to load.
- * - This will only work for shared address space. How should the service
- * args be transferred when address spaces are separated?
* - Can only start one service at a time.
* - Has no concept of privilege.
*
@@ -737,63 +1186,145 @@
StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
LPCWSTR *lpServiceArgVectors )
{
- static const WCHAR _WaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
- 'a','i','t','S','e','r','v','i',
- 'c','e','S','t','a','r','t',0};
static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
-
+ static const WCHAR _TypeW[] = {'T','y','p','e',0};
+
+ struct sc_handle *hsvc = hService;
WCHAR path[MAX_PATH],str[MAX_PATH];
- DWORD type,size;
+ HANDLE hLock, wait;
+ LPWSTR shmem_lock = NULL;
+ LPWSTR argptr, endptr;
+ HANDLE hSvcMem = NULL;
+ SERVICE_SHMEM *shmem_service = NULL;
+ DWORD ServiceType, type, size, lasterr, i;
long r;
- HANDLE data,wait;
PROCESS_INFORMATION procinfo;
STARTUPINFOW startupinfo;
+ BOOL ret = FALSE;
+
TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
lpServiceArgVectors);
size = sizeof(str);
- r = RegQueryValueExW(hService, _ImagePathW, NULL, &type, (LPVOID)str, &size);
+ r = RegQueryValueExW(hsvc->hKey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
if (r!=ERROR_SUCCESS)
return FALSE;
ExpandEnvironmentStringsW(str,path,sizeof(path));
- TRACE("Starting service %s\n", debugstr_w(path) );
-
- data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
- if (!data)
+ size = sizeof(DWORD);
+ r = RegQueryValueExW(hsvc->hKey, _TypeW,
+ NULL, &type, (LPVOID) &ServiceType, &size);
+ if (r!=ERROR_SUCCESS || type != REG_DWORD)
{
- ERR("Couldn't create data semaphore\n");
+ ERR("Couldn't read service type; r=%ld, type=%lu\n", r, type);
return FALSE;
}
- wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
- if (!wait)
+
+ /* FIXME: what about interactive services? */
+
+ ServiceType &= ~SERVICE_INTERACTIVE_PROCESS;
+
+ if( SERVICE_WIN32_OWN_PROCESS != ServiceType
+ && SERVICE_WIN32_SHARE_PROCESS != ServiceType )
{
- ERR("Couldn't create wait semaphore\n");
+ ERR("Invalid service type %lu\n",ServiceType);
+ /* FIXME: what error code should be here? */
+ SetLastError(ERROR_ACCESS_DENIED);
return FALSE;
}
+ /* lock service database and get pointer to shared memory */
+ hLock = LockServiceDatabase( hsvc->hdata.service.sc_manager );
+ if( NULL == hLock )
+ return FALSE;
+
/*
- * FIXME: lpServiceArgsVectors need to be stored and returned to
- * the service when it calls StartServiceCtrlDispatcher
- *
- * Chuck these in a global (yuk) so we can pass them to
- * another process - address space separation will break this.
+ * FIXME: start dependent services
*/
- r = WaitForSingleObject(data,INFINITE);
+ shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
+ 0, 0, LOCK_OBJECT_SIZE );
+ if( NULL == shmem_lock )
+ {
+ ERR("Couldn't map shared memory\n");
+ lasterr = GetLastError();
+ goto done;
+ }
+
+ /* set argv[0] (service name) for service thread */
+ strcpyW( shmem_lock, hsvc->hdata.service.service_name );
+
+ /* create dedicated shared memory object for service */
+ snprintfW( str, MAX_PATH, szServiceObjectNameFmtW,
+ szShMemNameW, shmem_lock );
+ hSvcMem = CreateFileMappingW( INVALID_HANDLE_VALUE,
+ NULL,
+ PAGE_READWRITE,
+ 0, sizeof(SERVICE_SHMEM),
+ str );
+ if( NULL == hSvcMem )
+ {
+ ERR("Couldn't create shared memory object\n");
+ lasterr = GetLastError();
+ goto done;
+ }
+ if( GetLastError() == ERROR_ALREADY_EXISTS )
+ {
+ lasterr = ERROR_SERVICE_ALREADY_RUNNING;
+ goto done;
+ }
+ shmem_service = MapViewOfFile( hSvcMem, FILE_MAP_ALL_ACCESS,
+ 0, 0, sizeof(SERVICE_SHMEM) );
+ if( NULL == shmem_service )
+ {
+ ERR("Couldn't map shared memory\n");
+ lasterr = GetLastError();
+ goto done;
+ }
+
+ /* copy service args */
+ shmem_service->argc = dwNumServiceArgs;
+ argptr = &shmem_service->argdata[0];
+ endptr = argptr + sizeof(shmem_service->argdata)
+ / sizeof(shmem_service->argdata[0]);
+ for( i = 0; i < dwNumServiceArgs; i++ )
+ {
+ int len = strlenW( argptr ) + 1;
+ if( argptr + len >= endptr )
+ {
+ /* FIXME: use dynamic allocation */
+ shmem_service->argc = i;
+ break;
+ }
+ strcpyW( argptr, lpServiceArgVectors[ i ] );
+ argptr += len;
+ }
- if( r == WAIT_FAILED)
- return FALSE;
+ if( SERVICE_WIN32_SHARE_PROCESS == ServiceType )
+ {
+ /*
+ * FIXME: implement SERVICE_WIN32_SHARE_PROCESS startup.
+ * We need CreateRemoteThread for this.
+ */
+ FIXME(": SERVICE_WIN32_SHARE_PROCESS\n");
+ lasterr = ERROR_ACCESS_DENIED;
+ goto done;
+ }
- FIXME("problematic because of address space separation.\n");
- start_dwNumServiceArgs = dwNumServiceArgs;
- start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
+ /* create wait object for process startup */
+ wait = CreateEventW(NULL,FALSE,FALSE,szWaitServiceStartW);
+ if( NULL == wait )
+ {
+ ERR("Couldn't create wait event\n");
+ lasterr = GetLastError();
+ goto done;
+ }
ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
startupinfo.cb = sizeof(STARTUPINFOW);
- r = CreateProcessW(path,
- NULL,
+ r = CreateProcessW(NULL, /* name of executable module */
+ path, /* command line string */
NULL, /* process security attribs */
NULL, /* thread security attribs */
FALSE, /* inherit handles */
@@ -802,23 +1333,44 @@
NULL, /* current directory */
&startupinfo, /* startup info */
&procinfo); /* process info */
-
if(r == FALSE)
{
ERR("Couldn't start process\n");
- /* ReleaseSemaphore(data, 1, NULL);
- return FALSE; */
+ lasterr = GetLastError();
+ CloseHandle( wait );
+ goto done;
}
+ CloseHandle( procinfo.hThread );
/* docs for StartServiceCtrlDispatcher say this should be 30 sec */
r = WaitForSingleObject(wait,30000);
-
- ReleaseSemaphore(data, 1, NULL);
-
- if( r == WAIT_FAILED)
- return FALSE;
-
- return TRUE;
+ if( WAIT_FAILED == r )
+ {
+ lasterr = GetLastError();
+ CloseHandle( procinfo.hProcess );
+ goto done;
+ }
+ if( WAIT_TIMEOUT == r )
+ {
+ TerminateProcess( procinfo.hProcess, 1 );
+ CloseHandle( procinfo.hProcess );
+ lasterr = ERROR_SERVICE_REQUEST_TIMEOUT;
+ goto done;
+ }
+ CloseHandle( procinfo.hProcess );
+ CloseHandle( wait );
+
+ /* allright */
+ lasterr = 0;
+ ret = TRUE;
+
+done:
+ if( shmem_service != NULL ) UnmapViewOfFile( shmem_service );
+ if( hSvcMem != NULL ) CloseHandle( hSvcMem );
+ if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock );
+ UnlockServiceDatabase( hLock );
+ SetLastError( lasterr );
+ return ret;
}
/******************************************************************************
@@ -832,30 +1384,91 @@
BOOL WINAPI
QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
{
- LONG r;
+ struct sc_handle *hsvc = hService;
+ WCHAR object_name[ MAX_PATH ];
+ HANDLE mutex, shmem = NULL;
+ SERVICE_SHMEM *shmem_ptr = NULL;
+ DWORD lasterr, r;
DWORD type, val, size;
+ BOOL ret = FALSE, mutex_acquired = FALSE;
- FIXME("(%p,%p) partial\n",hService,lpservicestatus);
+ /* try to open mutex */
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szMutexNameW, hsvc->hdata.service.service_name );
+ mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
+ if( NULL == mutex )
+ {
+stopped:
+ /* service stopped */
+ /* read the service type from the registry */
+ size = sizeof(val);
+ r = RegQueryValueExA(hsvc->hKey, "Type", NULL, &type, (LPBYTE)&val, &size);
+ if(type!=REG_DWORD)
+ {
+ ERR("invalid Type\n");
+ return FALSE;
+ }
+ lpservicestatus->dwServiceType = val;
+ lpservicestatus->dwCurrentState = SERVICE_STOPPED;
+ lpservicestatus->dwControlsAccepted = 0;
+ lpservicestatus->dwWin32ExitCode = NO_ERROR;
+ lpservicestatus->dwServiceSpecificExitCode = 0;
+ lpservicestatus->dwCheckPoint = 0;
+ lpservicestatus->dwWaitHint = 0;
+
+ return TRUE;
+ }
- /* read the service type from the registry */
- size = sizeof(val);
- r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
- if(type!=REG_DWORD)
+ /* acquire mutex */
+ r = WaitForSingleObject( mutex, 30000 );
+ if( WAIT_FAILED == r )
{
- ERR("invalid Type\n");
- return FALSE;
+ lasterr = GetLastError();
+ goto done;
}
- lpservicestatus->dwServiceType = val;
- /* FIXME: how are these determined or read from the registry? */
- /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
- lpservicestatus->dwCurrentState = 1;
- lpservicestatus->dwControlsAccepted = 0;
- lpservicestatus->dwWin32ExitCode = NO_ERROR;
- lpservicestatus->dwServiceSpecificExitCode = 0;
- lpservicestatus->dwCheckPoint = 0;
- lpservicestatus->dwWaitHint = 0;
+ if( WAIT_TIMEOUT == r )
+ {
+ lasterr = ERROR_SERVICE_REQUEST_TIMEOUT;
+ goto done;
+ }
+ mutex_acquired = TRUE;
- return TRUE;
+ if( WAIT_ABANDONED == r )
+ {
+ lasterr = ERROR_SERVICE_NOT_ACTIVE;
+ CloseHandle( mutex );
+ goto stopped;
+ }
+
+ /* open shared memory */
+ snprintfW( object_name, MAX_PATH, szServiceObjectNameFmtW,
+ szShMemNameW, hsvc->hdata.service.service_name );
+ shmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
+ if( NULL == shmem )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+ shmem_ptr = MapViewOfFile( shmem, FILE_MAP_ALL_ACCESS,
+ 0, 0, sizeof(SERVICE_SHMEM) );
+ if( NULL == shmem_ptr )
+ {
+ lasterr = GetLastError();
+ goto done;
+ }
+
+ /* allright */
+ memcpy( lpservicestatus, &shmem_ptr->status, sizeof(SERVICE_STATUS) );
+ ret = TRUE;
+ lasterr = 0;
+
+done:
+ if( shmem_ptr != NULL ) UnmapViewOfFile( shmem_ptr );
+ if( shmem != NULL ) CloseHandle( shmem );
+ if( mutex_acquired ) ReleaseMutex( mutex );
+ CloseHandle( mutex );
+ SetLastError( lasterr );
+ return ret;
}
/******************************************************************************
@@ -891,9 +1504,135 @@
LPQUERY_SERVICE_CONFIGA lpServiceConfig,
DWORD cbBufSize, LPDWORD pcbBytesNeeded)
{
- FIXME("%p %p %ld %p\n", hService, lpServiceConfig,
+ static const CHAR szDisplayName[] = {
+ 'D','i','s','p','l','a','y','N','a','m','e', 0 };
+ static const CHAR szType[] = {'T','y','p','e',0};
+ static const CHAR szStart[] = {'S','t','a','r','t',0};
+ static const CHAR szError[] = {
+ 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
+ static const CHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
+ static const CHAR szGroup[] = {'G','r','o','u','p',0};
+ static const CHAR szDependencies[] = {
+ 'D','e','p','e','n','d','e','n','c','i','e','s',0};
+ struct sc_handle *hsvc = hService;
+ CHAR str[ MAX_PATH ], path[ MAX_PATH ];
+ LONG r;
+ DWORD type, val, sz, total, n;
+ LPBYTE p;
+
+ TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
cbBufSize, pcbBytesNeeded);
- return FALSE;
+
+ /* calculate the size required first */
+ total = sizeof (QUERY_SERVICE_CONFIGA);
+
+ sz = sizeof(str);
+ r = RegQueryValueExA( hsvc->hKey, szImagePath, 0, &type, str, &sz );
+ if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
+ {
+ ExpandEnvironmentStringsA(str,path,sizeof(path));
+ total += strlen(path) + 1;
+ }
+ else
+ {
+ /* FIXME: set last error */
+ return FALSE;
+ }
+
+ /* FIXME: ImagePath is required, how about other members? */
+ sz = 0;
+ r = RegQueryValueExA( hsvc->hKey, szGroup, 0, &type, NULL, &sz );
+ if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
+ total += sz;
+
+ sz = 0;
+ r = RegQueryValueExA( hsvc->hKey, szDependencies, 0, &type, NULL, &sz );
+ if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
+ total += sz;
+
+ sz = 0;
+ r = RegQueryValueExA( hsvc->hKey, szStart, 0, &type, NULL, &sz );
+ if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
+ total += sz;
+
+ sz = 0;
+ r = RegQueryValueExA( hsvc->hKey, szDisplayName, 0, &type, NULL, &sz );
+ if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
+ total += sz;
+
+ /* if there's not enough memory, return an error */
+ if( total > *pcbBytesNeeded )
+ {
+ *pcbBytesNeeded = total;
+ SetLastError( ERROR_INSUFFICIENT_BUFFER );
+ return FALSE;
+ }
+
+ *pcbBytesNeeded = total;
+ ZeroMemory( lpServiceConfig, total );
+
+ sz = sizeof val;
+ r = RegQueryValueExA( hsvc->hKey, szType, 0, &type, (LPBYTE)&val, &sz );
+ if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
+ lpServiceConfig->dwServiceType = val;
+
+ sz = sizeof val;
+ r = RegQueryValueExA( hsvc->hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
+ if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
+ lpServiceConfig->dwStartType = val;
+
+ sz = sizeof val;
+ r = RegQueryValueExA( hsvc->hKey, szError, 0, &type, (LPBYTE)&val, &sz );
+ if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
+ lpServiceConfig->dwErrorControl = val;
+
+ /* now do the strings */
+ p = (LPBYTE) &lpServiceConfig[1];
+ n = total - sizeof (QUERY_SERVICE_CONFIGA);
+
+ sz = sizeof(str);
+ r = RegQueryValueExA( hsvc->hKey, szImagePath, 0, &type, str, &sz );
+ if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
+ {
+ ExpandEnvironmentStringsA(str,path,sizeof(path));
+ strncpy( (LPSTR) p, path, n );
+ *(p + n - 1) = 0;
+ lpServiceConfig->lpBinaryPathName = (LPSTR) p;
+ sz = strlen( path ) + 1;
+ p += sz;
+ n -= sz;
+ }
+ else
+ {
+ /* FIXME: set last error */
+ return FALSE;
+ }
+
+ sz = n;
+ r = RegQueryValueExA( hsvc->hKey, szGroup, 0, &type, p, &sz );
+ if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
+ {
+ lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
+ p += sz;
+ n -= sz;
+ }
+
+ sz = n;
+ r = RegQueryValueExA( hsvc->hKey, szDependencies, 0, &type, p, &sz );
+ if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
+ {
+ lpServiceConfig->lpDependencies = (LPSTR) p;
+ p += sz;
+ n -= sz;
+ }
+
+ if( n < 0 )
+ ERR("Buffer overflow!\n");
+
+ TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
+ TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
+
+ return TRUE;
}
/******************************************************************************
@@ -914,6 +1653,8 @@
static const WCHAR szGroup[] = {'G','r','o','u','p',0};
static const WCHAR szDependencies[] = {
'D','e','p','e','n','d','e','n','c','i','e','s',0};
+ struct sc_handle *hsvc = hService;
+ WCHAR str[ MAX_PATH ], path[ MAX_PATH ];
LONG r;
DWORD type, val, sz, total, n;
LPBYTE p;
@@ -924,28 +1665,37 @@
/* calculate the size required first */
total = sizeof (QUERY_SERVICE_CONFIGW);
- sz = 0;
- r = RegQueryValueExW( hService, szImagePath, 0, &type, NULL, &sz );
- if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
- total += sz;
+ sz = sizeof(str);
+ r = RegQueryValueExW( hsvc->hKey, szImagePath, 0, &type, (LPBYTE) str, &sz );
+ if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
+ {
+ ExpandEnvironmentStringsW(str,path,sizeof(path));
+ total += sizeof(WCHAR) * (strlenW(path) + 1);
+ }
+ else
+ {
+ /* FIXME: set last error */
+ return FALSE;
+ }
+ /* FIXME: ImagePath is required, how about other members? */
sz = 0;
- r = RegQueryValueExW( hService, szGroup, 0, &type, NULL, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szGroup, 0, &type, NULL, &sz );
if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
total += sz;
sz = 0;
- r = RegQueryValueExW( hService, szDependencies, 0, &type, NULL, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szDependencies, 0, &type, NULL, &sz );
if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
total += sz;
sz = 0;
- r = RegQueryValueExW( hService, szStart, 0, &type, NULL, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szStart, 0, &type, NULL, &sz );
if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
total += sz;
sz = 0;
- r = RegQueryValueExW( hService, szDisplayName, 0, &type, NULL, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szDisplayName, 0, &type, NULL, &sz );
if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
total += sz;
@@ -961,17 +1711,17 @@
ZeroMemory( lpServiceConfig, total );
sz = sizeof val;
- r = RegQueryValueExW( hService, szType, 0, &type, (LPBYTE)&val, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szType, 0, &type, (LPBYTE)&val, &sz );
if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
lpServiceConfig->dwServiceType = val;
sz = sizeof val;
- r = RegQueryValueExW( hService, szStart, 0, &type, (LPBYTE)&val, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
lpServiceConfig->dwStartType = val;
sz = sizeof val;
- r = RegQueryValueExW( hService, szError, 0, &type, (LPBYTE)&val, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szError, 0, &type, (LPBYTE)&val, &sz );
if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
lpServiceConfig->dwErrorControl = val;
@@ -979,17 +1729,26 @@
p = (LPBYTE) &lpServiceConfig[1];
n = total - sizeof (QUERY_SERVICE_CONFIGW);
- sz = n;
- r = RegQueryValueExW( hService, szImagePath, 0, &type, p, &sz );
- if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
- {
+ sz = sizeof(str);
+ r = RegQueryValueExW( hsvc->hKey, szImagePath, 0, &type, (LPBYTE) str, &sz );
+ if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
+ {
+ ExpandEnvironmentStringsW(str,path,sizeof(path));
+ strncpyW( (LPWSTR) p, path, n >> 1 );
+ *(LPWSTR) (p + n - sizeof(WCHAR)) = 0;
lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
+ sz = sizeof(WCHAR) * (strlenW( path ) + 1);
p += sz;
n -= sz;
}
+ else
+ {
+ /* FIXME: set last error */
+ return FALSE;
+ }
sz = n;
- r = RegQueryValueExW( hService, szGroup, 0, &type, p, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szGroup, 0, &type, p, &sz );
if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
{
lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
@@ -998,7 +1757,7 @@
}
sz = n;
- r = RegQueryValueExW( hService, szDependencies, 0, &type, p, &sz );
+ r = RegQueryValueExW( hsvc->hKey, szDependencies, 0, &type, p, &sz );
if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
{
lpServiceConfig->lpDependencies = (LPWSTR) p;
@@ -1063,6 +1822,8 @@
BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
LPVOID lpInfo)
{
+ struct sc_handle *hsvc = hService;
+
if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
{
static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
@@ -1071,9 +1832,9 @@
{
TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
if (sd->lpDescription[0] == 0)
- RegDeleteValueW(hService,szDescription);
+ RegDeleteValueW(hsvc->hKey,szDescription);
else
- RegSetValueExW(hService, szDescription, 0, REG_SZ,
+ RegSetValueExW(hsvc->hKey, szDescription, 0, REG_SZ,
(LPVOID)sd->lpDescription,
sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
}
More information about the wine-patches
mailing list