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 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(SIZE_T len
)
50 return HeapAlloc(GetProcessHeap(), 0, len
);
53 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
55 HeapFree(GetProcessHeap(), 0, ptr
);
58 typedef struct service_data_t
60 LPHANDLER_FUNCTION_EX handler
;
66 LPSERVICE_MAIN_FUNCTIONA a
;
67 LPSERVICE_MAIN_FUNCTIONW w
;
73 static CRITICAL_SECTION service_cs
;
74 static CRITICAL_SECTION_DEBUG service_cs_debug
=
77 { &service_cs_debug
.ProcessLocksList
,
78 &service_cs_debug
.ProcessLocksList
},
79 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
81 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
83 static service_data
**services
;
84 static unsigned int nb_services
;
85 static HANDLE service_event
;
87 extern HANDLE CDECL
__wine_make_process_system(void);
89 /******************************************************************************
90 * String management functions (same behaviour as strdup)
91 * NOTE: the caller of those functions is responsible for calling HeapFree
92 * in order to release the memory allocated by those functions.
94 static inline LPWSTR
SERV_dup( LPCSTR str
)
101 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
102 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
103 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
107 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
115 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
116 n
+= (strlen( &str
[n
] ) + 1);
121 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
122 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
126 static inline DWORD
multisz_cb(LPCWSTR wmultisz
)
128 const WCHAR
*wptr
= wmultisz
;
130 if (wmultisz
== NULL
)
134 wptr
+= lstrlenW(wptr
)+1;
135 return (wptr
- wmultisz
+ 1)*sizeof(WCHAR
);
138 /******************************************************************************
139 * RPC connection with services.exe
142 DECLSPEC_HIDDEN handle_t __RPC_USER
MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName
)
144 WCHAR transport
[] = SVCCTL_TRANSPORT
;
145 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
146 RPC_WSTR binding_str
;
150 status
= RpcStringBindingComposeW(NULL
, transport
, (RPC_WSTR
)MachineName
, endpoint
, NULL
, &binding_str
);
151 if (status
!= RPC_S_OK
)
153 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
157 status
= RpcBindingFromStringBindingW(binding_str
, &rpc_handle
);
158 RpcStringFreeW(&binding_str
);
160 if (status
!= RPC_S_OK
)
162 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
169 DECLSPEC_HIDDEN
void __RPC_USER
MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName
, handle_t h
)
174 static LONG WINAPI
rpc_filter(EXCEPTION_POINTERS
*eptr
)
176 return I_RpcExceptionFilter(eptr
->ExceptionRecord
->ExceptionCode
);
179 static DWORD
map_exception_code(DWORD exception_code
)
181 switch (exception_code
)
183 case RPC_X_NULL_REF_POINTER
:
184 return ERROR_INVALID_ADDRESS
;
185 case RPC_X_ENUM_VALUE_OUT_OF_RANGE
:
186 case RPC_X_BYTE_COUNT_TOO_SMALL
:
187 return ERROR_INVALID_PARAMETER
;
188 case RPC_S_INVALID_BINDING
:
189 case RPC_X_SS_IN_NULL_CONTEXT
:
190 return ERROR_INVALID_HANDLE
;
192 return exception_code
;
196 /******************************************************************************
197 * Service IPC functions
199 static LPWSTR
service_get_pipe_name(void)
201 static const WCHAR format
[] = { '\\','\\','.','\\','p','i','p','e','\\',
202 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
203 static const WCHAR service_current_key_str
[] = { 'S','Y','S','T','E','M','\\',
204 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
205 'C','o','n','t','r','o','l','\\',
206 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
209 HKEY service_current_key
;
210 DWORD service_current
;
214 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, service_current_key_str
, 0,
215 KEY_QUERY_VALUE
, &service_current_key
);
216 if (ret
!= ERROR_SUCCESS
)
218 len
= sizeof(service_current
);
219 ret
= RegQueryValueExW(service_current_key
, NULL
, NULL
, &type
,
220 (BYTE
*)&service_current
, &len
);
221 RegCloseKey(service_current_key
);
222 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
224 len
= sizeof(format
)/sizeof(WCHAR
) + 10 /* strlenW("4294967295") */;
225 name
= HeapAlloc(GetProcessHeap(), 0, len
* sizeof(WCHAR
));
228 snprintfW(name
, len
, format
, service_current
);
232 static HANDLE
service_open_pipe(void)
234 LPWSTR szPipe
= service_get_pipe_name();
235 HANDLE handle
= INVALID_HANDLE_VALUE
;
238 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
239 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
240 if (handle
!= INVALID_HANDLE_VALUE
)
242 if (GetLastError() != ERROR_PIPE_BUSY
)
244 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
245 HeapFree(GetProcessHeap(), 0, szPipe
);
250 static service_data
*find_service_by_name( const WCHAR
*name
)
254 if (nb_services
== 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
256 for (i
= 0; i
< nb_services
; i
++)
257 if (!strcmpiW( name
, services
[i
]->name
)) return services
[i
];
261 /******************************************************************************
264 * Call into the main service routine provided by StartServiceCtrlDispatcher.
266 static DWORD WINAPI
service_thread(LPVOID arg
)
268 service_data
*info
= arg
;
269 LPWSTR str
= info
->args
;
270 DWORD argc
= 0, len
= 0;
276 len
+= strlenW(&str
[len
]) + 1;
285 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
286 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
290 info
->proc
.w(argc
, argv
);
291 HeapFree(GetProcessHeap(), 0, argv
);
295 LPSTR strA
, *argv
, p
;
298 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
299 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
300 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
302 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
303 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
307 info
->proc
.a(argc
, argv
);
308 HeapFree(GetProcessHeap(), 0, argv
);
309 HeapFree(GetProcessHeap(), 0, strA
);
314 /******************************************************************************
315 * service_handle_start
317 static DWORD
service_handle_start(service_data
*service
, const WCHAR
*data
, DWORD count
)
319 TRACE("%s argsize %u\n", debugstr_w(service
->name
), count
);
323 WARN("service is not stopped\n");
324 return ERROR_SERVICE_ALREADY_RUNNING
;
327 HeapFree(GetProcessHeap(), 0, service
->args
);
328 service
->args
= HeapAlloc(GetProcessHeap(), 0, count
* sizeof(WCHAR
));
329 memcpy( service
->args
, data
, count
* sizeof(WCHAR
) );
330 service
->thread
= CreateThread( NULL
, 0, service_thread
,
332 SetEvent( service_event
); /* notify the main loop */
336 /******************************************************************************
337 * service_handle_control
339 static DWORD
service_handle_control(const service_data
*service
, DWORD dwControl
)
341 DWORD ret
= ERROR_INVALID_SERVICE_CONTROL
;
343 TRACE("%s control %u\n", debugstr_w(service
->name
), dwControl
);
345 if (service
->handler
)
346 ret
= service
->handler(dwControl
, 0, NULL
, service
->context
);
350 /******************************************************************************
351 * service_control_dispatcher
353 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
358 if (!(manager
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
)))
360 ERR("failed to open service manager error %u\n", GetLastError());
364 pipe
= service_open_pipe();
366 if (pipe
==INVALID_HANDLE_VALUE
)
368 ERR("failed to create control pipe error = %d\n", GetLastError());
372 /* dispatcher loop */
375 service_data
*service
;
376 service_start_info info
;
379 DWORD data_size
= 0, count
, result
;
381 r
= ReadFile( pipe
, &info
, FIELD_OFFSET(service_start_info
,data
), &count
, NULL
);
384 if (GetLastError() != ERROR_BROKEN_PIPE
)
385 ERR( "pipe read failed error %u\n", GetLastError() );
388 if (count
!= FIELD_OFFSET(service_start_info
,data
))
390 ERR( "partial pipe read %u\n", count
);
393 if (count
< info
.total_size
)
395 data_size
= info
.total_size
- FIELD_OFFSET(service_start_info
,data
);
396 data
= HeapAlloc( GetProcessHeap(), 0, data_size
);
397 r
= ReadFile( pipe
, data
, data_size
, &count
, NULL
);
400 if (GetLastError() != ERROR_BROKEN_PIPE
)
401 ERR( "pipe read failed error %u\n", GetLastError() );
404 if (count
!= data_size
)
406 ERR( "partial pipe read %u/%u\n", count
, data_size
);
411 /* find the service */
413 if (!(service
= find_service_by_name( data
)))
415 FIXME( "got request %u for unknown service %s\n", info
.cmd
, debugstr_w(data
));
416 result
= ERROR_INVALID_PARAMETER
;
420 TRACE( "got request %u for service %s\n", info
.cmd
, debugstr_w(data
) );
422 /* handle the request */
425 case WINESERV_STARTINFO
:
426 if (!service
->handle
)
428 if (!(service
->handle
= OpenServiceW( manager
, data
, SERVICE_SET_STATUS
)))
429 FIXME( "failed to open service %s\n", debugstr_w(data
) );
431 result
= service_handle_start(service
, data
+ info
.name_size
,
432 data_size
/ sizeof(WCHAR
) - info
.name_size
);
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(pipe
, &result
, sizeof(result
), &count
, NULL
);
445 HeapFree( GetProcessHeap(), 0, data
);
449 CloseServiceHandle( manager
);
453 /******************************************************************************
454 * service_run_main_thread
456 static BOOL
service_run_main_thread(void)
459 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
460 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
462 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
464 /* FIXME: service_control_dispatcher should be merged into the main thread */
465 wait_handles
[0] = __wine_make_process_system();
466 wait_handles
[1] = CreateThread( NULL
, 0, service_control_dispatcher
, NULL
, 0, NULL
);
467 wait_handles
[2] = service_event
;
469 TRACE("Starting %d services running as process %d\n",
470 nb_services
, GetCurrentProcessId());
472 /* wait for all the threads to pack up and exit */
475 EnterCriticalSection( &service_cs
);
476 for (i
= 0, n
= 3; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
478 if (!services
[i
]->thread
) continue;
479 wait_services
[n
] = i
;
480 wait_handles
[n
++] = services
[i
]->thread
;
482 LeaveCriticalSection( &service_cs
);
484 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
485 if (!ret
) /* system process event */
487 TRACE( "last user process exited, shutting down\n" );
488 /* FIXME: we should maybe send a shutdown control to running services */
493 TRACE( "control dispatcher exited, shutting down\n" );
494 /* FIXME: we should maybe send a shutdown control to running services */
499 continue; /* rebuild the list */
503 services
[wait_services
[ret
]]->thread
= 0;
504 CloseHandle( wait_handles
[ret
] );
505 if (n
== 4) return TRUE
; /* it was the last running thread */
511 /******************************************************************************
512 * StartServiceCtrlDispatcherA [ADVAPI32.@]
514 * See StartServiceCtrlDispatcherW.
516 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
522 TRACE("%p\n", servent
);
526 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
529 while (servent
[nb_services
].lpServiceName
) nb_services
++;
530 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
532 for (i
= 0; i
< nb_services
; i
++)
534 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
535 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
536 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
537 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
538 info
->proc
.a
= servent
[i
].lpServiceProc
;
539 info
->unicode
= FALSE
;
543 service_run_main_thread();
548 /******************************************************************************
549 * StartServiceCtrlDispatcherW [ADVAPI32.@]
551 * Connects a process containing one or more services to the service control
555 * servent [I] A list of the service names and service procedures
561 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
567 TRACE("%p\n", servent
);
571 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
574 while (servent
[nb_services
].lpServiceName
) nb_services
++;
575 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
577 for (i
= 0; i
< nb_services
; i
++)
579 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
580 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
581 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
582 strcpyW(info
->name
, servent
[i
].lpServiceName
);
583 info
->proc
.w
= servent
[i
].lpServiceProc
;
584 info
->unicode
= TRUE
;
588 service_run_main_thread();
593 /******************************************************************************
594 * LockServiceDatabase [ADVAPI32.@]
596 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
598 SC_RPC_LOCK hLock
= NULL
;
601 TRACE("%p\n",hSCManager
);
605 err
= svcctl_LockServiceDatabase(hSCManager
, &hLock
);
609 err
= map_exception_code(GetExceptionCode());
612 if (err
!= ERROR_SUCCESS
)
620 /******************************************************************************
621 * UnlockServiceDatabase [ADVAPI32.@]
623 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
626 SC_RPC_LOCK hRpcLock
= ScLock
;
628 TRACE("%p\n",ScLock
);
632 err
= svcctl_UnlockServiceDatabase(&hRpcLock
);
636 err
= map_exception_code(GetExceptionCode());
639 if (err
!= ERROR_SUCCESS
)
647 /******************************************************************************
648 * SetServiceStatus [ADVAPI32.@]
655 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
659 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
660 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
661 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
662 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
663 lpStatus
->dwWaitHint
);
667 err
= svcctl_SetServiceStatus( hService
, lpStatus
);
671 err
= map_exception_code(GetExceptionCode());
674 if (err
!= ERROR_SUCCESS
)
680 if (lpStatus
->dwCurrentState
== SERVICE_STOPPED
)
681 CloseServiceHandle((SC_HANDLE
)hService
);
687 /******************************************************************************
688 * OpenSCManagerA [ADVAPI32.@]
690 * Establish a connection to the service control manager and open its database.
693 * lpMachineName [I] Pointer to machine name string
694 * lpDatabaseName [I] Pointer to database name string
695 * dwDesiredAccess [I] Type of access
698 * Success: A Handle to the service control manager database
701 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
702 DWORD dwDesiredAccess
)
704 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
707 lpMachineNameW
= SERV_dup(lpMachineName
);
708 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
709 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
710 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW
);
711 HeapFree(GetProcessHeap(), 0, lpMachineNameW
);
715 /******************************************************************************
716 * OpenSCManagerW [ADVAPI32.@]
718 * See OpenSCManagerA.
720 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
721 DWORD dwDesiredAccess
)
726 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
727 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
731 r
= svcctl_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)&handle
);
735 r
= map_exception_code(GetExceptionCode());
739 if (r
!=ERROR_SUCCESS
)
745 TRACE("returning %p\n", handle
);
749 /******************************************************************************
750 * ControlService [ADVAPI32.@]
752 * Send a control code to a service.
755 * hService [I] Handle of the service control manager database
756 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
757 * lpServiceStatus [O] Destination for the status of the service, if available
764 * Unlike M$' implementation, control requests are not serialized and may be
765 * processed asynchronously.
767 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
768 LPSERVICE_STATUS lpServiceStatus
)
772 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
776 err
= svcctl_ControlService(hService
, dwControl
, lpServiceStatus
);
780 err
= map_exception_code(GetExceptionCode());
783 if (err
!= ERROR_SUCCESS
)
792 /******************************************************************************
793 * CloseServiceHandle [ADVAPI32.@]
795 * Close a handle to a service or the service control manager database.
798 * hSCObject [I] Handle to service or service control manager database
805 CloseServiceHandle( SC_HANDLE hSCObject
)
809 TRACE("%p\n", hSCObject
);
813 err
= svcctl_CloseServiceHandle((SC_RPC_HANDLE
*)&hSCObject
);
817 err
= map_exception_code(GetExceptionCode());
821 if (err
!= ERROR_SUCCESS
)
830 /******************************************************************************
831 * OpenServiceA [ADVAPI32.@]
833 * Open a handle to a service.
836 * hSCManager [I] Handle of the service control manager database
837 * lpServiceName [I] Name of the service to open
838 * dwDesiredAccess [I] Access required to the service
841 * Success: Handle to the service
844 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
845 DWORD dwDesiredAccess
)
847 LPWSTR lpServiceNameW
;
850 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
852 lpServiceNameW
= SERV_dup(lpServiceName
);
853 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
854 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
859 /******************************************************************************
860 * OpenServiceW [ADVAPI32.@]
864 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
865 DWORD dwDesiredAccess
)
870 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
874 SetLastError( ERROR_INVALID_HANDLE
);
880 err
= svcctl_OpenServiceW(hSCManager
, lpServiceName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)&handle
);
884 err
= map_exception_code(GetExceptionCode());
888 if (err
!= ERROR_SUCCESS
)
894 TRACE("returning %p\n",handle
);
898 /******************************************************************************
899 * CreateServiceW [ADVAPI32.@]
902 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
903 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
904 DWORD dwServiceType
, DWORD dwStartType
,
905 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
906 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
907 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
914 TRACE("%p %s %s\n", hSCManager
,
915 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
919 SetLastError( ERROR_INVALID_HANDLE
);
924 passwdlen
= (strlenW(lpPassword
) + 1) * sizeof(WCHAR
);
930 err
= svcctl_CreateServiceW(hSCManager
, lpServiceName
,
931 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
932 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (const BYTE
*)lpDependencies
,
933 multisz_cb(lpDependencies
), lpServiceStartName
, (const BYTE
*)lpPassword
, passwdlen
,
934 (SC_RPC_HANDLE
*)&handle
);
938 err
= map_exception_code(GetExceptionCode());
942 if (err
!= ERROR_SUCCESS
)
951 /******************************************************************************
952 * CreateServiceA [ADVAPI32.@]
955 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
956 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
957 DWORD dwServiceType
, DWORD dwStartType
,
958 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
959 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
960 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
963 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
964 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
967 TRACE("%p %s %s\n", hSCManager
,
968 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
970 lpServiceNameW
= SERV_dup( lpServiceName
);
971 lpDisplayNameW
= SERV_dup( lpDisplayName
);
972 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
973 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
974 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
975 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
976 lpPasswordW
= SERV_dup( lpPassword
);
978 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
979 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
980 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
981 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
983 HeapFree( GetProcessHeap(), 0, lpServiceNameW
);
984 HeapFree( GetProcessHeap(), 0, lpDisplayNameW
);
985 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW
);
986 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW
);
987 HeapFree( GetProcessHeap(), 0, lpDependenciesW
);
988 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW
);
989 HeapFree( GetProcessHeap(), 0, lpPasswordW
);
995 /******************************************************************************
996 * DeleteService [ADVAPI32.@]
998 * Delete a service from the service control manager database.
1001 * hService [I] Handle of the service to delete
1007 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1013 err
= svcctl_DeleteService(hService
);
1015 __EXCEPT(rpc_filter
)
1017 err
= map_exception_code(GetExceptionCode());
1030 /******************************************************************************
1031 * StartServiceA [ADVAPI32.@]
1036 * hService [I] Handle of service
1037 * dwNumServiceArgs [I] Number of arguments
1038 * lpServiceArgVectors [I] Address of array of argument strings
1041 * - NT implements this function using an obscure RPC call.
1042 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1043 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1044 * - This will only work for shared address space. How should the service
1045 * args be transferred when address spaces are separated?
1046 * - Can only start one service at a time.
1047 * - Has no concept of privilege.
1053 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1054 LPCSTR
*lpServiceArgVectors
)
1056 LPWSTR
*lpwstr
=NULL
;
1060 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1062 if (dwNumServiceArgs
)
1063 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1064 dwNumServiceArgs
*sizeof(LPWSTR
) );
1066 for(i
=0; i
<dwNumServiceArgs
; i
++)
1067 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1069 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1071 if (dwNumServiceArgs
)
1073 for(i
=0; i
<dwNumServiceArgs
; i
++)
1074 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
1075 HeapFree(GetProcessHeap(), 0, lpwstr
);
1082 /******************************************************************************
1083 * StartServiceW [ADVAPI32.@]
1085 * See StartServiceA.
1087 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1088 LPCWSTR
*lpServiceArgVectors
)
1092 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1096 err
= svcctl_StartServiceW(hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1098 __EXCEPT(rpc_filter
)
1100 err
= map_exception_code(GetExceptionCode());
1103 if (err
!= ERROR_SUCCESS
)
1112 /******************************************************************************
1113 * QueryServiceStatus [ADVAPI32.@]
1116 * hService [I] Handle to service to get information about
1117 * lpservicestatus [O] buffer to receive the status information for the service
1120 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1121 LPSERVICE_STATUS lpservicestatus
)
1123 SERVICE_STATUS_PROCESS SvcStatusData
;
1127 TRACE("%p %p\n", hService
, lpservicestatus
);
1131 SetLastError(ERROR_INVALID_HANDLE
);
1134 if (!lpservicestatus
)
1136 SetLastError(ERROR_INVALID_ADDRESS
);
1140 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1141 sizeof(SERVICE_STATUS_PROCESS
), &dummy
);
1142 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1147 /******************************************************************************
1148 * QueryServiceStatusEx [ADVAPI32.@]
1150 * Get information about a service.
1153 * hService [I] Handle to service to get information about
1154 * InfoLevel [I] Level of information to get
1155 * lpBuffer [O] Destination for requested information
1156 * cbBufSize [I] Size of lpBuffer in bytes
1157 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1163 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1164 LPBYTE lpBuffer
, DWORD cbBufSize
,
1165 LPDWORD pcbBytesNeeded
)
1169 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1171 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1173 err
= ERROR_INVALID_LEVEL
;
1175 else if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1177 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1178 err
= ERROR_INSUFFICIENT_BUFFER
;
1184 err
= svcctl_QueryServiceStatusEx(hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1186 __EXCEPT(rpc_filter
)
1188 err
= map_exception_code(GetExceptionCode());
1192 if (err
!= ERROR_SUCCESS
)
1200 /******************************************************************************
1201 * QueryServiceConfigA [ADVAPI32.@]
1203 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1204 DWORD size
, LPDWORD needed
)
1209 QUERY_SERVICE_CONFIGW
*configW
;
1211 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1213 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1215 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1218 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1219 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1220 if (!ret
) goto done
;
1222 config
->dwServiceType
= configW
->dwServiceType
;
1223 config
->dwStartType
= configW
->dwStartType
;
1224 config
->dwErrorControl
= configW
->dwErrorControl
;
1225 config
->lpBinaryPathName
= NULL
;
1226 config
->lpLoadOrderGroup
= NULL
;
1227 config
->dwTagId
= configW
->dwTagId
;
1228 config
->lpDependencies
= NULL
;
1229 config
->lpServiceStartName
= NULL
;
1230 config
->lpDisplayName
= NULL
;
1232 p
= (LPSTR
)(config
+ 1);
1233 n
= size
- sizeof(*config
);
1236 #define MAP_STR(str) \
1240 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1241 if (!sz) goto done; \
1248 MAP_STR( lpBinaryPathName
);
1249 MAP_STR( lpLoadOrderGroup
);
1250 MAP_STR( lpDependencies
);
1251 MAP_STR( lpServiceStartName
);
1252 MAP_STR( lpDisplayName
);
1255 *needed
= p
- (LPSTR
)config
;
1259 HeapFree( GetProcessHeap(), 0, buffer
);
1263 static DWORD
move_string_to_buffer(BYTE
**buf
, LPWSTR
*string_ptr
)
1270 memset(*buf
, 0, cb
);
1274 cb
= (strlenW(*string_ptr
) + 1)*sizeof(WCHAR
);
1275 memcpy(*buf
, *string_ptr
, cb
);
1276 MIDL_user_free(*string_ptr
);
1279 *string_ptr
= (LPWSTR
)*buf
;
1285 static DWORD
size_string(LPCWSTR string
)
1287 return (string
? (strlenW(string
) + 1)*sizeof(WCHAR
) : sizeof(WCHAR
));
1290 /******************************************************************************
1291 * QueryServiceConfigW [ADVAPI32.@]
1294 QueryServiceConfigW( SC_HANDLE hService
,
1295 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1296 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1298 QUERY_SERVICE_CONFIGW config
;
1303 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1304 cbBufSize
, pcbBytesNeeded
);
1306 memset(&config
, 0, sizeof(config
));
1310 err
= svcctl_QueryServiceConfigW(hService
, &config
);
1312 __EXCEPT(rpc_filter
)
1314 err
= map_exception_code(GetExceptionCode());
1318 if (err
!= ERROR_SUCCESS
)
1320 TRACE("services.exe: error %u\n", err
);
1325 /* calculate the size required first */
1326 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1327 total
+= size_string(config
.lpBinaryPathName
);
1328 total
+= size_string(config
.lpLoadOrderGroup
);
1329 total
+= size_string(config
.lpDependencies
);
1330 total
+= size_string(config
.lpServiceStartName
);
1331 total
+= size_string(config
.lpDisplayName
);
1333 *pcbBytesNeeded
= total
;
1335 /* if there's not enough memory, return an error */
1336 if( total
> cbBufSize
)
1338 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1339 MIDL_user_free(config
.lpBinaryPathName
);
1340 MIDL_user_free(config
.lpLoadOrderGroup
);
1341 MIDL_user_free(config
.lpDependencies
);
1342 MIDL_user_free(config
.lpServiceStartName
);
1343 MIDL_user_free(config
.lpDisplayName
);
1347 *lpServiceConfig
= config
;
1348 bufpos
= ((BYTE
*)lpServiceConfig
) + sizeof(QUERY_SERVICE_CONFIGW
);
1349 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpBinaryPathName
);
1350 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpLoadOrderGroup
);
1351 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDependencies
);
1352 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpServiceStartName
);
1353 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDisplayName
);
1355 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1356 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1357 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
1358 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
1359 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
1364 /******************************************************************************
1365 * QueryServiceConfig2A [ADVAPI32.@]
1368 * observed under win2k:
1369 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1370 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1372 BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1373 DWORD size
, LPDWORD needed
)
1376 LPBYTE bufferW
= NULL
;
1379 bufferW
= HeapAlloc( GetProcessHeap(), 0, size
);
1381 ret
= QueryServiceConfig2W(hService
, dwLevel
, bufferW
, size
, needed
);
1382 if(!ret
) goto cleanup
;
1385 case SERVICE_CONFIG_DESCRIPTION
:
1386 if (buffer
&& bufferW
) {
1387 LPSERVICE_DESCRIPTIONA configA
= (LPSERVICE_DESCRIPTIONA
) buffer
;
1388 LPSERVICE_DESCRIPTIONW configW
= (LPSERVICE_DESCRIPTIONW
) bufferW
;
1389 if (configW
->lpDescription
&& (size
> sizeof(SERVICE_DESCRIPTIONA
))) {
1391 configA
->lpDescription
= (LPSTR
)(configA
+ 1);
1392 sz
= WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1,
1393 configA
->lpDescription
, size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
1395 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1397 configA
->lpDescription
= NULL
;
1400 else configA
->lpDescription
= NULL
;
1404 FIXME("conversation W->A not implemented for level %d\n", dwLevel
);
1410 HeapFree( GetProcessHeap(), 0, bufferW
);
1414 /******************************************************************************
1415 * QueryServiceConfig2W [ADVAPI32.@]
1417 * See QueryServiceConfig2A.
1419 BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1420 DWORD size
, LPDWORD needed
)
1424 if(dwLevel
!= SERVICE_CONFIG_DESCRIPTION
) {
1425 FIXME("Level %d not implemented\n", dwLevel
);
1426 SetLastError(ERROR_INVALID_LEVEL
);
1430 if(!buffer
&& size
) {
1431 SetLastError(ERROR_INVALID_ADDRESS
);
1435 TRACE("%p 0x%d %p 0x%d %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1439 err
= svcctl_QueryServiceConfig2W(hService
, dwLevel
, buffer
, size
, needed
);
1441 __EXCEPT(rpc_filter
)
1443 err
= map_exception_code(GetExceptionCode());
1447 if (err
!= ERROR_SUCCESS
)
1449 SetLastError( err
);
1455 case SERVICE_CONFIG_DESCRIPTION
:
1458 SERVICE_DESCRIPTIONW
*descr
= (SERVICE_DESCRIPTIONW
*)buffer
;
1459 if (descr
->lpDescription
) /* make it an absolute pointer */
1460 descr
->lpDescription
= (WCHAR
*)(buffer
+ (ULONG_PTR
)descr
->lpDescription
);
1468 /******************************************************************************
1469 * EnumServicesStatusA [ADVAPI32.@]
1472 EnumServicesStatusA( SC_HANDLE hmngr
, DWORD type
, DWORD state
, LPENUM_SERVICE_STATUSA
1473 services
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1474 LPDWORD resume_handle
)
1478 ENUM_SERVICE_STATUSW
*servicesW
= NULL
;
1482 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr
, type
, state
, services
, size
, needed
,
1483 returned
, resume_handle
);
1485 sz
= max( 2 * size
, sizeof(*servicesW
) );
1486 if (!(servicesW
= HeapAlloc( GetProcessHeap(), 0, sz
)))
1488 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1492 ret
= EnumServicesStatusW( hmngr
, type
, state
, servicesW
, sz
, needed
, returned
, resume_handle
);
1493 if (!ret
) goto done
;
1495 p
= (char *)services
+ *returned
* sizeof(ENUM_SERVICE_STATUSA
);
1496 n
= size
- (p
- (char *)services
);
1498 for (i
= 0; i
< *returned
; i
++)
1500 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpServiceName
, -1, p
, n
, NULL
, NULL
);
1502 services
[i
].lpServiceName
= p
;
1505 if (servicesW
[i
].lpDisplayName
)
1507 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpDisplayName
, -1, p
, n
, NULL
, NULL
);
1509 services
[i
].lpDisplayName
= p
;
1513 else services
[i
].lpDisplayName
= NULL
;
1514 services
[i
].ServiceStatus
= servicesW
[i
].ServiceStatus
;
1520 HeapFree( GetProcessHeap(), 0, servicesW
);
1524 /******************************************************************************
1525 * EnumServicesStatusW [ADVAPI32.@]
1528 EnumServicesStatusW( SC_HANDLE hmngr
, DWORD type
, DWORD state
, LPENUM_SERVICE_STATUSW
1529 services
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1530 LPDWORD resume_handle
)
1533 ENUM_SERVICE_STATUSW dummy_status
;
1535 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr
, type
, state
, services
, size
, needed
,
1536 returned
, resume_handle
);
1539 FIXME("resume handle not supported\n");
1543 SetLastError( ERROR_INVALID_HANDLE
);
1547 /* make sure we pass a valid pointer */
1548 if (!services
|| size
< sizeof(*services
))
1550 services
= &dummy_status
;
1551 size
= sizeof(dummy_status
);
1556 err
= svcctl_EnumServicesStatusW( hmngr
, type
, state
, (BYTE
*)services
, size
, needed
, returned
);
1558 __EXCEPT(rpc_filter
)
1560 err
= map_exception_code( GetExceptionCode() );
1564 if (err
!= ERROR_SUCCESS
)
1566 SetLastError( err
);
1570 for (i
= 0; i
< *returned
; i
++)
1572 /* convert buffer offsets into pointers */
1573 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ (DWORD_PTR
)services
[i
].lpServiceName
);
1574 if (services
[i
].lpDisplayName
)
1575 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ (DWORD_PTR
)services
[i
].lpDisplayName
);
1581 /******************************************************************************
1582 * EnumServicesStatusExA [ADVAPI32.@]
1585 EnumServicesStatusExA( SC_HANDLE hmngr
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1586 LPBYTE buffer
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1587 LPDWORD resume_handle
, LPCSTR group
)
1591 ENUM_SERVICE_STATUS_PROCESSA
*services
= (ENUM_SERVICE_STATUS_PROCESSA
*)buffer
;
1592 ENUM_SERVICE_STATUS_PROCESSW
*servicesW
= NULL
;
1593 WCHAR
*groupW
= NULL
;
1597 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr
, level
, type
, state
, buffer
,
1598 size
, needed
, returned
, resume_handle
, debugstr_a(group
));
1600 sz
= max( 2 * size
, sizeof(*servicesW
) );
1601 if (!(servicesW
= HeapAlloc( GetProcessHeap(), 0, sz
)))
1603 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1608 int len
= MultiByteToWideChar( CP_ACP
, 0, group
, -1, NULL
, 0 );
1609 if (!(groupW
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) )))
1611 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1612 HeapFree( GetProcessHeap(), 0, servicesW
);
1615 MultiByteToWideChar( CP_ACP
, 0, group
, -1, groupW
, len
* sizeof(WCHAR
) );
1618 ret
= EnumServicesStatusExW( hmngr
, level
, type
, state
, (BYTE
*)servicesW
, sz
,
1619 needed
, returned
, resume_handle
, groupW
);
1620 if (!ret
) goto done
;
1622 p
= (char *)services
+ *returned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
);
1623 n
= size
- (p
- (char *)services
);
1625 for (i
= 0; i
< *returned
; i
++)
1627 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpServiceName
, -1, p
, n
, NULL
, NULL
);
1629 services
[i
].lpServiceName
= p
;
1632 if (servicesW
[i
].lpDisplayName
)
1634 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpDisplayName
, -1, p
, n
, NULL
, NULL
);
1636 services
[i
].lpDisplayName
= p
;
1640 else services
[i
].lpDisplayName
= NULL
;
1641 services
[i
].ServiceStatusProcess
= servicesW
[i
].ServiceStatusProcess
;
1647 HeapFree( GetProcessHeap(), 0, servicesW
);
1648 HeapFree( GetProcessHeap(), 0, groupW
);
1652 /******************************************************************************
1653 * EnumServicesStatusExW [ADVAPI32.@]
1656 EnumServicesStatusExW( SC_HANDLE hmngr
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1657 LPBYTE buffer
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1658 LPDWORD resume_handle
, LPCWSTR group
)
1661 ENUM_SERVICE_STATUS_PROCESSW dummy_status
;
1662 ENUM_SERVICE_STATUS_PROCESSW
*services
= (ENUM_SERVICE_STATUS_PROCESSW
*)buffer
;
1664 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr
, level
, type
, state
, buffer
,
1665 size
, needed
, returned
, resume_handle
, debugstr_w(group
));
1668 FIXME("resume handle not supported\n");
1670 if (level
!= SC_ENUM_PROCESS_INFO
)
1672 SetLastError( ERROR_INVALID_LEVEL
);
1677 SetLastError( ERROR_INVALID_HANDLE
);
1681 /* make sure we pass a valid buffer pointer */
1682 if (!services
|| size
< sizeof(*services
))
1684 buffer
= (BYTE
*)&dummy_status
;
1685 size
= sizeof(dummy_status
);
1690 err
= svcctl_EnumServicesStatusExW( hmngr
, type
, state
, buffer
, size
, needed
,
1693 __EXCEPT(rpc_filter
)
1695 err
= map_exception_code( GetExceptionCode() );
1699 if (err
!= ERROR_SUCCESS
)
1701 SetLastError( err
);
1705 for (i
= 0; i
< *returned
; i
++)
1707 /* convert buffer offsets into pointers */
1708 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ (DWORD_PTR
)services
[i
].lpServiceName
);
1709 if (services
[i
].lpDisplayName
)
1710 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ (DWORD_PTR
)services
[i
].lpDisplayName
);
1716 /******************************************************************************
1717 * GetServiceKeyNameA [ADVAPI32.@]
1719 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
1720 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
1722 LPWSTR lpDisplayNameW
, lpServiceNameW
;
1726 TRACE("%p %s %p %p\n", hSCManager
,
1727 debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1729 lpDisplayNameW
= SERV_dup(lpDisplayName
);
1731 lpServiceNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
1733 lpServiceNameW
= NULL
;
1735 sizeW
= *lpcchBuffer
;
1736 if (!GetServiceKeyNameW(hSCManager
, lpDisplayNameW
, lpServiceNameW
, &sizeW
))
1738 if (lpServiceName
&& *lpcchBuffer
)
1739 lpServiceName
[0] = 0;
1740 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1744 if (!WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, (sizeW
+ 1), lpServiceName
,
1745 *lpcchBuffer
, NULL
, NULL
))
1747 if (*lpcchBuffer
&& lpServiceName
)
1748 lpServiceName
[0] = 0;
1749 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, -1, NULL
, 0, NULL
, NULL
);
1753 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1757 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1758 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
1762 /******************************************************************************
1763 * GetServiceKeyNameW [ADVAPI32.@]
1765 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
1766 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
1772 TRACE("%p %s %p %p\n", hSCManager
,
1773 debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
1777 SetLastError( ERROR_INVALID_HANDLE
);
1781 /* provide a buffer if the caller didn't */
1782 if (!lpServiceName
|| *lpcchBuffer
< 2)
1784 lpServiceName
= buffer
;
1785 /* A size of 1 would be enough, but tests show that Windows returns 2,
1786 * probably because of a WCHAR/bytes mismatch in their code.
1791 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1792 * includes the nul-terminator on input. */
1793 size
= *lpcchBuffer
- 1;
1797 err
= svcctl_GetServiceKeyNameW(hSCManager
, lpDisplayName
, lpServiceName
,
1800 __EXCEPT(rpc_filter
)
1802 err
= map_exception_code(GetExceptionCode());
1806 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1807 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
1808 *lpcchBuffer
= size
;
1812 return err
== ERROR_SUCCESS
;
1815 /******************************************************************************
1816 * QueryServiceLockStatusA [ADVAPI32.@]
1818 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
1819 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
1820 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1822 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1827 /******************************************************************************
1828 * QueryServiceLockStatusW [ADVAPI32.@]
1830 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
1831 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
1832 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1834 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
1839 /******************************************************************************
1840 * GetServiceDisplayNameA [ADVAPI32.@]
1842 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1843 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1845 LPWSTR lpServiceNameW
, lpDisplayNameW
;
1849 TRACE("%p %s %p %p\n", hSCManager
,
1850 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1852 lpServiceNameW
= SERV_dup(lpServiceName
);
1854 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
1856 lpDisplayNameW
= NULL
;
1858 sizeW
= *lpcchBuffer
;
1859 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
1861 if (lpDisplayName
&& *lpcchBuffer
)
1862 lpDisplayName
[0] = 0;
1863 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
1867 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
1868 *lpcchBuffer
, NULL
, NULL
))
1870 if (*lpcchBuffer
&& lpDisplayName
)
1871 lpDisplayName
[0] = 0;
1872 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
1876 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1877 * (but if the function succeeded it means that is a good upper estimation of the size) */
1881 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
1882 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1886 /******************************************************************************
1887 * GetServiceDisplayNameW [ADVAPI32.@]
1889 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1890 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
1896 TRACE("%p %s %p %p\n", hSCManager
,
1897 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
1901 SetLastError( ERROR_INVALID_HANDLE
);
1905 /* provide a buffer if the caller didn't */
1906 if (!lpDisplayName
|| *lpcchBuffer
< 2)
1908 lpDisplayName
= buffer
;
1909 /* A size of 1 would be enough, but tests show that Windows returns 2,
1910 * probably because of a WCHAR/bytes mismatch in their code.
1915 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1916 * includes the nul-terminator on input. */
1917 size
= *lpcchBuffer
- 1;
1921 err
= svcctl_GetServiceDisplayNameW(hSCManager
, lpServiceName
, lpDisplayName
,
1924 __EXCEPT(rpc_filter
)
1926 err
= map_exception_code(GetExceptionCode());
1930 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1931 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
1932 *lpcchBuffer
= size
;
1936 return err
== ERROR_SUCCESS
;
1939 /******************************************************************************
1940 * ChangeServiceConfigW [ADVAPI32.@]
1942 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1943 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1944 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1945 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1950 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1951 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1952 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1953 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1954 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1956 cb_pwd
= lpPassword
? (strlenW(lpPassword
) + 1)*sizeof(WCHAR
) : 0;
1960 err
= svcctl_ChangeServiceConfigW(hService
, dwServiceType
,
1961 dwStartType
, dwErrorControl
, lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
,
1962 (const BYTE
*)lpDependencies
, multisz_cb(lpDependencies
), lpServiceStartName
,
1963 (const BYTE
*)lpPassword
, cb_pwd
, lpDisplayName
);
1965 __EXCEPT(rpc_filter
)
1967 err
= map_exception_code(GetExceptionCode());
1971 if (err
!= ERROR_SUCCESS
)
1974 return err
== ERROR_SUCCESS
;
1977 /******************************************************************************
1978 * ChangeServiceConfigA [ADVAPI32.@]
1980 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1981 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1982 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
1983 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
1985 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
1986 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
1989 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1990 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1991 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
1992 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
1993 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
1995 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
1996 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
1997 wDependencies
= SERV_dupmulti( lpDependencies
);
1998 wServiceStartName
= SERV_dup( lpServiceStartName
);
1999 wPassword
= SERV_dup( lpPassword
);
2000 wDisplayName
= SERV_dup( lpDisplayName
);
2002 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2003 dwStartType
, dwErrorControl
, wBinaryPathName
,
2004 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2005 wServiceStartName
, wPassword
, wDisplayName
);
2007 HeapFree( GetProcessHeap(), 0, wBinaryPathName
);
2008 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup
);
2009 HeapFree( GetProcessHeap(), 0, wDependencies
);
2010 HeapFree( GetProcessHeap(), 0, wServiceStartName
);
2011 HeapFree( GetProcessHeap(), 0, wPassword
);
2012 HeapFree( GetProcessHeap(), 0, wDisplayName
);
2017 /******************************************************************************
2018 * ChangeServiceConfig2A [ADVAPI32.@]
2020 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2025 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2027 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2029 LPSERVICE_DESCRIPTIONA sd
= lpInfo
;
2030 SERVICE_DESCRIPTIONW sdw
;
2032 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2034 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2036 HeapFree( GetProcessHeap(), 0, sdw
.lpDescription
);
2038 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2040 LPSERVICE_FAILURE_ACTIONSA fa
= lpInfo
;
2041 SERVICE_FAILURE_ACTIONSW faw
;
2043 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2044 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2045 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2046 faw
.cActions
= fa
->cActions
;
2047 faw
.lpsaActions
= fa
->lpsaActions
;
2049 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2051 HeapFree( GetProcessHeap(), 0, faw
.lpRebootMsg
);
2052 HeapFree( GetProcessHeap(), 0, faw
.lpCommand
);
2055 SetLastError( ERROR_INVALID_PARAMETER
);
2060 /******************************************************************************
2061 * ChangeServiceConfig2W [ADVAPI32.@]
2063 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2070 err
= svcctl_ChangeServiceConfig2W( hService
, dwInfoLevel
, lpInfo
);
2072 __EXCEPT(rpc_filter
)
2074 err
= map_exception_code(GetExceptionCode());
2078 if (err
!= ERROR_SUCCESS
)
2081 return err
== ERROR_SUCCESS
;
2084 /******************************************************************************
2085 * QueryServiceObjectSecurity [ADVAPI32.@]
2087 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2088 SECURITY_INFORMATION dwSecurityInformation
,
2089 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2090 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2092 SECURITY_DESCRIPTOR descriptor
;
2097 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2098 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2100 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2101 FIXME("information %d not supported\n", dwSecurityInformation
);
2103 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2105 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2106 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2109 succ
= MakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2110 *pcbBytesNeeded
= size
;
2114 /******************************************************************************
2115 * SetServiceObjectSecurity [ADVAPI32.@]
2117 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2118 SECURITY_INFORMATION dwSecurityInformation
,
2119 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2121 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2125 /******************************************************************************
2126 * SetServiceBits [ADVAPI32.@]
2128 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2129 DWORD dwServiceBits
,
2131 BOOL bUpdateImmediately
)
2133 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2134 bSetBitsOn
, bUpdateImmediately
);
2138 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2139 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
2141 LPHANDLER_FUNCTION func
= context
;
2144 return ERROR_SUCCESS
;
2147 /******************************************************************************
2148 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2150 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
2152 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
2155 /******************************************************************************
2156 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2158 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
2160 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
2163 /******************************************************************************
2164 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2166 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
2169 SERVICE_STATUS_HANDLE ret
;
2171 nameW
= SERV_dup(name
);
2172 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
2173 HeapFree( GetProcessHeap(), 0, nameW
);
2177 /******************************************************************************
2178 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2180 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2181 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2183 service_data
*service
;
2184 SC_HANDLE hService
= 0;
2187 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2189 EnterCriticalSection( &service_cs
);
2190 if ((service
= find_service_by_name( lpServiceName
)))
2192 service
->handler
= lpHandlerProc
;
2193 service
->context
= lpContext
;
2194 hService
= service
->handle
;
2197 LeaveCriticalSection( &service_cs
);
2199 if (!found
) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2201 return (SERVICE_STATUS_HANDLE
)hService
;
2204 /******************************************************************************
2205 * EnumDependentServicesA [ADVAPI32.@]
2207 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2208 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2209 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2211 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2212 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2214 *lpServicesReturned
= 0;
2218 /******************************************************************************
2219 * EnumDependentServicesW [ADVAPI32.@]
2221 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2222 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2223 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2225 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2226 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2228 *lpServicesReturned
= 0;