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
24 #include "wine/port.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
44 #include "wine/exception.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(service
);
48 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
49 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
50 'S','e','r','v','i','c','e','s',0 };
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 typedef struct service_data_t
64 LPHANDLER_FUNCTION_EX handler
;
70 LPSERVICE_MAIN_FUNCTIONA a
;
71 LPSERVICE_MAIN_FUNCTIONW w
;
77 static CRITICAL_SECTION service_cs
;
78 static CRITICAL_SECTION_DEBUG service_cs_debug
=
81 { &service_cs_debug
.ProcessLocksList
,
82 &service_cs_debug
.ProcessLocksList
},
83 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
85 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
87 static service_data
**services
;
88 static unsigned int nb_services
;
89 static HANDLE service_event
;
91 extern HANDLE CDECL
__wine_make_process_system(void);
93 /******************************************************************************
94 * String management functions (same behaviour as strdup)
95 * NOTE: the caller of those functions is responsible for calling HeapFree
96 * in order to release the memory allocated by those functions.
98 static inline LPWSTR
SERV_dup( LPCSTR str
)
105 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
106 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
107 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
111 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
119 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
120 n
+= (strlen( &str
[n
] ) + 1);
125 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
126 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
130 static inline DWORD
multisz_cb(LPCWSTR wmultisz
)
132 const WCHAR
*wptr
= wmultisz
;
134 if (wmultisz
== NULL
)
138 wptr
+= lstrlenW(wptr
)+1;
139 return (wptr
- wmultisz
+ 1)*sizeof(WCHAR
);
142 /******************************************************************************
143 * RPC connection with services.exe
146 handle_t __RPC_USER
MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName
)
148 WCHAR transport
[] = SVCCTL_TRANSPORT
;
149 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
150 RPC_WSTR binding_str
;
154 status
= RpcStringBindingComposeW(NULL
, transport
, (RPC_WSTR
)MachineName
, endpoint
, NULL
, &binding_str
);
155 if (status
!= RPC_S_OK
)
157 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
161 status
= RpcBindingFromStringBindingW(binding_str
, &rpc_handle
);
162 RpcStringFreeW(&binding_str
);
164 if (status
!= RPC_S_OK
)
166 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
173 void __RPC_USER
MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName
, handle_t h
)
178 static LONG WINAPI
rpc_filter(EXCEPTION_POINTERS
*eptr
)
180 return I_RpcExceptionFilter(eptr
->ExceptionRecord
->ExceptionCode
);
183 static DWORD
map_exception_code(DWORD exception_code
)
185 switch (exception_code
)
187 case RPC_X_NULL_REF_POINTER
:
188 return ERROR_INVALID_ADDRESS
;
189 case RPC_X_ENUM_VALUE_OUT_OF_RANGE
:
190 case RPC_X_BYTE_COUNT_TOO_SMALL
:
191 return ERROR_INVALID_PARAMETER
;
192 case RPC_S_INVALID_BINDING
:
193 case RPC_X_SS_IN_NULL_CONTEXT
:
194 return ERROR_INVALID_HANDLE
;
196 return exception_code
;
200 /******************************************************************************
201 * Service IPC functions
203 static LPWSTR
service_get_pipe_name(void)
205 static const WCHAR format
[] = { '\\','\\','.','\\','p','i','p','e','\\',
206 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
207 static const WCHAR service_current_key_str
[] = { 'S','Y','S','T','E','M','\\',
208 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
209 'C','o','n','t','r','o','l','\\',
210 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
213 HKEY service_current_key
;
214 DWORD service_current
;
218 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, service_current_key_str
, 0,
219 KEY_QUERY_VALUE
, &service_current_key
);
220 if (ret
!= ERROR_SUCCESS
)
222 len
= sizeof(service_current
);
223 ret
= RegQueryValueExW(service_current_key
, NULL
, NULL
, &type
,
224 (BYTE
*)&service_current
, &len
);
225 RegCloseKey(service_current_key
);
226 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
228 len
= sizeof(format
)/sizeof(WCHAR
) + 10 /* strlenW("4294967295") */;
229 name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
232 snprintfW(name
, len
, format
, service_current
);
236 static HANDLE
service_open_pipe(void)
238 LPWSTR szPipe
= service_get_pipe_name();
239 HANDLE handle
= INVALID_HANDLE_VALUE
;
242 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
243 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
244 if (handle
!= INVALID_HANDLE_VALUE
)
246 if (GetLastError() != ERROR_PIPE_BUSY
)
248 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
249 HeapFree(GetProcessHeap(), 0, szPipe
);
254 static service_data
*find_service_by_name( const WCHAR
*name
)
258 if (nb_services
== 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
260 for (i
= 0; i
< nb_services
; i
++)
261 if (!strcmpiW( name
, services
[i
]->name
)) return services
[i
];
265 /******************************************************************************
268 * Call into the main service routine provided by StartServiceCtrlDispatcher.
270 static DWORD WINAPI
service_thread(LPVOID arg
)
272 service_data
*info
= arg
;
273 LPWSTR str
= info
->args
;
274 DWORD argc
= 0, len
= 0;
280 len
+= strlenW(&str
[len
]) + 1;
289 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
290 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
294 info
->proc
.w(argc
, argv
);
295 HeapFree(GetProcessHeap(), 0, argv
);
299 LPSTR strA
, *argv
, p
;
302 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
303 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
304 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
306 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
307 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
311 info
->proc
.a(argc
, argv
);
312 HeapFree(GetProcessHeap(), 0, argv
);
313 HeapFree(GetProcessHeap(), 0, strA
);
318 /******************************************************************************
319 * service_handle_start
321 static DWORD
service_handle_start(service_data
*service
, const WCHAR
*data
, DWORD count
)
323 TRACE("%s argsize %u\n", debugstr_w(service
->name
), count
);
327 WARN("service is not stopped\n");
328 return ERROR_SERVICE_ALREADY_RUNNING
;
331 HeapFree(GetProcessHeap(), 0, service
->args
);
332 service
->args
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WCHAR
));
333 memcpy( service
->args
, data
, count
* sizeof(WCHAR
) );
334 service
->thread
= CreateThread( NULL
, 0, service_thread
,
336 SetEvent( service_event
); /* notify the main loop */
340 /******************************************************************************
341 * service_handle_control
343 static DWORD
service_handle_control(const service_data
*service
, DWORD dwControl
)
345 DWORD ret
= ERROR_INVALID_SERVICE_CONTROL
;
347 TRACE("%s control %u\n", debugstr_w(service
->name
), dwControl
);
349 if (service
->handler
)
350 ret
= service
->handler(dwControl
, 0, NULL
, service
->context
);
354 /******************************************************************************
355 * service_control_dispatcher
357 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
362 if (!(manager
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
)))
364 ERR("failed to open service manager error %u\n", GetLastError());
368 pipe
= service_open_pipe();
370 if (pipe
==INVALID_HANDLE_VALUE
)
372 ERR("failed to create control pipe error = %d\n", GetLastError());
376 /* dispatcher loop */
379 service_data
*service
;
380 service_start_info info
;
383 DWORD data_size
= 0, count
, result
;
385 r
= ReadFile( pipe
, &info
, FIELD_OFFSET(service_start_info
,data
), &count
, NULL
);
388 if (GetLastError() != ERROR_BROKEN_PIPE
)
389 ERR( "pipe read failed error %u\n", GetLastError() );
392 if (count
!= FIELD_OFFSET(service_start_info
,data
))
394 ERR( "partial pipe read %u\n", count
);
397 if (count
< info
.total_size
)
399 data_size
= info
.total_size
- FIELD_OFFSET(service_start_info
,data
);
400 data
= HeapAlloc( GetProcessHeap(), 0, data_size
);
401 r
= ReadFile( pipe
, data
, data_size
, &count
, NULL
);
404 if (GetLastError() != ERROR_BROKEN_PIPE
)
405 ERR( "pipe read failed error %u\n", GetLastError() );
408 if (count
!= data_size
)
410 ERR( "partial pipe read %u/%u\n", count
, data_size
);
415 /* find the service */
417 if (!(service
= find_service_by_name( data
)))
419 FIXME( "got request %u for unknown service %s\n", info
.cmd
, debugstr_w(data
));
420 result
= ERROR_INVALID_PARAMETER
;
424 TRACE( "got request %u for service %s\n", info
.cmd
, debugstr_w(data
) );
426 /* handle the request */
429 case WINESERV_STARTINFO
:
430 if (!service
->handle
)
432 if (!(service
->handle
= OpenServiceW( manager
, data
, SERVICE_SET_STATUS
)))
433 FIXME( "failed to open service %s\n", debugstr_w(data
) );
435 result
= service_handle_start(service
, data
+ info
.name_size
,
436 data_size
/ sizeof(WCHAR
) - info
.name_size
);
438 case WINESERV_SENDCONTROL
:
439 result
= service_handle_control(service
, info
.control
);
442 ERR("received invalid command %u\n", info
.cmd
);
443 result
= ERROR_INVALID_PARAMETER
;
448 WriteFile(pipe
, &result
, sizeof(result
), &count
, NULL
);
449 HeapFree( GetProcessHeap(), 0, data
);
453 CloseServiceHandle( manager
);
457 /******************************************************************************
458 * service_run_main_thread
460 static BOOL
service_run_main_thread(void)
463 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
464 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
466 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
468 /* FIXME: service_control_dispatcher should be merged into the main thread */
469 wait_handles
[0] = __wine_make_process_system();
470 wait_handles
[1] = CreateThread( NULL
, 0, service_control_dispatcher
, NULL
, 0, NULL
);
471 wait_handles
[2] = service_event
;
473 TRACE("Starting %d services running as process %d\n",
474 nb_services
, GetCurrentProcessId());
476 /* wait for all the threads to pack up and exit */
479 EnterCriticalSection( &service_cs
);
480 for (i
= 0, n
= 3; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
482 if (!services
[i
]->thread
) continue;
483 wait_services
[n
] = i
;
484 wait_handles
[n
++] = services
[i
]->thread
;
486 LeaveCriticalSection( &service_cs
);
488 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
489 if (!ret
) /* system process event */
491 TRACE( "last user process exited, shutting down\n" );
492 /* FIXME: we should maybe send a shutdown control to running services */
497 TRACE( "control dispatcher exited, shutting down\n" );
498 /* FIXME: we should maybe send a shutdown control to running services */
503 continue; /* rebuild the list */
507 services
[wait_services
[ret
]]->thread
= 0;
508 CloseHandle( wait_handles
[ret
] );
509 if (n
== 4) return TRUE
; /* it was the last running thread */
515 /******************************************************************************
516 * StartServiceCtrlDispatcherA [ADVAPI32.@]
518 * See StartServiceCtrlDispatcherW.
520 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
526 TRACE("%p\n", servent
);
530 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
533 while (servent
[nb_services
].lpServiceName
) nb_services
++;
534 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
536 for (i
= 0; i
< nb_services
; i
++)
538 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
539 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
540 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
541 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
542 info
->proc
.a
= servent
[i
].lpServiceProc
;
543 info
->unicode
= FALSE
;
547 service_run_main_thread();
552 /******************************************************************************
553 * StartServiceCtrlDispatcherW [ADVAPI32.@]
555 * Connects a process containing one or more services to the service control
559 * servent [I] A list of the service names and service procedures
565 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
571 TRACE("%p\n", servent
);
575 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
578 while (servent
[nb_services
].lpServiceName
) nb_services
++;
579 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
581 for (i
= 0; i
< nb_services
; i
++)
583 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
584 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
585 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
586 strcpyW(info
->name
, servent
[i
].lpServiceName
);
587 info
->proc
.w
= servent
[i
].lpServiceProc
;
588 info
->unicode
= TRUE
;
592 service_run_main_thread();
597 /******************************************************************************
598 * LockServiceDatabase [ADVAPI32.@]
600 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
602 SC_RPC_LOCK hLock
= NULL
;
605 TRACE("%p\n",hSCManager
);
609 err
= svcctl_LockServiceDatabase(hSCManager
, &hLock
);
613 err
= map_exception_code(GetExceptionCode());
616 if (err
!= ERROR_SUCCESS
)
624 /******************************************************************************
625 * UnlockServiceDatabase [ADVAPI32.@]
627 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
630 SC_RPC_LOCK hRpcLock
= ScLock
;
632 TRACE("%p\n",ScLock
);
636 err
= svcctl_UnlockServiceDatabase(&hRpcLock
);
640 err
= map_exception_code(GetExceptionCode());
643 if (err
!= ERROR_SUCCESS
)
651 /******************************************************************************
652 * SetServiceStatus [ADVAPI32.@]
659 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
663 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
664 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
665 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
666 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
667 lpStatus
->dwWaitHint
);
671 err
= svcctl_SetServiceStatus( hService
, lpStatus
);
675 err
= map_exception_code(GetExceptionCode());
678 if (err
!= ERROR_SUCCESS
)
684 if (lpStatus
->dwCurrentState
== SERVICE_STOPPED
)
685 CloseServiceHandle((SC_HANDLE
)hService
);
691 /******************************************************************************
692 * OpenSCManagerA [ADVAPI32.@]
694 * Establish a connection to the service control manager and open its database.
697 * lpMachineName [I] Pointer to machine name string
698 * lpDatabaseName [I] Pointer to database name string
699 * dwDesiredAccess [I] Type of access
702 * Success: A Handle to the service control manager database
705 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
706 DWORD dwDesiredAccess
)
708 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
711 lpMachineNameW
= SERV_dup(lpMachineName
);
712 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
713 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
714 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW
);
715 HeapFree(GetProcessHeap(), 0, lpMachineNameW
);
719 /******************************************************************************
720 * OpenSCManagerW [ADVAPI32.@]
722 * See OpenSCManagerA.
724 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
725 DWORD dwDesiredAccess
)
730 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
731 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
735 r
= svcctl_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)&handle
);
739 r
= map_exception_code(GetExceptionCode());
743 if (r
!=ERROR_SUCCESS
)
749 TRACE("returning %p\n", handle
);
753 /******************************************************************************
754 * ControlService [ADVAPI32.@]
756 * Send a control code to a service.
759 * hService [I] Handle of the service control manager database
760 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
761 * lpServiceStatus [O] Destination for the status of the service, if available
768 * Unlike M$' implementation, control requests are not serialized and may be
769 * processed asynchronously.
771 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
772 LPSERVICE_STATUS lpServiceStatus
)
776 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
780 err
= svcctl_ControlService(hService
, dwControl
, lpServiceStatus
);
784 err
= map_exception_code(GetExceptionCode());
787 if (err
!= ERROR_SUCCESS
)
796 /******************************************************************************
797 * CloseServiceHandle [ADVAPI32.@]
799 * Close a handle to a service or the service control manager database.
802 * hSCObject [I] Handle to service or service control manager database
809 CloseServiceHandle( SC_HANDLE hSCObject
)
813 TRACE("%p\n", hSCObject
);
817 err
= svcctl_CloseServiceHandle((SC_RPC_HANDLE
*)&hSCObject
);
821 err
= map_exception_code(GetExceptionCode());
825 if (err
!= ERROR_SUCCESS
)
834 /******************************************************************************
835 * OpenServiceA [ADVAPI32.@]
837 * Open a handle to a service.
840 * hSCManager [I] Handle of the service control manager database
841 * lpServiceName [I] Name of the service to open
842 * dwDesiredAccess [I] Access required to the service
845 * Success: Handle to the service
848 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
849 DWORD dwDesiredAccess
)
851 LPWSTR lpServiceNameW
;
854 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
856 lpServiceNameW
= SERV_dup(lpServiceName
);
857 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
858 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
863 /******************************************************************************
864 * OpenServiceW [ADVAPI32.@]
868 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
869 DWORD dwDesiredAccess
)
874 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
878 SetLastError( ERROR_INVALID_HANDLE
);
884 err
= svcctl_OpenServiceW(hSCManager
, lpServiceName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)&handle
);
888 err
= map_exception_code(GetExceptionCode());
892 if (err
!= ERROR_SUCCESS
)
898 TRACE("returning %p\n",handle
);
902 /******************************************************************************
903 * CreateServiceW [ADVAPI32.@]
906 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
907 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
908 DWORD dwServiceType
, DWORD dwStartType
,
909 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
910 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
911 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
918 TRACE("%p %s %s\n", hSCManager
,
919 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
923 SetLastError( ERROR_INVALID_HANDLE
);
928 passwdlen
= (strlenW(lpPassword
) + 1) * sizeof(WCHAR
);
934 err
= svcctl_CreateServiceW(hSCManager
, lpServiceName
,
935 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
936 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (LPBYTE
)lpDependencies
,
937 multisz_cb(lpDependencies
), lpServiceStartName
, (LPBYTE
)lpPassword
, passwdlen
,
938 (SC_RPC_HANDLE
*)&handle
);
942 err
= map_exception_code(GetExceptionCode());
946 if (err
!= ERROR_SUCCESS
)
955 /******************************************************************************
956 * CreateServiceA [ADVAPI32.@]
959 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
960 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
961 DWORD dwServiceType
, DWORD dwStartType
,
962 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
963 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
964 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
967 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
968 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
971 TRACE("%p %s %s\n", hSCManager
,
972 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
974 lpServiceNameW
= SERV_dup( lpServiceName
);
975 lpDisplayNameW
= SERV_dup( lpDisplayName
);
976 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
977 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
978 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
979 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
980 lpPasswordW
= SERV_dup( lpPassword
);
982 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
983 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
984 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
985 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
987 HeapFree( GetProcessHeap(), 0, lpServiceNameW
);
988 HeapFree( GetProcessHeap(), 0, lpDisplayNameW
);
989 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW
);
990 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW
);
991 HeapFree( GetProcessHeap(), 0, lpDependenciesW
);
992 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW
);
993 HeapFree( GetProcessHeap(), 0, lpPasswordW
);
999 /******************************************************************************
1000 * DeleteService [ADVAPI32.@]
1002 * Delete a service from the service control manager database.
1005 * hService [I] Handle of the service to delete
1011 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1017 err
= svcctl_DeleteService(hService
);
1019 __EXCEPT(rpc_filter
)
1021 err
= map_exception_code(GetExceptionCode());
1034 /******************************************************************************
1035 * StartServiceA [ADVAPI32.@]
1040 * hService [I] Handle of service
1041 * dwNumServiceArgs [I] Number of arguments
1042 * lpServiceArgVectors [I] Address of array of argument strings
1045 * - NT implements this function using an obscure RPC call.
1046 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1047 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1048 * - This will only work for shared address space. How should the service
1049 * args be transferred when address spaces are separated?
1050 * - Can only start one service at a time.
1051 * - Has no concept of privilege.
1057 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1058 LPCSTR
*lpServiceArgVectors
)
1060 LPWSTR
*lpwstr
=NULL
;
1064 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1066 if (dwNumServiceArgs
)
1067 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1068 dwNumServiceArgs
*sizeof(LPWSTR
) );
1070 for(i
=0; i
<dwNumServiceArgs
; i
++)
1071 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1073 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1075 if (dwNumServiceArgs
)
1077 for(i
=0; i
<dwNumServiceArgs
; i
++)
1078 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
1079 HeapFree(GetProcessHeap(), 0, lpwstr
);
1086 /******************************************************************************
1087 * StartServiceW [ADVAPI32.@]
1089 * See StartServiceA.
1091 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1092 LPCWSTR
*lpServiceArgVectors
)
1096 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1100 err
= svcctl_StartServiceW(hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1102 __EXCEPT(rpc_filter
)
1104 err
= map_exception_code(GetExceptionCode());
1107 if (err
!= ERROR_SUCCESS
)
1116 /******************************************************************************
1117 * QueryServiceStatus [ADVAPI32.@]
1120 * hService [I] Handle to service to get information about
1121 * lpservicestatus [O] buffer to receive the status information for the service
1124 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1125 LPSERVICE_STATUS lpservicestatus
)
1127 SERVICE_STATUS_PROCESS SvcStatusData
;
1131 TRACE("%p %p\n", hService
, lpservicestatus
);
1133 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1134 sizeof(SERVICE_STATUS_PROCESS
), &dummy
);
1135 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1140 /******************************************************************************
1141 * QueryServiceStatusEx [ADVAPI32.@]
1143 * Get information about a service.
1146 * hService [I] Handle to service to get information about
1147 * InfoLevel [I] Level of information to get
1148 * lpBuffer [O] Destination for requested information
1149 * cbBufSize [I] Size of lpBuffer in bytes
1150 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1156 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1157 LPBYTE lpBuffer
, DWORD cbBufSize
,
1158 LPDWORD pcbBytesNeeded
)
1162 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1166 err
= svcctl_QueryServiceStatusEx(hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1168 __EXCEPT(rpc_filter
)
1170 err
= map_exception_code(GetExceptionCode());
1173 if (err
!= ERROR_SUCCESS
)
1182 /******************************************************************************
1183 * QueryServiceConfigA [ADVAPI32.@]
1185 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1186 DWORD size
, LPDWORD needed
)
1191 QUERY_SERVICE_CONFIGW
*configW
;
1193 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1195 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1197 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1200 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1201 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1202 if (!ret
) goto done
;
1204 config
->dwServiceType
= configW
->dwServiceType
;
1205 config
->dwStartType
= configW
->dwStartType
;
1206 config
->dwErrorControl
= configW
->dwErrorControl
;
1207 config
->lpBinaryPathName
= NULL
;
1208 config
->lpLoadOrderGroup
= NULL
;
1209 config
->dwTagId
= configW
->dwTagId
;
1210 config
->lpDependencies
= NULL
;
1211 config
->lpServiceStartName
= NULL
;
1212 config
->lpDisplayName
= NULL
;
1214 p
= (LPSTR
)(config
+ 1);
1215 n
= size
- sizeof(*config
);
1218 #define MAP_STR(str) \
1222 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1223 if (!sz) goto done; \
1230 MAP_STR( lpBinaryPathName
);
1231 MAP_STR( lpLoadOrderGroup
);
1232 MAP_STR( lpDependencies
);
1233 MAP_STR( lpServiceStartName
);
1234 MAP_STR( lpDisplayName
);
1237 *needed
= p
- (LPSTR
)config
;
1241 HeapFree( GetProcessHeap(), 0, buffer
);
1245 static DWORD
move_string_to_buffer(BYTE
**buf
, LPWSTR
*string_ptr
)
1252 memset(*buf
, 0, cb
);
1256 cb
= (strlenW(*string_ptr
) + 1)*sizeof(WCHAR
);
1257 memcpy(*buf
, *string_ptr
, cb
);
1258 MIDL_user_free(*string_ptr
);
1261 *string_ptr
= (LPWSTR
)*buf
;
1267 static DWORD
size_string(LPCWSTR string
)
1269 return (string
? (strlenW(string
) + 1)*sizeof(WCHAR
) : sizeof(WCHAR
));
1272 /******************************************************************************
1273 * QueryServiceConfigW [ADVAPI32.@]
1276 QueryServiceConfigW( SC_HANDLE hService
,
1277 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1278 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1280 QUERY_SERVICE_CONFIGW config
;
1285 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1286 cbBufSize
, pcbBytesNeeded
);
1288 memset(&config
, 0, sizeof(config
));
1292 err
= svcctl_QueryServiceConfigW(hService
, &config
);
1294 __EXCEPT(rpc_filter
)
1296 err
= map_exception_code(GetExceptionCode());
1300 if (err
!= ERROR_SUCCESS
)
1302 TRACE("services.exe: error %u\n", err
);
1307 /* calculate the size required first */
1308 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1309 total
+= size_string(config
.lpBinaryPathName
);
1310 total
+= size_string(config
.lpLoadOrderGroup
);
1311 total
+= size_string(config
.lpDependencies
);
1312 total
+= size_string(config
.lpServiceStartName
);
1313 total
+= size_string(config
.lpDisplayName
);
1315 *pcbBytesNeeded
= total
;
1317 /* if there's not enough memory, return an error */
1318 if( total
> cbBufSize
)
1320 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1321 MIDL_user_free(config
.lpBinaryPathName
);
1322 MIDL_user_free(config
.lpLoadOrderGroup
);
1323 MIDL_user_free(config
.lpDependencies
);
1324 MIDL_user_free(config
.lpServiceStartName
);
1325 MIDL_user_free(config
.lpDisplayName
);
1329 *lpServiceConfig
= config
;
1330 bufpos
= ((BYTE
*)lpServiceConfig
) + sizeof(QUERY_SERVICE_CONFIGW
);
1331 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpBinaryPathName
);
1332 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpLoadOrderGroup
);
1333 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDependencies
);
1334 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpServiceStartName
);
1335 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDisplayName
);
1337 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1338 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1339 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
1340 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
1341 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
1346 /******************************************************************************
1347 * QueryServiceConfig2A [ADVAPI32.@]
1350 * observed under win2k:
1351 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1352 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1354 BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1355 DWORD size
, LPDWORD needed
)
1358 LPBYTE bufferW
= NULL
;
1361 bufferW
= HeapAlloc( GetProcessHeap(), 0, size
);
1363 ret
= QueryServiceConfig2W(hService
, dwLevel
, bufferW
, size
, needed
);
1364 if(!ret
) goto cleanup
;
1367 case SERVICE_CONFIG_DESCRIPTION
:
1368 if (buffer
&& bufferW
) {
1369 LPSERVICE_DESCRIPTIONA configA
= (LPSERVICE_DESCRIPTIONA
) buffer
;
1370 LPSERVICE_DESCRIPTIONW configW
= (LPSERVICE_DESCRIPTIONW
) bufferW
;
1371 if (configW
->lpDescription
&& (size
> sizeof(SERVICE_DESCRIPTIONA
))) {
1373 configA
->lpDescription
= (LPSTR
)(configA
+ 1);
1374 sz
= WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1,
1375 configA
->lpDescription
, size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
1377 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1379 configA
->lpDescription
= NULL
;
1382 else configA
->lpDescription
= NULL
;
1386 FIXME("conversation W->A not implemented for level %d\n", dwLevel
);
1392 HeapFree( GetProcessHeap(), 0, bufferW
);
1396 /******************************************************************************
1397 * QueryServiceConfig2W [ADVAPI32.@]
1399 BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1400 DWORD size
, LPDWORD needed
)
1404 if(dwLevel
!= SERVICE_CONFIG_DESCRIPTION
) {
1405 if((dwLevel
== SERVICE_CONFIG_DELAYED_AUTO_START_INFO
) ||
1406 (dwLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
) ||
1407 (dwLevel
== SERVICE_CONFIG_FAILURE_ACTIONS_FLAG
) ||
1408 (dwLevel
== SERVICE_CONFIG_PRESHUTDOWN_INFO
) ||
1409 (dwLevel
== SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO
) ||
1410 (dwLevel
== SERVICE_CONFIG_SERVICE_SID_INFO
))
1411 FIXME("Level %d not implemented\n", dwLevel
);
1412 SetLastError(ERROR_INVALID_LEVEL
);
1416 if(!buffer
&& size
) {
1417 SetLastError(ERROR_INVALID_ADDRESS
);
1421 TRACE("%p 0x%d %p 0x%d %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1425 err
= svcctl_QueryServiceConfig2W(hService
, dwLevel
, buffer
, size
, needed
);
1427 __EXCEPT(rpc_filter
)
1429 err
= map_exception_code(GetExceptionCode());
1433 if (err
!= ERROR_SUCCESS
)
1435 SetLastError( err
);
1441 case SERVICE_CONFIG_DESCRIPTION
:
1444 SERVICE_DESCRIPTIONW
*descr
= (SERVICE_DESCRIPTIONW
*)buffer
;
1445 if (descr
->lpDescription
) /* make it an absolute pointer */
1446 descr
->lpDescription
= (WCHAR
*)(buffer
+ (ULONG_PTR
)descr
->lpDescription
);
1454 /******************************************************************************
1455 * EnumServicesStatusA [ADVAPI32.@]
1458 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1459 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
1460 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1461 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1463 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1464 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1465 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1466 SetLastError (ERROR_ACCESS_DENIED
);
1470 /******************************************************************************
1471 * EnumServicesStatusW [ADVAPI32.@]
1474 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
1475 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
1476 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1477 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
1479 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
1480 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1481 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
1482 SetLastError (ERROR_ACCESS_DENIED
);
1486 /******************************************************************************
1487 * EnumServicesStatusExA [ADVAPI32.@]
1490 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
1491 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1492 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
1494 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
1495 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1496 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
1497 if (lpServicesReturned
) *lpServicesReturned
= 0;
1498 SetLastError (ERROR_ACCESS_DENIED
);
1502 /******************************************************************************
1503 * EnumServicesStatusExW [ADVAPI32.@]
1506 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
1507 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
1508 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
1510 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
1511 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
1512 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
1513 SetLastError (ERROR_ACCESS_DENIED
);
1517 /******************************************************************************
1518 * GetServiceKeyNameA [ADVAPI32.@]
1520 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1521 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1523 LPWSTR lpDisplayNameW
, lpServiceNameW
;
1527 TRACE("%p %s %p %p\n", hSCManager
,
1528 debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1530 lpDisplayNameW
= SERV_dup(lpDisplayName
);
1532 lpServiceNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
1534 lpServiceNameW
= NULL
;
1536 sizeW
= *lpcchBuffer
;
1537 if (!GetServiceKeyNameW(hSCManager
, lpDisplayNameW
, lpServiceNameW
, &sizeW
))
1539 if (lpServiceName
&& *lpcchBuffer
)
1540 lpServiceName
[0] = 0;
1541 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1545 if (!WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, (sizeW
+ 1), lpServiceName
,
1546 *lpcchBuffer
, NULL
, NULL
))
1548 if (*lpcchBuffer
&& lpServiceName
)
1549 lpServiceName
[0] = 0;
1550 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, -1, NULL
, 0, NULL
, NULL
);
1554 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1558 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1559 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
1563 /******************************************************************************
1564 * GetServiceKeyNameW [ADVAPI32.@]
1566 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1567 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1573 TRACE("%p %s %p %p\n", hSCManager
,
1574 debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1578 SetLastError( ERROR_INVALID_HANDLE
);
1582 /* provide a buffer if the caller didn't */
1583 if (!lpServiceName
|| *lpcchBuffer
< 2)
1585 lpServiceName
= buffer
;
1586 /* A size of 1 would be enough, but tests show that Windows returns 2,
1587 * probably because of a WCHAR/bytes mismatch in their code.
1592 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1593 * includes the nul-terminator on input. */
1594 size
= *lpcchBuffer
- 1;
1598 err
= svcctl_GetServiceKeyNameW(hSCManager
, lpDisplayName
, lpServiceName
,
1601 __EXCEPT(rpc_filter
)
1603 err
= map_exception_code(GetExceptionCode());
1607 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1608 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
1609 *lpcchBuffer
= size
;
1613 return err
== ERROR_SUCCESS
;
1616 /******************************************************************************
1617 * QueryServiceLockStatusA [ADVAPI32.@]
1619 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1620 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1621 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1623 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1628 /******************************************************************************
1629 * QueryServiceLockStatusW [ADVAPI32.@]
1631 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
1632 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
1633 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1635 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1640 /******************************************************************************
1641 * GetServiceDisplayNameA [ADVAPI32.@]
1643 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1644 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1646 LPWSTR lpServiceNameW
, lpDisplayNameW
;
1650 TRACE("%p %s %p %p\n", hSCManager
,
1651 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1653 lpServiceNameW
= SERV_dup(lpServiceName
);
1655 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
1657 lpDisplayNameW
= NULL
;
1659 sizeW
= *lpcchBuffer
;
1660 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
1662 if (lpDisplayName
&& *lpcchBuffer
)
1663 lpDisplayName
[0] = 0;
1664 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1668 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
1669 *lpcchBuffer
, NULL
, NULL
))
1671 if (*lpcchBuffer
&& lpDisplayName
)
1672 lpDisplayName
[0] = 0;
1673 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
1677 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1678 * (but if the function succeeded it means that is a good upper estimation of the size) */
1682 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
1683 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1687 /******************************************************************************
1688 * GetServiceDisplayNameW [ADVAPI32.@]
1690 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1691 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1697 TRACE("%p %s %p %p\n", hSCManager
,
1698 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1702 SetLastError( ERROR_INVALID_HANDLE
);
1706 /* provide a buffer if the caller didn't */
1707 if (!lpDisplayName
|| *lpcchBuffer
< 2)
1709 lpDisplayName
= buffer
;
1710 /* A size of 1 would be enough, but tests show that Windows returns 2,
1711 * probably because of a WCHAR/bytes mismatch in their code.
1716 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1717 * includes the nul-terminator on input. */
1718 size
= *lpcchBuffer
- 1;
1722 err
= svcctl_GetServiceDisplayNameW(hSCManager
, lpServiceName
, lpDisplayName
,
1725 __EXCEPT(rpc_filter
)
1727 err
= map_exception_code(GetExceptionCode());
1731 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1732 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
1733 *lpcchBuffer
= size
;
1737 return err
== ERROR_SUCCESS
;
1740 /******************************************************************************
1741 * ChangeServiceConfigW [ADVAPI32.@]
1743 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1744 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1745 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1746 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1751 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1752 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1753 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1754 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1755 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1757 cb_pwd
= lpPassword
? (strlenW(lpPassword
) + 1)*sizeof(WCHAR
) : 0;
1761 err
= svcctl_ChangeServiceConfigW(hService
, dwServiceType
,
1762 dwStartType
, dwErrorControl
, lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
,
1763 (const BYTE
*)lpDependencies
, multisz_cb(lpDependencies
), lpServiceStartName
,
1764 (const BYTE
*)lpPassword
, cb_pwd
, lpDisplayName
);
1766 __EXCEPT(rpc_filter
)
1768 err
= map_exception_code(GetExceptionCode());
1772 if (err
!= ERROR_SUCCESS
)
1775 return err
== ERROR_SUCCESS
;
1778 /******************************************************************************
1779 * ChangeServiceConfigA [ADVAPI32.@]
1781 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1782 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1783 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
1784 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
1786 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
1787 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
1790 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1791 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1792 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
1793 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
1794 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
1796 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
1797 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
1798 wDependencies
= SERV_dupmulti( lpDependencies
);
1799 wServiceStartName
= SERV_dup( lpServiceStartName
);
1800 wPassword
= SERV_dup( lpPassword
);
1801 wDisplayName
= SERV_dup( lpDisplayName
);
1803 r
= ChangeServiceConfigW( hService
, dwServiceType
,
1804 dwStartType
, dwErrorControl
, wBinaryPathName
,
1805 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
1806 wServiceStartName
, wPassword
, wDisplayName
);
1808 HeapFree( GetProcessHeap(), 0, wBinaryPathName
);
1809 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup
);
1810 HeapFree( GetProcessHeap(), 0, wDependencies
);
1811 HeapFree( GetProcessHeap(), 0, wServiceStartName
);
1812 HeapFree( GetProcessHeap(), 0, wPassword
);
1813 HeapFree( GetProcessHeap(), 0, wDisplayName
);
1818 /******************************************************************************
1819 * ChangeServiceConfig2A [ADVAPI32.@]
1821 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
1826 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
1828 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
1830 LPSERVICE_DESCRIPTIONA sd
= lpInfo
;
1831 SERVICE_DESCRIPTIONW sdw
;
1833 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
1835 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
1837 HeapFree( GetProcessHeap(), 0, sdw
.lpDescription
);
1839 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
1841 LPSERVICE_FAILURE_ACTIONSA fa
= lpInfo
;
1842 SERVICE_FAILURE_ACTIONSW faw
;
1844 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
1845 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
1846 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
1847 faw
.cActions
= fa
->cActions
;
1848 faw
.lpsaActions
= fa
->lpsaActions
;
1850 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
1852 HeapFree( GetProcessHeap(), 0, faw
.lpRebootMsg
);
1853 HeapFree( GetProcessHeap(), 0, faw
.lpCommand
);
1856 SetLastError( ERROR_INVALID_PARAMETER
);
1861 /******************************************************************************
1862 * ChangeServiceConfig2W [ADVAPI32.@]
1864 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
1871 err
= svcctl_ChangeServiceConfig2W( hService
, dwInfoLevel
, lpInfo
);
1873 __EXCEPT(rpc_filter
)
1875 err
= map_exception_code(GetExceptionCode());
1879 if (err
!= ERROR_SUCCESS
)
1882 return err
== ERROR_SUCCESS
;
1885 /******************************************************************************
1886 * QueryServiceObjectSecurity [ADVAPI32.@]
1888 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
1889 SECURITY_INFORMATION dwSecurityInformation
,
1890 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
1891 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1893 SECURITY_DESCRIPTOR descriptor
;
1898 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
1899 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
1901 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
1902 FIXME("information %d not supported\n", dwSecurityInformation
);
1904 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
1906 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
1907 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
1910 succ
= MakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
1911 *pcbBytesNeeded
= size
;
1915 /******************************************************************************
1916 * SetServiceObjectSecurity [ADVAPI32.@]
1918 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
1919 SECURITY_INFORMATION dwSecurityInformation
,
1920 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
1922 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
1926 /******************************************************************************
1927 * SetServiceBits [ADVAPI32.@]
1929 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
1930 DWORD dwServiceBits
,
1932 BOOL bUpdateImmediately
)
1934 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
1935 bSetBitsOn
, bUpdateImmediately
);
1939 /* thunk for calling the RegisterServiceCtrlHandler handler function */
1940 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
1942 LPHANDLER_FUNCTION func
= context
;
1945 return ERROR_SUCCESS
;
1948 /******************************************************************************
1949 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
1951 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
1953 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
1956 /******************************************************************************
1957 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
1959 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
1961 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
1964 /******************************************************************************
1965 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
1967 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
1970 SERVICE_STATUS_HANDLE ret
;
1972 nameW
= SERV_dup(name
);
1973 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
1974 HeapFree( GetProcessHeap(), 0, nameW
);
1978 /******************************************************************************
1979 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
1981 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
1982 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
1984 service_data
*service
;
1985 SC_HANDLE hService
= 0;
1988 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
1990 EnterCriticalSection( &service_cs
);
1991 if ((service
= find_service_by_name( lpServiceName
)))
1993 service
->handler
= lpHandlerProc
;
1994 service
->context
= lpContext
;
1995 hService
= service
->handle
;
1998 LeaveCriticalSection( &service_cs
);
2000 if (!found
) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2002 return (SERVICE_STATUS_HANDLE
)hService
;
2005 /******************************************************************************
2006 * EnumDependentServicesA [ADVAPI32.@]
2008 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2009 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2010 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2012 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2013 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2015 *lpServicesReturned
= 0;
2019 /******************************************************************************
2020 * EnumDependentServicesW [ADVAPI32.@]
2022 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2023 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2024 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2026 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2027 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2029 *lpServicesReturned
= 0;