2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31 #include "wine/unicode.h"
32 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
37 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
38 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
39 'S','e','r','v','i','c','e','s','\\',0 };
40 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
42 static const WCHAR szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_',
43 'S','E','B','_','%','s',0};
44 static const WCHAR szServiceDispEventNameFmtW[] = {'A','D','V','A','P','I','_',
45 'D','I','S','P','_','%','s',0};
46 static const WCHAR szServiceMutexNameFmtW[] = {'A','D','V','A','P','I','_',
47 'M','U','X','_','%','s',0};
48 static const WCHAR szServiceAckEventNameFmtW[] = {'A','D','V','A','P','I','_',
49 'A','C','K','_','%','s',0};
50 static const WCHAR szWaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
51 'a','i','t','S','e','r','v','i',
52 'c','e','S','t','a','r','t',0};
54 struct SEB /* service environment block */
55 { /* resides in service's shared memory object */
56 DWORD control_code; /* service control code */
57 DWORD dispatcher_error; /* set by dispatcher if it fails to invoke control handler */
58 SERVICE_STATUS status;
60 /* variable part of SEB contains service arguments */
63 static HANDLE dispatcher_event; /* this is used by service thread to wakeup
64 * service control dispatcher when thread terminates */
66 static struct service_thread_data *service; /* FIXME: this should be a list */
68 /******************************************************************************
72 #define MAX_SERVICE_NAME 256
74 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
77 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
83 sc_handle_destructor destroy;
86 struct sc_manager /* service control manager handle */
89 HKEY hkey; /* handle to services database in the registry */
92 struct sc_service /* service handle */
95 HKEY hkey; /* handle to service entry in the registry (under hkey) */
96 struct sc_manager *scm; /* pointer to SCM handle */
100 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
101 sc_handle_destructor destroy)
103 struct sc_handle *hdr;
105 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
110 hdr->destroy = destroy;
112 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
116 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
118 struct sc_handle *hdr = (struct sc_handle *) handle;
122 if (hdr->htype != htype)
127 static void sc_handle_free(struct sc_handle* hdr)
131 if (--hdr->ref_count)
134 HeapFree(GetProcessHeap(), 0, hdr);
137 static void sc_handle_destroy_manager(struct sc_handle *handle)
139 struct sc_manager *mgr = (struct sc_manager*) handle;
141 TRACE("destroying SC Manager %p\n", mgr);
143 RegCloseKey(mgr->hkey);
146 static void sc_handle_destroy_service(struct sc_handle *handle)
148 struct sc_service *svc = (struct sc_service*) handle;
150 TRACE("destroying service %p\n", svc);
152 RegCloseKey(svc->hkey);
154 sc_handle_free(&svc->scm->hdr);
158 /******************************************************************************
159 * String management functions
161 static inline LPWSTR SERV_dup( LPCSTR str )
168 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
169 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
170 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
174 static inline LPWSTR SERV_dupmulti( LPCSTR str )
182 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
183 n += (strlen( &str[n] ) + 1);
188 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
189 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
193 static inline VOID SERV_free( LPWSTR wstr )
195 HeapFree( GetProcessHeap(), 0, wstr );
198 /******************************************************************************
201 * helper function for service control dispatcher
203 * SCM database is locked by StartService;
204 * open global SCM lock object and read service name
206 static BOOL read_scm_lock_data( LPWSTR buffer )
211 hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
214 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
217 argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
218 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
221 CloseHandle( hLock );
224 strcpyW( buffer, argptr );
225 UnmapViewOfFile( argptr );
226 CloseHandle( hLock );
230 /******************************************************************************
233 * helper function for service control dispatcher
235 static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
237 WCHAR object_name[ MAX_PATH ];
241 snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
242 hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
246 ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
250 *hServiceShmem = hmem;
254 /******************************************************************************
257 * helper function for start_new_service
259 * Allocate and initialize array of LPWSTRs to arguments in variable part
260 * of service environment block.
261 * First entry in the array is reserved for service name and not initialized.
263 static LPWSTR* build_arg_vectors( struct SEB* seb )
269 ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
273 argptr = (LPWSTR) &seb[1];
274 for( i = 0; i < seb->argc; i++ )
276 ret[ 1 + i ] = argptr;
277 argptr += 1 + strlenW( argptr );
282 /******************************************************************************
285 struct service_thread_data
287 WCHAR service_name[ MAX_SERVICE_NAME ];
288 CHAR service_nameA[ MAX_SERVICE_NAME ];
289 LPSERVICE_MAIN_FUNCTIONW service_main;
292 HANDLE hServiceShmem;
294 HANDLE thread_handle;
295 HANDLE mutex; /* provides serialization of control request */
296 HANDLE ack_event; /* control handler completion acknowledgement */
297 LPHANDLER_FUNCTION ctrl_handler;
300 static DWORD WINAPI service_thread( LPVOID arg )
302 struct service_thread_data *data = arg;
304 data->service_main( data->argc, data->argv );
305 SetEvent( dispatcher_event );
309 /******************************************************************************
310 * dispose_service_thread_data
312 * helper function for service control dispatcher
314 static void dispose_service_thread_data( struct service_thread_data* thread_data )
316 if( thread_data->mutex ) CloseHandle( thread_data->mutex );
317 if( thread_data->ack_event ) CloseHandle( thread_data->ack_event );
318 HeapFree( GetProcessHeap(), 0, thread_data->argv );
319 if( thread_data->seb ) UnmapViewOfFile( thread_data->seb );
320 if( thread_data->hServiceShmem ) CloseHandle( thread_data->hServiceShmem );
321 HeapFree( GetProcessHeap(), 0, thread_data );
324 /******************************************************************************
327 * helper function for service control dispatcher
329 static struct service_thread_data*
330 start_new_service( LPSERVICE_MAIN_FUNCTIONW service_main, BOOL ascii )
332 struct service_thread_data *thread_data;
334 WCHAR object_name[ MAX_PATH ];
336 thread_data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct service_thread_data) );
337 if( NULL == thread_data )
340 if( ! read_scm_lock_data( thread_data->service_name ) )
342 /* FIXME: Instead of exiting we allow
343 service to be executed as ordinary program.
344 This behaviour was specially introduced in the patch
345 submitted against revision 1.45 and so preserved here.
347 FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
348 service_main( 0, NULL );
349 HeapFree( GetProcessHeap(), 0, thread_data );
353 thread_data->seb = open_seb_shmem( thread_data->service_name, &thread_data->hServiceShmem );
354 if( NULL == thread_data->seb )
357 thread_data->argv = build_arg_vectors( thread_data->seb );
358 if( NULL == thread_data->argv )
361 thread_data->argv[0] = thread_data->service_name;
362 thread_data->argc = thread_data->seb->argc + 1;
366 /* Convert the Unicode arg vectors back to ASCII;
367 * but we'll need unicode service name (argv[0]) for object names */
368 WideCharToMultiByte( CP_ACP, 0, thread_data->argv[0], -1,
369 thread_data->service_nameA, MAX_SERVICE_NAME, NULL, NULL );
370 thread_data->argv[0] = (LPWSTR) thread_data->service_nameA;
372 for(i=1; i<thread_data->argc; i++)
374 LPWSTR src = thread_data->argv[i];
375 int len = WideCharToMultiByte( CP_ACP, 0, src, -1, NULL, 0, NULL, NULL );
376 LPSTR dest = HeapAlloc( GetProcessHeap(), 0, len );
379 WideCharToMultiByte( CP_ACP, 0, src, -1, dest, len, NULL, NULL );
380 /* copy converted string back */
381 memcpy( src, dest, len );
382 HeapFree( GetProcessHeap(), 0, dest );
386 /* init status according to docs for StartService */
387 thread_data->seb->status.dwCurrentState = SERVICE_START_PENDING;
388 thread_data->seb->status.dwControlsAccepted = 0;
389 thread_data->seb->status.dwCheckPoint = 0;
390 thread_data->seb->status.dwWaitHint = 2000;
392 /* create service mutex; mutex is initially owned */
393 snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, thread_data->service_name );
394 thread_data->mutex = CreateMutexW( NULL, TRUE, object_name );
395 if( NULL == thread_data->mutex )
398 if( ERROR_ALREADY_EXISTS == GetLastError() )
400 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
404 /* create service event */
405 snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, thread_data->service_name );
406 thread_data->ack_event = CreateEventW( NULL, FALSE, FALSE, object_name );
407 if( NULL == thread_data->ack_event )
410 if( ERROR_ALREADY_EXISTS == GetLastError() )
412 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
416 /* create service thread in suspended state
417 * to avoid race while caller handles return value */
418 thread_data->service_main = service_main;
419 thread_data->thread_handle = CreateThread( NULL, 0, service_thread,
420 thread_data, CREATE_SUSPENDED, NULL );
421 if( thread_data->thread_handle )
425 dispose_service_thread_data( thread_data );
429 /******************************************************************************
430 * service_ctrl_dispatcher
432 static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii )
434 WCHAR object_name[ MAX_PATH ];
437 /* FIXME: if shared service, find entry by service name */
439 /* FIXME: move this into dispatcher loop */
440 service = start_new_service( servent->lpServiceProc, ascii );
441 if( NULL == service )
444 ResumeThread( service->thread_handle );
446 /* create dispatcher event object */
447 /* FIXME: object_name should be based on executable image path because
448 * this object is common for all services in the process */
449 /* But what if own and shared services have the same executable? */
450 snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, service->service_name );
451 dispatcher_event = CreateEventW( NULL, FALSE, FALSE, object_name );
452 if( NULL == dispatcher_event )
454 dispose_service_thread_data( service );
458 if( ERROR_ALREADY_EXISTS == GetLastError() )
460 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
461 CloseHandle( dispatcher_event );
465 /* ready to accept control requests */
466 ReleaseMutex( service->mutex );
468 /* signal for StartService */
469 wait = OpenSemaphoreW( SEMAPHORE_MODIFY_STATE, FALSE, szWaitServiceStartW );
472 ReleaseSemaphore( wait, 1, NULL );
476 /* dispatcher loop */
481 WaitForSingleObject( dispatcher_event, INFINITE );
483 /* at first, look for terminated service thread
484 * FIXME: threads, if shared service */
485 if( !GetExitCodeThread( service->thread_handle, &ret ) )
486 ERR("Couldn't get thread exit code\n");
487 else if( ret != STILL_ACTIVE )
489 CloseHandle( service->thread_handle );
490 dispose_service_thread_data( service );
494 /* look for control requests */
495 if( service->seb->control_code )
497 if( NULL == service->ctrl_handler )
498 service->seb->dispatcher_error = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
501 service->ctrl_handler( service->seb->control_code );
502 service->seb->dispatcher_error = 0;
504 service->seb->control_code = 0;
505 SetEvent( service->ack_event );
508 /* FIXME: if shared service, check SCM lock object;
509 * if exists, a new service should be started */
512 CloseHandle( dispatcher_event );
516 /******************************************************************************
517 * StartServiceCtrlDispatcherA [ADVAPI32.@]
520 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
523 LPSERVICE_TABLE_ENTRYW ServiceTableW;
526 TRACE("(%p)\n", servent);
528 /* convert service table to unicode */
529 for( count = 0; servent[ count ].lpServiceName; )
531 ServiceTableW = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(SERVICE_TABLE_ENTRYW) );
532 if( NULL == ServiceTableW )
535 for( i = 0; i < count; i++ )
537 ServiceTableW[ i ].lpServiceName = SERV_dup( servent[ i ].lpServiceName );
538 ServiceTableW[ i ].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONW) servent[ i ].lpServiceProc;
540 ServiceTableW[ count ].lpServiceName = NULL;
541 ServiceTableW[ count ].lpServiceProc = NULL;
543 /* start dispatcher */
544 ret = service_ctrl_dispatcher( ServiceTableW, TRUE );
546 /* free service table */
547 for( i = 0; i < count; i++ )
548 SERV_free( ServiceTableW[ i ].lpServiceName );
549 HeapFree( GetProcessHeap(), 0, ServiceTableW );
553 /******************************************************************************
554 * StartServiceCtrlDispatcherW [ADVAPI32.@]
560 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
562 TRACE("(%p)\n", servent);
563 return service_ctrl_dispatcher( servent, FALSE );
566 /******************************************************************************
567 * LockServiceDatabase [ADVAPI32.@]
569 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
573 TRACE("%p\n",hSCManager);
575 ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
576 0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
577 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
581 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
584 TRACE("returning %p\n", ret);
589 /******************************************************************************
590 * UnlockServiceDatabase [ADVAPI32.@]
592 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
594 TRACE("%p\n",ScLock);
596 return CloseHandle( (HANDLE) ScLock );
599 /******************************************************************************
600 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
602 SERVICE_STATUS_HANDLE WINAPI
603 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
604 LPHANDLER_FUNCTION lpfHandler )
606 LPWSTR lpServiceNameW;
607 SERVICE_STATUS_HANDLE ret;
609 lpServiceNameW = SERV_dup(lpServiceName);
610 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
611 SERV_free(lpServiceNameW);
615 /******************************************************************************
616 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
622 SERVICE_STATUS_HANDLE WINAPI
623 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
624 LPHANDLER_FUNCTION lpfHandler )
626 /* FIXME: find service thread data by service name */
628 service->ctrl_handler = lpfHandler;
632 /******************************************************************************
633 * SetServiceStatus [ADVAPI32.@]
640 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
644 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
645 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
646 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
647 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
648 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
649 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
650 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
652 /* FIXME: find service thread data by status handle */
654 /* acquire mutex; note that mutex may already be owned
655 * when service handles control request
657 r = WaitForSingleObject( service->mutex, 0 );
658 memcpy( &service->seb->status, lpStatus, sizeof(SERVICE_STATUS) );
659 if( WAIT_OBJECT_0 == r || WAIT_ABANDONED == r )
660 ReleaseMutex( service->mutex );
664 /******************************************************************************
665 * OpenSCManagerA [ADVAPI32.@]
667 * Establish a connection to the service control manager and open its database.
670 * lpMachineName [I] Pointer to machine name string
671 * lpDatabaseName [I] Pointer to database name string
672 * dwDesiredAccess [I] Type of access
675 * Success: A Handle to the service control manager database
678 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
679 DWORD dwDesiredAccess )
681 LPWSTR lpMachineNameW, lpDatabaseNameW;
684 lpMachineNameW = SERV_dup(lpMachineName);
685 lpDatabaseNameW = SERV_dup(lpDatabaseName);
686 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
687 SERV_free(lpDatabaseNameW);
688 SERV_free(lpMachineNameW);
692 /******************************************************************************
693 * OpenSCManagerW [ADVAPI32.@]
695 * See OpenSCManagerA.
697 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
698 DWORD dwDesiredAccess )
700 struct sc_manager *manager;
704 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
705 debugstr_w(lpDatabaseName), dwDesiredAccess);
707 if( lpDatabaseName && lpDatabaseName[0] )
709 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
711 /* noop, all right */
713 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
715 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
720 SetLastError( ERROR_INVALID_NAME );
725 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
726 sc_handle_destroy_manager );
730 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
731 if (r!=ERROR_SUCCESS)
734 r = RegOpenKeyExW(hReg, szServiceManagerKey,
735 0, KEY_ALL_ACCESS, &manager->hkey);
737 if (r!=ERROR_SUCCESS)
740 TRACE("returning %p\n", manager);
742 return (SC_HANDLE) &manager->hdr;
745 sc_handle_free( &manager->hdr );
749 /******************************************************************************
750 * ControlService [ADVAPI32.@]
752 * Send a control code to a service.
755 * hService [I] Handle of the service control manager database
756 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
757 * lpServiceStatus [O] Destination for the status of the service, if available
764 * Unlike M$' implementation, control requests are not serialized and may be
765 * processed asynchronously.
767 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
768 LPSERVICE_STATUS lpServiceStatus )
770 struct sc_service *hsvc;
771 WCHAR object_name[ MAX_PATH ];
772 HANDLE mutex = NULL, shmem = NULL;
773 HANDLE disp_event = NULL, ack_event = NULL;
774 struct SEB *seb = NULL;
776 BOOL ret = FALSE, mutex_owned = FALSE;
778 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
781 SetLastError( ERROR_INVALID_HANDLE );
785 TRACE("%p(%s) %ld %p\n", hService, debugstr_w(hsvc->name),
786 dwControl, lpServiceStatus);
788 /* open and hold mutex */
789 snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->name );
790 mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
793 SetLastError( ERROR_SERVICE_NOT_ACTIVE );
797 r = WaitForSingleObject( mutex, 30000 );
798 if( WAIT_FAILED == r )
801 if( WAIT_TIMEOUT == r )
803 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
808 /* open event objects */
809 snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, hsvc->name );
810 disp_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
811 if( NULL == disp_event )
814 snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, hsvc->name );
815 ack_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
816 if( NULL == ack_event )
819 /* get service environment block */
820 seb = open_seb_shmem( hsvc->name, &shmem );
825 /* FIXME: check dwControl against controls accepted */
826 seb->control_code = dwControl;
827 SetEvent( disp_event );
829 /* wait for acknowledgement */
830 r = WaitForSingleObject( ack_event, 30000 );
831 if( WAIT_FAILED == r )
834 if( WAIT_TIMEOUT == r )
836 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
840 if( seb->dispatcher_error )
842 SetLastError( seb->dispatcher_error );
847 if( lpServiceStatus )
848 memcpy( lpServiceStatus, &seb->status, sizeof(SERVICE_STATUS) );
852 if( seb ) UnmapViewOfFile( seb );
853 if( shmem ) CloseHandle( shmem );
854 if( ack_event ) CloseHandle( ack_event );
855 if( disp_event ) CloseHandle( disp_event );
856 if( mutex_owned ) ReleaseMutex( mutex );
857 if( mutex ) CloseHandle( mutex );
861 /******************************************************************************
862 * CloseServiceHandle [ADVAPI32.@]
864 * Close a handle to a service or the service control manager database.
867 * hSCObject [I] Handle to service or service control manager database
874 CloseServiceHandle( SC_HANDLE hSCObject )
876 TRACE("%p\n", hSCObject);
878 sc_handle_free( (struct sc_handle*) hSCObject );
884 /******************************************************************************
885 * OpenServiceA [ADVAPI32.@]
887 * Open a handle to a service.
890 * hSCManager [I] Handle of the service control manager database
891 * lpServiceName [I] Name of the service to open
892 * dwDesiredAccess [I] Access required to the service
895 * Success: Handle to the service
898 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
899 DWORD dwDesiredAccess )
901 LPWSTR lpServiceNameW;
904 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
906 lpServiceNameW = SERV_dup(lpServiceName);
907 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
908 SERV_free(lpServiceNameW);
913 /******************************************************************************
914 * OpenServiceW [ADVAPI32.@]
918 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
919 DWORD dwDesiredAccess)
921 struct sc_manager *hscm;
922 struct sc_service *hsvc;
927 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
931 SetLastError(ERROR_INVALID_ADDRESS);
935 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
938 SetLastError( ERROR_INVALID_HANDLE );
942 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
943 if (r!=ERROR_SUCCESS)
945 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
949 len = strlenW(lpServiceName)+1;
950 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
951 sizeof (struct sc_service) + len*sizeof(WCHAR),
952 sc_handle_destroy_service );
955 strcpyW( hsvc->name, lpServiceName );
958 /* add reference to SCM handle */
959 hscm->hdr.ref_count++;
962 TRACE("returning %p\n",hsvc);
964 return (SC_HANDLE) &hsvc->hdr;
967 /******************************************************************************
968 * CreateServiceW [ADVAPI32.@]
971 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
972 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
973 DWORD dwServiceType, DWORD dwStartType,
974 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
975 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
976 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
979 struct sc_manager *hscm;
980 struct sc_service *hsvc = NULL;
984 static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
985 static const WCHAR szType[] = {'T','y','p','e',0};
986 static const WCHAR szStart[] = {'S','t','a','r','t',0};
987 static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
988 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
989 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
990 static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
992 FIXME("%p %s %s\n", hSCManager,
993 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
995 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
998 SetLastError( ERROR_INVALID_HANDLE );
1002 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1003 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1004 if (r!=ERROR_SUCCESS)
1007 if (dp != REG_CREATED_NEW_KEY)
1009 SetLastError(ERROR_SERVICE_EXISTS);
1015 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (const BYTE*)lpDisplayName,
1016 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
1017 if (r!=ERROR_SUCCESS)
1021 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
1022 if (r!=ERROR_SUCCESS)
1025 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
1026 if (r!=ERROR_SUCCESS)
1029 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
1030 (LPVOID)&dwErrorControl, sizeof (DWORD) );
1031 if (r!=ERROR_SUCCESS)
1034 if(lpBinaryPathName)
1036 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (const BYTE*)lpBinaryPathName,
1037 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
1038 if (r!=ERROR_SUCCESS)
1042 if(lpLoadOrderGroup)
1044 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (const BYTE*)lpLoadOrderGroup,
1045 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
1046 if (r!=ERROR_SUCCESS)
1054 /* determine the length of a double null terminated multi string */
1056 len += (strlenW(&lpDependencies[len])+1);
1057 } while (lpDependencies[len++]);
1059 r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
1060 (const BYTE*)lpDependencies, len );
1061 if (r!=ERROR_SUCCESS)
1067 FIXME("Don't know how to add a Password for a service.\n");
1070 if(lpServiceStartName)
1072 FIXME("Don't know how to add a ServiceStartName for a service.\n");
1075 len = strlenW(lpServiceName)+1;
1076 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1077 sizeof (struct sc_service) + len*sizeof(WCHAR),
1078 sc_handle_destroy_service );
1081 strcpyW( hsvc->name, lpServiceName );
1084 hscm->hdr.ref_count++;
1086 return (SC_HANDLE) &hsvc->hdr;
1090 sc_handle_free( &hsvc->hdr );
1095 /******************************************************************************
1096 * CreateServiceA [ADVAPI32.@]
1099 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1100 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1101 DWORD dwServiceType, DWORD dwStartType,
1102 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1103 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1104 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1107 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1108 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1111 TRACE("%p %s %s\n", hSCManager,
1112 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1114 lpServiceNameW = SERV_dup( lpServiceName );
1115 lpDisplayNameW = SERV_dup( lpDisplayName );
1116 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1117 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1118 lpDependenciesW = SERV_dupmulti( lpDependencies );
1119 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1120 lpPasswordW = SERV_dup( lpPassword );
1122 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1123 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1124 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1125 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1127 SERV_free( lpServiceNameW );
1128 SERV_free( lpDisplayNameW );
1129 SERV_free( lpBinaryPathNameW );
1130 SERV_free( lpLoadOrderGroupW );
1131 SERV_free( lpDependenciesW );
1132 SERV_free( lpServiceStartNameW );
1133 SERV_free( lpPasswordW );
1139 /******************************************************************************
1140 * DeleteService [ADVAPI32.@]
1142 * Delete a service from the service control manager database.
1145 * hService [I] Handle of the service to delete
1151 BOOL WINAPI DeleteService( SC_HANDLE hService )
1153 struct sc_service *hsvc;
1155 WCHAR valname[MAX_PATH+1];
1160 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1163 SetLastError( ERROR_INVALID_HANDLE );
1169 /* Clean out the values */
1170 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1171 while (rc == ERROR_SUCCESS)
1173 RegDeleteValueW(hKey,valname);
1176 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1182 /* delete the key */
1183 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1189 /******************************************************************************
1190 * StartServiceA [ADVAPI32.@]
1195 * hService [I] Handle of service
1196 * dwNumServiceArgs [I] Number of arguments
1197 * lpServiceArgVectors [I] Address of array of argument strings
1200 * - NT implements this function using an obscure RPC call.
1201 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1202 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1203 * - This will only work for shared address space. How should the service
1204 * args be transferred when address spaces are separated?
1205 * - Can only start one service at a time.
1206 * - Has no concept of privilege.
1213 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1214 LPCSTR *lpServiceArgVectors )
1216 LPWSTR *lpwstr=NULL;
1219 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1221 if(dwNumServiceArgs)
1222 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1223 dwNumServiceArgs*sizeof(LPWSTR) );
1225 for(i=0; i<dwNumServiceArgs; i++)
1226 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1228 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1230 if(dwNumServiceArgs)
1232 for(i=0; i<dwNumServiceArgs; i++)
1233 SERV_free(lpwstr[i]);
1234 HeapFree(GetProcessHeap(), 0, lpwstr);
1241 /******************************************************************************
1242 * StartServiceW [ADVAPI32.@]
1244 * See StartServiceA.
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_service *hsvc;
1253 WCHAR path[MAX_PATH],str[MAX_PATH];
1258 HANDLE hServiceShmem = NULL;
1260 LPWSTR shmem_lock = NULL;
1261 struct SEB *seb = NULL;
1263 PROCESS_INFORMATION procinfo;
1264 STARTUPINFOW startupinfo;
1267 TRACE("%p %ld %p\n",hService,dwNumServiceArgs,
1268 lpServiceArgVectors);
1270 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1273 SetLastError( ERROR_INVALID_HANDLE );
1278 r = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
1279 if (r!=ERROR_SUCCESS)
1281 ExpandEnvironmentStringsW(str,path,sizeof(path));
1283 TRACE("Starting service %s\n", debugstr_w(path) );
1285 hLock = LockServiceDatabase( (SC_HANDLE) &hsvc->scm->hdr );
1290 * FIXME: start dependent services
1293 /* pass argv[0] (service name) to the service via global SCM lock object */
1294 shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
1295 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
1296 if( NULL == shmem_lock )
1298 ERR("Couldn't map shared memory\n");
1301 strcpyW( shmem_lock, hsvc->name );
1303 /* create service environment block */
1304 size = sizeof(struct SEB);
1305 for( i = 0; i < dwNumServiceArgs; i++ )
1306 size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] ));
1308 snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->name );
1309 hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1310 NULL, PAGE_READWRITE, 0, size, str );
1311 if( NULL == hServiceShmem )
1313 ERR("Couldn't create shared memory object\n");
1316 if( GetLastError() == ERROR_ALREADY_EXISTS )
1318 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1321 seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1324 ERR("Couldn't map shared memory\n");
1328 /* copy service args to SEB */
1329 seb->argc = dwNumServiceArgs;
1330 argptr = (LPWSTR) &seb[1];
1331 for( i = 0; i < dwNumServiceArgs; i++ )
1333 strcpyW( argptr, lpServiceArgVectors[ i ] );
1334 argptr += 1 + strlenW( argptr );
1337 wait = CreateSemaphoreW(NULL,0,1,szWaitServiceStartW);
1340 ERR("Couldn't create wait semaphore\n");
1344 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1345 startupinfo.cb = sizeof(STARTUPINFOW);
1347 r = CreateProcessW(NULL,
1349 NULL, /* process security attribs */
1350 NULL, /* thread security attribs */
1351 FALSE, /* inherit handles */
1352 0, /* creation flags */
1353 NULL, /* environment */
1354 NULL, /* current directory */
1355 &startupinfo, /* startup info */
1356 &procinfo); /* process info */
1360 ERR("Couldn't start process\n");
1363 CloseHandle( procinfo.hThread );
1365 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1366 r = WaitForSingleObject(wait,30000);
1367 if( WAIT_FAILED == r )
1369 CloseHandle( procinfo.hProcess );
1372 if( WAIT_TIMEOUT == r )
1374 TerminateProcess( procinfo.hProcess, 1 );
1375 CloseHandle( procinfo.hProcess );
1376 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
1381 CloseHandle( procinfo.hProcess );
1385 if( wait ) CloseHandle( wait );
1386 if( seb != NULL ) UnmapViewOfFile( seb );
1387 if( hServiceShmem != NULL ) CloseHandle( hServiceShmem );
1388 if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock );
1389 UnlockServiceDatabase( hLock );
1393 /******************************************************************************
1394 * QueryServiceStatus [ADVAPI32.@]
1398 * lpservicestatus []
1402 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1404 struct sc_service *hsvc;
1406 DWORD type, val, size;
1407 WCHAR object_name[ MAX_PATH ];
1408 HANDLE mutex, shmem = NULL;
1409 struct SEB *seb = NULL;
1410 BOOL ret = FALSE, mutex_owned = FALSE;
1412 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1415 SetLastError( ERROR_INVALID_HANDLE );
1419 /* try to open service mutex */
1420 snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->name );
1421 mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
1426 r = WaitForSingleObject( mutex, 30000 );
1427 if( WAIT_FAILED == r )
1430 if( WAIT_TIMEOUT == r )
1432 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
1437 /* get service environment block */
1438 seb = open_seb_shmem( hsvc->name, &shmem );
1443 memcpy( lpservicestatus, &seb->status, sizeof(SERVICE_STATUS) );
1447 if( seb ) UnmapViewOfFile( seb );
1448 if( shmem ) CloseHandle( shmem );
1449 if( mutex_owned ) ReleaseMutex( mutex );
1450 CloseHandle( mutex );
1454 /* service stopped */
1455 /* read the service type from the registry */
1457 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1460 ERR("invalid Type\n");
1463 lpservicestatus->dwServiceType = val;
1464 lpservicestatus->dwCurrentState = 1; /* stopped */
1465 lpservicestatus->dwControlsAccepted = 0;
1466 lpservicestatus->dwWin32ExitCode = NO_ERROR;
1467 lpservicestatus->dwServiceSpecificExitCode = 0;
1468 lpservicestatus->dwCheckPoint = 0;
1469 lpservicestatus->dwWaitHint = 0;
1474 /******************************************************************************
1475 * QueryServiceStatusEx [ADVAPI32.@]
1477 * Get information about a service.
1480 * hService [I] Handle to service to get information about
1481 * InfoLevel [I] Level of information to get
1482 * lpBuffer [O] Destination for requested information
1483 * cbBufSize [I] Size of lpBuffer in bytes
1484 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1490 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1491 LPBYTE lpBuffer, DWORD cbBufSize,
1492 LPDWORD pcbBytesNeeded)
1495 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1499 /******************************************************************************
1500 * QueryServiceConfigA [ADVAPI32.@]
1503 QueryServiceConfigA( SC_HANDLE hService,
1504 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1505 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1507 static const CHAR szDisplayName[] = "DisplayName";
1508 static const CHAR szType[] = "Type";
1509 static const CHAR szStart[] = "Start";
1510 static const CHAR szError[] = "ErrorControl";
1511 static const CHAR szImagePath[] = "ImagePath";
1512 static const CHAR szGroup[] = "Group";
1513 static const CHAR szDependencies[] = "Dependencies";
1514 struct sc_service *hsvc;
1516 CHAR str_buffer[ MAX_PATH ];
1518 DWORD type, val, sz, total, n;
1521 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1522 cbBufSize, pcbBytesNeeded);
1524 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1527 SetLastError( ERROR_INVALID_HANDLE );
1532 /* calculate the size required first */
1533 total = sizeof (QUERY_SERVICE_CONFIGA);
1535 sz = sizeof(str_buffer);
1536 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1537 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1539 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1540 if( 0 == sz ) return FALSE;
1546 /* FIXME: set last error */
1551 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1552 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1556 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1557 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1561 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1562 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1566 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1567 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1570 /* if there's not enough memory, return an error */
1571 if( total > *pcbBytesNeeded )
1573 *pcbBytesNeeded = total;
1574 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1578 *pcbBytesNeeded = total;
1579 ZeroMemory( lpServiceConfig, total );
1582 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1583 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1584 lpServiceConfig->dwServiceType = val;
1587 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1588 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1589 lpServiceConfig->dwStartType = val;
1592 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1593 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1594 lpServiceConfig->dwErrorControl = val;
1596 /* now do the strings */
1597 p = (LPBYTE) &lpServiceConfig[1];
1598 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1600 sz = sizeof(str_buffer);
1601 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1602 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1604 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1605 if( 0 == sz || sz > n ) return FALSE;
1607 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1613 /* FIXME: set last error */
1618 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1619 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1621 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1627 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1628 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1630 lpServiceConfig->lpDependencies = (LPSTR) p;
1636 ERR("Buffer overflow!\n");
1638 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1639 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1644 /******************************************************************************
1645 * QueryServiceConfigW [ADVAPI32.@]
1648 QueryServiceConfigW( SC_HANDLE hService,
1649 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1650 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1652 static const WCHAR szDisplayName[] = {
1653 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1654 static const WCHAR szType[] = {'T','y','p','e',0};
1655 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1656 static const WCHAR szError[] = {
1657 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1658 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1659 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1660 static const WCHAR szDependencies[] = {
1661 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1662 WCHAR str_buffer[ MAX_PATH ];
1664 DWORD type, val, sz, total, n;
1667 struct sc_service *hsvc;
1669 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1670 cbBufSize, pcbBytesNeeded);
1672 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1675 SetLastError( ERROR_INVALID_HANDLE );
1680 /* calculate the size required first */
1681 total = sizeof (QUERY_SERVICE_CONFIGW);
1683 sz = sizeof(str_buffer);
1684 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1685 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1687 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1688 if( 0 == sz ) return FALSE;
1690 total += sizeof(WCHAR) * sz;
1694 /* FIXME: set last error */
1699 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1700 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1704 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1705 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1709 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1710 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1714 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1715 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1718 /* if there's not enough memory, return an error */
1719 if( total > *pcbBytesNeeded )
1721 *pcbBytesNeeded = total;
1722 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1726 *pcbBytesNeeded = total;
1727 ZeroMemory( lpServiceConfig, total );
1730 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1731 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1732 lpServiceConfig->dwServiceType = val;
1735 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1736 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1737 lpServiceConfig->dwStartType = val;
1740 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1741 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1742 lpServiceConfig->dwErrorControl = val;
1744 /* now do the strings */
1745 p = (LPBYTE) &lpServiceConfig[1];
1746 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1748 sz = sizeof(str_buffer);
1749 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1750 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1752 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1753 sz *= sizeof(WCHAR);
1754 if( 0 == sz || sz > n ) return FALSE;
1756 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1762 /* FIXME: set last error */
1767 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1768 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1770 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1776 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1777 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1779 lpServiceConfig->lpDependencies = (LPWSTR) p;
1785 ERR("Buffer overflow!\n");
1787 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1788 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1793 /******************************************************************************
1794 * EnumServicesStatusA [ADVAPI32.@]
1797 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1798 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1799 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1800 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1802 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1803 dwServiceType, dwServiceState, lpServices, cbBufSize,
1804 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1805 SetLastError (ERROR_ACCESS_DENIED);
1809 /******************************************************************************
1810 * EnumServicesStatusW [ADVAPI32.@]
1813 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1814 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1815 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1816 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1818 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1819 dwServiceType, dwServiceState, lpServices, cbBufSize,
1820 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1821 SetLastError (ERROR_ACCESS_DENIED);
1825 /******************************************************************************
1826 * GetServiceKeyNameA [ADVAPI32.@]
1828 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1829 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1831 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1835 /******************************************************************************
1836 * GetServiceKeyNameW [ADVAPI32.@]
1838 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1839 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1841 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1845 /******************************************************************************
1846 * QueryServiceLockStatusA [ADVAPI32.@]
1848 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1849 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1850 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1852 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1857 /******************************************************************************
1858 * QueryServiceLockStatusW [ADVAPI32.@]
1860 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1861 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1862 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1864 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1869 /******************************************************************************
1870 * GetServiceDisplayNameA [ADVAPI32.@]
1872 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1873 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1875 FIXME("%p %s %p %p\n", hSCManager,
1876 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1880 /******************************************************************************
1881 * GetServiceDisplayNameW [ADVAPI32.@]
1883 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1884 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1886 FIXME("%p %s %p %p\n", hSCManager,
1887 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1891 /******************************************************************************
1892 * ChangeServiceConfigW [ADVAPI32.@]
1894 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1895 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1896 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1897 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1899 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1900 hService, dwServiceType, dwStartType, dwErrorControl,
1901 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1902 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1903 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1907 /******************************************************************************
1908 * ChangeServiceConfigA [ADVAPI32.@]
1910 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1911 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1912 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1913 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1915 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1916 LPWSTR wServiceStartName, wPassword, wDisplayName;
1919 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1920 hService, dwServiceType, dwStartType, dwErrorControl,
1921 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1922 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1923 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1925 wBinaryPathName = SERV_dup( lpBinaryPathName );
1926 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1927 wDependencies = SERV_dupmulti( lpDependencies );
1928 wServiceStartName = SERV_dup( lpServiceStartName );
1929 wPassword = SERV_dup( lpPassword );
1930 wDisplayName = SERV_dup( lpDisplayName );
1932 r = ChangeServiceConfigW( hService, dwServiceType,
1933 dwStartType, dwErrorControl, wBinaryPathName,
1934 wLoadOrderGroup, lpdwTagId, wDependencies,
1935 wServiceStartName, wPassword, wDisplayName);
1937 SERV_free( wBinaryPathName );
1938 SERV_free( wLoadOrderGroup );
1939 SERV_free( wDependencies );
1940 SERV_free( wServiceStartName );
1941 SERV_free( wPassword );
1942 SERV_free( wDisplayName );
1947 /******************************************************************************
1948 * ChangeServiceConfig2A [ADVAPI32.@]
1950 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1955 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
1957 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1959 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
1960 SERVICE_DESCRIPTIONW sdw;
1962 sdw.lpDescription = SERV_dup( sd->lpDescription );
1964 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
1966 SERV_free( sdw.lpDescription );
1968 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
1970 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
1971 SERVICE_FAILURE_ACTIONSW faw;
1973 faw.dwResetPeriod = fa->dwResetPeriod;
1974 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
1975 faw.lpCommand = SERV_dup( fa->lpCommand );
1976 faw.cActions = fa->cActions;
1977 faw.lpsaActions = fa->lpsaActions;
1979 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
1981 SERV_free( faw.lpRebootMsg );
1982 SERV_free( faw.lpCommand );
1985 SetLastError( ERROR_INVALID_PARAMETER );
1990 /******************************************************************************
1991 * ChangeServiceConfig2W [ADVAPI32.@]
1993 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1997 struct sc_service *hsvc;
1999 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2002 SetLastError( ERROR_INVALID_HANDLE );
2007 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2009 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2010 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2011 if (sd->lpDescription)
2013 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2014 if (sd->lpDescription[0] == 0)
2015 RegDeleteValueW(hKey,szDescription);
2017 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2018 (LPVOID)sd->lpDescription,
2019 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2023 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2027 /******************************************************************************
2028 * QueryServiceObjectSecurity [ADVAPI32.@]
2030 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2031 SECURITY_INFORMATION dwSecurityInformation,
2032 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2033 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2037 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2038 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2040 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2042 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2043 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2044 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2048 /******************************************************************************
2049 * SetServiceObjectSecurity [ADVAPI32.@]
2051 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2052 SECURITY_INFORMATION dwSecurityInformation,
2053 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2055 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2059 /******************************************************************************
2060 * SetServiceBits [ADVAPI32.@]
2062 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2063 DWORD dwServiceBits,
2065 BOOL bUpdateImmediately)
2067 FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2068 bSetBitsOn, bUpdateImmediately);