In OpenSCManagerW() allow lpDatabaseName to be an empty string.
[wine.git] / dlls / advapi32 / service.c
blob404d51ebd91e67c50590ca1e20b44b67eb9c0ee4
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include <stdarg.h>
22 #include <string.h>
23 #include <time.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winsvc.h"
28 #include "winerror.h"
29 #include "winreg.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32 #include "winternl.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
36 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
37 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
38 'S','e','r','v','i','c','e','s','\\',0 };
39 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
40 'L','O','C','K',0};
41 static const WCHAR szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_',
42 'S','E','B','_','%','s',0};
43 static const WCHAR szServiceDispEventNameFmtW[] = {'A','D','V','A','P','I','_',
44 'D','I','S','P','_','%','s',0};
45 static const WCHAR szServiceMutexNameFmtW[] = {'A','D','V','A','P','I','_',
46 'M','U','X','_','%','s',0};
47 static const WCHAR szServiceAckEventNameFmtW[] = {'A','D','V','A','P','I','_',
48 'A','C','K','_','%','s',0};
49 static const WCHAR szWaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
50 'a','i','t','S','e','r','v','i',
51 'c','e','S','t','a','r','t',0};
53 struct SEB /* service environment block */
54 { /* resides in service's shared memory object */
55 DWORD control_code; /* service control code */
56 DWORD dispatcher_error; /* set by dispatcher if it fails to invoke control handler */
57 SERVICE_STATUS status;
58 DWORD argc;
59 /* variable part of SEB contains service arguments */
62 static HANDLE dispatcher_event; /* this is used by service thread to wakeup
63 * service control dispatcher when thread terminates */
65 static struct service_thread_data *service; /* FIXME: this should be a list */
67 /******************************************************************************
68 * SC_HANDLEs
71 #define MAX_SERVICE_NAME 256
73 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
75 struct sc_handle;
77 struct sc_manager /* SCM handle */
79 HKEY hkey_scm_db; /* handle to services database in the registry */
80 LONG ref_count; /* handle must remain alive until any related service */
81 /* handle exists because DeleteService requires it */
84 struct sc_service /* service handle */
86 HKEY hkey; /* handle to service entry in the registry (under hkey_scm_db) */
87 struct sc_handle *sc_manager; /* pointer to SCM handle */
88 WCHAR name[ MAX_SERVICE_NAME ];
91 struct sc_handle
93 SC_HANDLE_TYPE htype;
94 union
96 struct sc_manager manager;
97 struct sc_service service;
98 } u;
101 static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
103 struct sc_handle *retval;
105 retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
106 if( retval != NULL )
108 retval->htype = htype;
110 TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
111 return retval;
114 static void free_sc_handle( struct sc_handle* handle )
116 if( NULL == handle )
117 return;
119 switch( handle->htype )
121 case SC_HTYPE_MANAGER:
123 if( InterlockedDecrement( &handle->u.manager.ref_count ) )
124 /* there are references to this handle */
125 return;
127 if( handle->u.manager.hkey_scm_db )
128 RegCloseKey( handle->u.manager.hkey_scm_db );
129 break;
132 case SC_HTYPE_SERVICE:
134 struct sc_handle *h = handle->u.service.sc_manager;
136 if( h )
138 /* release SCM handle */
139 if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
141 /* it's time to destroy SCM handle */
142 if( h->u.manager.hkey_scm_db )
143 RegCloseKey( h->u.manager.hkey_scm_db );
145 TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
147 HeapFree( GetProcessHeap(), 0, h );
150 if( handle->u.service.hkey )
151 RegCloseKey( handle->u.service.hkey );
152 break;
156 TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
158 HeapFree( GetProcessHeap(), 0, handle );
161 static void init_service_handle( struct sc_handle* handle,
162 struct sc_handle* sc_manager,
163 HKEY hKey, LPCWSTR lpServiceName )
165 /* init sc_service structure */
166 handle->u.service.hkey = hKey;
167 lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
169 /* add reference to SCM handle */
170 InterlockedIncrement( &sc_manager->u.manager.ref_count );
171 handle->u.service.sc_manager = sc_manager;
174 static inline LPWSTR SERV_dup( LPCSTR str )
176 UINT len;
177 LPWSTR wstr;
179 if( !str )
180 return NULL;
181 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
182 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
183 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
184 return wstr;
187 static inline LPWSTR SERV_dupmulti( LPCSTR str )
189 UINT len = 0, n = 0;
190 LPWSTR wstr;
192 if( !str )
193 return NULL;
194 do {
195 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
196 n += (strlen( &str[n] ) + 1);
197 } while (str[n]);
198 len++;
199 n++;
201 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
202 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
203 return wstr;
206 static inline VOID SERV_free( LPWSTR wstr )
208 HeapFree( GetProcessHeap(), 0, wstr );
211 /******************************************************************************
212 * EnumServicesStatusA [ADVAPI32.@]
214 BOOL WINAPI
215 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
216 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
217 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
218 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
219 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
220 dwServiceType, dwServiceState, lpServices, cbBufSize,
221 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
222 SetLastError (ERROR_ACCESS_DENIED);
223 return FALSE;
226 /******************************************************************************
227 * EnumServicesStatusW [ADVAPI32.@]
229 BOOL WINAPI
230 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
231 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
232 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
233 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
234 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
235 dwServiceType, dwServiceState, lpServices, cbBufSize,
236 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
237 SetLastError (ERROR_ACCESS_DENIED);
238 return FALSE;
241 /******************************************************************************
242 * read_scm_lock_data
244 * helper function for service control dispatcher
246 * SCM database is locked by StartService;
247 * open global SCM lock object and read service name
249 static BOOL read_scm_lock_data( LPWSTR buffer )
251 HANDLE hLock;
252 LPWSTR argptr;
254 hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
255 if( NULL == hLock )
257 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
258 return FALSE;
260 argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
261 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
262 if( NULL == argptr )
264 CloseHandle( hLock );
265 return FALSE;
267 strcpyW( buffer, argptr );
268 UnmapViewOfFile( argptr );
269 CloseHandle( hLock );
270 return TRUE;
273 /******************************************************************************
274 * open_seb_shmem
276 * helper function for service control dispatcher
278 static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
280 WCHAR object_name[ MAX_PATH ];
281 HANDLE hmem;
282 struct SEB *ret;
284 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
285 hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
286 if( NULL == hmem )
287 return NULL;
289 ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
290 if( NULL == ret )
291 CloseHandle( hmem );
292 else
293 *hServiceShmem = hmem;
294 return ret;
297 /******************************************************************************
298 * build_arg_vectors
300 * helper function for start_new_service
302 * Allocate and initialize array of LPWSTRs to arguments in variable part
303 * of service environment block.
304 * First entry in the array is reserved for service name and not initialized.
306 static LPWSTR* build_arg_vectors( struct SEB* seb )
308 LPWSTR *ret;
309 LPWSTR argptr;
310 DWORD i;
312 ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
313 if( NULL == ret )
314 return NULL;
316 argptr = (LPWSTR) &seb[1];
317 for( i = 0; i < seb->argc; i++ )
319 ret[ 1 + i ] = argptr;
320 argptr += 1 + strlenW( argptr );
322 return ret;
325 /******************************************************************************
326 * service thread
328 struct service_thread_data
330 WCHAR service_name[ MAX_SERVICE_NAME ];
331 CHAR service_nameA[ MAX_SERVICE_NAME ];
332 LPSERVICE_MAIN_FUNCTIONW service_main;
333 DWORD argc;
334 LPWSTR *argv;
335 HANDLE hServiceShmem;
336 struct SEB *seb;
337 HANDLE thread_handle;
338 HANDLE mutex; /* provides serialization of control request */
339 HANDLE ack_event; /* control handler completion acknowledgement */
340 LPHANDLER_FUNCTION ctrl_handler;
343 static DWORD WINAPI service_thread( LPVOID arg )
345 struct service_thread_data *data = arg;
347 data->service_main( data->argc, data->argv );
348 SetEvent( dispatcher_event );
349 return 0;
352 /******************************************************************************
353 * dispose_service_thread_data
355 * helper function for service control dispatcher
357 static void dispose_service_thread_data( struct service_thread_data* thread_data )
359 if( thread_data->mutex ) CloseHandle( thread_data->mutex );
360 if( thread_data->ack_event ) CloseHandle( thread_data->ack_event );
361 if( thread_data->argv ) HeapFree( GetProcessHeap(), 0, thread_data->argv );
362 if( thread_data->seb ) UnmapViewOfFile( thread_data->seb );
363 if( thread_data->hServiceShmem ) CloseHandle( thread_data->hServiceShmem );
364 HeapFree( GetProcessHeap(), 0, thread_data );
367 /******************************************************************************
368 * start_new_service
370 * helper function for service control dispatcher
372 static struct service_thread_data*
373 start_new_service( LPSERVICE_MAIN_FUNCTIONW service_main, BOOL ascii )
375 struct service_thread_data *thread_data;
376 unsigned int i;
377 WCHAR object_name[ MAX_PATH ];
379 thread_data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct service_thread_data) );
380 if( NULL == thread_data )
381 return NULL;
383 if( ! read_scm_lock_data( thread_data->service_name ) )
385 /* FIXME: Instead of exiting we allow
386 service to be executed as ordinary program.
387 This behaviour was specially introduced in the patch
388 submitted against revision 1.45 and so preserved here.
390 FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
391 service_main( 0, NULL );
392 HeapFree( GetProcessHeap(), 0, thread_data );
393 return NULL;
396 thread_data->seb = open_seb_shmem( thread_data->service_name, &thread_data->hServiceShmem );
397 if( NULL == thread_data->seb )
398 goto error;
400 thread_data->argv = build_arg_vectors( thread_data->seb );
401 if( NULL == thread_data->argv )
402 goto error;
404 thread_data->argv[0] = thread_data->service_name;
405 thread_data->argc = thread_data->seb->argc + 1;
407 if( ascii )
409 /* Convert the Unicode arg vectors back to ASCII;
410 * but we'll need unicode service name (argv[0]) for object names */
411 WideCharToMultiByte( CP_ACP, 0, thread_data->argv[0], -1,
412 thread_data->service_nameA, MAX_SERVICE_NAME, NULL, NULL );
413 thread_data->argv[0] = (LPWSTR) thread_data->service_nameA;
415 for(i=1; i<thread_data->argc; i++)
417 LPWSTR src = thread_data->argv[i];
418 int len = WideCharToMultiByte( CP_ACP, 0, src, -1, NULL, 0, NULL, NULL );
419 LPSTR dest = HeapAlloc( GetProcessHeap(), 0, len );
420 if( NULL == dest )
421 goto error;
422 WideCharToMultiByte( CP_ACP, 0, src, -1, dest, len, NULL, NULL );
423 /* copy converted string back */
424 memcpy( src, dest, len );
425 HeapFree( GetProcessHeap(), 0, dest );
429 /* init status according to docs for StartService */
430 thread_data->seb->status.dwCurrentState = SERVICE_START_PENDING;
431 thread_data->seb->status.dwControlsAccepted = 0;
432 thread_data->seb->status.dwCheckPoint = 0;
433 thread_data->seb->status.dwWaitHint = 2000;
435 /* create service mutex; mutex is initially owned */
436 snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, thread_data->service_name );
437 thread_data->mutex = CreateMutexW( NULL, TRUE, object_name );
438 if( NULL == thread_data->mutex )
439 goto error;
441 if( ERROR_ALREADY_EXISTS == GetLastError() )
443 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
444 goto error;
447 /* create service event */
448 snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, thread_data->service_name );
449 thread_data->ack_event = CreateEventW( NULL, FALSE, FALSE, object_name );
450 if( NULL == thread_data->ack_event )
451 goto error;
453 if( ERROR_ALREADY_EXISTS == GetLastError() )
455 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
456 goto error;
459 /* create service thread in suspended state
460 * to avoid race while caller handles return value */
461 thread_data->service_main = service_main;
462 thread_data->thread_handle = CreateThread( NULL, 0, service_thread,
463 thread_data, CREATE_SUSPENDED, NULL );
464 if( thread_data->thread_handle )
465 return thread_data;
467 error:
468 dispose_service_thread_data( thread_data );
469 return FALSE;
472 /******************************************************************************
473 * service_ctrl_dispatcher
475 static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii )
477 WCHAR object_name[ MAX_PATH ];
478 HANDLE wait;
480 /* FIXME: if shared service, find entry by service name */
482 /* FIXME: move this into dispatcher loop */
483 service = start_new_service( servent->lpServiceProc, ascii );
484 if( NULL == service )
485 return FALSE;
487 ResumeThread( service->thread_handle );
489 /* create dispatcher event object */
490 /* FIXME: object_name should be based on executable image path because
491 * this object is common for all services in the process */
492 /* But what if own and shared services have the same executable? */
493 snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, service->service_name );
494 dispatcher_event = CreateEventW( NULL, FALSE, FALSE, object_name );
495 if( NULL == dispatcher_event )
497 dispose_service_thread_data( service );
498 return FALSE;
501 if( ERROR_ALREADY_EXISTS == GetLastError() )
503 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
504 CloseHandle( dispatcher_event );
505 return FALSE;
508 /* ready to accept control requests */
509 ReleaseMutex( service->mutex );
511 /* signal for StartService */
512 wait = OpenSemaphoreW( SEMAPHORE_MODIFY_STATE, FALSE, szWaitServiceStartW );
513 if( wait )
515 ReleaseSemaphore( wait, 1, NULL );
516 CloseHandle( wait );
519 /* dispatcher loop */
520 for(;;)
522 DWORD ret;
524 WaitForSingleObject( dispatcher_event, INFINITE );
526 /* at first, look for terminated service thread
527 * FIXME: threads, if shared service */
528 if( !GetExitCodeThread( service->thread_handle, &ret ) )
529 ERR("Couldn't get thread exit code\n");
530 else if( ret != STILL_ACTIVE )
532 CloseHandle( service->thread_handle );
533 dispose_service_thread_data( service );
534 break;
537 /* look for control requests */
538 if( service->seb->control_code )
540 if( NULL == service->ctrl_handler )
541 service->seb->dispatcher_error = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
542 else
544 service->ctrl_handler( service->seb->control_code );
545 service->seb->dispatcher_error = 0;
547 service->seb->control_code = 0;
548 SetEvent( service->ack_event );
551 /* FIXME: if shared service, check SCM lock object;
552 * if exists, a new service should be started */
555 CloseHandle( dispatcher_event );
556 return TRUE;
559 /******************************************************************************
560 * StartServiceCtrlDispatcherA [ADVAPI32.@]
562 BOOL WINAPI
563 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
565 int count, i;
566 LPSERVICE_TABLE_ENTRYW ServiceTableW;
567 BOOL ret;
569 TRACE("(%p)\n", servent);
571 /* convert service table to unicode */
572 for( count = 0; servent[ count ].lpServiceName; )
573 count++;
574 ServiceTableW = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(SERVICE_TABLE_ENTRYW) );
575 if( NULL == ServiceTableW )
576 return FALSE;
578 for( i = 0; i < count; i++ )
580 ServiceTableW[ i ].lpServiceName = SERV_dup( servent[ i ].lpServiceName );
581 ServiceTableW[ i ].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONW) servent[ i ].lpServiceProc;
583 ServiceTableW[ count ].lpServiceName = NULL;
584 ServiceTableW[ count ].lpServiceProc = NULL;
586 /* start dispatcher */
587 ret = service_ctrl_dispatcher( ServiceTableW, TRUE );
589 /* free service table */
590 for( i = 0; i < count; i++ )
591 SERV_free( ServiceTableW[ i ].lpServiceName );
592 HeapFree( GetProcessHeap(), 0, ServiceTableW );
593 return ret;
596 /******************************************************************************
597 * StartServiceCtrlDispatcherW [ADVAPI32.@]
599 * PARAMS
600 * servent []
602 BOOL WINAPI
603 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
605 TRACE("(%p)\n", servent);
606 return service_ctrl_dispatcher( servent, FALSE );
609 /******************************************************************************
610 * LockServiceDatabase [ADVAPI32.@]
612 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
614 HANDLE ret;
616 TRACE("%p\n",hSCManager);
618 ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
619 0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
620 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
622 CloseHandle( ret );
623 ret = NULL;
624 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
627 TRACE("returning %p\n", ret);
629 return ret;
632 /******************************************************************************
633 * UnlockServiceDatabase [ADVAPI32.@]
635 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
637 TRACE("%p\n",ScLock);
639 return CloseHandle( (HANDLE) ScLock );
642 /******************************************************************************
643 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
645 SERVICE_STATUS_HANDLE WINAPI
646 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
647 LPHANDLER_FUNCTION lpfHandler )
649 UNICODE_STRING lpServiceNameW;
650 SERVICE_STATUS_HANDLE ret;
652 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
653 ret = RegisterServiceCtrlHandlerW( lpServiceNameW.Buffer, lpfHandler );
654 RtlFreeUnicodeString(&lpServiceNameW);
655 return ret;
658 /******************************************************************************
659 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
661 * PARAMS
662 * lpServiceName []
663 * lpfHandler []
665 SERVICE_STATUS_HANDLE WINAPI
666 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
667 LPHANDLER_FUNCTION lpfHandler )
669 /* FIXME: find service thread data by service name */
671 service->ctrl_handler = lpfHandler;
672 return 0xcacacafe;
675 /******************************************************************************
676 * SetServiceStatus [ADVAPI32.@]
678 * PARAMS
679 * hService []
680 * lpStatus []
682 BOOL WINAPI
683 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
685 DWORD r;
687 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
688 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
689 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
690 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
691 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
692 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
693 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
695 /* FIXME: find service thread data by status handle */
697 /* acquire mutex; note that mutex may already be owned
698 * when service handles control request
700 r = WaitForSingleObject( service->mutex, 0 );
701 memcpy( &service->seb->status, lpStatus, sizeof(SERVICE_STATUS) );
702 if( WAIT_OBJECT_0 == r || WAIT_ABANDONED == r )
703 ReleaseMutex( service->mutex );
704 return TRUE;
707 /******************************************************************************
708 * OpenSCManagerA [ADVAPI32.@]
710 * Establish a connection to the service control manager and open its database.
712 * PARAMS
713 * lpMachineName [I] Pointer to machine name string
714 * lpDatabaseName [I] Pointer to database name string
715 * dwDesiredAccess [I] Type of access
717 * RETURNS
718 * Success: A Handle to the service control manager database
719 * Failure: NULL
721 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
722 DWORD dwDesiredAccess )
724 UNICODE_STRING lpMachineNameW;
725 UNICODE_STRING lpDatabaseNameW;
726 SC_HANDLE ret;
728 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
729 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
730 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
731 RtlFreeUnicodeString(&lpDatabaseNameW);
732 RtlFreeUnicodeString(&lpMachineNameW);
733 return ret;
736 /******************************************************************************
737 * OpenSCManagerW [ADVAPI32.@]
739 * See OpenSCManagerA.
741 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
742 DWORD dwDesiredAccess )
744 struct sc_handle *retval;
745 HKEY hReg;
746 LONG r;
748 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
749 debugstr_w(lpDatabaseName), dwDesiredAccess);
751 if( lpDatabaseName && lpDatabaseName[0] )
753 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
755 /* noop, all right */
757 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
759 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
760 return NULL;
762 else
764 SetLastError( ERROR_INVALID_NAME );
765 return NULL;
769 retval = alloc_sc_handle( SC_HTYPE_MANAGER );
770 if( NULL == retval ) return NULL;
772 retval->u.manager.ref_count = 1;
774 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
775 if (r!=ERROR_SUCCESS)
776 goto error;
778 r = RegOpenKeyExW(hReg, szServiceManagerKey,
779 0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
780 RegCloseKey( hReg );
781 if (r!=ERROR_SUCCESS)
782 goto error;
784 TRACE("returning %p\n", retval);
786 return (SC_HANDLE) retval;
788 error:
789 free_sc_handle( retval );
790 return NULL;
793 /******************************************************************************
794 * ControlService [ADVAPI32.@]
796 * Send a control code to a service.
798 * PARAMS
799 * hService [I] Handle of the service control manager database
800 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
801 * lpServiceStatus [O] Destination for the status of the service, if available
803 * RETURNS
804 * Success: TRUE.
805 * Failure: FALSE.
807 * BUGS
808 * Unlike M$' implementation, control requests are not serialized and may be
809 * processed asynchronously.
811 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
812 LPSERVICE_STATUS lpServiceStatus )
814 struct sc_handle *hsvc = hService;
815 WCHAR object_name[ MAX_PATH ];
816 HANDLE mutex = NULL, shmem = NULL;
817 HANDLE disp_event = NULL, ack_event = NULL;
818 struct SEB *seb = NULL;
819 DWORD r;
820 BOOL ret = FALSE, mutex_owned = FALSE;
822 /* open and hold mutex */
823 snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->u.service.name );
824 mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
825 if( NULL == mutex )
827 SetLastError( ERROR_SERVICE_NOT_ACTIVE );
828 return FALSE;
831 r = WaitForSingleObject( mutex, 30000 );
832 if( WAIT_FAILED == r )
833 goto done;
835 if( WAIT_TIMEOUT == r )
837 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
838 goto done;
840 mutex_owned = TRUE;
842 /* open event objects */
843 snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, hsvc->u.service.name );
844 disp_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
845 if( NULL == disp_event )
846 goto done;
848 snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, hsvc->u.service.name );
849 ack_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
850 if( NULL == ack_event )
851 goto done;
853 /* get service environment block */
854 seb = open_seb_shmem( hsvc->u.service.name, &shmem );
855 if( NULL == seb )
856 goto done;
858 /* send request */
859 /* FIXME: check dwControl against controls accepted */
860 seb->control_code = dwControl;
861 SetEvent( disp_event );
863 /* wait for acknowledgement */
864 r = WaitForSingleObject( ack_event, 30000 );
865 if( WAIT_FAILED == r )
866 goto done;
868 if( WAIT_TIMEOUT == r )
870 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
871 goto done;
874 if( seb->dispatcher_error )
876 SetLastError( seb->dispatcher_error );
877 goto done;
880 /* get status */
881 if( lpServiceStatus )
882 memcpy( lpServiceStatus, &seb->status, sizeof(SERVICE_STATUS) );
883 ret = TRUE;
885 done:
886 if( seb ) UnmapViewOfFile( seb );
887 if( shmem ) CloseHandle( shmem );
888 if( ack_event ) CloseHandle( ack_event );
889 if( disp_event ) CloseHandle( disp_event );
890 if( mutex_owned ) ReleaseMutex( mutex );
891 if( mutex ) CloseHandle( mutex );
892 return ret;
895 /******************************************************************************
896 * CloseServiceHandle [ADVAPI32.@]
898 * Close a handle to a service or the service control manager database.
900 * PARAMS
901 * hSCObject [I] Handle to service or service control manager database
903 * RETURNS
904 * Success: TRUE
905 * Failure: FALSE
907 BOOL WINAPI
908 CloseServiceHandle( SC_HANDLE hSCObject )
910 TRACE("(%p)\n", hSCObject);
912 free_sc_handle( (struct sc_handle*) hSCObject );
914 return TRUE;
918 /******************************************************************************
919 * OpenServiceA [ADVAPI32.@]
921 * Open a handle to a service.
923 * PARAMS
924 * hSCManager [I] Handle of the service control manager database
925 * lpServiceName [I] Name of the service to open
926 * dwDesiredAccess [I] Access required to the service
928 * RETURNS
929 * Success: Handle to the service
930 * Failure: NULL
932 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
933 DWORD dwDesiredAccess )
935 UNICODE_STRING lpServiceNameW;
936 SC_HANDLE ret;
937 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
938 if(lpServiceName)
939 TRACE("Request for service %s\n",lpServiceName);
940 else
941 return FALSE;
942 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
943 RtlFreeUnicodeString(&lpServiceNameW);
944 return ret;
948 /******************************************************************************
949 * OpenServiceW [ADVAPI32.@]
951 * See OpenServiceA.
953 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
954 DWORD dwDesiredAccess)
956 struct sc_handle *hscm = hSCManager;
957 struct sc_handle *retval;
958 HKEY hKey;
959 long r;
961 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
962 dwDesiredAccess);
964 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
965 if( NULL == retval )
966 return NULL;
968 r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
969 lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
970 if (r!=ERROR_SUCCESS)
972 free_sc_handle( retval );
973 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
974 return NULL;
977 init_service_handle( retval, hscm, hKey, lpServiceName );
979 TRACE("returning %p\n",retval);
981 return (SC_HANDLE) retval;
984 /******************************************************************************
985 * CreateServiceW [ADVAPI32.@]
987 SC_HANDLE WINAPI
988 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
989 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
990 DWORD dwServiceType, DWORD dwStartType,
991 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
992 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
993 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
994 LPCWSTR lpPassword )
996 struct sc_handle *hscm = hSCManager;
997 struct sc_handle *retval;
998 HKEY hKey;
999 LONG r;
1000 DWORD dp;
1001 static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1002 static const WCHAR szType[] = {'T','y','p','e',0};
1003 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1004 static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1005 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1006 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1007 static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1009 FIXME("%p %s %s\n", hSCManager,
1010 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1012 retval = alloc_sc_handle( SC_HTYPE_SERVICE );
1013 if( NULL == retval )
1014 return NULL;
1016 r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
1017 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1018 if (r!=ERROR_SUCCESS)
1019 goto error;
1021 init_service_handle( retval, hscm, hKey, lpServiceName );
1023 if (dp != REG_CREATED_NEW_KEY)
1024 goto error;
1026 if(lpDisplayName)
1028 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (const BYTE*)lpDisplayName,
1029 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
1030 if (r!=ERROR_SUCCESS)
1031 goto error;
1034 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
1035 if (r!=ERROR_SUCCESS)
1036 goto error;
1038 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
1039 if (r!=ERROR_SUCCESS)
1040 goto error;
1042 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
1043 (LPVOID)&dwErrorControl, sizeof (DWORD) );
1044 if (r!=ERROR_SUCCESS)
1045 goto error;
1047 if(lpBinaryPathName)
1049 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (const BYTE*)lpBinaryPathName,
1050 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
1051 if (r!=ERROR_SUCCESS)
1052 goto error;
1055 if(lpLoadOrderGroup)
1057 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (const BYTE*)lpLoadOrderGroup,
1058 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
1059 if (r!=ERROR_SUCCESS)
1060 goto error;
1063 if(lpDependencies)
1065 DWORD len = 0;
1067 /* determine the length of a double null terminated multi string */
1068 do {
1069 len += (strlenW(&lpDependencies[len])+1);
1070 } while (lpDependencies[len++]);
1072 r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
1073 (const BYTE*)lpDependencies, len );
1074 if (r!=ERROR_SUCCESS)
1075 goto error;
1078 if(lpPassword)
1080 FIXME("Don't know how to add a Password for a service.\n");
1083 if(lpServiceStartName)
1085 FIXME("Don't know how to add a ServiceStartName for a service.\n");
1088 return (SC_HANDLE) retval;
1090 error:
1091 free_sc_handle( retval );
1092 return NULL;
1096 /******************************************************************************
1097 * CreateServiceA [ADVAPI32.@]
1099 SC_HANDLE WINAPI
1100 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1101 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1102 DWORD dwServiceType, DWORD dwStartType,
1103 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1104 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1105 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1106 LPCSTR lpPassword )
1108 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1109 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1110 SC_HANDLE r;
1112 TRACE("%p %s %s\n", hSCManager,
1113 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1115 lpServiceNameW = SERV_dup( lpServiceName );
1116 lpDisplayNameW = SERV_dup( lpDisplayName );
1117 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1118 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1119 lpDependenciesW = SERV_dupmulti( lpDependencies );
1120 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1121 lpPasswordW = SERV_dup( lpPassword );
1123 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1124 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1125 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1126 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1128 SERV_free( lpServiceNameW );
1129 SERV_free( lpDisplayNameW );
1130 SERV_free( lpBinaryPathNameW );
1131 SERV_free( lpLoadOrderGroupW );
1132 SERV_free( lpDependenciesW );
1133 SERV_free( lpServiceStartNameW );
1134 SERV_free( lpPasswordW );
1136 return r;
1140 /******************************************************************************
1141 * DeleteService [ADVAPI32.@]
1143 * Delete a service from the service control manager database.
1145 * PARAMS
1146 * hService [I] Handle of the service to delete
1148 * RETURNS
1149 * Success: TRUE
1150 * Failure: FALSE
1152 BOOL WINAPI DeleteService( SC_HANDLE hService )
1154 struct sc_handle *hsvc = hService;
1155 HKEY hKey = hsvc->u.service.hkey;
1156 WCHAR valname[MAX_PATH+1];
1157 INT index = 0;
1158 LONG rc;
1159 DWORD size;
1161 size = MAX_PATH+1;
1162 /* Clean out the values */
1163 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1164 while (rc == ERROR_SUCCESS)
1166 RegDeleteValueW(hKey,valname);
1167 index++;
1168 size = MAX_PATH+1;
1169 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1172 RegCloseKey(hKey);
1173 hsvc->u.service.hkey = NULL;
1175 /* delete the key */
1176 RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
1177 hsvc->u.service.name);
1179 return TRUE;
1183 /******************************************************************************
1184 * StartServiceA [ADVAPI32.@]
1186 * Start a service
1188 * PARAMS
1189 * hService [I] Handle of service
1190 * dwNumServiceArgs [I] Number of arguments
1191 * lpServiceArgVectors [I] Address of array of argument strings
1193 * NOTES
1194 * - NT implements this function using an obscure RPC call.
1195 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1196 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1197 * - This will only work for shared address space. How should the service
1198 * args be transferred when address spaces are separated?
1199 * - Can only start one service at a time.
1200 * - Has no concept of privilege.
1202 * RETURNS
1203 * Success: TRUE.
1204 * Failure: FALSE
1206 BOOL WINAPI
1207 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1208 LPCSTR *lpServiceArgVectors )
1210 LPWSTR *lpwstr=NULL;
1211 UNICODE_STRING usBuffer;
1212 unsigned int i;
1214 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1216 if(dwNumServiceArgs)
1217 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
1218 dwNumServiceArgs*sizeof(LPWSTR) );
1219 else
1220 lpwstr = NULL;
1222 for(i=0; i<dwNumServiceArgs; i++)
1224 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
1225 lpwstr[i]=usBuffer.Buffer;
1228 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1230 if(dwNumServiceArgs)
1232 for(i=0; i<dwNumServiceArgs; i++)
1233 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1234 HeapFree(GetProcessHeap(), 0, lpwstr);
1237 return TRUE;
1241 /******************************************************************************
1242 * StartServiceW [ADVAPI32.@]
1244 * See StartServiceA.
1246 BOOL WINAPI
1247 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
1248 LPCWSTR *lpServiceArgVectors )
1250 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1252 struct sc_handle *hsvc = hService;
1253 WCHAR path[MAX_PATH],str[MAX_PATH];
1254 DWORD type,size;
1255 DWORD i;
1256 long r;
1257 HANDLE hLock;
1258 HANDLE hServiceShmem = NULL;
1259 HANDLE wait = NULL;
1260 LPWSTR shmem_lock = NULL;
1261 struct SEB *seb = NULL;
1262 LPWSTR argptr;
1263 PROCESS_INFORMATION procinfo;
1264 STARTUPINFOW startupinfo;
1265 BOOL ret = FALSE;
1267 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
1268 lpServiceArgVectors);
1270 size = sizeof(str);
1271 r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
1272 if (r!=ERROR_SUCCESS)
1273 return FALSE;
1274 ExpandEnvironmentStringsW(str,path,sizeof(path));
1276 TRACE("Starting service %s\n", debugstr_w(path) );
1278 hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
1279 if( NULL == hLock )
1280 return FALSE;
1283 * FIXME: start dependent services
1286 /* pass argv[0] (service name) to the service via global SCM lock object */
1287 shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
1288 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
1289 if( NULL == shmem_lock )
1291 ERR("Couldn't map shared memory\n");
1292 goto done;
1294 strcpyW( shmem_lock, hsvc->u.service.name );
1296 /* create service environment block */
1297 size = sizeof(struct SEB);
1298 for( i = 0; i < dwNumServiceArgs; i++ )
1299 size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] ));
1301 snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1302 hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1303 NULL, PAGE_READWRITE, 0, size, str );
1304 if( NULL == hServiceShmem )
1306 ERR("Couldn't create shared memory object\n");
1307 goto done;
1309 if( GetLastError() == ERROR_ALREADY_EXISTS )
1311 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1312 goto done;
1314 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1315 if( NULL == seb )
1317 ERR("Couldn't map shared memory\n");
1318 goto done;
1321 /* copy service args to SEB */
1322 seb->argc = dwNumServiceArgs;
1323 argptr = (LPWSTR) &seb[1];
1324 for( i = 0; i < dwNumServiceArgs; i++ )
1326 strcpyW( argptr, lpServiceArgVectors[ i ] );
1327 argptr += 1 + strlenW( argptr );
1330 wait = CreateSemaphoreW(NULL,0,1,szWaitServiceStartW);
1331 if (!wait)
1333 ERR("Couldn't create wait semaphore\n");
1334 goto done;
1337 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1338 startupinfo.cb = sizeof(STARTUPINFOW);
1340 r = CreateProcessW(NULL,
1341 path,
1342 NULL, /* process security attribs */
1343 NULL, /* thread security attribs */
1344 FALSE, /* inherit handles */
1345 0, /* creation flags */
1346 NULL, /* environment */
1347 NULL, /* current directory */
1348 &startupinfo, /* startup info */
1349 &procinfo); /* process info */
1351 if(r == FALSE)
1353 ERR("Couldn't start process\n");
1354 goto done;
1356 CloseHandle( procinfo.hThread );
1358 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1359 r = WaitForSingleObject(wait,30000);
1360 if( WAIT_FAILED == r )
1362 CloseHandle( procinfo.hProcess );
1363 goto done;
1365 if( WAIT_TIMEOUT == r )
1367 TerminateProcess( procinfo.hProcess, 1 );
1368 CloseHandle( procinfo.hProcess );
1369 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
1370 goto done;
1373 /* allright */
1374 CloseHandle( procinfo.hProcess );
1375 ret = TRUE;
1377 done:
1378 if( wait ) CloseHandle( wait );
1379 if( seb != NULL ) UnmapViewOfFile( seb );
1380 if( hServiceShmem != NULL ) CloseHandle( hServiceShmem );
1381 if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock );
1382 UnlockServiceDatabase( hLock );
1383 return ret;
1386 /******************************************************************************
1387 * QueryServiceStatus [ADVAPI32.@]
1389 * PARAMS
1390 * hService []
1391 * lpservicestatus []
1394 BOOL WINAPI
1395 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1397 struct sc_handle *hsvc = hService;
1398 LONG r;
1399 DWORD type, val, size;
1400 WCHAR object_name[ MAX_PATH ];
1401 HANDLE mutex, shmem = NULL;
1402 struct SEB *seb = NULL;
1403 BOOL ret = FALSE, mutex_owned = FALSE;
1405 /* try to open service mutex */
1406 snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->u.service.name );
1407 mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
1408 if( NULL == mutex )
1409 goto stopped;
1411 /* hold mutex */
1412 r = WaitForSingleObject( mutex, 30000 );
1413 if( WAIT_FAILED == r )
1414 goto done;
1416 if( WAIT_TIMEOUT == r )
1418 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
1419 goto done;
1421 mutex_owned = TRUE;
1423 /* get service environment block */
1424 seb = open_seb_shmem( hsvc->u.service.name, &shmem );
1425 if( NULL == seb )
1426 goto done;
1428 /* get status */
1429 memcpy( lpservicestatus, &seb->status, sizeof(SERVICE_STATUS) );
1430 ret = TRUE;
1432 done:
1433 if( seb ) UnmapViewOfFile( seb );
1434 if( shmem ) CloseHandle( shmem );
1435 if( mutex_owned ) ReleaseMutex( mutex );
1436 CloseHandle( mutex );
1437 return ret;
1439 stopped:
1440 /* service stopped */
1441 /* read the service type from the registry */
1442 size = sizeof(val);
1443 r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1444 if(type!=REG_DWORD)
1446 ERR("invalid Type\n");
1447 return FALSE;
1449 lpservicestatus->dwServiceType = val;
1450 lpservicestatus->dwCurrentState = 1; /* stopped */
1451 lpservicestatus->dwControlsAccepted = 0;
1452 lpservicestatus->dwWin32ExitCode = NO_ERROR;
1453 lpservicestatus->dwServiceSpecificExitCode = 0;
1454 lpservicestatus->dwCheckPoint = 0;
1455 lpservicestatus->dwWaitHint = 0;
1457 return TRUE;
1460 /******************************************************************************
1461 * QueryServiceStatusEx [ADVAPI32.@]
1463 * Get information about a service.
1465 * PARAMS
1466 * hService [I] Handle to service to get information about
1467 * InfoLevel [I] Level of information to get
1468 * lpBuffer [O] Destination for requested information
1469 * cbBufSize [I] Size of lpBuffer in bytes
1470 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1472 * RETURNS
1473 * Success: TRUE
1474 * FAILURE: FALSE
1476 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1477 LPBYTE lpBuffer, DWORD cbBufSize,
1478 LPDWORD pcbBytesNeeded)
1480 FIXME("stub\n");
1481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1482 return FALSE;
1485 /******************************************************************************
1486 * QueryServiceConfigA [ADVAPI32.@]
1488 BOOL WINAPI
1489 QueryServiceConfigA( SC_HANDLE hService,
1490 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1491 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1493 static const CHAR szDisplayName[] = "DisplayName";
1494 static const CHAR szType[] = "Type";
1495 static const CHAR szStart[] = "Start";
1496 static const CHAR szError[] = "ErrorControl";
1497 static const CHAR szImagePath[] = "ImagePath";
1498 static const CHAR szGroup[] = "Group";
1499 static const CHAR szDependencies[] = "Dependencies";
1500 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1501 CHAR str_buffer[ MAX_PATH ];
1502 LONG r;
1503 DWORD type, val, sz, total, n;
1504 LPBYTE p;
1506 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1507 cbBufSize, pcbBytesNeeded);
1509 /* calculate the size required first */
1510 total = sizeof (QUERY_SERVICE_CONFIGA);
1512 sz = sizeof(str_buffer);
1513 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1514 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1516 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1517 if( 0 == sz ) return FALSE;
1519 total += sz;
1521 else
1523 /* FIXME: set last error */
1524 return FALSE;
1527 sz = 0;
1528 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1529 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1530 total += sz;
1532 sz = 0;
1533 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1534 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1535 total += sz;
1537 sz = 0;
1538 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1539 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1540 total += sz;
1542 sz = 0;
1543 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1544 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1545 total += sz;
1547 /* if there's not enough memory, return an error */
1548 if( total > *pcbBytesNeeded )
1550 *pcbBytesNeeded = total;
1551 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1552 return FALSE;
1555 *pcbBytesNeeded = total;
1556 ZeroMemory( lpServiceConfig, total );
1558 sz = sizeof val;
1559 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1560 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1561 lpServiceConfig->dwServiceType = val;
1563 sz = sizeof val;
1564 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1565 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1566 lpServiceConfig->dwStartType = val;
1568 sz = sizeof val;
1569 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1570 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1571 lpServiceConfig->dwErrorControl = val;
1573 /* now do the strings */
1574 p = (LPBYTE) &lpServiceConfig[1];
1575 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1577 sz = sizeof(str_buffer);
1578 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1579 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1581 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1582 if( 0 == sz || sz > n ) return FALSE;
1584 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1585 p += sz;
1586 n -= sz;
1588 else
1590 /* FIXME: set last error */
1591 return FALSE;
1594 sz = n;
1595 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1596 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1598 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1599 p += sz;
1600 n -= sz;
1603 sz = n;
1604 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1605 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1607 lpServiceConfig->lpDependencies = (LPSTR) p;
1608 p += sz;
1609 n -= sz;
1612 if( n < 0 )
1613 ERR("Buffer overflow!\n");
1615 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1616 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1618 return TRUE;
1621 /******************************************************************************
1622 * QueryServiceConfigW [ADVAPI32.@]
1624 BOOL WINAPI
1625 QueryServiceConfigW( SC_HANDLE hService,
1626 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1627 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1629 static const WCHAR szDisplayName[] = {
1630 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1631 static const WCHAR szType[] = {'T','y','p','e',0};
1632 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1633 static const WCHAR szError[] = {
1634 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1635 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1636 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1637 static const WCHAR szDependencies[] = {
1638 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1639 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1640 WCHAR str_buffer[ MAX_PATH ];
1641 LONG r;
1642 DWORD type, val, sz, total, n;
1643 LPBYTE p;
1645 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1646 cbBufSize, pcbBytesNeeded);
1648 /* calculate the size required first */
1649 total = sizeof (QUERY_SERVICE_CONFIGW);
1651 sz = sizeof(str_buffer);
1652 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1653 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1655 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1656 if( 0 == sz ) return FALSE;
1658 total += sizeof(WCHAR) * sz;
1660 else
1662 /* FIXME: set last error */
1663 return FALSE;
1666 sz = 0;
1667 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1668 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1669 total += sz;
1671 sz = 0;
1672 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1673 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1674 total += sz;
1676 sz = 0;
1677 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1678 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1679 total += sz;
1681 sz = 0;
1682 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1683 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1684 total += sz;
1686 /* if there's not enough memory, return an error */
1687 if( total > *pcbBytesNeeded )
1689 *pcbBytesNeeded = total;
1690 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1691 return FALSE;
1694 *pcbBytesNeeded = total;
1695 ZeroMemory( lpServiceConfig, total );
1697 sz = sizeof val;
1698 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1699 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1700 lpServiceConfig->dwServiceType = val;
1702 sz = sizeof val;
1703 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1704 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1705 lpServiceConfig->dwStartType = val;
1707 sz = sizeof val;
1708 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1709 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1710 lpServiceConfig->dwErrorControl = val;
1712 /* now do the strings */
1713 p = (LPBYTE) &lpServiceConfig[1];
1714 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1716 sz = sizeof(str_buffer);
1717 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1718 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1720 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1721 sz *= sizeof(WCHAR);
1722 if( 0 == sz || sz > n ) return FALSE;
1724 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1725 p += sz;
1726 n -= sz;
1728 else
1730 /* FIXME: set last error */
1731 return FALSE;
1734 sz = n;
1735 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1736 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1738 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1739 p += sz;
1740 n -= sz;
1743 sz = n;
1744 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1745 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1747 lpServiceConfig->lpDependencies = (LPWSTR) p;
1748 p += sz;
1749 n -= sz;
1752 if( n < 0 )
1753 ERR("Buffer overflow!\n");
1755 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1756 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1758 return TRUE;
1762 /******************************************************************************
1763 * GetServiceDisplayNameA [ADVAPI32.@]
1765 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1766 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1768 FIXME("%p %s %p %p\n", hSCManager,
1769 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1770 return FALSE;
1774 /******************************************************************************
1775 * GetServiceDisplayNameW [ADVAPI32.@]
1777 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1778 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1780 FIXME("%p %s %p %p\n", hSCManager,
1781 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1782 return FALSE;
1786 /******************************************************************************
1787 * ChangeServiceConfigW [ADVAPI32.@]
1789 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1790 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1791 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1792 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1794 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1795 hService, dwServiceType, dwStartType, dwErrorControl,
1796 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1797 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1798 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1799 return TRUE;
1802 /******************************************************************************
1803 * ChangeServiceConfigA [ADVAPI32.@]
1805 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1806 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1807 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1808 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1810 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1811 LPWSTR wServiceStartName, wPassword, wDisplayName;
1812 BOOL r;
1814 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1815 hService, dwServiceType, dwStartType, dwErrorControl,
1816 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1817 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1818 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1820 wBinaryPathName = SERV_dup( lpBinaryPathName );
1821 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1822 wDependencies = SERV_dupmulti( lpDependencies );
1823 wServiceStartName = SERV_dup( lpServiceStartName );
1824 wPassword = SERV_dup( lpPassword );
1825 wDisplayName = SERV_dup( lpDisplayName );
1827 r = ChangeServiceConfigW( hService, dwServiceType,
1828 dwStartType, dwErrorControl, wBinaryPathName,
1829 wLoadOrderGroup, lpdwTagId, wDependencies,
1830 wServiceStartName, wPassword, wDisplayName);
1832 SERV_free( wBinaryPathName );
1833 SERV_free( wLoadOrderGroup );
1834 SERV_free( wDependencies );
1835 SERV_free( wServiceStartName );
1836 SERV_free( wPassword );
1837 SERV_free( wDisplayName );
1839 return r;
1842 /******************************************************************************
1843 * ChangeServiceConfig2A [ADVAPI32.@]
1845 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1846 LPVOID lpInfo)
1848 BOOL r = FALSE;
1850 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
1852 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1854 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
1855 SERVICE_DESCRIPTIONW sdw;
1857 sdw.lpDescription = SERV_dup( sd->lpDescription );
1859 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
1861 SERV_free( sdw.lpDescription );
1863 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
1865 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
1866 SERVICE_FAILURE_ACTIONSW faw;
1868 faw.dwResetPeriod = fa->dwResetPeriod;
1869 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
1870 faw.lpCommand = SERV_dup( fa->lpCommand );
1871 faw.cActions = fa->cActions;
1872 faw.lpsaActions = fa->lpsaActions;
1874 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
1876 SERV_free( faw.lpRebootMsg );
1877 SERV_free( faw.lpCommand );
1879 else
1880 SetLastError( ERROR_INVALID_PARAMETER );
1882 return r;
1885 /******************************************************************************
1886 * ChangeServiceConfig2W [ADVAPI32.@]
1888 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1889 LPVOID lpInfo)
1891 HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1893 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1895 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1896 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1897 if (sd->lpDescription)
1899 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1900 if (sd->lpDescription[0] == 0)
1901 RegDeleteValueW(hKey,szDescription);
1902 else
1903 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1904 (LPVOID)sd->lpDescription,
1905 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1908 else
1909 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1910 return TRUE;
1913 /******************************************************************************
1914 * QueryServiceObjectSecurity [ADVAPI32.@]
1916 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1917 SECURITY_INFORMATION dwSecurityInformation,
1918 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1919 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1921 PACL pACL = NULL;
1922 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1923 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1926 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
1928 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
1929 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
1930 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
1931 return TRUE;
1934 /******************************************************************************
1935 * SetServiceObjectSecurity [ADVAPI32.@]
1937 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1938 SECURITY_INFORMATION dwSecurityInformation,
1939 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1941 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1942 return TRUE;