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"
32 #define WIN32_NO_STATUS
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
46 #include "advapi32_misc.h"
48 #include "wine/exception.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(service
);
52 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(SIZE_T len
)
54 return heap_alloc(len
);
57 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
62 typedef struct service_data_t
64 LPHANDLER_FUNCTION_EX handler
;
68 SC_HANDLE full_access_handle
;
71 LPSERVICE_MAIN_FUNCTIONA a
;
72 LPSERVICE_MAIN_FUNCTIONW w
;
78 typedef struct dispatcher_data_t
84 static CRITICAL_SECTION service_cs
;
85 static CRITICAL_SECTION_DEBUG service_cs_debug
=
88 { &service_cs_debug
.ProcessLocksList
,
89 &service_cs_debug
.ProcessLocksList
},
90 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
92 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
94 static service_data
**services
;
95 static unsigned int nb_services
;
96 static HANDLE service_event
;
97 static HANDLE stop_event
;
99 extern HANDLE CDECL
__wine_make_process_system(void);
101 /******************************************************************************
102 * String management functions (same behaviour as strdup)
103 * NOTE: the caller of those functions is responsible for calling HeapFree
104 * in order to release the memory allocated by those functions.
106 LPWSTR
SERV_dup( LPCSTR str
)
113 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
114 wstr
= heap_alloc( len
*sizeof (WCHAR
) );
115 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
119 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
127 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
128 n
+= (strlen( &str
[n
] ) + 1);
133 wstr
= heap_alloc( len
*sizeof (WCHAR
) );
134 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
138 static inline DWORD
multisz_cb(LPCWSTR wmultisz
)
140 const WCHAR
*wptr
= wmultisz
;
142 if (wmultisz
== NULL
)
146 wptr
+= lstrlenW(wptr
)+1;
147 return (wptr
- wmultisz
+ 1)*sizeof(WCHAR
);
150 /******************************************************************************
151 * RPC connection with services.exe
154 DECLSPEC_HIDDEN handle_t __RPC_USER
MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName
)
156 WCHAR transport
[] = SVCCTL_TRANSPORT
;
157 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
158 RPC_WSTR binding_str
;
162 status
= RpcStringBindingComposeW(NULL
, transport
, (RPC_WSTR
)MachineName
, endpoint
, NULL
, &binding_str
);
163 if (status
!= RPC_S_OK
)
165 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
169 status
= RpcBindingFromStringBindingW(binding_str
, &rpc_handle
);
170 RpcStringFreeW(&binding_str
);
172 if (status
!= RPC_S_OK
)
174 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
181 DECLSPEC_HIDDEN
void __RPC_USER
MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName
, handle_t h
)
186 static LONG WINAPI
rpc_filter(EXCEPTION_POINTERS
*eptr
)
188 return I_RpcExceptionFilter(eptr
->ExceptionRecord
->ExceptionCode
);
191 static DWORD
map_exception_code(DWORD exception_code
)
193 switch (exception_code
)
195 case RPC_X_NULL_REF_POINTER
:
196 return ERROR_INVALID_ADDRESS
;
197 case RPC_X_ENUM_VALUE_OUT_OF_RANGE
:
198 case RPC_X_BYTE_COUNT_TOO_SMALL
:
199 return ERROR_INVALID_PARAMETER
;
200 case RPC_S_INVALID_BINDING
:
201 case RPC_X_SS_IN_NULL_CONTEXT
:
202 return ERROR_INVALID_HANDLE
;
204 return exception_code
;
208 /******************************************************************************
209 * Service IPC functions
211 static LPWSTR
service_get_pipe_name(void)
213 static const WCHAR format
[] = { '\\','\\','.','\\','p','i','p','e','\\',
214 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
215 static const WCHAR service_current_key_str
[] = { 'S','Y','S','T','E','M','\\',
216 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
217 'C','o','n','t','r','o','l','\\',
218 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
221 HKEY service_current_key
;
222 DWORD service_current
;
226 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, service_current_key_str
, 0,
227 KEY_QUERY_VALUE
, &service_current_key
);
228 if (ret
!= ERROR_SUCCESS
)
230 len
= sizeof(service_current
);
231 ret
= RegQueryValueExW(service_current_key
, NULL
, NULL
, &type
,
232 (BYTE
*)&service_current
, &len
);
233 RegCloseKey(service_current_key
);
234 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
236 len
= sizeof(format
)/sizeof(WCHAR
) + 10 /* strlenW("4294967295") */;
237 name
= heap_alloc(len
* sizeof(WCHAR
));
240 snprintfW(name
, len
, format
, service_current
);
244 static HANDLE
service_open_pipe(void)
246 LPWSTR szPipe
= service_get_pipe_name();
247 HANDLE handle
= INVALID_HANDLE_VALUE
;
250 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
251 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
252 if (handle
!= INVALID_HANDLE_VALUE
)
254 if (GetLastError() != ERROR_PIPE_BUSY
)
256 } while (WaitNamedPipeW(szPipe
, NMPWAIT_USE_DEFAULT_WAIT
));
262 static service_data
*find_service_by_name( const WCHAR
*name
)
266 if (nb_services
== 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
268 for (i
= 0; i
< nb_services
; i
++)
269 if (!strcmpiW( name
, services
[i
]->name
)) return services
[i
];
273 /******************************************************************************
276 * Call into the main service routine provided by StartServiceCtrlDispatcher.
278 static DWORD WINAPI
service_thread(LPVOID arg
)
280 service_data
*info
= arg
;
281 LPWSTR str
= info
->args
;
282 DWORD argc
= 0, len
= 0;
288 len
+= strlenW(&str
[len
]) + 1;
297 argv
= heap_alloc((argc
+1)*sizeof(LPWSTR
));
298 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
302 info
->proc
.w(argc
, argv
);
307 LPSTR strA
, *argv
, p
;
310 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
311 strA
= heap_alloc(lenA
);
312 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
314 argv
= heap_alloc((argc
+1)*sizeof(LPSTR
));
315 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
319 info
->proc
.a(argc
, argv
);
326 /******************************************************************************
327 * service_handle_start
329 static DWORD
service_handle_start(service_data
*service
, const WCHAR
*data
, DWORD count
)
331 TRACE("%s argsize %u\n", debugstr_w(service
->name
), count
);
335 WARN("service is not stopped\n");
336 return ERROR_SERVICE_ALREADY_RUNNING
;
339 heap_free(service
->args
);
340 service
->args
= heap_alloc(count
* sizeof(WCHAR
));
341 memcpy( service
->args
, data
, count
* sizeof(WCHAR
) );
342 service
->thread
= CreateThread( NULL
, 0, service_thread
,
344 SetEvent( service_event
); /* notify the main loop */
348 /******************************************************************************
349 * service_handle_control
351 static DWORD
service_handle_control(const service_data
*service
, DWORD dwControl
)
353 DWORD ret
= ERROR_INVALID_SERVICE_CONTROL
;
355 TRACE("%s control %u\n", debugstr_w(service
->name
), dwControl
);
357 if (service
->handler
)
358 ret
= service
->handler(dwControl
, 0, NULL
, service
->context
);
362 /******************************************************************************
363 * service_control_dispatcher
365 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
367 dispatcher_data
*disp
= arg
;
369 /* dispatcher loop */
372 service_data
*service
;
373 service_start_info info
;
376 DWORD data_size
= 0, count
, result
;
378 r
= ReadFile( disp
->pipe
, &info
, FIELD_OFFSET(service_start_info
,data
), &count
, NULL
);
381 if (GetLastError() != ERROR_BROKEN_PIPE
)
382 ERR( "pipe read failed error %u\n", GetLastError() );
385 if (count
!= FIELD_OFFSET(service_start_info
,data
))
387 ERR( "partial pipe read %u\n", count
);
390 if (count
< info
.total_size
)
392 data_size
= info
.total_size
- FIELD_OFFSET(service_start_info
,data
);
393 data
= heap_alloc( data_size
);
394 r
= ReadFile( disp
->pipe
, data
, data_size
, &count
, NULL
);
397 if (GetLastError() != ERROR_BROKEN_PIPE
)
398 ERR( "pipe read failed error %u\n", GetLastError() );
402 if (count
!= data_size
)
404 ERR( "partial pipe read %u/%u\n", count
, data_size
);
410 /* find the service */
412 if (!(service
= find_service_by_name( data
)))
414 FIXME( "got request %u for unknown service %s\n", info
.cmd
, debugstr_w(data
));
415 result
= ERROR_INVALID_PARAMETER
;
419 TRACE( "got request %u for service %s\n", info
.cmd
, debugstr_w(data
) );
421 /* handle the request */
424 case WINESERV_STARTINFO
:
425 if (!service
->handle
)
427 if (!(service
->handle
= OpenServiceW( disp
->manager
, data
, SERVICE_SET_STATUS
)) ||
428 !(service
->full_access_handle
= OpenServiceW( disp
->manager
, data
,
429 GENERIC_READ
|GENERIC_WRITE
)))
430 FIXME( "failed to open service %s\n", debugstr_w(data
) );
432 result
= service_handle_start(service
, data
, data_size
/ sizeof(WCHAR
));
434 case WINESERV_SENDCONTROL
:
435 result
= service_handle_control(service
, info
.control
);
438 ERR("received invalid command %u\n", info
.cmd
);
439 result
= ERROR_INVALID_PARAMETER
;
444 WriteFile( disp
->pipe
, &result
, sizeof(result
), &count
, NULL
);
448 CloseHandle( disp
->pipe
);
449 CloseServiceHandle( disp
->manager
);
454 /******************************************************************************
455 * service_run_main_thread
457 static BOOL
service_run_main_thread(void)
460 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
461 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
462 dispatcher_data
*disp
= heap_alloc( sizeof(*disp
) );
464 disp
->manager
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
467 ERR("failed to open service manager error %u\n", GetLastError());
472 disp
->pipe
= service_open_pipe();
473 if (disp
->pipe
== INVALID_HANDLE_VALUE
)
475 WARN("failed to create control pipe error %u\n", GetLastError());
476 CloseServiceHandle( disp
->manager
);
478 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
);
482 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
483 stop_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
485 /* FIXME: service_control_dispatcher should be merged into the main thread */
486 wait_handles
[0] = __wine_make_process_system();
487 wait_handles
[1] = CreateThread( NULL
, 0, service_control_dispatcher
, disp
, 0, NULL
);
488 wait_handles
[2] = service_event
;
489 wait_handles
[3] = stop_event
;
491 TRACE("Starting %d services running as process %d\n",
492 nb_services
, GetCurrentProcessId());
494 /* wait for all the threads to pack up and exit */
497 EnterCriticalSection( &service_cs
);
498 for (i
= 0, n
= 4; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
500 if (!services
[i
]->thread
) continue;
501 wait_services
[n
] = i
;
502 wait_handles
[n
++] = services
[i
]->thread
;
504 LeaveCriticalSection( &service_cs
);
506 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
507 if (!ret
) /* system process event */
510 SERVICE_PRESHUTDOWN_INFO spi
;
511 DWORD timeout
= 5000;
514 EnterCriticalSection( &service_cs
);
516 for (i
= 0; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
518 if (!services
[i
]->thread
) continue;
520 res
= QueryServiceStatus(services
[i
]->full_access_handle
, &st
);
522 if (res
&& (st
.dwControlsAccepted
& SERVICE_ACCEPT_PRESHUTDOWN
))
524 res
= QueryServiceConfig2W( services
[i
]->full_access_handle
, SERVICE_CONFIG_PRESHUTDOWN_INFO
,
525 (LPBYTE
)&spi
, sizeof(spi
), &i
);
528 FIXME("service should be able to delay shutdown\n");
529 timeout
+= spi
.dwPreshutdownTimeout
;
530 ret
= service_handle_control( services
[i
], SERVICE_CONTROL_PRESHUTDOWN
);
531 wait_handles
[n
++] = services
[i
]->thread
;
534 else if (res
&& (st
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
))
536 ret
= service_handle_control( services
[i
], SERVICE_CONTROL_SHUTDOWN
);
537 wait_handles
[n
++] = services
[i
]->thread
;
540 LeaveCriticalSection( &service_cs
);
542 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout
);
543 WaitForMultipleObjects( n
, wait_handles
, TRUE
, timeout
);
548 TRACE( "control dispatcher exited, shutting down\n" );
549 /* FIXME: we should maybe send a shutdown control to running services */
554 continue; /* rebuild the list */
562 services
[wait_services
[ret
]]->thread
= 0;
563 CloseHandle( wait_handles
[ret
] );
569 /******************************************************************************
570 * StartServiceCtrlDispatcherA [ADVAPI32.@]
572 * See StartServiceCtrlDispatcherW.
574 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
579 TRACE("%p\n", servent
);
583 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
586 while (servent
[nb_services
].lpServiceName
) nb_services
++;
589 SetLastError( ERROR_INVALID_PARAMETER
);
593 services
= heap_alloc( nb_services
* sizeof(*services
) );
595 for (i
= 0; i
< nb_services
; i
++)
597 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
598 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
599 info
= heap_alloc_zero( sz
);
600 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
601 info
->proc
.a
= servent
[i
].lpServiceProc
;
602 info
->unicode
= FALSE
;
606 return service_run_main_thread();
609 /******************************************************************************
610 * StartServiceCtrlDispatcherW [ADVAPI32.@]
612 * Connects a process containing one or more services to the service control
616 * servent [I] A list of the service names and service procedures
622 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
627 TRACE("%p\n", servent
);
631 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
634 while (servent
[nb_services
].lpServiceName
) nb_services
++;
637 SetLastError( ERROR_INVALID_PARAMETER
);
641 services
= heap_alloc( nb_services
* sizeof(*services
) );
643 for (i
= 0; i
< nb_services
; i
++)
645 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
646 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
647 info
= heap_alloc_zero( sz
);
648 strcpyW(info
->name
, servent
[i
].lpServiceName
);
649 info
->proc
.w
= servent
[i
].lpServiceProc
;
650 info
->unicode
= TRUE
;
654 return service_run_main_thread();
657 /******************************************************************************
658 * LockServiceDatabase [ADVAPI32.@]
660 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
662 SC_RPC_LOCK hLock
= NULL
;
665 TRACE("%p\n",hSCManager
);
669 err
= svcctl_LockServiceDatabase(hSCManager
, &hLock
);
673 err
= map_exception_code(GetExceptionCode());
676 if (err
!= ERROR_SUCCESS
)
684 /******************************************************************************
685 * UnlockServiceDatabase [ADVAPI32.@]
687 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
690 SC_RPC_LOCK hRpcLock
= ScLock
;
692 TRACE("%p\n",ScLock
);
696 err
= svcctl_UnlockServiceDatabase(&hRpcLock
);
700 err
= map_exception_code(GetExceptionCode());
703 if (err
!= ERROR_SUCCESS
)
711 /******************************************************************************
712 * SetServiceStatus [ADVAPI32.@]
719 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
723 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
724 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
725 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
726 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
727 lpStatus
->dwWaitHint
);
731 err
= svcctl_SetServiceStatus( hService
, lpStatus
);
735 err
= map_exception_code(GetExceptionCode());
738 if (err
!= ERROR_SUCCESS
)
744 if (lpStatus
->dwCurrentState
== SERVICE_STOPPED
) {
745 SetEvent(stop_event
);
746 CloseServiceHandle((SC_HANDLE
)hService
);
753 /******************************************************************************
754 * OpenSCManagerA [ADVAPI32.@]
756 * Establish a connection to the service control manager and open its database.
759 * lpMachineName [I] Pointer to machine name string
760 * lpDatabaseName [I] Pointer to database name string
761 * dwDesiredAccess [I] Type of access
764 * Success: A Handle to the service control manager database
767 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
768 DWORD dwDesiredAccess
)
770 LPWSTR machineW
, databaseW
;
773 machineW
= SERV_dup(lpMachineName
);
774 databaseW
= SERV_dup(lpDatabaseName
);
775 ret
= OpenSCManagerW(machineW
, databaseW
, dwDesiredAccess
);
776 heap_free(databaseW
);
781 /******************************************************************************
782 * OpenSCManagerW [ADVAPI32.@]
784 * See OpenSCManagerA.
786 DWORD
SERV_OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
787 DWORD dwDesiredAccess
, SC_HANDLE
*handle
)
791 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
792 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
796 r
= svcctl_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)handle
);
800 r
= map_exception_code(GetExceptionCode());
804 if (r
!=ERROR_SUCCESS
)
807 TRACE("returning %p\n", *handle
);
811 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
812 DWORD dwDesiredAccess
)
814 SC_HANDLE handle
= 0;
817 r
= SERV_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, &handle
);
818 if (r
!=ERROR_SUCCESS
)
823 /******************************************************************************
824 * ControlService [ADVAPI32.@]
826 * Send a control code to a service.
829 * hService [I] Handle of the service control manager database
830 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
831 * lpServiceStatus [O] Destination for the status of the service, if available
838 * Unlike M$' implementation, control requests are not serialized and may be
839 * processed asynchronously.
841 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
842 LPSERVICE_STATUS lpServiceStatus
)
846 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
850 err
= svcctl_ControlService(hService
, dwControl
, lpServiceStatus
);
854 err
= map_exception_code(GetExceptionCode());
857 if (err
!= ERROR_SUCCESS
)
866 /******************************************************************************
867 * CloseServiceHandle [ADVAPI32.@]
869 * Close a handle to a service or the service control manager database.
872 * hSCObject [I] Handle to service or service control manager database
879 CloseServiceHandle( SC_HANDLE hSCObject
)
883 TRACE("%p\n", hSCObject
);
887 err
= svcctl_CloseServiceHandle((SC_RPC_HANDLE
*)&hSCObject
);
891 err
= map_exception_code(GetExceptionCode());
895 if (err
!= ERROR_SUCCESS
)
904 /******************************************************************************
905 * OpenServiceA [ADVAPI32.@]
907 * Open a handle to a service.
910 * hSCManager [I] Handle of the service control manager database
911 * lpServiceName [I] Name of the service to open
912 * dwDesiredAccess [I] Access required to the service
915 * Success: Handle to the service
918 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
919 DWORD dwDesiredAccess
)
921 LPWSTR lpServiceNameW
;
924 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
926 lpServiceNameW
= SERV_dup(lpServiceName
);
927 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
928 heap_free(lpServiceNameW
);
933 /******************************************************************************
934 * OpenServiceW [ADVAPI32.@]
938 DWORD
SERV_OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
939 DWORD dwDesiredAccess
, SC_HANDLE
*handle
)
943 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
946 return ERROR_INVALID_HANDLE
;
950 err
= svcctl_OpenServiceW(hSCManager
, lpServiceName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)handle
);
954 err
= map_exception_code(GetExceptionCode());
958 if (err
!= ERROR_SUCCESS
)
961 TRACE("returning %p\n", *handle
);
965 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
966 DWORD dwDesiredAccess
)
968 SC_HANDLE handle
= 0;
971 err
= SERV_OpenServiceW(hSCManager
, lpServiceName
, dwDesiredAccess
, &handle
);
972 if (err
!= ERROR_SUCCESS
)
977 /******************************************************************************
978 * CreateServiceW [ADVAPI32.@]
981 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
982 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
983 DWORD dwServiceType
, DWORD dwStartType
,
984 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
985 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
986 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
989 SC_HANDLE handle
= 0;
993 TRACE("%p %s %s\n", hSCManager
,
994 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
998 SetLastError( ERROR_INVALID_HANDLE
);
1003 passwdlen
= (strlenW(lpPassword
) + 1) * sizeof(WCHAR
);
1009 err
= svcctl_CreateServiceW(hSCManager
, lpServiceName
,
1010 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1011 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (const BYTE
*)lpDependencies
,
1012 multisz_cb(lpDependencies
), lpServiceStartName
, (const BYTE
*)lpPassword
, passwdlen
,
1013 (SC_RPC_HANDLE
*)&handle
);
1015 __EXCEPT(rpc_filter
)
1017 err
= map_exception_code(GetExceptionCode());
1021 if (err
!= ERROR_SUCCESS
)
1030 /******************************************************************************
1031 * CreateServiceA [ADVAPI32.@]
1034 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1035 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1036 DWORD dwServiceType
, DWORD dwStartType
,
1037 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1038 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1039 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1042 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1043 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1046 TRACE("%p %s %s\n", hSCManager
,
1047 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1049 lpServiceNameW
= SERV_dup( lpServiceName
);
1050 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1051 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1052 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1053 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1054 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1055 lpPasswordW
= SERV_dup( lpPassword
);
1057 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1058 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1059 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1060 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1062 heap_free( lpServiceNameW
);
1063 heap_free( lpDisplayNameW
);
1064 heap_free( lpBinaryPathNameW
);
1065 heap_free( lpLoadOrderGroupW
);
1066 heap_free( lpDependenciesW
);
1067 heap_free( lpServiceStartNameW
);
1068 heap_free( lpPasswordW
);
1074 /******************************************************************************
1075 * DeleteService [ADVAPI32.@]
1077 * Delete a service from the service control manager database.
1080 * hService [I] Handle of the service to delete
1086 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1090 TRACE("%p\n", hService
);
1094 err
= svcctl_DeleteService(hService
);
1096 __EXCEPT(rpc_filter
)
1098 err
= map_exception_code(GetExceptionCode());
1111 /******************************************************************************
1112 * StartServiceA [ADVAPI32.@]
1117 * hService [I] Handle of service
1118 * dwNumServiceArgs [I] Number of arguments
1119 * lpServiceArgVectors [I] Address of array of argument strings
1122 * - NT implements this function using an obscure RPC call.
1123 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1124 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1125 * - This will only work for shared address space. How should the service
1126 * args be transferred when address spaces are separated?
1127 * - Can only start one service at a time.
1128 * - Has no concept of privilege.
1134 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1135 LPCSTR
*lpServiceArgVectors
)
1137 LPWSTR
*lpwstr
=NULL
;
1141 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1143 if (dwNumServiceArgs
)
1144 lpwstr
= heap_alloc( dwNumServiceArgs
*sizeof(LPWSTR
) );
1146 for(i
=0; i
<dwNumServiceArgs
; i
++)
1147 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1149 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1151 if (dwNumServiceArgs
)
1153 for(i
=0; i
<dwNumServiceArgs
; i
++)
1154 heap_free(lpwstr
[i
]);
1162 /******************************************************************************
1163 * StartServiceW [ADVAPI32.@]
1165 * See StartServiceA.
1167 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1168 LPCWSTR
*lpServiceArgVectors
)
1172 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1176 err
= svcctl_StartServiceW(hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1178 __EXCEPT(rpc_filter
)
1180 err
= map_exception_code(GetExceptionCode());
1183 if (err
!= ERROR_SUCCESS
)
1192 /******************************************************************************
1193 * QueryServiceStatus [ADVAPI32.@]
1196 * hService [I] Handle to service to get information about
1197 * lpservicestatus [O] buffer to receive the status information for the service
1200 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1201 LPSERVICE_STATUS lpservicestatus
)
1203 SERVICE_STATUS_PROCESS SvcStatusData
;
1207 TRACE("%p %p\n", hService
, lpservicestatus
);
1211 SetLastError(ERROR_INVALID_HANDLE
);
1214 if (!lpservicestatus
)
1216 SetLastError(ERROR_INVALID_ADDRESS
);
1220 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1221 sizeof(SERVICE_STATUS_PROCESS
), &dummy
);
1222 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1227 /******************************************************************************
1228 * QueryServiceStatusEx [ADVAPI32.@]
1230 * Get information about a service.
1233 * hService [I] Handle to service to get information about
1234 * InfoLevel [I] Level of information to get
1235 * lpBuffer [O] Destination for requested information
1236 * cbBufSize [I] Size of lpBuffer in bytes
1237 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1243 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1244 LPBYTE lpBuffer
, DWORD cbBufSize
,
1245 LPDWORD pcbBytesNeeded
)
1249 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1251 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1253 err
= ERROR_INVALID_LEVEL
;
1255 else if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1257 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1258 err
= ERROR_INSUFFICIENT_BUFFER
;
1264 err
= svcctl_QueryServiceStatusEx(hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1266 __EXCEPT(rpc_filter
)
1268 err
= map_exception_code(GetExceptionCode());
1272 if (err
!= ERROR_SUCCESS
)
1280 /******************************************************************************
1281 * QueryServiceConfigA [ADVAPI32.@]
1283 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1284 DWORD size
, LPDWORD needed
)
1289 QUERY_SERVICE_CONFIGW
*configW
;
1291 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1293 if (!(buffer
= heap_alloc( 2 * size
)))
1295 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1298 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1299 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1300 if (!ret
) goto done
;
1302 config
->dwServiceType
= configW
->dwServiceType
;
1303 config
->dwStartType
= configW
->dwStartType
;
1304 config
->dwErrorControl
= configW
->dwErrorControl
;
1305 config
->lpBinaryPathName
= NULL
;
1306 config
->lpLoadOrderGroup
= NULL
;
1307 config
->dwTagId
= configW
->dwTagId
;
1308 config
->lpDependencies
= NULL
;
1309 config
->lpServiceStartName
= NULL
;
1310 config
->lpDisplayName
= NULL
;
1312 p
= (LPSTR
)(config
+ 1);
1313 n
= size
- sizeof(*config
);
1316 #define MAP_STR(str) \
1320 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1321 if (!sz) goto done; \
1328 MAP_STR( lpBinaryPathName
);
1329 MAP_STR( lpLoadOrderGroup
);
1330 MAP_STR( lpDependencies
);
1331 MAP_STR( lpServiceStartName
);
1332 MAP_STR( lpDisplayName
);
1335 *needed
= p
- (LPSTR
)config
;
1339 heap_free( buffer
);
1343 static DWORD
move_string_to_buffer(BYTE
**buf
, LPWSTR
*string_ptr
)
1350 memset(*buf
, 0, cb
);
1354 cb
= (strlenW(*string_ptr
) + 1)*sizeof(WCHAR
);
1355 memcpy(*buf
, *string_ptr
, cb
);
1356 MIDL_user_free(*string_ptr
);
1359 *string_ptr
= (LPWSTR
)*buf
;
1365 static DWORD
size_string(LPCWSTR string
)
1367 return (string
? (strlenW(string
) + 1)*sizeof(WCHAR
) : sizeof(WCHAR
));
1370 /******************************************************************************
1371 * QueryServiceConfigW [ADVAPI32.@]
1374 QueryServiceConfigW( SC_HANDLE hService
,
1375 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1376 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1378 QUERY_SERVICE_CONFIGW config
;
1383 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1384 cbBufSize
, pcbBytesNeeded
);
1386 memset(&config
, 0, sizeof(config
));
1390 err
= svcctl_QueryServiceConfigW(hService
, &config
);
1392 __EXCEPT(rpc_filter
)
1394 err
= map_exception_code(GetExceptionCode());
1398 if (err
!= ERROR_SUCCESS
)
1400 TRACE("services.exe: error %u\n", err
);
1405 /* calculate the size required first */
1406 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1407 total
+= size_string(config
.lpBinaryPathName
);
1408 total
+= size_string(config
.lpLoadOrderGroup
);
1409 total
+= size_string(config
.lpDependencies
);
1410 total
+= size_string(config
.lpServiceStartName
);
1411 total
+= size_string(config
.lpDisplayName
);
1413 *pcbBytesNeeded
= total
;
1415 /* if there's not enough memory, return an error */
1416 if( total
> cbBufSize
)
1418 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1419 MIDL_user_free(config
.lpBinaryPathName
);
1420 MIDL_user_free(config
.lpLoadOrderGroup
);
1421 MIDL_user_free(config
.lpDependencies
);
1422 MIDL_user_free(config
.lpServiceStartName
);
1423 MIDL_user_free(config
.lpDisplayName
);
1427 *lpServiceConfig
= config
;
1428 bufpos
= ((BYTE
*)lpServiceConfig
) + sizeof(QUERY_SERVICE_CONFIGW
);
1429 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpBinaryPathName
);
1430 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpLoadOrderGroup
);
1431 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDependencies
);
1432 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpServiceStartName
);
1433 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDisplayName
);
1435 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1436 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1437 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
1438 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
1439 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
1444 /******************************************************************************
1445 * QueryServiceConfig2A [ADVAPI32.@]
1448 * observed under win2k:
1449 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1450 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1452 BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1453 DWORD size
, LPDWORD needed
)
1456 LPBYTE bufferW
= NULL
;
1459 bufferW
= heap_alloc(size
);
1461 ret
= QueryServiceConfig2W(hService
, dwLevel
, bufferW
, size
, needed
);
1462 if(!ret
) goto cleanup
;
1465 case SERVICE_CONFIG_DESCRIPTION
:
1466 if (buffer
&& bufferW
) {
1467 LPSERVICE_DESCRIPTIONA configA
= (LPSERVICE_DESCRIPTIONA
) buffer
;
1468 LPSERVICE_DESCRIPTIONW configW
= (LPSERVICE_DESCRIPTIONW
) bufferW
;
1469 if (configW
->lpDescription
&& (size
> sizeof(SERVICE_DESCRIPTIONA
))) {
1471 configA
->lpDescription
= (LPSTR
)(configA
+ 1);
1472 sz
= WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1,
1473 configA
->lpDescription
, size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
1475 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1477 configA
->lpDescription
= NULL
;
1480 else configA
->lpDescription
= NULL
;
1483 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
1484 if (buffer
&& bufferW
&& *needed
<=size
)
1485 memcpy(buffer
, bufferW
, *needed
);
1488 FIXME("conversation W->A not implemented for level %d\n", dwLevel
);
1494 heap_free( bufferW
);
1498 /******************************************************************************
1499 * QueryServiceConfig2W [ADVAPI32.@]
1501 * See QueryServiceConfig2A.
1503 BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1504 DWORD size
, LPDWORD needed
)
1508 if(dwLevel
!=SERVICE_CONFIG_DESCRIPTION
&& dwLevel
!=SERVICE_CONFIG_PRESHUTDOWN_INFO
) {
1509 FIXME("Level %d not implemented\n", dwLevel
);
1510 SetLastError(ERROR_INVALID_LEVEL
);
1514 if(!buffer
&& size
) {
1515 SetLastError(ERROR_INVALID_ADDRESS
);
1519 TRACE("%p 0x%d %p 0x%d %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1523 err
= svcctl_QueryServiceConfig2W(hService
, dwLevel
, buffer
, size
, needed
);
1525 __EXCEPT(rpc_filter
)
1527 err
= map_exception_code(GetExceptionCode());
1531 if (err
!= ERROR_SUCCESS
)
1533 SetLastError( err
);
1539 case SERVICE_CONFIG_DESCRIPTION
:
1542 SERVICE_DESCRIPTIONW
*descr
= (SERVICE_DESCRIPTIONW
*)buffer
;
1543 if (descr
->lpDescription
) /* make it an absolute pointer */
1544 descr
->lpDescription
= (WCHAR
*)(buffer
+ (ULONG_PTR
)descr
->lpDescription
);
1552 /******************************************************************************
1553 * EnumServicesStatusA [ADVAPI32.@]
1556 EnumServicesStatusA( SC_HANDLE hmngr
, DWORD type
, DWORD state
, LPENUM_SERVICE_STATUSA
1557 services
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1558 LPDWORD resume_handle
)
1562 ENUM_SERVICE_STATUSW
*servicesW
= NULL
;
1566 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr
, type
, state
, services
, size
, needed
,
1567 returned
, resume_handle
);
1569 sz
= max( 2 * size
, sizeof(*servicesW
) );
1570 if (!(servicesW
= heap_alloc( sz
)))
1572 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1576 ret
= EnumServicesStatusW( hmngr
, type
, state
, servicesW
, sz
, needed
, returned
, resume_handle
);
1577 if (!ret
) goto done
;
1579 p
= (char *)services
+ *returned
* sizeof(ENUM_SERVICE_STATUSA
);
1580 n
= size
- (p
- (char *)services
);
1582 for (i
= 0; i
< *returned
; i
++)
1584 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpServiceName
, -1, p
, n
, NULL
, NULL
);
1586 services
[i
].lpServiceName
= p
;
1589 if (servicesW
[i
].lpDisplayName
)
1591 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpDisplayName
, -1, p
, n
, NULL
, NULL
);
1593 services
[i
].lpDisplayName
= p
;
1597 else services
[i
].lpDisplayName
= NULL
;
1598 services
[i
].ServiceStatus
= servicesW
[i
].ServiceStatus
;
1604 heap_free( servicesW
);
1608 /******************************************************************************
1609 * EnumServicesStatusW [ADVAPI32.@]
1612 EnumServicesStatusW( SC_HANDLE hmngr
, DWORD type
, DWORD state
, LPENUM_SERVICE_STATUSW
1613 services
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1614 LPDWORD resume_handle
)
1617 ENUM_SERVICE_STATUSW dummy_status
;
1619 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr
, type
, state
, services
, size
, needed
,
1620 returned
, resume_handle
);
1623 FIXME("resume handle not supported\n");
1627 SetLastError( ERROR_INVALID_HANDLE
);
1631 /* make sure we pass a valid pointer */
1632 if (!services
|| size
< sizeof(*services
))
1634 services
= &dummy_status
;
1635 size
= sizeof(dummy_status
);
1640 err
= svcctl_EnumServicesStatusW( hmngr
, type
, state
, (BYTE
*)services
, size
, needed
, returned
);
1642 __EXCEPT(rpc_filter
)
1644 err
= map_exception_code( GetExceptionCode() );
1648 if (err
!= ERROR_SUCCESS
)
1650 SetLastError( err
);
1654 for (i
= 0; i
< *returned
; i
++)
1656 /* convert buffer offsets into pointers */
1657 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ (DWORD_PTR
)services
[i
].lpServiceName
);
1658 if (services
[i
].lpDisplayName
)
1659 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ (DWORD_PTR
)services
[i
].lpDisplayName
);
1665 /******************************************************************************
1666 * EnumServicesStatusExA [ADVAPI32.@]
1669 EnumServicesStatusExA( SC_HANDLE hmngr
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1670 LPBYTE buffer
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1671 LPDWORD resume_handle
, LPCSTR group
)
1675 ENUM_SERVICE_STATUS_PROCESSA
*services
= (ENUM_SERVICE_STATUS_PROCESSA
*)buffer
;
1676 ENUM_SERVICE_STATUS_PROCESSW
*servicesW
= NULL
;
1677 WCHAR
*groupW
= NULL
;
1681 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr
, level
, type
, state
, buffer
,
1682 size
, needed
, returned
, resume_handle
, debugstr_a(group
));
1684 sz
= max( 2 * size
, sizeof(*servicesW
) );
1685 if (!(servicesW
= heap_alloc( sz
)))
1687 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1692 int len
= MultiByteToWideChar( CP_ACP
, 0, group
, -1, NULL
, 0 );
1693 if (!(groupW
= heap_alloc( len
* sizeof(WCHAR
) )))
1695 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1696 heap_free( servicesW
);
1699 MultiByteToWideChar( CP_ACP
, 0, group
, -1, groupW
, len
* sizeof(WCHAR
) );
1702 ret
= EnumServicesStatusExW( hmngr
, level
, type
, state
, (BYTE
*)servicesW
, sz
,
1703 needed
, returned
, resume_handle
, groupW
);
1704 if (!ret
) goto done
;
1706 p
= (char *)services
+ *returned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
);
1707 n
= size
- (p
- (char *)services
);
1709 for (i
= 0; i
< *returned
; i
++)
1711 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpServiceName
, -1, p
, n
, NULL
, NULL
);
1713 services
[i
].lpServiceName
= p
;
1716 if (servicesW
[i
].lpDisplayName
)
1718 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpDisplayName
, -1, p
, n
, NULL
, NULL
);
1720 services
[i
].lpDisplayName
= p
;
1724 else services
[i
].lpDisplayName
= NULL
;
1725 services
[i
].ServiceStatusProcess
= servicesW
[i
].ServiceStatusProcess
;
1731 heap_free( servicesW
);
1732 heap_free( groupW
);
1736 /******************************************************************************
1737 * EnumServicesStatusExW [ADVAPI32.@]
1740 EnumServicesStatusExW( SC_HANDLE hmngr
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1741 LPBYTE buffer
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1742 LPDWORD resume_handle
, LPCWSTR group
)
1745 ENUM_SERVICE_STATUS_PROCESSW dummy_status
;
1746 ENUM_SERVICE_STATUS_PROCESSW
*services
= (ENUM_SERVICE_STATUS_PROCESSW
*)buffer
;
1748 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr
, level
, type
, state
, buffer
,
1749 size
, needed
, returned
, resume_handle
, debugstr_w(group
));
1752 FIXME("resume handle not supported\n");
1754 if (level
!= SC_ENUM_PROCESS_INFO
)
1756 SetLastError( ERROR_INVALID_LEVEL
);
1761 SetLastError( ERROR_INVALID_HANDLE
);
1765 /* make sure we pass a valid buffer pointer */
1766 if (!services
|| size
< sizeof(*services
))
1768 buffer
= (BYTE
*)&dummy_status
;
1769 size
= sizeof(dummy_status
);
1774 err
= svcctl_EnumServicesStatusExW( hmngr
, type
, state
, buffer
, size
, needed
,
1777 __EXCEPT(rpc_filter
)
1779 err
= map_exception_code( GetExceptionCode() );
1783 if (err
!= ERROR_SUCCESS
)
1785 SetLastError( err
);
1789 for (i
= 0; i
< *returned
; i
++)
1791 /* convert buffer offsets into pointers */
1792 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ (DWORD_PTR
)services
[i
].lpServiceName
);
1793 if (services
[i
].lpDisplayName
)
1794 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ (DWORD_PTR
)services
[i
].lpDisplayName
);
1800 /******************************************************************************
1801 * GetServiceKeyNameA [ADVAPI32.@]
1803 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1804 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1806 LPWSTR lpDisplayNameW
, lpServiceNameW
;
1810 TRACE("%p %s %p %p\n", hSCManager
,
1811 debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1813 lpDisplayNameW
= SERV_dup(lpDisplayName
);
1815 lpServiceNameW
= heap_alloc(*lpcchBuffer
* sizeof(WCHAR
));
1817 lpServiceNameW
= NULL
;
1819 sizeW
= *lpcchBuffer
;
1820 if (!GetServiceKeyNameW(hSCManager
, lpDisplayNameW
, lpServiceNameW
, &sizeW
))
1822 if (lpServiceName
&& *lpcchBuffer
)
1823 lpServiceName
[0] = 0;
1824 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1828 if (!WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, (sizeW
+ 1), lpServiceName
,
1829 *lpcchBuffer
, NULL
, NULL
))
1831 if (*lpcchBuffer
&& lpServiceName
)
1832 lpServiceName
[0] = 0;
1833 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, -1, NULL
, 0, NULL
, NULL
);
1837 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1841 heap_free(lpServiceNameW
);
1842 heap_free(lpDisplayNameW
);
1846 /******************************************************************************
1847 * GetServiceKeyNameW [ADVAPI32.@]
1849 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1850 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1856 TRACE("%p %s %p %p\n", hSCManager
,
1857 debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1861 SetLastError( ERROR_INVALID_HANDLE
);
1865 /* provide a buffer if the caller didn't */
1866 if (!lpServiceName
|| *lpcchBuffer
< 2)
1868 lpServiceName
= buffer
;
1869 /* A size of 1 would be enough, but tests show that Windows returns 2,
1870 * probably because of a WCHAR/bytes mismatch in their code.
1875 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1876 * includes the nul-terminator on input. */
1877 size
= *lpcchBuffer
- 1;
1881 err
= svcctl_GetServiceKeyNameW(hSCManager
, lpDisplayName
, lpServiceName
,
1884 __EXCEPT(rpc_filter
)
1886 err
= map_exception_code(GetExceptionCode());
1890 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1891 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
1892 *lpcchBuffer
= size
;
1896 return err
== ERROR_SUCCESS
;
1899 /******************************************************************************
1900 * QueryServiceLockStatusA [ADVAPI32.@]
1902 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1903 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1904 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1906 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1911 /******************************************************************************
1912 * QueryServiceLockStatusW [ADVAPI32.@]
1914 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
1915 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
1916 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1918 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1923 /******************************************************************************
1924 * GetServiceDisplayNameA [ADVAPI32.@]
1926 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1927 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1929 LPWSTR lpServiceNameW
, lpDisplayNameW
;
1933 TRACE("%p %s %p %p\n", hSCManager
,
1934 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1936 lpServiceNameW
= SERV_dup(lpServiceName
);
1938 lpDisplayNameW
= heap_alloc(*lpcchBuffer
* sizeof(WCHAR
));
1940 lpDisplayNameW
= NULL
;
1942 sizeW
= *lpcchBuffer
;
1943 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
1945 if (lpDisplayName
&& *lpcchBuffer
)
1946 lpDisplayName
[0] = 0;
1947 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1951 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
1952 *lpcchBuffer
, NULL
, NULL
))
1954 if (*lpcchBuffer
&& lpDisplayName
)
1955 lpDisplayName
[0] = 0;
1956 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
1960 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1961 * (but if the function succeeded it means that is a good upper estimation of the size) */
1965 heap_free(lpDisplayNameW
);
1966 heap_free(lpServiceNameW
);
1970 /******************************************************************************
1971 * GetServiceDisplayNameW [ADVAPI32.@]
1973 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1974 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1980 TRACE("%p %s %p %p\n", hSCManager
,
1981 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1985 SetLastError( ERROR_INVALID_HANDLE
);
1989 /* provide a buffer if the caller didn't */
1990 if (!lpDisplayName
|| *lpcchBuffer
< 2)
1992 lpDisplayName
= buffer
;
1993 /* A size of 1 would be enough, but tests show that Windows returns 2,
1994 * probably because of a WCHAR/bytes mismatch in their code.
1999 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2000 * includes the nul-terminator on input. */
2001 size
= *lpcchBuffer
- 1;
2005 err
= svcctl_GetServiceDisplayNameW(hSCManager
, lpServiceName
, lpDisplayName
,
2008 __EXCEPT(rpc_filter
)
2010 err
= map_exception_code(GetExceptionCode());
2014 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2015 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
2016 *lpcchBuffer
= size
;
2020 return err
== ERROR_SUCCESS
;
2023 /******************************************************************************
2024 * ChangeServiceConfigW [ADVAPI32.@]
2026 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2027 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2028 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2029 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2034 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2035 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2036 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2037 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2038 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2040 cb_pwd
= lpPassword
? (strlenW(lpPassword
) + 1)*sizeof(WCHAR
) : 0;
2044 err
= svcctl_ChangeServiceConfigW(hService
, dwServiceType
,
2045 dwStartType
, dwErrorControl
, lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
,
2046 (const BYTE
*)lpDependencies
, multisz_cb(lpDependencies
), lpServiceStartName
,
2047 (const BYTE
*)lpPassword
, cb_pwd
, lpDisplayName
);
2049 __EXCEPT(rpc_filter
)
2051 err
= map_exception_code(GetExceptionCode());
2055 if (err
!= ERROR_SUCCESS
)
2058 return err
== ERROR_SUCCESS
;
2061 /******************************************************************************
2062 * ChangeServiceConfigA [ADVAPI32.@]
2064 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2065 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2066 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2067 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2069 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2070 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2073 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2074 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2075 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2076 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2077 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2079 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2080 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2081 wDependencies
= SERV_dupmulti( lpDependencies
);
2082 wServiceStartName
= SERV_dup( lpServiceStartName
);
2083 wPassword
= SERV_dup( lpPassword
);
2084 wDisplayName
= SERV_dup( lpDisplayName
);
2086 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2087 dwStartType
, dwErrorControl
, wBinaryPathName
,
2088 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2089 wServiceStartName
, wPassword
, wDisplayName
);
2091 heap_free( wBinaryPathName
);
2092 heap_free( wLoadOrderGroup
);
2093 heap_free( wDependencies
);
2094 heap_free( wServiceStartName
);
2095 heap_free( wPassword
);
2096 heap_free( wDisplayName
);
2101 /******************************************************************************
2102 * ChangeServiceConfig2A [ADVAPI32.@]
2104 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2109 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2111 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2113 LPSERVICE_DESCRIPTIONA sd
= lpInfo
;
2114 SERVICE_DESCRIPTIONW sdw
;
2116 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2118 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2120 heap_free( sdw
.lpDescription
);
2122 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2124 LPSERVICE_FAILURE_ACTIONSA fa
= lpInfo
;
2125 SERVICE_FAILURE_ACTIONSW faw
;
2127 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2128 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2129 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2130 faw
.cActions
= fa
->cActions
;
2131 faw
.lpsaActions
= fa
->lpsaActions
;
2133 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2135 heap_free( faw
.lpRebootMsg
);
2136 heap_free( faw
.lpCommand
);
2138 else if (dwInfoLevel
== SERVICE_CONFIG_PRESHUTDOWN_INFO
)
2140 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, lpInfo
);
2143 SetLastError( ERROR_INVALID_PARAMETER
);
2148 /******************************************************************************
2149 * ChangeServiceConfig2W [ADVAPI32.@]
2151 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2158 err
= svcctl_ChangeServiceConfig2W( hService
, dwInfoLevel
, lpInfo
);
2160 __EXCEPT(rpc_filter
)
2162 err
= map_exception_code(GetExceptionCode());
2166 if (err
!= ERROR_SUCCESS
)
2169 return err
== ERROR_SUCCESS
;
2172 NTSTATUS
SERV_QueryServiceObjectSecurity(SC_HANDLE hService
,
2173 SECURITY_INFORMATION dwSecurityInformation
,
2174 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2175 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2177 SECURITY_DESCRIPTOR descriptor
;
2182 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2183 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2185 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2186 FIXME("information %d not supported\n", dwSecurityInformation
);
2188 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2190 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2191 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2194 status
= RtlMakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2195 *pcbBytesNeeded
= size
;
2199 /******************************************************************************
2200 * QueryServiceObjectSecurity [ADVAPI32.@]
2202 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2203 SECURITY_INFORMATION dwSecurityInformation
,
2204 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2205 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2207 NTSTATUS status
= SERV_QueryServiceObjectSecurity(hService
, dwSecurityInformation
, lpSecurityDescriptor
,
2208 cbBufSize
, pcbBytesNeeded
);
2209 if (status
!= STATUS_SUCCESS
)
2211 SetLastError(RtlNtStatusToDosError(status
));
2217 /******************************************************************************
2218 * SetServiceObjectSecurity [ADVAPI32.@]
2221 * - SetSecurityInfo should be updated to call this function once it's implemented.
2223 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2224 SECURITY_INFORMATION dwSecurityInformation
,
2225 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2227 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2231 /******************************************************************************
2232 * SetServiceBits [ADVAPI32.@]
2234 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2235 DWORD dwServiceBits
,
2237 BOOL bUpdateImmediately
)
2239 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2240 bSetBitsOn
, bUpdateImmediately
);
2244 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2245 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
2247 LPHANDLER_FUNCTION func
= context
;
2250 return ERROR_SUCCESS
;
2253 /******************************************************************************
2254 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2256 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
2258 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
2261 /******************************************************************************
2262 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2264 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
2266 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
2269 /******************************************************************************
2270 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2272 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
2275 SERVICE_STATUS_HANDLE ret
;
2277 nameW
= SERV_dup(name
);
2278 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
2283 /******************************************************************************
2284 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2286 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2287 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2289 service_data
*service
;
2290 SC_HANDLE hService
= 0;
2293 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2295 EnterCriticalSection( &service_cs
);
2296 if ((service
= find_service_by_name( lpServiceName
)))
2298 service
->handler
= lpHandlerProc
;
2299 service
->context
= lpContext
;
2300 hService
= service
->handle
;
2303 LeaveCriticalSection( &service_cs
);
2305 if (!found
) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2307 return (SERVICE_STATUS_HANDLE
)hService
;
2310 /******************************************************************************
2311 * EnumDependentServicesA [ADVAPI32.@]
2313 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2314 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2315 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2317 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2318 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2320 *lpServicesReturned
= 0;
2324 /******************************************************************************
2325 * EnumDependentServicesW [ADVAPI32.@]
2327 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2328 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2329 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2331 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2332 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2334 *lpServicesReturned
= 0;