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
30 #include "wine/unicode.h"
31 #include "wine/debug.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',
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
;
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 /******************************************************************************
71 #define MAX_SERVICE_NAME 256
73 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
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
];
96 struct sc_manager manager
;
97 struct sc_service service
;
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
) );
108 retval
->htype
= htype
;
110 TRACE("SC_HANDLE type=%d -> %p\n",htype
,retval
);
114 static void free_sc_handle( struct sc_handle
* handle
)
119 switch( handle
->htype
)
121 case SC_HTYPE_MANAGER
:
123 if( InterlockedDecrement( &handle
->u
.manager
.ref_count
) )
124 /* there are references to this handle */
127 if( handle
->u
.manager
.hkey_scm_db
)
128 RegCloseKey( handle
->u
.manager
.hkey_scm_db
);
132 case SC_HTYPE_SERVICE
:
134 struct sc_handle
*h
= handle
->u
.service
.sc_manager
;
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
);
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
)
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
);
187 static inline LPWSTR
SERV_dupmulti( LPCSTR str
)
195 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
196 n
+= (strlen( &str
[n
] ) + 1);
201 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
202 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
206 static inline VOID
SERV_free( LPWSTR wstr
)
208 HeapFree( GetProcessHeap(), 0, wstr
);
211 /******************************************************************************
212 * EnumServicesStatusA [ADVAPI32.@]
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
);
226 /******************************************************************************
227 * EnumServicesStatusW [ADVAPI32.@]
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
);
241 /******************************************************************************
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
)
254 hLock
= OpenFileMappingW( FILE_MAP_ALL_ACCESS
, FALSE
, szSCMLock
);
257 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
);
260 argptr
= MapViewOfFile( hLock
, FILE_MAP_ALL_ACCESS
,
261 0, 0, MAX_SERVICE_NAME
* sizeof(WCHAR
) );
264 CloseHandle( hLock
);
267 strcpyW( buffer
, argptr
);
268 UnmapViewOfFile( argptr
);
269 CloseHandle( hLock
);
273 /******************************************************************************
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
];
284 snprintfW( object_name
, MAX_PATH
, szServiceShmemNameFmtW
, service_name
);
285 hmem
= OpenFileMappingW( FILE_MAP_ALL_ACCESS
, FALSE
, object_name
);
289 ret
= MapViewOfFile( hmem
, FILE_MAP_ALL_ACCESS
, 0, 0, 0 );
293 *hServiceShmem
= hmem
;
297 /******************************************************************************
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
)
312 ret
= HeapAlloc( GetProcessHeap(), 0, (1 + seb
->argc
) * sizeof(LPWSTR
) );
316 argptr
= (LPWSTR
) &seb
[1];
317 for( i
= 0; i
< seb
->argc
; i
++ )
319 ret
[ 1 + i
] = argptr
;
320 argptr
+= 1 + strlenW( argptr
);
325 /******************************************************************************
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
;
335 HANDLE hServiceShmem
;
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
);
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 /******************************************************************************
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
;
377 WCHAR object_name
[ MAX_PATH
];
379 thread_data
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct service_thread_data
) );
380 if( NULL
== thread_data
)
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
);
396 thread_data
->seb
= open_seb_shmem( thread_data
->service_name
, &thread_data
->hServiceShmem
);
397 if( NULL
== thread_data
->seb
)
400 thread_data
->argv
= build_arg_vectors( thread_data
->seb
);
401 if( NULL
== thread_data
->argv
)
404 thread_data
->argv
[0] = thread_data
->service_name
;
405 thread_data
->argc
= thread_data
->seb
->argc
+ 1;
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
);
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
)
441 if( ERROR_ALREADY_EXISTS
== GetLastError() )
443 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
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
)
453 if( ERROR_ALREADY_EXISTS
== GetLastError() )
455 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
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
)
468 dispose_service_thread_data( thread_data
);
472 /******************************************************************************
473 * service_ctrl_dispatcher
475 static BOOL
service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent
, BOOL ascii
)
477 WCHAR object_name
[ MAX_PATH
];
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
)
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
);
501 if( ERROR_ALREADY_EXISTS
== GetLastError() )
503 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
504 CloseHandle( dispatcher_event
);
508 /* ready to accept control requests */
509 ReleaseMutex( service
->mutex
);
511 /* signal for StartService */
512 wait
= OpenSemaphoreW( SEMAPHORE_MODIFY_STATE
, FALSE
, szWaitServiceStartW
);
515 ReleaseSemaphore( wait
, 1, NULL
);
519 /* dispatcher loop */
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
);
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
;
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
);
559 /******************************************************************************
560 * StartServiceCtrlDispatcherA [ADVAPI32.@]
563 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
566 LPSERVICE_TABLE_ENTRYW ServiceTableW
;
569 TRACE("(%p)\n", servent
);
571 /* convert service table to unicode */
572 for( count
= 0; servent
[ count
].lpServiceName
; )
574 ServiceTableW
= HeapAlloc( GetProcessHeap(), 0, (count
+ 1) * sizeof(SERVICE_TABLE_ENTRYW
) );
575 if( NULL
== ServiceTableW
)
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
);
596 /******************************************************************************
597 * StartServiceCtrlDispatcherW [ADVAPI32.@]
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
)
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
)
624 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
627 TRACE("returning %p\n", 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
);
658 /******************************************************************************
659 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
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
;
675 /******************************************************************************
676 * SetServiceStatus [ADVAPI32.@]
683 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
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
);
707 /******************************************************************************
708 * OpenSCManagerA [ADVAPI32.@]
710 * Establish a connection to the service control manager and open its database.
713 * lpMachineName [I] Pointer to machine name string
714 * lpDatabaseName [I] Pointer to database name string
715 * dwDesiredAccess [I] Type of access
718 * Success: A Handle to the service control manager database
721 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
722 DWORD dwDesiredAccess
)
724 UNICODE_STRING lpMachineNameW
;
725 UNICODE_STRING lpDatabaseNameW
;
728 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW
,lpMachineName
);
729 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW
,lpDatabaseName
);
730 ret
= OpenSCManagerW(lpMachineNameW
.Buffer
,lpDatabaseNameW
.Buffer
, dwDesiredAccess
);
731 RtlFreeUnicodeString(&lpDatabaseNameW
);
732 RtlFreeUnicodeString(&lpMachineNameW
);
736 /******************************************************************************
737 * OpenSCManagerW [ADVAPI32.@]
739 * See OpenSCManagerA.
741 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
742 DWORD dwDesiredAccess
)
744 struct sc_handle
*retval
;
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
);
764 SetLastError( ERROR_INVALID_NAME
);
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
)
778 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
779 0, KEY_ALL_ACCESS
, &retval
->u
.manager
.hkey_scm_db
);
781 if (r
!=ERROR_SUCCESS
)
784 TRACE("returning %p\n", retval
);
786 return (SC_HANDLE
) retval
;
789 free_sc_handle( retval
);
793 /******************************************************************************
794 * ControlService [ADVAPI32.@]
796 * Send a control code to a service.
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
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
;
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
);
827 SetLastError( ERROR_SERVICE_NOT_ACTIVE
);
831 r
= WaitForSingleObject( mutex
, 30000 );
832 if( WAIT_FAILED
== r
)
835 if( WAIT_TIMEOUT
== r
)
837 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT
);
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
)
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
)
853 /* get service environment block */
854 seb
= open_seb_shmem( hsvc
->u
.service
.name
, &shmem
);
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
)
868 if( WAIT_TIMEOUT
== r
)
870 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT
);
874 if( seb
->dispatcher_error
)
876 SetLastError( seb
->dispatcher_error
);
881 if( lpServiceStatus
)
882 memcpy( lpServiceStatus
, &seb
->status
, sizeof(SERVICE_STATUS
) );
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
);
895 /******************************************************************************
896 * CloseServiceHandle [ADVAPI32.@]
898 * Close a handle to a service or the service control manager database.
901 * hSCObject [I] Handle to service or service control manager database
908 CloseServiceHandle( SC_HANDLE hSCObject
)
910 TRACE("(%p)\n", hSCObject
);
912 free_sc_handle( (struct sc_handle
*) hSCObject
);
918 /******************************************************************************
919 * OpenServiceA [ADVAPI32.@]
921 * Open a handle to a service.
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
929 * Success: Handle to the service
932 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
933 DWORD dwDesiredAccess
)
935 UNICODE_STRING lpServiceNameW
;
937 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW
,lpServiceName
);
939 TRACE("Request for service %s\n",lpServiceName
);
942 ret
= OpenServiceW( hSCManager
, lpServiceNameW
.Buffer
, dwDesiredAccess
);
943 RtlFreeUnicodeString(&lpServiceNameW
);
948 /******************************************************************************
949 * OpenServiceW [ADVAPI32.@]
953 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
954 DWORD dwDesiredAccess
)
956 struct sc_handle
*hscm
= hSCManager
;
957 struct sc_handle
*retval
;
961 TRACE("(%p,%p,%ld)\n",hSCManager
, lpServiceName
,
964 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
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
);
977 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
979 TRACE("returning %p\n",retval
);
981 return (SC_HANDLE
) retval
;
984 /******************************************************************************
985 * CreateServiceW [ADVAPI32.@]
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
,
996 struct sc_handle
*hscm
= hSCManager
;
997 struct sc_handle
*retval
;
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
)
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
)
1021 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
1023 if (dp
!= REG_CREATED_NEW_KEY
)
1028 r
= RegSetValueExW(hKey
, szDisplayName
, 0, REG_SZ
, (const BYTE
*)lpDisplayName
,
1029 (strlenW(lpDisplayName
)+1)*sizeof(WCHAR
) );
1030 if (r
!=ERROR_SUCCESS
)
1034 r
= RegSetValueExW(hKey
, szType
, 0, REG_DWORD
, (LPVOID
)&dwServiceType
, sizeof (DWORD
) );
1035 if (r
!=ERROR_SUCCESS
)
1038 r
= RegSetValueExW(hKey
, szStart
, 0, REG_DWORD
, (LPVOID
)&dwStartType
, sizeof (DWORD
) );
1039 if (r
!=ERROR_SUCCESS
)
1042 r
= RegSetValueExW(hKey
, szError
, 0, REG_DWORD
,
1043 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
1044 if (r
!=ERROR_SUCCESS
)
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
)
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
)
1067 /* determine the length of a double null terminated multi string */
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
)
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
;
1091 free_sc_handle( retval
);
1096 /******************************************************************************
1097 * CreateServiceA [ADVAPI32.@]
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
,
1108 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1109 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
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
);
1140 /******************************************************************************
1141 * DeleteService [ADVAPI32.@]
1143 * Delete a service from the service control manager database.
1146 * hService [I] Handle of the service to delete
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];
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
);
1169 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
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
);
1183 /******************************************************************************
1184 * StartServiceA [ADVAPI32.@]
1189 * hService [I] Handle of service
1190 * dwNumServiceArgs [I] Number of arguments
1191 * lpServiceArgVectors [I] Address of array of argument strings
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.
1207 StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1208 LPCSTR
*lpServiceArgVectors
)
1210 LPWSTR
*lpwstr
=NULL
;
1211 UNICODE_STRING usBuffer
;
1214 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1216 if(dwNumServiceArgs
)
1217 lpwstr
= (LPWSTR
*) HeapAlloc( GetProcessHeap(), 0,
1218 dwNumServiceArgs
*sizeof(LPWSTR
) );
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
);
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_handle
*hsvc
= hService
;
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
);
1271 r
= RegQueryValueExW(hsvc
->u
.service
.hkey
, _ImagePathW
, NULL
, &type
, (LPVOID
)str
, &size
);
1272 if (r
!=ERROR_SUCCESS
)
1274 ExpandEnvironmentStringsW(str
,path
,sizeof(path
));
1276 TRACE("Starting service %s\n", debugstr_w(path
) );
1278 hLock
= LockServiceDatabase( hsvc
->u
.service
.sc_manager
);
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");
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");
1309 if( GetLastError() == ERROR_ALREADY_EXISTS
)
1311 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
1314 seb
= MapViewOfFile( hServiceShmem
, FILE_MAP_ALL_ACCESS
, 0, 0, 0 );
1317 ERR("Couldn't map shared memory\n");
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
);
1333 ERR("Couldn't create wait semaphore\n");
1337 ZeroMemory(&startupinfo
,sizeof(STARTUPINFOW
));
1338 startupinfo
.cb
= sizeof(STARTUPINFOW
);
1340 r
= CreateProcessW(NULL
,
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 */
1353 ERR("Couldn't start process\n");
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
);
1365 if( WAIT_TIMEOUT
== r
)
1367 TerminateProcess( procinfo
.hProcess
, 1 );
1368 CloseHandle( procinfo
.hProcess
);
1369 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT
);
1374 CloseHandle( procinfo
.hProcess
);
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
);
1386 /******************************************************************************
1387 * QueryServiceStatus [ADVAPI32.@]
1391 * lpservicestatus []
1395 QueryServiceStatus( SC_HANDLE hService
, LPSERVICE_STATUS lpservicestatus
)
1397 struct sc_handle
*hsvc
= hService
;
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
);
1412 r
= WaitForSingleObject( mutex
, 30000 );
1413 if( WAIT_FAILED
== r
)
1416 if( WAIT_TIMEOUT
== r
)
1418 SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT
);
1423 /* get service environment block */
1424 seb
= open_seb_shmem( hsvc
->u
.service
.name
, &shmem
);
1429 memcpy( lpservicestatus
, &seb
->status
, sizeof(SERVICE_STATUS
) );
1433 if( seb
) UnmapViewOfFile( seb
);
1434 if( shmem
) CloseHandle( shmem
);
1435 if( mutex_owned
) ReleaseMutex( mutex
);
1436 CloseHandle( mutex
);
1440 /* service stopped */
1441 /* read the service type from the registry */
1443 r
= RegQueryValueExA(hsvc
->u
.service
.hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1446 ERR("invalid Type\n");
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;
1460 /******************************************************************************
1461 * QueryServiceStatusEx [ADVAPI32.@]
1463 * Get information about a service.
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
1476 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1477 LPBYTE lpBuffer
, DWORD cbBufSize
,
1478 LPDWORD pcbBytesNeeded
)
1481 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1485 /******************************************************************************
1486 * QueryServiceConfigA [ADVAPI32.@]
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
];
1503 DWORD type
, val
, sz
, total
, n
;
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
;
1523 /* FIXME: set last error */
1528 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1529 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1533 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1534 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1538 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1539 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1543 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1544 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1547 /* if there's not enough memory, return an error */
1548 if( total
> *pcbBytesNeeded
)
1550 *pcbBytesNeeded
= total
;
1551 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1555 *pcbBytesNeeded
= total
;
1556 ZeroMemory( lpServiceConfig
, total
);
1559 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1560 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1561 lpServiceConfig
->dwServiceType
= val
;
1564 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1565 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1566 lpServiceConfig
->dwStartType
= 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
;
1590 /* FIXME: set last error */
1595 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, p
, &sz
);
1596 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1598 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
) p
;
1604 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1605 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1607 lpServiceConfig
->lpDependencies
= (LPSTR
) p
;
1613 ERR("Buffer overflow!\n");
1615 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1616 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1621 /******************************************************************************
1622 * QueryServiceConfigW [ADVAPI32.@]
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
];
1642 DWORD type
, val
, sz
, total
, n
;
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
;
1662 /* FIXME: set last error */
1667 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1668 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1672 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1673 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1677 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1678 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1682 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1683 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1686 /* if there's not enough memory, return an error */
1687 if( total
> *pcbBytesNeeded
)
1689 *pcbBytesNeeded
= total
;
1690 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1694 *pcbBytesNeeded
= total
;
1695 ZeroMemory( lpServiceConfig
, total
);
1698 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1699 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1700 lpServiceConfig
->dwServiceType
= val
;
1703 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1704 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1705 lpServiceConfig
->dwStartType
= 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
;
1730 /* FIXME: set last error */
1735 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1736 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1738 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1744 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1745 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1747 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1753 ERR("Buffer overflow!\n");
1755 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1756 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
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
);
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
);
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
) );
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
;
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
);
1842 /******************************************************************************
1843 * ChangeServiceConfig2A [ADVAPI32.@]
1845 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
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
);
1880 SetLastError( ERROR_INVALID_PARAMETER
);
1885 /******************************************************************************
1886 * ChangeServiceConfig2W [ADVAPI32.@]
1888 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
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
);
1903 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
1904 (LPVOID
)sd
->lpDescription
,
1905 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
1909 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
1913 /******************************************************************************
1914 * QueryServiceObjectSecurity [ADVAPI32.@]
1916 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
1917 SECURITY_INFORMATION dwSecurityInformation
,
1918 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
1919 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
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
);
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
);