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 WINE_DEFAULT_DEBUG_CHANNEL(service
);
43 static const WCHAR szLocalSystem
[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
44 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
45 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
46 'S','e','r','v','i','c','e','s',0 };
47 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
50 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(size_t len
)
52 return HeapAlloc(GetProcessHeap(), 0, len
);
55 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
57 HeapFree(GetProcessHeap(), 0, ptr
);
60 static const GENERIC_MAPPING scm_generic
= {
61 (STANDARD_RIGHTS_READ
| SC_MANAGER_ENUMERATE_SERVICE
| SC_MANAGER_QUERY_LOCK_STATUS
),
62 (STANDARD_RIGHTS_WRITE
| SC_MANAGER_CREATE_SERVICE
| SC_MANAGER_MODIFY_BOOT_CONFIG
),
63 (STANDARD_RIGHTS_EXECUTE
| SC_MANAGER_CONNECT
| SC_MANAGER_LOCK
),
67 static const GENERIC_MAPPING svc_generic
= {
68 (STANDARD_RIGHTS_READ
| SERVICE_QUERY_CONFIG
| SERVICE_QUERY_STATUS
| SERVICE_INTERROGATE
| SERVICE_ENUMERATE_DEPENDENTS
),
69 (STANDARD_RIGHTS_WRITE
| SERVICE_CHANGE_CONFIG
),
70 (STANDARD_RIGHTS_EXECUTE
| SERVICE_START
| SERVICE_STOP
| SERVICE_PAUSE_CONTINUE
| SERVICE_USER_DEFINED_CONTROL
),
74 typedef struct service_data_t
76 LPHANDLER_FUNCTION_EX handler
;
81 LPSERVICE_MAIN_FUNCTIONA a
;
82 LPSERVICE_MAIN_FUNCTIONW w
;
88 static CRITICAL_SECTION service_cs
;
89 static CRITICAL_SECTION_DEBUG service_cs_debug
=
92 { &service_cs_debug
.ProcessLocksList
,
93 &service_cs_debug
.ProcessLocksList
},
94 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
96 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
98 static service_data
**services
;
99 static unsigned int nb_services
;
100 static HANDLE service_event
;
102 extern HANDLE
__wine_make_process_system(void);
104 /******************************************************************************
108 #define MAX_SERVICE_NAME 256
110 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
113 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
117 SC_HANDLE_TYPE htype
;
119 sc_handle_destructor destroy
;
120 SC_RPC_HANDLE server_handle
; /* server-side handle */
123 struct sc_manager
/* service control manager handle */
125 struct sc_handle hdr
;
126 HKEY hkey
; /* handle to services database in the registry */
130 struct sc_service
/* service handle */
132 struct sc_handle hdr
;
133 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
135 struct sc_manager
*scm
; /* pointer to SCM handle */
139 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
140 sc_handle_destructor destroy
)
142 struct sc_handle
*hdr
;
144 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
149 hdr
->destroy
= destroy
;
151 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
155 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
157 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
161 if (hdr
->htype
!= htype
)
166 static void sc_handle_free(struct sc_handle
* hdr
)
170 if (--hdr
->ref_count
)
173 HeapFree(GetProcessHeap(), 0, hdr
);
176 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
178 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
180 TRACE("destroying SC Manager %p\n", mgr
);
182 RegCloseKey(mgr
->hkey
);
185 static void sc_handle_destroy_service(struct sc_handle
*handle
)
187 struct sc_service
*svc
= (struct sc_service
*) handle
;
189 TRACE("destroying service %p\n", svc
);
191 RegCloseKey(svc
->hkey
);
193 sc_handle_free(&svc
->scm
->hdr
);
197 /******************************************************************************
198 * String management functions (same behaviour as strdup)
199 * NOTE: the caller of those functions is responsible for calling HeapFree
200 * in order to release the memory allocated by those functions.
202 static inline LPWSTR
SERV_dup( LPCSTR str
)
209 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
210 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
211 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
215 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
223 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
224 n
+= (strlen( &str
[n
] ) + 1);
229 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
230 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
234 static inline DWORD
multisz_cb(LPCWSTR wmultisz
)
236 const WCHAR
*wptr
= wmultisz
;
238 if (wmultisz
== NULL
)
242 wptr
+= lstrlenW(wptr
)+1;
243 return (wptr
- wmultisz
+ 1)*sizeof(WCHAR
);
246 /******************************************************************************
247 * RPC connection with servies.exe
250 static BOOL
check_services_exe(void)
252 static const WCHAR svcctl_started_event
[] = SVCCTL_STARTED_EVENT
;
253 HANDLE hEvent
= OpenEventW(SYNCHRONIZE
, FALSE
, svcctl_started_event
);
254 if (hEvent
== NULL
) /* need to start services.exe */
256 static const WCHAR services
[] = {'\\','s','e','r','v','i','c','e','s','.','e','x','e',0};
257 PROCESS_INFORMATION out
;
259 HANDLE wait_handles
[2];
260 WCHAR path
[MAX_PATH
];
262 if (!GetSystemDirectoryW(path
, MAX_PATH
- strlenW(services
)))
264 strcatW(path
, services
);
265 ZeroMemory(&si
, sizeof(si
));
267 if (!CreateProcessW(path
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &out
))
269 ERR("Couldn't start services.exe: error %u\n", GetLastError());
272 CloseHandle(out
.hThread
);
274 hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, svcctl_started_event
);
275 wait_handles
[0] = hEvent
;
276 wait_handles
[1] = out
.hProcess
;
278 /* wait for the event to become available or the process to exit */
279 if ((WaitForMultipleObjects(2, wait_handles
, FALSE
, INFINITE
)) == WAIT_OBJECT_0
+ 1)
282 GetExitCodeProcess(out
.hProcess
, &exit_code
);
283 ERR("Unexpected termination of services.exe - exit code %d\n", exit_code
);
284 CloseHandle(out
.hProcess
);
289 TRACE("services.exe started successfully\n");
290 CloseHandle(out
.hProcess
);
295 TRACE("Waiting for services.exe to be available\n");
296 WaitForSingleObject(hEvent
, INFINITE
);
297 TRACE("Services.exe are available\n");
303 handle_t __RPC_USER
MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName
)
305 WCHAR transport
[] = SVCCTL_TRANSPORT
;
306 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
307 LPWSTR server_copy
= NULL
;
308 RPC_WSTR binding_str
;
312 /* unlike Windows we start services.exe on demand. We start it always as
313 * checking if this is our address can be tricky */
314 if (!check_services_exe())
317 status
= RpcStringBindingComposeW(NULL
, transport
, (RPC_WSTR
)MachineName
, endpoint
, NULL
, &binding_str
);
318 HeapFree(GetProcessHeap(), 0, server_copy
);
319 if (status
!= RPC_S_OK
)
321 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
325 status
= RpcBindingFromStringBindingW(binding_str
, &rpc_handle
);
326 RpcStringFreeW(&binding_str
);
328 if (status
!= RPC_S_OK
)
330 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
337 void __RPC_USER
MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName
, handle_t h
)
342 /******************************************************************************
343 * Service IPC functions
345 static LPWSTR
service_get_pipe_name(void)
347 static const WCHAR format
[] = { '\\','\\','.','\\','p','i','p','e','\\',
348 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
349 static const WCHAR service_current_key_str
[] = { 'S','Y','S','T','E','M','\\',
350 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
351 'C','o','n','t','r','o','l','\\',
352 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
355 HKEY service_current_key
;
356 DWORD service_current
;
360 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, service_current_key_str
, 0,
361 KEY_QUERY_VALUE
, &service_current_key
);
362 if (ret
!= ERROR_SUCCESS
)
364 len
= sizeof(service_current
);
365 ret
= RegQueryValueExW(service_current_key
, NULL
, NULL
, &type
,
366 (BYTE
*)&service_current
, &len
);
367 RegCloseKey(service_current_key
);
368 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
370 len
= sizeof(format
)/sizeof(WCHAR
) + 10 /* strlenW("4294967295") */;
371 name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
374 snprintfW(name
, len
, format
, service_current
);
378 static HANDLE
service_open_pipe(void)
380 LPWSTR szPipe
= service_get_pipe_name();
381 HANDLE handle
= INVALID_HANDLE_VALUE
;
384 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
385 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
386 if (handle
!= INVALID_HANDLE_VALUE
)
388 if (GetLastError() != ERROR_PIPE_BUSY
)
390 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
391 HeapFree(GetProcessHeap(), 0, szPipe
);
396 /******************************************************************************
399 * Call into the main service routine provided by StartServiceCtrlDispatcher.
401 static DWORD WINAPI
service_thread(LPVOID arg
)
403 service_data
*info
= arg
;
404 LPWSTR str
= info
->args
;
405 DWORD argc
= 0, len
= 0;
411 len
+= strlenW(&str
[len
]) + 1;
418 info
->proc
.w(0, NULL
);
420 info
->proc
.a(0, NULL
);
428 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
429 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
433 info
->proc
.w(argc
, argv
);
434 HeapFree(GetProcessHeap(), 0, argv
);
438 LPSTR strA
, *argv
, p
;
441 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
442 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
443 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
445 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
446 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
450 info
->proc
.a(argc
, argv
);
451 HeapFree(GetProcessHeap(), 0, argv
);
452 HeapFree(GetProcessHeap(), 0, strA
);
457 /******************************************************************************
458 * service_handle_start
460 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
462 DWORD read
= 0, result
= 0;
466 TRACE("%p %p %d\n", pipe
, service
, count
);
468 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
469 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
470 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
472 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
473 r
, count
, read
, debugstr_wn(args
, count
));
479 WARN("service is not stopped\n");
480 result
= ERROR_SERVICE_ALREADY_RUNNING
;
484 HeapFree(GetProcessHeap(), 0, service
->args
);
485 service
->args
= args
;
487 service
->thread
= CreateThread( NULL
, 0, service_thread
,
489 SetEvent( service_event
); /* notify the main loop */
492 HeapFree(GetProcessHeap(), 0, args
);
493 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
498 /******************************************************************************
499 * service_handle_control
501 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
504 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
506 TRACE("received control %d\n", dwControl
);
508 if (service
->handler
)
509 ret
= service
->handler(dwControl
, 0, NULL
, service
->context
);
510 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
513 /******************************************************************************
514 * service_control_dispatcher
516 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
518 service_data
*service
= arg
;
521 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
523 pipe
= service_open_pipe();
525 if (pipe
==INVALID_HANDLE_VALUE
)
527 ERR("failed to create pipe for %s, error = %d\n",
528 debugstr_w(service
->name
), GetLastError());
532 /* dispatcher loop */
536 DWORD count
, req
[2] = {0,0};
538 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
541 if (GetLastError() != ERROR_BROKEN_PIPE
)
542 ERR( "pipe read failed error %u\n", GetLastError() );
545 if (count
!= sizeof(req
))
547 ERR( "partial pipe read %u\n", count
);
551 /* handle the request */
554 case WINESERV_STARTINFO
:
555 service_handle_start(pipe
, service
, req
[1]);
557 case WINESERV_SENDCONTROL
:
558 service_handle_control(pipe
, service
, req
[1]);
561 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
569 /******************************************************************************
570 * service_run_threads
572 static BOOL
service_run_threads(void)
575 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
576 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
578 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
580 wait_handles
[0] = __wine_make_process_system();
581 wait_handles
[1] = service_event
;
583 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
584 nb_services
, GetCurrentProcessId());
586 EnterCriticalSection( &service_cs
);
587 for (i
= 0; i
< nb_services
; i
++)
588 CloseHandle( CreateThread( NULL
, 0, service_control_dispatcher
, services
[i
], 0, NULL
));
589 LeaveCriticalSection( &service_cs
);
591 /* wait for all the threads to pack up and exit */
594 EnterCriticalSection( &service_cs
);
595 for (i
= 0, n
= 2; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
597 if (!services
[i
]->thread
) continue;
598 wait_services
[n
] = i
;
599 wait_handles
[n
++] = services
[i
]->thread
;
601 LeaveCriticalSection( &service_cs
);
603 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
604 if (!ret
) /* system process event */
606 TRACE( "last user process exited, shutting down\n" );
607 /* FIXME: we should maybe send a shutdown control to running services */
612 continue; /* rebuild the list */
616 services
[wait_services
[ret
]]->thread
= 0;
617 CloseHandle( wait_handles
[ret
] );
618 if (n
== 3) return TRUE
; /* it was the last running thread */
624 /******************************************************************************
625 * StartServiceCtrlDispatcherA [ADVAPI32.@]
627 * See StartServiceCtrlDispatcherW.
629 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
635 TRACE("%p\n", servent
);
639 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
642 while (servent
[nb_services
].lpServiceName
) nb_services
++;
643 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
645 for (i
= 0; i
< nb_services
; i
++)
647 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
648 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
649 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
650 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
651 info
->proc
.a
= servent
[i
].lpServiceProc
;
652 info
->unicode
= FALSE
;
656 service_run_threads();
661 /******************************************************************************
662 * StartServiceCtrlDispatcherW [ADVAPI32.@]
664 * Connects a process containing one or more services to the service control
668 * servent [I] A list of the service names and service procedures
674 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
680 TRACE("%p\n", servent
);
684 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
687 while (servent
[nb_services
].lpServiceName
) nb_services
++;
688 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
690 for (i
= 0; i
< nb_services
; i
++)
692 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
693 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
694 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
695 strcpyW(info
->name
, servent
[i
].lpServiceName
);
696 info
->proc
.w
= servent
[i
].lpServiceProc
;
697 info
->unicode
= TRUE
;
701 service_run_threads();
706 /******************************************************************************
707 * LockServiceDatabase [ADVAPI32.@]
709 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
711 struct sc_manager
*hscm
;
715 TRACE("%p\n",hSCManager
);
717 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
720 SetLastError( ERROR_INVALID_HANDLE
);
724 err
= svcctl_LockServiceDatabase(hscm
->hdr
.server_handle
, &hLock
);
725 if (err
!= ERROR_SUCCESS
)
733 /******************************************************************************
734 * UnlockServiceDatabase [ADVAPI32.@]
736 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
739 SC_RPC_LOCK hRpcLock
= ScLock
;
741 TRACE("%p\n",ScLock
);
743 err
= svcctl_UnlockServiceDatabase(&hRpcLock
);
744 if (err
!= ERROR_SUCCESS
)
752 /******************************************************************************
753 * SetServiceStatus [ADVAPI32.@]
760 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
762 struct sc_service
*hsvc
;
765 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
766 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
767 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
768 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
769 lpStatus
->dwWaitHint
);
771 hsvc
= sc_handle_get_handle_data((SC_HANDLE
)hService
, SC_HTYPE_SERVICE
);
774 SetLastError( ERROR_INVALID_HANDLE
);
778 err
= svcctl_SetServiceStatus( hsvc
->hdr
.server_handle
, lpStatus
);
779 if (err
!= ERROR_SUCCESS
)
785 if (lpStatus
->dwCurrentState
== SERVICE_STOPPED
)
786 CloseServiceHandle((SC_HANDLE
)hService
);
792 /******************************************************************************
793 * OpenSCManagerA [ADVAPI32.@]
795 * Establish a connection to the service control manager and open its database.
798 * lpMachineName [I] Pointer to machine name string
799 * lpDatabaseName [I] Pointer to database name string
800 * dwDesiredAccess [I] Type of access
803 * Success: A Handle to the service control manager database
806 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
807 DWORD dwDesiredAccess
)
809 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
812 lpMachineNameW
= SERV_dup(lpMachineName
);
813 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
814 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
815 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW
);
816 HeapFree(GetProcessHeap(), 0, lpMachineNameW
);
820 /******************************************************************************
821 * OpenSCManagerW [ADVAPI32.@]
823 * See OpenSCManagerA.
825 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
826 DWORD dwDesiredAccess
)
828 struct sc_manager
*manager
;
831 DWORD new_mask
= dwDesiredAccess
;
833 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
834 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
836 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
837 sc_handle_destroy_manager
);
841 r
= svcctl_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, &manager
->hdr
.server_handle
);
842 if (r
!=ERROR_SUCCESS
)
845 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
846 if (r
!=ERROR_SUCCESS
)
849 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
851 if (r
!=ERROR_SUCCESS
)
854 RtlMapGenericMask(&new_mask
, &scm_generic
);
855 manager
->dwAccess
= new_mask
;
856 TRACE("returning %p (access : 0x%08x)\n", manager
, manager
->dwAccess
);
858 return (SC_HANDLE
) &manager
->hdr
;
861 sc_handle_free( &manager
->hdr
);
866 /******************************************************************************
867 * ControlService [ADVAPI32.@]
869 * Send a control code to a service.
872 * hService [I] Handle of the service control manager database
873 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
874 * lpServiceStatus [O] Destination for the status of the service, if available
881 * Unlike M$' implementation, control requests are not serialized and may be
882 * processed asynchronously.
884 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
885 LPSERVICE_STATUS lpServiceStatus
)
887 struct sc_service
*hsvc
;
890 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
892 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
895 SetLastError( ERROR_INVALID_HANDLE
);
899 err
= svcctl_ControlService(hsvc
->hdr
.server_handle
, dwControl
, lpServiceStatus
);
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
;
935 err
= svcctl_CloseServiceHandle(&obj
->server_handle
);
936 sc_handle_free( obj
);
938 if (err
!= ERROR_SUCCESS
)
947 /******************************************************************************
948 * OpenServiceA [ADVAPI32.@]
950 * Open a handle to a service.
953 * hSCManager [I] Handle of the service control manager database
954 * lpServiceName [I] Name of the service to open
955 * dwDesiredAccess [I] Access required to the service
958 * Success: Handle to the service
961 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
962 DWORD dwDesiredAccess
)
964 LPWSTR lpServiceNameW
;
967 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
969 lpServiceNameW
= SERV_dup(lpServiceName
);
970 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
971 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
976 /******************************************************************************
977 * OpenServiceW [ADVAPI32.@]
981 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
982 DWORD dwDesiredAccess
)
984 struct sc_manager
*hscm
;
985 struct sc_service
*hsvc
;
988 DWORD new_mask
= dwDesiredAccess
;
990 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
992 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
995 SetLastError( ERROR_INVALID_HANDLE
);
1001 SetLastError(ERROR_INVALID_ADDRESS
);
1005 len
= strlenW(lpServiceName
)+1;
1006 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1007 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1008 sc_handle_destroy_service
);
1011 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1014 strcpyW( hsvc
->name
, lpServiceName
);
1016 /* add reference to SCM handle */
1017 hscm
->hdr
.ref_count
++;
1020 err
= svcctl_OpenServiceW(hscm
->hdr
.server_handle
, lpServiceName
, dwDesiredAccess
, &hsvc
->hdr
.server_handle
);
1022 if (err
!= ERROR_SUCCESS
)
1024 sc_handle_free(&hsvc
->hdr
);
1029 /* for parts of advapi32 not using services.exe yet */
1030 RtlMapGenericMask(&new_mask
, &svc_generic
);
1031 hsvc
->dwAccess
= new_mask
;
1033 err
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hsvc
->hkey
);
1034 if (err
!= ERROR_SUCCESS
)
1035 ERR("Shouldn't hapen - service key for service validated by services.exe doesn't exist\n");
1037 TRACE("returning %p\n",hsvc
);
1039 return (SC_HANDLE
) &hsvc
->hdr
;
1042 /******************************************************************************
1043 * CreateServiceW [ADVAPI32.@]
1046 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1047 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1048 DWORD dwServiceType
, DWORD dwStartType
,
1049 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1050 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1051 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1052 LPCWSTR lpPassword
)
1054 struct sc_manager
*hscm
;
1055 struct sc_service
*hsvc
= NULL
;
1056 DWORD new_mask
= dwDesiredAccess
;
1060 TRACE("%p %s %s\n", hSCManager
,
1061 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1063 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1066 SetLastError( ERROR_INVALID_HANDLE
);
1070 if (!lpServiceName
|| !lpBinaryPathName
)
1072 SetLastError(ERROR_INVALID_ADDRESS
);
1077 passwdlen
= (strlenW(lpPassword
) + 1) * sizeof(WCHAR
);
1081 len
= strlenW(lpServiceName
)+1;
1082 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1083 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1086 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1089 lstrcpyW( hsvc
->name
, lpServiceName
);
1092 hscm
->hdr
.ref_count
++;
1094 err
= svcctl_CreateServiceW(hscm
->hdr
.server_handle
, lpServiceName
,
1095 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1096 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (LPBYTE
)lpDependencies
,
1097 multisz_cb(lpDependencies
), lpServiceStartName
, (LPBYTE
)lpPassword
, passwdlen
,
1098 &hsvc
->hdr
.server_handle
);
1100 if (err
!= ERROR_SUCCESS
)
1103 sc_handle_free(&hsvc
->hdr
);
1107 /* for parts of advapi32 not using services.exe yet */
1108 err
= RegOpenKeyW(hscm
->hkey
, lpServiceName
, &hsvc
->hkey
);
1109 if (err
!= ERROR_SUCCESS
)
1110 WINE_ERR("Couldn't open key that should have been created by services.exe\n");
1112 RtlMapGenericMask(&new_mask
, &svc_generic
);
1113 hsvc
->dwAccess
= new_mask
;
1115 return (SC_HANDLE
) &hsvc
->hdr
;
1119 /******************************************************************************
1120 * CreateServiceA [ADVAPI32.@]
1123 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1124 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1125 DWORD dwServiceType
, DWORD dwStartType
,
1126 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1127 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1128 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1131 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1132 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1135 TRACE("%p %s %s\n", hSCManager
,
1136 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1138 lpServiceNameW
= SERV_dup( lpServiceName
);
1139 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1140 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1141 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1142 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1143 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1144 lpPasswordW
= SERV_dup( lpPassword
);
1146 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1147 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1148 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1149 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1151 HeapFree( GetProcessHeap(), 0, lpServiceNameW
);
1152 HeapFree( GetProcessHeap(), 0, lpDisplayNameW
);
1153 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW
);
1154 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW
);
1155 HeapFree( GetProcessHeap(), 0, lpDependenciesW
);
1156 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW
);
1157 HeapFree( GetProcessHeap(), 0, lpPasswordW
);
1163 /******************************************************************************
1164 * DeleteService [ADVAPI32.@]
1166 * Delete a service from the service control manager database.
1169 * hService [I] Handle of the service to delete
1175 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1177 struct sc_service
*hsvc
;
1180 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1183 SetLastError( ERROR_INVALID_HANDLE
);
1187 err
= svcctl_DeleteService(hsvc
->hdr
.server_handle
);
1194 /* Close the key to the service */
1195 RegCloseKey(hsvc
->hkey
);
1201 /******************************************************************************
1202 * StartServiceA [ADVAPI32.@]
1207 * hService [I] Handle of service
1208 * dwNumServiceArgs [I] Number of arguments
1209 * lpServiceArgVectors [I] Address of array of argument strings
1212 * - NT implements this function using an obscure RPC call.
1213 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1214 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1215 * - This will only work for shared address space. How should the service
1216 * args be transferred when address spaces are separated?
1217 * - Can only start one service at a time.
1218 * - Has no concept of privilege.
1224 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1225 LPCSTR
*lpServiceArgVectors
)
1227 LPWSTR
*lpwstr
=NULL
;
1231 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1233 if (dwNumServiceArgs
)
1234 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1235 dwNumServiceArgs
*sizeof(LPWSTR
) );
1237 for(i
=0; i
<dwNumServiceArgs
; i
++)
1238 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1240 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1242 if (dwNumServiceArgs
)
1244 for(i
=0; i
<dwNumServiceArgs
; i
++)
1245 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
1246 HeapFree(GetProcessHeap(), 0, lpwstr
);
1253 /******************************************************************************
1254 * StartServiceW [ADVAPI32.@]
1256 * See StartServiceA.
1258 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1259 LPCWSTR
*lpServiceArgVectors
)
1261 struct sc_service
*hsvc
;
1264 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1266 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1269 SetLastError(ERROR_INVALID_HANDLE
);
1273 err
= svcctl_StartServiceW(hsvc
->hdr
.server_handle
, dwNumServiceArgs
, lpServiceArgVectors
);
1274 if (err
!= ERROR_SUCCESS
)
1283 /******************************************************************************
1284 * QueryServiceStatus [ADVAPI32.@]
1287 * hService [I] Handle to service to get information about
1288 * lpservicestatus [O] buffer to receive the status information for the service
1291 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1292 LPSERVICE_STATUS lpservicestatus
)
1294 SERVICE_STATUS_PROCESS SvcStatusData
;
1298 TRACE("%p %p\n", hService
, lpservicestatus
);
1300 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1301 sizeof(SERVICE_STATUS_PROCESS
), &dummy
);
1302 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1307 /******************************************************************************
1308 * QueryServiceStatusEx [ADVAPI32.@]
1310 * Get information about a service.
1313 * hService [I] Handle to service to get information about
1314 * InfoLevel [I] Level of information to get
1315 * lpBuffer [O] Destination for requested information
1316 * cbBufSize [I] Size of lpBuffer in bytes
1317 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1323 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1324 LPBYTE lpBuffer
, DWORD cbBufSize
,
1325 LPDWORD pcbBytesNeeded
)
1327 struct sc_service
*hsvc
;
1330 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1332 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1335 SetLastError( ERROR_INVALID_HANDLE
);
1339 err
= svcctl_QueryServiceStatusEx(hsvc
->hdr
.server_handle
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1340 if (err
!= ERROR_SUCCESS
)
1349 /******************************************************************************
1350 * QueryServiceConfigA [ADVAPI32.@]
1352 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1353 DWORD size
, LPDWORD needed
)
1358 QUERY_SERVICE_CONFIGW
*configW
;
1360 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1362 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1364 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1367 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1368 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1369 if (!ret
) goto done
;
1371 config
->dwServiceType
= configW
->dwServiceType
;
1372 config
->dwStartType
= configW
->dwStartType
;
1373 config
->dwErrorControl
= configW
->dwErrorControl
;
1374 config
->lpBinaryPathName
= NULL
;
1375 config
->lpLoadOrderGroup
= NULL
;
1376 config
->dwTagId
= configW
->dwTagId
;
1377 config
->lpDependencies
= NULL
;
1378 config
->lpServiceStartName
= NULL
;
1379 config
->lpDisplayName
= NULL
;
1381 p
= (LPSTR
)(config
+ 1);
1382 n
= size
- sizeof(*config
);
1385 #define MAP_STR(str) \
1389 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1390 if (!sz) goto done; \
1397 MAP_STR( lpBinaryPathName
);
1398 MAP_STR( lpLoadOrderGroup
);
1399 MAP_STR( lpDependencies
);
1400 MAP_STR( lpServiceStartName
);
1401 MAP_STR( lpDisplayName
);
1404 *needed
= p
- (LPSTR
)config
;
1408 HeapFree( GetProcessHeap(), 0, buffer
);
1412 static DWORD
move_string_to_buffer(BYTE
**buf
, LPWSTR
*string_ptr
)
1415 WCHAR empty_str
[] = {0};
1418 *string_ptr
= empty_str
;
1420 cb
= (strlenW(*string_ptr
) + 1)*sizeof(WCHAR
);
1422 memcpy(*buf
, *string_ptr
, cb
);
1423 MIDL_user_free(*string_ptr
);
1424 *string_ptr
= (LPWSTR
)*buf
;
1430 static DWORD
size_string(LPWSTR string
)
1432 return (string
? (strlenW(string
) + 1)*sizeof(WCHAR
) : sizeof(WCHAR
));
1435 /******************************************************************************
1436 * QueryServiceConfigW [ADVAPI32.@]
1439 QueryServiceConfigW( SC_HANDLE hService
,
1440 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1441 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1443 QUERY_SERVICE_CONFIGW config
;
1444 struct sc_service
*hsvc
;
1449 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1450 cbBufSize
, pcbBytesNeeded
);
1452 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1455 SetLastError( ERROR_INVALID_HANDLE
);
1459 memset(&config
, 0, sizeof(config
));
1461 if ((err
= svcctl_QueryServiceConfigW(hsvc
->hdr
.server_handle
, &config
)) != 0)
1463 TRACE("services.exe: error %u\n", err
);
1468 /* calculate the size required first */
1469 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1470 total
+= size_string(config
.lpBinaryPathName
);
1471 total
+= size_string(config
.lpLoadOrderGroup
);
1472 total
+= size_string(config
.lpDependencies
);
1473 total
+= size_string(config
.lpServiceStartName
);
1474 total
+= size_string(config
.lpDisplayName
);
1476 *pcbBytesNeeded
= total
;
1478 /* if there's not enough memory, return an error */
1479 if( total
> cbBufSize
)
1481 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1482 MIDL_user_free(config
.lpBinaryPathName
);
1483 MIDL_user_free(config
.lpLoadOrderGroup
);
1484 MIDL_user_free(config
.lpDependencies
);
1485 MIDL_user_free(config
.lpServiceStartName
);
1486 MIDL_user_free(config
.lpDisplayName
);
1490 *lpServiceConfig
= config
;
1491 bufpos
= ((BYTE
*)lpServiceConfig
) + sizeof(QUERY_SERVICE_CONFIGW
);
1492 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpBinaryPathName
);
1493 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpLoadOrderGroup
);
1494 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDependencies
);
1495 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpServiceStartName
);
1496 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDisplayName
);
1498 if (bufpos
- (LPBYTE
)lpServiceConfig
> cbBufSize
)
1499 ERR("Buffer overflow!\n");
1501 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1502 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1503 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
1504 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
1505 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
1510 /******************************************************************************
1511 * QueryServiceConfig2A [ADVAPI32.@]
1514 * observed under win2k:
1515 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1516 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1518 BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1519 DWORD size
, LPDWORD needed
)
1522 LPBYTE bufferW
= NULL
;
1525 bufferW
= HeapAlloc( GetProcessHeap(), 0, size
);
1527 ret
= QueryServiceConfig2W(hService
, dwLevel
, bufferW
, size
, needed
);
1528 if(!ret
) goto cleanup
;
1531 case SERVICE_CONFIG_DESCRIPTION
:
1532 { LPSERVICE_DESCRIPTIONA configA
= (LPSERVICE_DESCRIPTIONA
) buffer
;
1533 LPSERVICE_DESCRIPTIONW configW
= (LPSERVICE_DESCRIPTIONW
) bufferW
;
1534 if (configW
->lpDescription
) {
1536 configA
->lpDescription
= (LPSTR
)(configA
+ 1);
1537 sz
= WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1,
1538 configA
->lpDescription
, size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
1540 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1542 configA
->lpDescription
= NULL
;
1545 else configA
->lpDescription
= NULL
;
1549 FIXME("conversation W->A not implemented for level %d\n", dwLevel
);
1554 HeapFree( GetProcessHeap(), 0, bufferW
);
1558 /******************************************************************************
1559 * QueryServiceConfig2W [ADVAPI32.@]
1561 BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1562 DWORD size
, LPDWORD needed
)
1567 struct sc_service
*hsvc
;
1569 if(dwLevel
!= SERVICE_CONFIG_DESCRIPTION
) {
1570 if((dwLevel
== SERVICE_CONFIG_DELAYED_AUTO_START_INFO
) ||
1571 (dwLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
) ||
1572 (dwLevel
== SERVICE_CONFIG_FAILURE_ACTIONS_FLAG
) ||
1573 (dwLevel
== SERVICE_CONFIG_PRESHUTDOWN_INFO
) ||
1574 (dwLevel
== SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO
) ||
1575 (dwLevel
== SERVICE_CONFIG_SERVICE_SID_INFO
))
1576 FIXME("Level %d not implemented\n", dwLevel
);
1577 SetLastError(ERROR_INVALID_LEVEL
);
1580 if(!needed
|| (!buffer
&& size
)) {
1581 SetLastError(ERROR_INVALID_ADDRESS
);
1585 TRACE("%p 0x%d %p 0x%d %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1587 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1590 SetLastError(ERROR_INVALID_HANDLE
);
1596 case SERVICE_CONFIG_DESCRIPTION
: {
1597 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1598 LPSERVICE_DESCRIPTIONW config
= (LPSERVICE_DESCRIPTIONW
) buffer
;
1599 LPBYTE strbuf
= NULL
;
1600 *needed
= sizeof (SERVICE_DESCRIPTIONW
);
1601 sz
= size
- *needed
;
1602 if(config
&& (*needed
<= size
))
1603 strbuf
= (LPBYTE
) (config
+ 1);
1604 r
= RegQueryValueExW( hKey
, szDescription
, 0, &type
, strbuf
, &sz
);
1605 if((r
== ERROR_SUCCESS
) && ( type
!= REG_SZ
)) {
1606 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type
);
1611 if(r
== ERROR_SUCCESS
)
1612 config
->lpDescription
= (LPWSTR
) (config
+ 1);
1614 config
->lpDescription
= NULL
;
1620 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
1622 return (*needed
<= size
);
1625 /******************************************************************************
1626 * EnumServicesStatusA [ADVAPI32.@]
1629 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1630 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
1631 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1632 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1634 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1635 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1636 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1637 SetLastError (ERROR_ACCESS_DENIED
);
1641 /******************************************************************************
1642 * EnumServicesStatusW [ADVAPI32.@]
1645 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1646 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
1647 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1648 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1650 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1651 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1652 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1653 SetLastError (ERROR_ACCESS_DENIED
);
1657 /******************************************************************************
1658 * EnumServicesStatusExA [ADVAPI32.@]
1661 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
1662 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1663 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
1665 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
1666 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1667 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
1668 *lpServicesReturned
= 0;
1669 SetLastError (ERROR_ACCESS_DENIED
);
1673 /******************************************************************************
1674 * EnumServicesStatusExW [ADVAPI32.@]
1677 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
1678 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1679 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
1681 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
1682 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1683 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
1684 SetLastError (ERROR_ACCESS_DENIED
);
1688 /******************************************************************************
1689 * GetServiceKeyNameA [ADVAPI32.@]
1691 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1692 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1694 LPWSTR lpDisplayNameW
, lpServiceNameW
;
1698 TRACE("%p %s %p %p\n", hSCManager
,
1699 debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1701 lpDisplayNameW
= SERV_dup(lpDisplayName
);
1703 lpServiceNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
1705 lpServiceNameW
= NULL
;
1707 sizeW
= *lpcchBuffer
;
1708 if (!GetServiceKeyNameW(hSCManager
, lpDisplayNameW
, lpServiceNameW
, &sizeW
))
1710 if (*lpcchBuffer
&& lpServiceName
)
1711 lpServiceName
[0] = 0;
1712 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1716 if (!WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, (sizeW
+ 1), lpServiceName
,
1717 *lpcchBuffer
, NULL
, NULL
))
1719 if (*lpcchBuffer
&& lpServiceName
)
1720 lpServiceName
[0] = 0;
1721 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, -1, NULL
, 0, NULL
, NULL
);
1725 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1729 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1730 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
1734 /******************************************************************************
1735 * GetServiceKeyNameW [ADVAPI32.@]
1737 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1738 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1740 struct sc_manager
*hscm
;
1743 TRACE("%p %s %p %p\n", hSCManager
,
1744 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1746 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
1749 SetLastError(ERROR_INVALID_HANDLE
);
1755 SetLastError(ERROR_INVALID_ADDRESS
);
1759 err
= svcctl_GetServiceKeyNameW(hscm
->hdr
.server_handle
,
1760 lpDisplayName
, lpServiceName
, lpServiceName
? *lpcchBuffer
: 0, lpcchBuffer
);
1764 return err
== ERROR_SUCCESS
;
1767 /******************************************************************************
1768 * QueryServiceLockStatusA [ADVAPI32.@]
1770 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1771 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1772 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1774 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1779 /******************************************************************************
1780 * QueryServiceLockStatusW [ADVAPI32.@]
1782 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
1783 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
1784 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1786 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1791 /******************************************************************************
1792 * GetServiceDisplayNameA [ADVAPI32.@]
1794 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1795 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1797 LPWSTR lpServiceNameW
, lpDisplayNameW
;
1801 TRACE("%p %s %p %p\n", hSCManager
,
1802 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1804 lpServiceNameW
= SERV_dup(lpServiceName
);
1806 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
1808 lpDisplayNameW
= NULL
;
1810 sizeW
= *lpcchBuffer
;
1811 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
1813 if (*lpcchBuffer
&& lpDisplayName
)
1814 lpDisplayName
[0] = 0;
1815 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1819 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
1820 *lpcchBuffer
, NULL
, NULL
))
1822 if (*lpcchBuffer
&& lpDisplayName
)
1823 lpDisplayName
[0] = 0;
1824 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
1828 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1829 * (but if the function succeeded it means that is a good upper estimation of the size) */
1833 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
1834 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1838 /******************************************************************************
1839 * GetServiceDisplayNameW [ADVAPI32.@]
1841 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1842 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1844 struct sc_manager
*hscm
;
1847 TRACE("%p %s %p %p\n", hSCManager
,
1848 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1850 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
1853 SetLastError(ERROR_INVALID_HANDLE
);
1859 SetLastError(ERROR_INVALID_ADDRESS
);
1863 err
= svcctl_GetServiceDisplayNameW(hscm
->hdr
.server_handle
,
1864 lpServiceName
, lpDisplayName
, lpDisplayName
? *lpcchBuffer
: 0, lpcchBuffer
);
1868 return err
== ERROR_SUCCESS
;
1871 /******************************************************************************
1872 * ChangeServiceConfigW [ADVAPI32.@]
1874 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1875 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1876 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1877 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1879 struct sc_service
*hsvc
;
1883 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1884 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1885 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1886 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1887 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1889 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1892 SetLastError( ERROR_INVALID_HANDLE
);
1896 cb_pwd
= lpPassword
? (strlenW(lpPassword
) + 1)*sizeof(WCHAR
) : 0;
1898 err
= svcctl_ChangeServiceConfigW(hsvc
->hdr
.server_handle
, dwServiceType
,
1899 dwStartType
, dwErrorControl
, lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
,
1900 (const BYTE
*)lpDependencies
, multisz_cb(lpDependencies
), lpServiceStartName
,
1901 (const BYTE
*)lpPassword
, cb_pwd
, lpDisplayName
);
1903 if (err
!= ERROR_SUCCESS
)
1906 return err
== ERROR_SUCCESS
;
1909 /******************************************************************************
1910 * ChangeServiceConfigA [ADVAPI32.@]
1912 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1913 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1914 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
1915 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
1917 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
1918 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
1921 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1922 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1923 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
1924 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
1925 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
1927 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
1928 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
1929 wDependencies
= SERV_dupmulti( lpDependencies
);
1930 wServiceStartName
= SERV_dup( lpServiceStartName
);
1931 wPassword
= SERV_dup( lpPassword
);
1932 wDisplayName
= SERV_dup( lpDisplayName
);
1934 r
= ChangeServiceConfigW( hService
, dwServiceType
,
1935 dwStartType
, dwErrorControl
, wBinaryPathName
,
1936 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
1937 wServiceStartName
, wPassword
, wDisplayName
);
1939 HeapFree( GetProcessHeap(), 0, wBinaryPathName
);
1940 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup
);
1941 HeapFree( GetProcessHeap(), 0, wDependencies
);
1942 HeapFree( GetProcessHeap(), 0, wServiceStartName
);
1943 HeapFree( GetProcessHeap(), 0, wPassword
);
1944 HeapFree( GetProcessHeap(), 0, wDisplayName
);
1949 /******************************************************************************
1950 * ChangeServiceConfig2A [ADVAPI32.@]
1952 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
1957 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
1959 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
1961 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
1962 SERVICE_DESCRIPTIONW sdw
;
1964 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
1966 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
1968 HeapFree( GetProcessHeap(), 0, sdw
.lpDescription
);
1970 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
1972 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
1973 SERVICE_FAILURE_ACTIONSW faw
;
1975 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
1976 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
1977 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
1978 faw
.cActions
= fa
->cActions
;
1979 faw
.lpsaActions
= fa
->lpsaActions
;
1981 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
1983 HeapFree( GetProcessHeap(), 0, faw
.lpRebootMsg
);
1984 HeapFree( GetProcessHeap(), 0, faw
.lpCommand
);
1987 SetLastError( ERROR_INVALID_PARAMETER
);
1992 /******************************************************************************
1993 * ChangeServiceConfig2W [ADVAPI32.@]
1995 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
1999 struct sc_service
*hsvc
;
2001 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2004 SetLastError( ERROR_INVALID_HANDLE
);
2009 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2011 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2012 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2013 if (sd
->lpDescription
)
2015 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2016 if (sd
->lpDescription
[0] == 0)
2017 RegDeleteValueW(hKey
,szDescription
);
2019 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2020 (LPVOID
)sd
->lpDescription
,
2021 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2025 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2029 /******************************************************************************
2030 * QueryServiceObjectSecurity [ADVAPI32.@]
2032 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2033 SECURITY_INFORMATION dwSecurityInformation
,
2034 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2035 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2037 SECURITY_DESCRIPTOR descriptor
;
2042 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2043 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2045 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2046 FIXME("information %d not supported\n", dwSecurityInformation
);
2048 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2050 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2051 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2054 succ
= MakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2055 *pcbBytesNeeded
= size
;
2059 /******************************************************************************
2060 * SetServiceObjectSecurity [ADVAPI32.@]
2062 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2063 SECURITY_INFORMATION dwSecurityInformation
,
2064 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2066 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2070 /******************************************************************************
2071 * SetServiceBits [ADVAPI32.@]
2073 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2074 DWORD dwServiceBits
,
2076 BOOL bUpdateImmediately
)
2078 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2079 bSetBitsOn
, bUpdateImmediately
);
2083 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2084 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
2086 LPHANDLER_FUNCTION func
= context
;
2089 return ERROR_SUCCESS
;
2092 /******************************************************************************
2093 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2095 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
2097 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
2100 /******************************************************************************
2101 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2103 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
2105 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
2108 /******************************************************************************
2109 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2111 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
2114 SERVICE_STATUS_HANDLE ret
;
2116 nameW
= SERV_dup(name
);
2117 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
2118 HeapFree( GetProcessHeap(), 0, nameW
);
2122 /******************************************************************************
2123 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2125 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2126 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2133 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2135 hSCM
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
2138 hService
= OpenServiceW( hSCM
, lpServiceName
, SERVICE_SET_STATUS
);
2139 CloseServiceHandle(hSCM
);
2143 EnterCriticalSection( &service_cs
);
2144 for (i
= 0; i
< nb_services
; i
++)
2146 if(!strcmpW(lpServiceName
, services
[i
]->name
))
2148 services
[i
]->handler
= lpHandlerProc
;
2149 services
[i
]->context
= lpContext
;
2154 LeaveCriticalSection( &service_cs
);
2158 CloseServiceHandle(hService
);
2159 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2163 return (SERVICE_STATUS_HANDLE
)hService
;
2166 /******************************************************************************
2167 * EnumDependentServicesA [ADVAPI32.@]
2169 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2170 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2171 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2173 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2174 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2176 *lpServicesReturned
= 0;
2180 /******************************************************************************
2181 * EnumDependentServicesW [ADVAPI32.@]
2183 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2184 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2185 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2187 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2188 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2190 *lpServicesReturned
= 0;