2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
41 #include "wine/exception.h"
43 WINE_DEFAULT_DEBUG_CHANNEL(service
);
45 static const WCHAR szLocalSystem
[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
46 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
47 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
48 'S','e','r','v','i','c','e','s',0 };
49 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
52 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(size_t len
)
54 return HeapAlloc(GetProcessHeap(), 0, len
);
57 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
59 HeapFree(GetProcessHeap(), 0, ptr
);
62 static const GENERIC_MAPPING scm_generic
= {
63 (STANDARD_RIGHTS_READ
| SC_MANAGER_ENUMERATE_SERVICE
| SC_MANAGER_QUERY_LOCK_STATUS
),
64 (STANDARD_RIGHTS_WRITE
| SC_MANAGER_CREATE_SERVICE
| SC_MANAGER_MODIFY_BOOT_CONFIG
),
65 (STANDARD_RIGHTS_EXECUTE
| SC_MANAGER_CONNECT
| SC_MANAGER_LOCK
),
69 static const GENERIC_MAPPING svc_generic
= {
70 (STANDARD_RIGHTS_READ
| SERVICE_QUERY_CONFIG
| SERVICE_QUERY_STATUS
| SERVICE_INTERROGATE
| SERVICE_ENUMERATE_DEPENDENTS
),
71 (STANDARD_RIGHTS_WRITE
| SERVICE_CHANGE_CONFIG
),
72 (STANDARD_RIGHTS_EXECUTE
| SERVICE_START
| SERVICE_STOP
| SERVICE_PAUSE_CONTINUE
| SERVICE_USER_DEFINED_CONTROL
),
76 typedef struct service_data_t
78 LPHANDLER_FUNCTION_EX handler
;
83 LPSERVICE_MAIN_FUNCTIONA a
;
84 LPSERVICE_MAIN_FUNCTIONW w
;
90 static CRITICAL_SECTION service_cs
;
91 static CRITICAL_SECTION_DEBUG service_cs_debug
=
94 { &service_cs_debug
.ProcessLocksList
,
95 &service_cs_debug
.ProcessLocksList
},
96 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
98 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
100 static service_data
**services
;
101 static unsigned int nb_services
;
102 static HANDLE service_event
;
104 extern HANDLE
__wine_make_process_system(void);
106 /******************************************************************************
110 #define MAX_SERVICE_NAME 256
112 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
115 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
119 SC_HANDLE_TYPE htype
;
121 sc_handle_destructor destroy
;
122 SC_RPC_HANDLE server_handle
; /* server-side handle */
125 struct sc_manager
/* service control manager handle */
127 struct sc_handle hdr
;
128 HKEY hkey
; /* handle to services database in the registry */
132 struct sc_service
/* service handle */
134 struct sc_handle hdr
;
135 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
137 struct sc_manager
*scm
; /* pointer to SCM handle */
141 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
142 sc_handle_destructor destroy
)
144 struct sc_handle
*hdr
;
146 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
151 hdr
->destroy
= destroy
;
153 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
157 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
159 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
163 if (hdr
->htype
!= htype
)
168 static void sc_handle_free(struct sc_handle
* hdr
)
172 if (--hdr
->ref_count
)
175 HeapFree(GetProcessHeap(), 0, hdr
);
178 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
180 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
182 TRACE("destroying SC Manager %p\n", mgr
);
184 RegCloseKey(mgr
->hkey
);
187 static void sc_handle_destroy_service(struct sc_handle
*handle
)
189 struct sc_service
*svc
= (struct sc_service
*) handle
;
191 TRACE("destroying service %p\n", svc
);
193 RegCloseKey(svc
->hkey
);
195 sc_handle_free(&svc
->scm
->hdr
);
199 /******************************************************************************
200 * String management functions (same behaviour as strdup)
201 * NOTE: the caller of those functions is responsible for calling HeapFree
202 * in order to release the memory allocated by those functions.
204 static inline LPWSTR
SERV_dup( LPCSTR str
)
211 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
212 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
213 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
217 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
225 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
226 n
+= (strlen( &str
[n
] ) + 1);
231 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
232 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
236 static inline DWORD
multisz_cb(LPCWSTR wmultisz
)
238 const WCHAR
*wptr
= wmultisz
;
240 if (wmultisz
== NULL
)
244 wptr
+= lstrlenW(wptr
)+1;
245 return (wptr
- wmultisz
+ 1)*sizeof(WCHAR
);
248 /******************************************************************************
249 * RPC connection with services.exe
252 handle_t __RPC_USER
MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName
)
254 WCHAR transport
[] = SVCCTL_TRANSPORT
;
255 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
256 RPC_WSTR binding_str
;
260 status
= RpcStringBindingComposeW(NULL
, transport
, (RPC_WSTR
)MachineName
, endpoint
, NULL
, &binding_str
);
261 if (status
!= RPC_S_OK
)
263 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
267 status
= RpcBindingFromStringBindingW(binding_str
, &rpc_handle
);
268 RpcStringFreeW(&binding_str
);
270 if (status
!= RPC_S_OK
)
272 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
279 void __RPC_USER
MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName
, handle_t h
)
284 static LONG WINAPI
rpc_filter(EXCEPTION_POINTERS
*eptr
)
286 return I_RpcExceptionFilter(eptr
->ExceptionRecord
->ExceptionCode
);
289 static DWORD
map_exception_code(DWORD exception_code
)
291 switch (exception_code
)
293 case RPC_X_NULL_REF_POINTER
:
294 case RPC_X_ENUM_VALUE_OUT_OF_RANGE
:
295 case RPC_X_BYTE_COUNT_TOO_SMALL
:
296 return ERROR_INVALID_PARAMETER
;
298 return exception_code
;
302 /******************************************************************************
303 * Service IPC functions
305 static LPWSTR
service_get_pipe_name(void)
307 static const WCHAR format
[] = { '\\','\\','.','\\','p','i','p','e','\\',
308 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
309 static const WCHAR service_current_key_str
[] = { 'S','Y','S','T','E','M','\\',
310 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
311 'C','o','n','t','r','o','l','\\',
312 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
315 HKEY service_current_key
;
316 DWORD service_current
;
320 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, service_current_key_str
, 0,
321 KEY_QUERY_VALUE
, &service_current_key
);
322 if (ret
!= ERROR_SUCCESS
)
324 len
= sizeof(service_current
);
325 ret
= RegQueryValueExW(service_current_key
, NULL
, NULL
, &type
,
326 (BYTE
*)&service_current
, &len
);
327 RegCloseKey(service_current_key
);
328 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
330 len
= sizeof(format
)/sizeof(WCHAR
) + 10 /* strlenW("4294967295") */;
331 name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
334 snprintfW(name
, len
, format
, service_current
);
338 static HANDLE
service_open_pipe(void)
340 LPWSTR szPipe
= service_get_pipe_name();
341 HANDLE handle
= INVALID_HANDLE_VALUE
;
344 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
345 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
346 if (handle
!= INVALID_HANDLE_VALUE
)
348 if (GetLastError() != ERROR_PIPE_BUSY
)
350 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
351 HeapFree(GetProcessHeap(), 0, szPipe
);
356 /******************************************************************************
359 * Call into the main service routine provided by StartServiceCtrlDispatcher.
361 static DWORD WINAPI
service_thread(LPVOID arg
)
363 service_data
*info
= arg
;
364 LPWSTR str
= info
->args
;
365 DWORD argc
= 0, len
= 0;
371 len
+= strlenW(&str
[len
]) + 1;
378 info
->proc
.w(0, NULL
);
380 info
->proc
.a(0, NULL
);
388 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
389 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
393 info
->proc
.w(argc
, argv
);
394 HeapFree(GetProcessHeap(), 0, argv
);
398 LPSTR strA
, *argv
, p
;
401 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
402 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
403 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
405 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
406 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
410 info
->proc
.a(argc
, argv
);
411 HeapFree(GetProcessHeap(), 0, argv
);
412 HeapFree(GetProcessHeap(), 0, strA
);
417 /******************************************************************************
418 * service_handle_start
420 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
422 DWORD read
= 0, result
= 0;
426 TRACE("%p %p %d\n", pipe
, service
, count
);
428 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
429 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
430 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
432 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
433 r
, count
, read
, debugstr_wn(args
, count
));
439 WARN("service is not stopped\n");
440 result
= ERROR_SERVICE_ALREADY_RUNNING
;
444 HeapFree(GetProcessHeap(), 0, service
->args
);
445 service
->args
= args
;
447 service
->thread
= CreateThread( NULL
, 0, service_thread
,
449 SetEvent( service_event
); /* notify the main loop */
452 HeapFree(GetProcessHeap(), 0, args
);
453 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
458 /******************************************************************************
459 * service_handle_control
461 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
464 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
466 TRACE("received control %d\n", dwControl
);
468 if (service
->handler
)
469 ret
= service
->handler(dwControl
, 0, NULL
, service
->context
);
470 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
473 /******************************************************************************
474 * service_control_dispatcher
476 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
478 service_data
*service
= arg
;
481 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
483 pipe
= service_open_pipe();
485 if (pipe
==INVALID_HANDLE_VALUE
)
487 ERR("failed to create pipe for %s, error = %d\n",
488 debugstr_w(service
->name
), GetLastError());
492 /* dispatcher loop */
496 DWORD count
, req
[2] = {0,0};
498 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
501 if (GetLastError() != ERROR_BROKEN_PIPE
)
502 ERR( "pipe read failed error %u\n", GetLastError() );
505 if (count
!= sizeof(req
))
507 ERR( "partial pipe read %u\n", count
);
511 /* handle the request */
514 case WINESERV_STARTINFO
:
515 service_handle_start(pipe
, service
, req
[1]);
517 case WINESERV_SENDCONTROL
:
518 service_handle_control(pipe
, service
, req
[1]);
521 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
529 /******************************************************************************
530 * service_run_threads
532 static BOOL
service_run_threads(void)
535 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
536 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
538 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
540 wait_handles
[0] = __wine_make_process_system();
541 wait_handles
[1] = service_event
;
543 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
544 nb_services
, GetCurrentProcessId());
546 EnterCriticalSection( &service_cs
);
547 for (i
= 0; i
< nb_services
; i
++)
548 CloseHandle( CreateThread( NULL
, 0, service_control_dispatcher
, services
[i
], 0, NULL
));
549 LeaveCriticalSection( &service_cs
);
551 /* wait for all the threads to pack up and exit */
554 EnterCriticalSection( &service_cs
);
555 for (i
= 0, n
= 2; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
557 if (!services
[i
]->thread
) continue;
558 wait_services
[n
] = i
;
559 wait_handles
[n
++] = services
[i
]->thread
;
561 LeaveCriticalSection( &service_cs
);
563 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
564 if (!ret
) /* system process event */
566 TRACE( "last user process exited, shutting down\n" );
567 /* FIXME: we should maybe send a shutdown control to running services */
572 continue; /* rebuild the list */
576 services
[wait_services
[ret
]]->thread
= 0;
577 CloseHandle( wait_handles
[ret
] );
578 if (n
== 3) return TRUE
; /* it was the last running thread */
584 /******************************************************************************
585 * StartServiceCtrlDispatcherA [ADVAPI32.@]
587 * See StartServiceCtrlDispatcherW.
589 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
595 TRACE("%p\n", servent
);
599 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
602 while (servent
[nb_services
].lpServiceName
) nb_services
++;
603 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
605 for (i
= 0; i
< nb_services
; i
++)
607 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
608 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
609 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
610 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
611 info
->proc
.a
= servent
[i
].lpServiceProc
;
612 info
->unicode
= FALSE
;
616 service_run_threads();
621 /******************************************************************************
622 * StartServiceCtrlDispatcherW [ADVAPI32.@]
624 * Connects a process containing one or more services to the service control
628 * servent [I] A list of the service names and service procedures
634 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
640 TRACE("%p\n", servent
);
644 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
647 while (servent
[nb_services
].lpServiceName
) nb_services
++;
648 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
650 for (i
= 0; i
< nb_services
; i
++)
652 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
653 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
654 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
655 strcpyW(info
->name
, servent
[i
].lpServiceName
);
656 info
->proc
.w
= servent
[i
].lpServiceProc
;
657 info
->unicode
= TRUE
;
661 service_run_threads();
666 /******************************************************************************
667 * LockServiceDatabase [ADVAPI32.@]
669 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
671 struct sc_manager
*hscm
;
672 SC_RPC_LOCK hLock
= NULL
;
675 TRACE("%p\n",hSCManager
);
677 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
680 SetLastError( ERROR_INVALID_HANDLE
);
686 err
= svcctl_LockServiceDatabase(hscm
->hdr
.server_handle
, &hLock
);
690 err
= map_exception_code(GetExceptionCode());
693 if (err
!= ERROR_SUCCESS
)
701 /******************************************************************************
702 * UnlockServiceDatabase [ADVAPI32.@]
704 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
707 SC_RPC_LOCK hRpcLock
= ScLock
;
709 TRACE("%p\n",ScLock
);
713 err
= svcctl_UnlockServiceDatabase(&hRpcLock
);
717 err
= map_exception_code(GetExceptionCode());
720 if (err
!= ERROR_SUCCESS
)
728 /******************************************************************************
729 * SetServiceStatus [ADVAPI32.@]
736 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
738 struct sc_service
*hsvc
;
741 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
742 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
743 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
744 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
745 lpStatus
->dwWaitHint
);
747 hsvc
= sc_handle_get_handle_data((SC_HANDLE
)hService
, SC_HTYPE_SERVICE
);
750 SetLastError( ERROR_INVALID_HANDLE
);
756 err
= svcctl_SetServiceStatus( hsvc
->hdr
.server_handle
, lpStatus
);
760 err
= map_exception_code(GetExceptionCode());
763 if (err
!= ERROR_SUCCESS
)
769 if (lpStatus
->dwCurrentState
== SERVICE_STOPPED
)
770 CloseServiceHandle((SC_HANDLE
)hService
);
776 /******************************************************************************
777 * OpenSCManagerA [ADVAPI32.@]
779 * Establish a connection to the service control manager and open its database.
782 * lpMachineName [I] Pointer to machine name string
783 * lpDatabaseName [I] Pointer to database name string
784 * dwDesiredAccess [I] Type of access
787 * Success: A Handle to the service control manager database
790 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
791 DWORD dwDesiredAccess
)
793 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
796 lpMachineNameW
= SERV_dup(lpMachineName
);
797 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
798 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
799 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW
);
800 HeapFree(GetProcessHeap(), 0, lpMachineNameW
);
804 /******************************************************************************
805 * OpenSCManagerW [ADVAPI32.@]
807 * See OpenSCManagerA.
809 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
810 DWORD dwDesiredAccess
)
812 struct sc_manager
*manager
;
815 DWORD new_mask
= dwDesiredAccess
;
817 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
818 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
820 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
821 sc_handle_destroy_manager
);
827 r
= svcctl_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, &manager
->hdr
.server_handle
);
831 r
= map_exception_code(GetExceptionCode());
834 if (r
!=ERROR_SUCCESS
)
837 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
838 if (r
!=ERROR_SUCCESS
)
841 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
843 if (r
!=ERROR_SUCCESS
)
846 RtlMapGenericMask(&new_mask
, &scm_generic
);
847 manager
->dwAccess
= new_mask
;
848 TRACE("returning %p (access : 0x%08x)\n", manager
, manager
->dwAccess
);
850 return (SC_HANDLE
) &manager
->hdr
;
853 sc_handle_free( &manager
->hdr
);
858 /******************************************************************************
859 * ControlService [ADVAPI32.@]
861 * Send a control code to a service.
864 * hService [I] Handle of the service control manager database
865 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
866 * lpServiceStatus [O] Destination for the status of the service, if available
873 * Unlike M$' implementation, control requests are not serialized and may be
874 * processed asynchronously.
876 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
877 LPSERVICE_STATUS lpServiceStatus
)
879 struct sc_service
*hsvc
;
882 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
884 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
887 SetLastError( ERROR_INVALID_HANDLE
);
893 err
= svcctl_ControlService(hsvc
->hdr
.server_handle
, dwControl
, lpServiceStatus
);
897 err
= map_exception_code(GetExceptionCode());
900 if (err
!= ERROR_SUCCESS
)
909 /******************************************************************************
910 * CloseServiceHandle [ADVAPI32.@]
912 * Close a handle to a service or the service control manager database.
915 * hSCObject [I] Handle to service or service control manager database
922 CloseServiceHandle( SC_HANDLE hSCObject
)
924 struct sc_handle
*obj
;
927 TRACE("%p\n", hSCObject
);
928 if (hSCObject
== NULL
)
930 SetLastError(ERROR_INVALID_HANDLE
);
934 obj
= (struct sc_handle
*)hSCObject
;
937 err
= svcctl_CloseServiceHandle(&obj
->server_handle
);
941 err
= map_exception_code(GetExceptionCode());
944 sc_handle_free( obj
);
946 if (err
!= ERROR_SUCCESS
)
955 /******************************************************************************
956 * OpenServiceA [ADVAPI32.@]
958 * Open a handle to a service.
961 * hSCManager [I] Handle of the service control manager database
962 * lpServiceName [I] Name of the service to open
963 * dwDesiredAccess [I] Access required to the service
966 * Success: Handle to the service
969 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
970 DWORD dwDesiredAccess
)
972 LPWSTR lpServiceNameW
;
975 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
977 lpServiceNameW
= SERV_dup(lpServiceName
);
978 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
979 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
984 /******************************************************************************
985 * OpenServiceW [ADVAPI32.@]
989 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
990 DWORD dwDesiredAccess
)
992 struct sc_manager
*hscm
;
993 struct sc_service
*hsvc
;
996 DWORD new_mask
= dwDesiredAccess
;
998 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1000 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1003 SetLastError( ERROR_INVALID_HANDLE
);
1009 SetLastError(ERROR_INVALID_ADDRESS
);
1013 len
= strlenW(lpServiceName
)+1;
1014 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1015 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1016 sc_handle_destroy_service
);
1019 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1022 strcpyW( hsvc
->name
, lpServiceName
);
1024 /* add reference to SCM handle */
1025 hscm
->hdr
.ref_count
++;
1030 err
= svcctl_OpenServiceW(hscm
->hdr
.server_handle
, lpServiceName
, dwDesiredAccess
, &hsvc
->hdr
.server_handle
);
1032 __EXCEPT(rpc_filter
)
1034 err
= map_exception_code(GetExceptionCode());
1038 if (err
!= ERROR_SUCCESS
)
1040 sc_handle_free(&hsvc
->hdr
);
1045 /* for parts of advapi32 not using services.exe yet */
1046 RtlMapGenericMask(&new_mask
, &svc_generic
);
1047 hsvc
->dwAccess
= new_mask
;
1049 err
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hsvc
->hkey
);
1050 if (err
!= ERROR_SUCCESS
)
1051 ERR("Shouldn't hapen - service key for service validated by services.exe doesn't exist\n");
1053 TRACE("returning %p\n",hsvc
);
1055 return (SC_HANDLE
) &hsvc
->hdr
;
1058 /******************************************************************************
1059 * CreateServiceW [ADVAPI32.@]
1062 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1063 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1064 DWORD dwServiceType
, DWORD dwStartType
,
1065 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1066 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1067 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1068 LPCWSTR lpPassword
)
1070 struct sc_manager
*hscm
;
1071 struct sc_service
*hsvc
= NULL
;
1072 DWORD new_mask
= dwDesiredAccess
;
1076 TRACE("%p %s %s\n", hSCManager
,
1077 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1079 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1082 SetLastError( ERROR_INVALID_HANDLE
);
1086 if (!lpServiceName
|| !lpBinaryPathName
)
1088 SetLastError(ERROR_INVALID_ADDRESS
);
1093 passwdlen
= (strlenW(lpPassword
) + 1) * sizeof(WCHAR
);
1097 len
= strlenW(lpServiceName
)+1;
1098 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1099 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1102 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1105 lstrcpyW( hsvc
->name
, lpServiceName
);
1108 hscm
->hdr
.ref_count
++;
1112 err
= svcctl_CreateServiceW(hscm
->hdr
.server_handle
, lpServiceName
,
1113 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1114 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (LPBYTE
)lpDependencies
,
1115 multisz_cb(lpDependencies
), lpServiceStartName
, (LPBYTE
)lpPassword
, passwdlen
,
1116 &hsvc
->hdr
.server_handle
);
1118 __EXCEPT(rpc_filter
)
1120 err
= map_exception_code(GetExceptionCode());
1124 if (err
!= ERROR_SUCCESS
)
1127 sc_handle_free(&hsvc
->hdr
);
1131 /* for parts of advapi32 not using services.exe yet */
1132 err
= RegOpenKeyW(hscm
->hkey
, lpServiceName
, &hsvc
->hkey
);
1133 if (err
!= ERROR_SUCCESS
)
1134 WINE_ERR("Couldn't open key that should have been created by services.exe\n");
1136 RtlMapGenericMask(&new_mask
, &svc_generic
);
1137 hsvc
->dwAccess
= new_mask
;
1139 return (SC_HANDLE
) &hsvc
->hdr
;
1143 /******************************************************************************
1144 * CreateServiceA [ADVAPI32.@]
1147 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1148 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1149 DWORD dwServiceType
, DWORD dwStartType
,
1150 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1151 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1152 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1155 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1156 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1159 TRACE("%p %s %s\n", hSCManager
,
1160 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1162 lpServiceNameW
= SERV_dup( lpServiceName
);
1163 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1164 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1165 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1166 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1167 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1168 lpPasswordW
= SERV_dup( lpPassword
);
1170 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1171 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1172 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1173 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1175 HeapFree( GetProcessHeap(), 0, lpServiceNameW
);
1176 HeapFree( GetProcessHeap(), 0, lpDisplayNameW
);
1177 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW
);
1178 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW
);
1179 HeapFree( GetProcessHeap(), 0, lpDependenciesW
);
1180 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW
);
1181 HeapFree( GetProcessHeap(), 0, lpPasswordW
);
1187 /******************************************************************************
1188 * DeleteService [ADVAPI32.@]
1190 * Delete a service from the service control manager database.
1193 * hService [I] Handle of the service to delete
1199 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1201 struct sc_service
*hsvc
;
1204 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1207 SetLastError( ERROR_INVALID_HANDLE
);
1213 err
= svcctl_DeleteService(hsvc
->hdr
.server_handle
);
1215 __EXCEPT(rpc_filter
)
1217 err
= map_exception_code(GetExceptionCode());
1226 /* Close the key to the service */
1227 RegCloseKey(hsvc
->hkey
);
1233 /******************************************************************************
1234 * StartServiceA [ADVAPI32.@]
1239 * hService [I] Handle of service
1240 * dwNumServiceArgs [I] Number of arguments
1241 * lpServiceArgVectors [I] Address of array of argument strings
1244 * - NT implements this function using an obscure RPC call.
1245 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1246 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1247 * - This will only work for shared address space. How should the service
1248 * args be transferred when address spaces are separated?
1249 * - Can only start one service at a time.
1250 * - Has no concept of privilege.
1256 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1257 LPCSTR
*lpServiceArgVectors
)
1259 LPWSTR
*lpwstr
=NULL
;
1263 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1265 if (dwNumServiceArgs
)
1266 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1267 dwNumServiceArgs
*sizeof(LPWSTR
) );
1269 for(i
=0; i
<dwNumServiceArgs
; i
++)
1270 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1272 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1274 if (dwNumServiceArgs
)
1276 for(i
=0; i
<dwNumServiceArgs
; i
++)
1277 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
1278 HeapFree(GetProcessHeap(), 0, lpwstr
);
1285 /******************************************************************************
1286 * StartServiceW [ADVAPI32.@]
1288 * See StartServiceA.
1290 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1291 LPCWSTR
*lpServiceArgVectors
)
1293 struct sc_service
*hsvc
;
1296 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1298 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1301 SetLastError(ERROR_INVALID_HANDLE
);
1307 err
= svcctl_StartServiceW(hsvc
->hdr
.server_handle
, dwNumServiceArgs
, lpServiceArgVectors
);
1309 __EXCEPT(rpc_filter
)
1311 err
= map_exception_code(GetExceptionCode());
1314 if (err
!= ERROR_SUCCESS
)
1323 /******************************************************************************
1324 * QueryServiceStatus [ADVAPI32.@]
1327 * hService [I] Handle to service to get information about
1328 * lpservicestatus [O] buffer to receive the status information for the service
1331 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1332 LPSERVICE_STATUS lpservicestatus
)
1334 SERVICE_STATUS_PROCESS SvcStatusData
;
1338 TRACE("%p %p\n", hService
, lpservicestatus
);
1340 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1341 sizeof(SERVICE_STATUS_PROCESS
), &dummy
);
1342 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1347 /******************************************************************************
1348 * QueryServiceStatusEx [ADVAPI32.@]
1350 * Get information about a service.
1353 * hService [I] Handle to service to get information about
1354 * InfoLevel [I] Level of information to get
1355 * lpBuffer [O] Destination for requested information
1356 * cbBufSize [I] Size of lpBuffer in bytes
1357 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1363 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1364 LPBYTE lpBuffer
, DWORD cbBufSize
,
1365 LPDWORD pcbBytesNeeded
)
1367 struct sc_service
*hsvc
;
1370 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1372 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1375 SetLastError( ERROR_INVALID_HANDLE
);
1381 err
= svcctl_QueryServiceStatusEx(hsvc
->hdr
.server_handle
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1383 __EXCEPT(rpc_filter
)
1385 err
= map_exception_code(GetExceptionCode());
1388 if (err
!= ERROR_SUCCESS
)
1397 /******************************************************************************
1398 * QueryServiceConfigA [ADVAPI32.@]
1400 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1401 DWORD size
, LPDWORD needed
)
1406 QUERY_SERVICE_CONFIGW
*configW
;
1408 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1410 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1412 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1415 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1416 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1417 if (!ret
) goto done
;
1419 config
->dwServiceType
= configW
->dwServiceType
;
1420 config
->dwStartType
= configW
->dwStartType
;
1421 config
->dwErrorControl
= configW
->dwErrorControl
;
1422 config
->lpBinaryPathName
= NULL
;
1423 config
->lpLoadOrderGroup
= NULL
;
1424 config
->dwTagId
= configW
->dwTagId
;
1425 config
->lpDependencies
= NULL
;
1426 config
->lpServiceStartName
= NULL
;
1427 config
->lpDisplayName
= NULL
;
1429 p
= (LPSTR
)(config
+ 1);
1430 n
= size
- sizeof(*config
);
1433 #define MAP_STR(str) \
1437 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1438 if (!sz) goto done; \
1445 MAP_STR( lpBinaryPathName
);
1446 MAP_STR( lpLoadOrderGroup
);
1447 MAP_STR( lpDependencies
);
1448 MAP_STR( lpServiceStartName
);
1449 MAP_STR( lpDisplayName
);
1452 *needed
= p
- (LPSTR
)config
;
1456 HeapFree( GetProcessHeap(), 0, buffer
);
1460 static DWORD
move_string_to_buffer(BYTE
**buf
, LPWSTR
*string_ptr
)
1467 memset(*buf
, 0, cb
);
1471 cb
= (strlenW(*string_ptr
) + 1)*sizeof(WCHAR
);
1472 memcpy(*buf
, *string_ptr
, cb
);
1473 MIDL_user_free(*string_ptr
);
1476 *string_ptr
= (LPWSTR
)*buf
;
1482 static DWORD
size_string(LPWSTR string
)
1484 return (string
? (strlenW(string
) + 1)*sizeof(WCHAR
) : sizeof(WCHAR
));
1487 /******************************************************************************
1488 * QueryServiceConfigW [ADVAPI32.@]
1491 QueryServiceConfigW( SC_HANDLE hService
,
1492 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1493 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1495 QUERY_SERVICE_CONFIGW config
;
1496 struct sc_service
*hsvc
;
1501 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1502 cbBufSize
, pcbBytesNeeded
);
1504 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1507 SetLastError( ERROR_INVALID_HANDLE
);
1511 memset(&config
, 0, sizeof(config
));
1515 err
= svcctl_QueryServiceConfigW(hsvc
->hdr
.server_handle
, &config
);
1517 __EXCEPT(rpc_filter
)
1519 err
= map_exception_code(GetExceptionCode());
1523 if (err
!= ERROR_SUCCESS
)
1525 TRACE("services.exe: error %u\n", err
);
1530 /* calculate the size required first */
1531 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1532 total
+= size_string(config
.lpBinaryPathName
);
1533 total
+= size_string(config
.lpLoadOrderGroup
);
1534 total
+= size_string(config
.lpDependencies
);
1535 total
+= size_string(config
.lpServiceStartName
);
1536 total
+= size_string(config
.lpDisplayName
);
1538 *pcbBytesNeeded
= total
;
1540 /* if there's not enough memory, return an error */
1541 if( total
> cbBufSize
)
1543 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1544 MIDL_user_free(config
.lpBinaryPathName
);
1545 MIDL_user_free(config
.lpLoadOrderGroup
);
1546 MIDL_user_free(config
.lpDependencies
);
1547 MIDL_user_free(config
.lpServiceStartName
);
1548 MIDL_user_free(config
.lpDisplayName
);
1552 *lpServiceConfig
= config
;
1553 bufpos
= ((BYTE
*)lpServiceConfig
) + sizeof(QUERY_SERVICE_CONFIGW
);
1554 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpBinaryPathName
);
1555 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpLoadOrderGroup
);
1556 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDependencies
);
1557 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpServiceStartName
);
1558 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDisplayName
);
1560 if (bufpos
- (LPBYTE
)lpServiceConfig
> cbBufSize
)
1561 ERR("Buffer overflow!\n");
1563 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1564 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1565 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
1566 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
1567 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
1572 /******************************************************************************
1573 * QueryServiceConfig2A [ADVAPI32.@]
1576 * observed under win2k:
1577 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1578 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1580 BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1581 DWORD size
, LPDWORD needed
)
1584 LPBYTE bufferW
= NULL
;
1587 bufferW
= HeapAlloc( GetProcessHeap(), 0, size
);
1589 ret
= QueryServiceConfig2W(hService
, dwLevel
, bufferW
, size
, needed
);
1590 if(!ret
) goto cleanup
;
1593 case SERVICE_CONFIG_DESCRIPTION
:
1594 { LPSERVICE_DESCRIPTIONA configA
= (LPSERVICE_DESCRIPTIONA
) buffer
;
1595 LPSERVICE_DESCRIPTIONW configW
= (LPSERVICE_DESCRIPTIONW
) bufferW
;
1596 if (configW
->lpDescription
) {
1598 configA
->lpDescription
= (LPSTR
)(configA
+ 1);
1599 sz
= WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1,
1600 configA
->lpDescription
, size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
1602 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1604 configA
->lpDescription
= NULL
;
1607 else configA
->lpDescription
= NULL
;
1611 FIXME("conversation W->A not implemented for level %d\n", dwLevel
);
1616 HeapFree( GetProcessHeap(), 0, bufferW
);
1620 /******************************************************************************
1621 * QueryServiceConfig2W [ADVAPI32.@]
1623 BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1624 DWORD size
, LPDWORD needed
)
1629 struct sc_service
*hsvc
;
1631 if(dwLevel
!= SERVICE_CONFIG_DESCRIPTION
) {
1632 if((dwLevel
== SERVICE_CONFIG_DELAYED_AUTO_START_INFO
) ||
1633 (dwLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
) ||
1634 (dwLevel
== SERVICE_CONFIG_FAILURE_ACTIONS_FLAG
) ||
1635 (dwLevel
== SERVICE_CONFIG_PRESHUTDOWN_INFO
) ||
1636 (dwLevel
== SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO
) ||
1637 (dwLevel
== SERVICE_CONFIG_SERVICE_SID_INFO
))
1638 FIXME("Level %d not implemented\n", dwLevel
);
1639 SetLastError(ERROR_INVALID_LEVEL
);
1642 if(!needed
|| (!buffer
&& size
)) {
1643 SetLastError(ERROR_INVALID_ADDRESS
);
1647 TRACE("%p 0x%d %p 0x%d %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1649 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1652 SetLastError(ERROR_INVALID_HANDLE
);
1658 case SERVICE_CONFIG_DESCRIPTION
: {
1659 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1660 LPSERVICE_DESCRIPTIONW config
= (LPSERVICE_DESCRIPTIONW
) buffer
;
1661 LPBYTE strbuf
= NULL
;
1662 *needed
= sizeof (SERVICE_DESCRIPTIONW
);
1663 sz
= size
- *needed
;
1664 if(config
&& (*needed
<= size
))
1665 strbuf
= (LPBYTE
) (config
+ 1);
1666 r
= RegQueryValueExW( hKey
, szDescription
, 0, &type
, strbuf
, &sz
);
1667 if((r
== ERROR_SUCCESS
) && ( type
!= REG_SZ
)) {
1668 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type
);
1673 if(r
== ERROR_SUCCESS
)
1674 config
->lpDescription
= (LPWSTR
) (config
+ 1);
1676 config
->lpDescription
= NULL
;
1682 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1684 return (*needed
<= size
);
1687 /******************************************************************************
1688 * EnumServicesStatusA [ADVAPI32.@]
1691 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1692 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
1693 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1694 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1696 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1697 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1698 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1699 SetLastError (ERROR_ACCESS_DENIED
);
1703 /******************************************************************************
1704 * EnumServicesStatusW [ADVAPI32.@]
1707 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1708 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
1709 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1710 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1712 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1713 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1714 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1715 SetLastError (ERROR_ACCESS_DENIED
);
1719 /******************************************************************************
1720 * EnumServicesStatusExA [ADVAPI32.@]
1723 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
1724 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1725 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
1727 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
1728 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1729 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
1730 *lpServicesReturned
= 0;
1731 SetLastError (ERROR_ACCESS_DENIED
);
1735 /******************************************************************************
1736 * EnumServicesStatusExW [ADVAPI32.@]
1739 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
1740 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1741 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
1743 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
1744 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1745 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
1746 SetLastError (ERROR_ACCESS_DENIED
);
1750 /******************************************************************************
1751 * GetServiceKeyNameA [ADVAPI32.@]
1753 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1754 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1756 LPWSTR lpDisplayNameW
, lpServiceNameW
;
1760 TRACE("%p %s %p %p\n", hSCManager
,
1761 debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1763 lpDisplayNameW
= SERV_dup(lpDisplayName
);
1765 lpServiceNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
1767 lpServiceNameW
= NULL
;
1769 sizeW
= *lpcchBuffer
;
1770 if (!GetServiceKeyNameW(hSCManager
, lpDisplayNameW
, lpServiceNameW
, &sizeW
))
1772 if (*lpcchBuffer
&& lpServiceName
)
1773 lpServiceName
[0] = 0;
1774 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1778 if (!WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, (sizeW
+ 1), lpServiceName
,
1779 *lpcchBuffer
, NULL
, NULL
))
1781 if (*lpcchBuffer
&& lpServiceName
)
1782 lpServiceName
[0] = 0;
1783 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, -1, NULL
, 0, NULL
, NULL
);
1787 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1791 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1792 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
1796 /******************************************************************************
1797 * GetServiceKeyNameW [ADVAPI32.@]
1799 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1800 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1802 struct sc_manager
*hscm
;
1805 TRACE("%p %s %p %p\n", hSCManager
,
1806 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1808 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
1811 SetLastError(ERROR_INVALID_HANDLE
);
1817 SetLastError(ERROR_INVALID_ADDRESS
);
1823 err
= svcctl_GetServiceKeyNameW(hscm
->hdr
.server_handle
,
1824 lpDisplayName
, lpServiceName
, lpServiceName
? *lpcchBuffer
: 0, lpcchBuffer
);
1826 __EXCEPT(rpc_filter
)
1828 err
= map_exception_code(GetExceptionCode());
1834 return err
== ERROR_SUCCESS
;
1837 /******************************************************************************
1838 * QueryServiceLockStatusA [ADVAPI32.@]
1840 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1841 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1842 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1844 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1849 /******************************************************************************
1850 * QueryServiceLockStatusW [ADVAPI32.@]
1852 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
1853 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
1854 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1856 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1861 /******************************************************************************
1862 * GetServiceDisplayNameA [ADVAPI32.@]
1864 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1865 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1867 LPWSTR lpServiceNameW
, lpDisplayNameW
;
1871 TRACE("%p %s %p %p\n", hSCManager
,
1872 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1874 lpServiceNameW
= SERV_dup(lpServiceName
);
1876 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
1878 lpDisplayNameW
= NULL
;
1880 sizeW
= *lpcchBuffer
;
1881 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
1883 if (*lpcchBuffer
&& lpDisplayName
)
1884 lpDisplayName
[0] = 0;
1885 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1889 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
1890 *lpcchBuffer
, NULL
, NULL
))
1892 if (*lpcchBuffer
&& lpDisplayName
)
1893 lpDisplayName
[0] = 0;
1894 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
1898 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1899 * (but if the function succeeded it means that is a good upper estimation of the size) */
1903 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
1904 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1908 /******************************************************************************
1909 * GetServiceDisplayNameW [ADVAPI32.@]
1911 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1912 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1914 struct sc_manager
*hscm
;
1917 TRACE("%p %s %p %p\n", hSCManager
,
1918 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1920 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
1923 SetLastError(ERROR_INVALID_HANDLE
);
1929 SetLastError(ERROR_INVALID_ADDRESS
);
1935 err
= svcctl_GetServiceDisplayNameW(hscm
->hdr
.server_handle
,
1936 lpServiceName
, lpDisplayName
, lpDisplayName
? *lpcchBuffer
: 0, lpcchBuffer
);
1938 __EXCEPT(rpc_filter
)
1940 err
= map_exception_code(GetExceptionCode());
1946 return err
== ERROR_SUCCESS
;
1949 /******************************************************************************
1950 * ChangeServiceConfigW [ADVAPI32.@]
1952 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1953 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1954 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1955 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1957 struct sc_service
*hsvc
;
1961 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1962 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1963 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1964 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1965 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1967 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1970 SetLastError( ERROR_INVALID_HANDLE
);
1974 cb_pwd
= lpPassword
? (strlenW(lpPassword
) + 1)*sizeof(WCHAR
) : 0;
1978 err
= svcctl_ChangeServiceConfigW(hsvc
->hdr
.server_handle
, dwServiceType
,
1979 dwStartType
, dwErrorControl
, lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
,
1980 (const BYTE
*)lpDependencies
, multisz_cb(lpDependencies
), lpServiceStartName
,
1981 (const BYTE
*)lpPassword
, cb_pwd
, lpDisplayName
);
1983 __EXCEPT(rpc_filter
)
1985 err
= map_exception_code(GetExceptionCode());
1989 if (err
!= ERROR_SUCCESS
)
1992 return err
== ERROR_SUCCESS
;
1995 /******************************************************************************
1996 * ChangeServiceConfigA [ADVAPI32.@]
1998 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1999 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2000 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2001 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2003 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2004 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2007 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2008 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2009 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2010 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2011 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2013 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2014 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2015 wDependencies
= SERV_dupmulti( lpDependencies
);
2016 wServiceStartName
= SERV_dup( lpServiceStartName
);
2017 wPassword
= SERV_dup( lpPassword
);
2018 wDisplayName
= SERV_dup( lpDisplayName
);
2020 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2021 dwStartType
, dwErrorControl
, wBinaryPathName
,
2022 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2023 wServiceStartName
, wPassword
, wDisplayName
);
2025 HeapFree( GetProcessHeap(), 0, wBinaryPathName
);
2026 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup
);
2027 HeapFree( GetProcessHeap(), 0, wDependencies
);
2028 HeapFree( GetProcessHeap(), 0, wServiceStartName
);
2029 HeapFree( GetProcessHeap(), 0, wPassword
);
2030 HeapFree( GetProcessHeap(), 0, wDisplayName
);
2035 /******************************************************************************
2036 * ChangeServiceConfig2A [ADVAPI32.@]
2038 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2043 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2045 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2047 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2048 SERVICE_DESCRIPTIONW sdw
;
2050 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2052 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2054 HeapFree( GetProcessHeap(), 0, sdw
.lpDescription
);
2056 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2058 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2059 SERVICE_FAILURE_ACTIONSW faw
;
2061 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2062 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2063 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2064 faw
.cActions
= fa
->cActions
;
2065 faw
.lpsaActions
= fa
->lpsaActions
;
2067 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2069 HeapFree( GetProcessHeap(), 0, faw
.lpRebootMsg
);
2070 HeapFree( GetProcessHeap(), 0, faw
.lpCommand
);
2073 SetLastError( ERROR_INVALID_PARAMETER
);
2078 /******************************************************************************
2079 * ChangeServiceConfig2W [ADVAPI32.@]
2081 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2085 struct sc_service
*hsvc
;
2087 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2090 SetLastError( ERROR_INVALID_HANDLE
);
2095 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2097 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2098 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2099 if (sd
->lpDescription
)
2101 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2102 if (sd
->lpDescription
[0] == 0)
2103 RegDeleteValueW(hKey
,szDescription
);
2105 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2106 (LPVOID
)sd
->lpDescription
,
2107 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2111 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2115 /******************************************************************************
2116 * QueryServiceObjectSecurity [ADVAPI32.@]
2118 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2119 SECURITY_INFORMATION dwSecurityInformation
,
2120 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2121 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2123 SECURITY_DESCRIPTOR descriptor
;
2128 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2129 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2131 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2132 FIXME("information %d not supported\n", dwSecurityInformation
);
2134 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2136 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2137 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2140 succ
= MakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2141 *pcbBytesNeeded
= size
;
2145 /******************************************************************************
2146 * SetServiceObjectSecurity [ADVAPI32.@]
2148 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2149 SECURITY_INFORMATION dwSecurityInformation
,
2150 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2152 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2156 /******************************************************************************
2157 * SetServiceBits [ADVAPI32.@]
2159 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2160 DWORD dwServiceBits
,
2162 BOOL bUpdateImmediately
)
2164 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2165 bSetBitsOn
, bUpdateImmediately
);
2169 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2170 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
2172 LPHANDLER_FUNCTION func
= context
;
2175 return ERROR_SUCCESS
;
2178 /******************************************************************************
2179 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2181 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
2183 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
2186 /******************************************************************************
2187 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2189 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
2191 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
2194 /******************************************************************************
2195 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2197 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
2200 SERVICE_STATUS_HANDLE ret
;
2202 nameW
= SERV_dup(name
);
2203 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
2204 HeapFree( GetProcessHeap(), 0, nameW
);
2208 /******************************************************************************
2209 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2211 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2212 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2219 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2221 hSCM
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
2224 hService
= OpenServiceW( hSCM
, lpServiceName
, SERVICE_SET_STATUS
);
2225 CloseServiceHandle(hSCM
);
2229 EnterCriticalSection( &service_cs
);
2230 for (i
= 0; i
< nb_services
; i
++)
2232 if(!strcmpW(lpServiceName
, services
[i
]->name
))
2234 services
[i
]->handler
= lpHandlerProc
;
2235 services
[i
]->context
= lpContext
;
2240 LeaveCriticalSection( &service_cs
);
2244 CloseServiceHandle(hService
);
2245 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2249 return (SERVICE_STATUS_HANDLE
)hService
;
2252 /******************************************************************************
2253 * EnumDependentServicesA [ADVAPI32.@]
2255 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2256 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2257 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2259 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2260 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2262 *lpServicesReturned
= 0;
2266 /******************************************************************************
2267 * EnumDependentServicesW [ADVAPI32.@]
2269 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2270 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2271 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2273 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2274 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2276 *lpServicesReturned
= 0;