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"
31 #define NONAMELESSUNION
34 #define WIN32_NO_STATUS
40 #include "wine/unicode.h"
41 #include "wine/debug.h"
48 #include "advapi32_misc.h"
50 #include "wine/exception.h"
52 WINE_DEFAULT_DEBUG_CHANNEL(service
);
54 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(SIZE_T len
)
56 return heap_alloc(len
);
59 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
64 typedef struct service_data_t
66 LPHANDLER_FUNCTION_EX handler
;
70 SC_HANDLE full_access_handle
;
73 LPSERVICE_MAIN_FUNCTIONA a
;
74 LPSERVICE_MAIN_FUNCTIONW w
;
80 typedef struct dispatcher_data_t
86 static CRITICAL_SECTION service_cs
;
87 static CRITICAL_SECTION_DEBUG service_cs_debug
=
90 { &service_cs_debug
.ProcessLocksList
,
91 &service_cs_debug
.ProcessLocksList
},
92 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
94 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
96 static service_data
**services
;
97 static unsigned int nb_services
;
98 static HANDLE service_event
;
99 static BOOL stop_service
;
101 extern HANDLE CDECL
__wine_make_process_system(void);
103 /******************************************************************************
104 * String management functions (same behaviour as strdup)
105 * NOTE: the caller of those functions is responsible for calling HeapFree
106 * in order to release the memory allocated by those functions.
108 LPWSTR
SERV_dup( LPCSTR str
)
115 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
116 wstr
= heap_alloc( len
*sizeof (WCHAR
) );
117 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
121 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
129 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
130 n
+= (strlen( &str
[n
] ) + 1);
135 wstr
= heap_alloc( len
*sizeof (WCHAR
) );
136 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
140 static inline DWORD
multisz_cb(LPCWSTR wmultisz
)
142 const WCHAR
*wptr
= wmultisz
;
144 if (wmultisz
== NULL
)
148 wptr
+= lstrlenW(wptr
)+1;
149 return (wptr
- wmultisz
+ 1)*sizeof(WCHAR
);
152 /******************************************************************************
153 * RPC connection with services.exe
155 static handle_t
rpc_wstr_bind(RPC_WSTR str
)
157 WCHAR transport
[] = SVCCTL_TRANSPORT
;
158 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
159 RPC_WSTR binding_str
;
163 status
= RpcStringBindingComposeW(NULL
, transport
, str
, endpoint
, NULL
, &binding_str
);
164 if (status
!= RPC_S_OK
)
166 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
170 status
= RpcBindingFromStringBindingW(binding_str
, &rpc_handle
);
171 RpcStringFreeW(&binding_str
);
173 if (status
!= RPC_S_OK
)
175 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
182 static handle_t
rpc_cstr_bind(RPC_CSTR str
)
184 RPC_CSTR transport
= (RPC_CSTR
)SVCCTL_TRANSPORTA
;
185 RPC_CSTR endpoint
= (RPC_CSTR
)SVCCTL_ENDPOINTA
;
186 RPC_CSTR binding_str
;
190 status
= RpcStringBindingComposeA(NULL
, transport
, str
, endpoint
, NULL
, &binding_str
);
191 if (status
!= RPC_S_OK
)
193 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
197 status
= RpcBindingFromStringBindingA(binding_str
, &rpc_handle
);
198 RpcStringFreeA(&binding_str
);
200 if (status
!= RPC_S_OK
)
202 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
209 DECLSPEC_HIDDEN handle_t __RPC_USER
MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName
)
211 return rpc_cstr_bind((RPC_CSTR
)MachineName
);
214 DECLSPEC_HIDDEN
void __RPC_USER
MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName
, handle_t h
)
219 DECLSPEC_HIDDEN handle_t __RPC_USER
MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName
)
221 return rpc_wstr_bind((RPC_WSTR
)MachineName
);
224 DECLSPEC_HIDDEN
void __RPC_USER
MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName
, handle_t h
)
229 DECLSPEC_HIDDEN handle_t __RPC_USER
SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName
)
231 return rpc_wstr_bind((RPC_WSTR
)MachineName
);
234 DECLSPEC_HIDDEN
void __RPC_USER
SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName
, handle_t h
)
239 static LONG WINAPI
rpc_filter(EXCEPTION_POINTERS
*eptr
)
241 return I_RpcExceptionFilter(eptr
->ExceptionRecord
->ExceptionCode
);
244 static DWORD
map_exception_code(DWORD exception_code
)
246 switch (exception_code
)
248 case RPC_X_NULL_REF_POINTER
:
249 return ERROR_INVALID_ADDRESS
;
250 case RPC_X_ENUM_VALUE_OUT_OF_RANGE
:
251 case RPC_X_BYTE_COUNT_TOO_SMALL
:
252 return ERROR_INVALID_PARAMETER
;
253 case RPC_S_INVALID_BINDING
:
254 case RPC_X_SS_IN_NULL_CONTEXT
:
255 return ERROR_INVALID_HANDLE
;
257 return exception_code
;
261 /******************************************************************************
262 * Service IPC functions
264 static LPWSTR
service_get_pipe_name(void)
266 static const WCHAR format
[] = { '\\','\\','.','\\','p','i','p','e','\\',
267 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
268 static const WCHAR service_current_key_str
[] = { 'S','Y','S','T','E','M','\\',
269 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
270 'C','o','n','t','r','o','l','\\',
271 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
274 HKEY service_current_key
;
275 DWORD service_current
;
279 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, service_current_key_str
, 0,
280 KEY_QUERY_VALUE
, &service_current_key
);
281 if (ret
!= ERROR_SUCCESS
)
283 len
= sizeof(service_current
);
284 ret
= RegQueryValueExW(service_current_key
, NULL
, NULL
, &type
,
285 (BYTE
*)&service_current
, &len
);
286 RegCloseKey(service_current_key
);
287 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
289 len
= sizeof(format
)/sizeof(WCHAR
) + 10 /* strlenW("4294967295") */;
290 name
= heap_alloc(len
* sizeof(WCHAR
));
293 snprintfW(name
, len
, format
, service_current
);
297 static HANDLE
service_open_pipe(void)
299 LPWSTR szPipe
= service_get_pipe_name();
300 HANDLE handle
= INVALID_HANDLE_VALUE
;
303 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
304 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
305 if (handle
!= INVALID_HANDLE_VALUE
)
307 if (GetLastError() != ERROR_PIPE_BUSY
)
309 } while (WaitNamedPipeW(szPipe
, NMPWAIT_USE_DEFAULT_WAIT
));
315 static service_data
*find_service_by_name( const WCHAR
*name
)
319 if (nb_services
== 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
321 for (i
= 0; i
< nb_services
; i
++)
322 if (!strcmpiW( name
, services
[i
]->name
)) return services
[i
];
326 /******************************************************************************
329 * Call into the main service routine provided by StartServiceCtrlDispatcher.
331 static DWORD WINAPI
service_thread(LPVOID arg
)
333 service_data
*info
= arg
;
334 LPWSTR str
= info
->args
;
335 DWORD argc
= 0, len
= 0;
341 len
+= strlenW(&str
[len
]) + 1;
350 argv
= heap_alloc((argc
+1)*sizeof(LPWSTR
));
351 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
355 info
->proc
.w(argc
, argv
);
360 LPSTR strA
, *argv
, p
;
363 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
364 strA
= heap_alloc(lenA
);
365 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
367 argv
= heap_alloc((argc
+1)*sizeof(LPSTR
));
368 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
372 info
->proc
.a(argc
, argv
);
379 /******************************************************************************
380 * service_handle_start
382 static DWORD
service_handle_start(service_data
*service
, const void *data
, DWORD data_size
)
384 DWORD count
= data_size
/ sizeof(WCHAR
);
388 WARN("service is not stopped\n");
389 return ERROR_SERVICE_ALREADY_RUNNING
;
392 heap_free(service
->args
);
393 service
->args
= heap_alloc((count
+ 2) * sizeof(WCHAR
));
394 if (count
) memcpy( service
->args
, data
, count
* sizeof(WCHAR
) );
395 service
->args
[count
++] = 0;
396 service
->args
[count
++] = 0;
398 service
->thread
= CreateThread( NULL
, 0, service_thread
,
400 SetEvent( service_event
); /* notify the main loop */
404 /******************************************************************************
405 * service_handle_control
407 static DWORD
service_handle_control(service_data
*service
, DWORD control
, const void *data
, DWORD data_size
)
409 DWORD ret
= ERROR_INVALID_SERVICE_CONTROL
;
411 TRACE("%s control %u data %p data_size %u\n", debugstr_w(service
->name
), control
, data
, data_size
);
413 if (control
== SERVICE_CONTROL_START
)
414 ret
= service_handle_start(service
, data
, data_size
);
415 else if (service
->handler
)
416 ret
= service
->handler(control
, 0, (void *)data
, service
->context
);
420 /******************************************************************************
421 * service_control_dispatcher
423 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
425 dispatcher_data
*disp
= arg
;
427 /* dispatcher loop */
430 service_data
*service
;
431 service_start_info info
;
435 DWORD data_size
= 0, count
, result
;
437 r
= ReadFile( disp
->pipe
, &info
, FIELD_OFFSET(service_start_info
,data
), &count
, NULL
);
440 if (GetLastError() != ERROR_BROKEN_PIPE
)
441 ERR( "pipe read failed error %u\n", GetLastError() );
444 if (count
!= FIELD_OFFSET(service_start_info
,data
))
446 ERR( "partial pipe read %u\n", count
);
449 if (count
< info
.total_size
)
451 data_size
= info
.total_size
- FIELD_OFFSET(service_start_info
,data
);
452 data
= heap_alloc( data_size
);
453 r
= ReadFile( disp
->pipe
, data
, data_size
, &count
, NULL
);
456 if (GetLastError() != ERROR_BROKEN_PIPE
)
457 ERR( "pipe read failed error %u\n", GetLastError() );
461 if (count
!= data_size
)
463 ERR( "partial pipe read %u/%u\n", count
, data_size
);
469 EnterCriticalSection( &service_cs
);
471 /* validate service name */
472 name
= (WCHAR
*)data
;
473 if (!info
.name_size
|| data_size
< info
.name_size
* sizeof(WCHAR
) || name
[info
.name_size
- 1])
475 ERR( "got request without valid service name\n" );
476 result
= ERROR_INVALID_PARAMETER
;
480 if (info
.magic
!= SERVICE_PROTOCOL_MAGIC
)
482 ERR( "received invalid request for service %s\n", debugstr_w(name
) );
483 result
= ERROR_INVALID_PARAMETER
;
487 /* find the service */
488 if (!(service
= find_service_by_name( name
)))
490 FIXME( "got request for unknown service %s\n", debugstr_w(name
) );
491 result
= ERROR_INVALID_PARAMETER
;
495 if (!service
->handle
)
497 if (!(service
->handle
= OpenServiceW( disp
->manager
, name
, SERVICE_SET_STATUS
)) ||
498 !(service
->full_access_handle
= OpenServiceW( disp
->manager
, name
,
499 GENERIC_READ
|GENERIC_WRITE
)))
500 FIXME( "failed to open service %s\n", debugstr_w(name
) );
503 data_size
-= info
.name_size
* sizeof(WCHAR
);
504 result
= service_handle_control(service
, info
.control
, data_size
?
505 &data
[info
.name_size
* sizeof(WCHAR
)] : NULL
, data_size
);
508 LeaveCriticalSection( &service_cs
);
509 WriteFile( disp
->pipe
, &result
, sizeof(result
), &count
, NULL
);
513 CloseHandle( disp
->pipe
);
514 CloseServiceHandle( disp
->manager
);
519 /******************************************************************************
520 * service_run_main_thread
522 static BOOL
service_run_main_thread(void)
525 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
526 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
527 dispatcher_data
*disp
= heap_alloc( sizeof(*disp
) );
529 disp
->manager
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
532 ERR("failed to open service manager error %u\n", GetLastError());
537 disp
->pipe
= service_open_pipe();
538 if (disp
->pipe
== INVALID_HANDLE_VALUE
)
540 WARN("failed to create control pipe error %u\n", GetLastError());
541 CloseServiceHandle( disp
->manager
);
543 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
);
547 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
548 stop_service
= FALSE
;
550 /* FIXME: service_control_dispatcher should be merged into the main thread */
551 wait_handles
[0] = __wine_make_process_system();
552 wait_handles
[1] = CreateThread( NULL
, 0, service_control_dispatcher
, disp
, 0, NULL
);
553 wait_handles
[2] = service_event
;
555 TRACE("Starting %d services running as process %d\n",
556 nb_services
, GetCurrentProcessId());
558 /* wait for all the threads to pack up and exit */
559 while (!stop_service
)
561 EnterCriticalSection( &service_cs
);
562 for (i
= 0, n
= 3; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
564 if (!services
[i
]->thread
) continue;
565 wait_services
[n
] = i
;
566 wait_handles
[n
++] = services
[i
]->thread
;
568 LeaveCriticalSection( &service_cs
);
570 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
571 if (!ret
) /* system process event */
574 SERVICE_PRESHUTDOWN_INFO spi
;
575 DWORD timeout
= 5000;
578 EnterCriticalSection( &service_cs
);
580 for (i
= 0; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
582 if (!services
[i
]->thread
) continue;
584 res
= QueryServiceStatus(services
[i
]->full_access_handle
, &st
);
586 if (res
&& (st
.dwControlsAccepted
& SERVICE_ACCEPT_PRESHUTDOWN
))
588 res
= QueryServiceConfig2W( services
[i
]->full_access_handle
, SERVICE_CONFIG_PRESHUTDOWN_INFO
,
589 (LPBYTE
)&spi
, sizeof(spi
), &i
);
592 FIXME("service should be able to delay shutdown\n");
593 timeout
+= spi
.dwPreshutdownTimeout
;
594 ret
= service_handle_control( services
[i
], SERVICE_CONTROL_PRESHUTDOWN
, NULL
, 0 );
595 wait_handles
[n
++] = services
[i
]->thread
;
598 else if (res
&& (st
.dwControlsAccepted
& SERVICE_ACCEPT_SHUTDOWN
))
600 ret
= service_handle_control( services
[i
], SERVICE_CONTROL_SHUTDOWN
, NULL
, 0 );
601 wait_handles
[n
++] = services
[i
]->thread
;
604 LeaveCriticalSection( &service_cs
);
606 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout
);
607 WaitForMultipleObjects( n
, wait_handles
, TRUE
, timeout
);
612 TRACE( "control dispatcher exited, shutting down\n" );
613 /* FIXME: we should maybe send a shutdown control to running services */
618 continue; /* rebuild the list */
622 i
= wait_services
[ret
];
623 EnterCriticalSection( &service_cs
);
624 CloseHandle( services
[i
]->thread
);
625 services
[i
]->thread
= NULL
;
626 LeaveCriticalSection( &service_cs
);
634 /******************************************************************************
635 * StartServiceCtrlDispatcherA [ADVAPI32.@]
637 * See StartServiceCtrlDispatcherW.
639 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
644 TRACE("%p\n", servent
);
648 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
651 while (servent
[nb_services
].lpServiceName
) nb_services
++;
654 SetLastError( ERROR_INVALID_PARAMETER
);
658 services
= heap_alloc( nb_services
* sizeof(*services
) );
660 for (i
= 0; i
< nb_services
; i
++)
662 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
663 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
664 info
= heap_alloc_zero( sz
);
665 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
666 info
->proc
.a
= servent
[i
].lpServiceProc
;
667 info
->unicode
= FALSE
;
671 return service_run_main_thread();
674 /******************************************************************************
675 * StartServiceCtrlDispatcherW [ADVAPI32.@]
677 * Connects a process containing one or more services to the service control
681 * servent [I] A list of the service names and service procedures
687 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
692 TRACE("%p\n", servent
);
696 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
699 while (servent
[nb_services
].lpServiceName
) nb_services
++;
702 SetLastError( ERROR_INVALID_PARAMETER
);
706 services
= heap_alloc( nb_services
* sizeof(*services
) );
708 for (i
= 0; i
< nb_services
; i
++)
710 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
711 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
712 info
= heap_alloc_zero( sz
);
713 strcpyW(info
->name
, servent
[i
].lpServiceName
);
714 info
->proc
.w
= servent
[i
].lpServiceProc
;
715 info
->unicode
= TRUE
;
719 return service_run_main_thread();
722 /******************************************************************************
723 * LockServiceDatabase [ADVAPI32.@]
725 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
727 SC_RPC_LOCK hLock
= NULL
;
730 TRACE("%p\n",hSCManager
);
734 err
= svcctl_LockServiceDatabase(hSCManager
, &hLock
);
738 err
= map_exception_code(GetExceptionCode());
741 if (err
!= ERROR_SUCCESS
)
749 /******************************************************************************
750 * UnlockServiceDatabase [ADVAPI32.@]
752 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
755 SC_RPC_LOCK hRpcLock
= ScLock
;
757 TRACE("%p\n",ScLock
);
761 err
= svcctl_UnlockServiceDatabase(&hRpcLock
);
765 err
= map_exception_code(GetExceptionCode());
768 if (err
!= ERROR_SUCCESS
)
776 /******************************************************************************
777 * SetServiceStatus [ADVAPI32.@]
784 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
788 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
789 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
790 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
791 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
792 lpStatus
->dwWaitHint
);
796 err
= svcctl_SetServiceStatus( hService
, lpStatus
);
800 err
= map_exception_code(GetExceptionCode());
803 if (err
!= ERROR_SUCCESS
)
809 if (lpStatus
->dwCurrentState
== SERVICE_STOPPED
)
811 unsigned int i
, count
= 0;
812 EnterCriticalSection( &service_cs
);
813 for (i
= 0; i
< nb_services
; i
++)
815 if (services
[i
]->handle
== (SC_HANDLE
)hService
) continue;
816 if (services
[i
]->thread
) count
++;
821 SetEvent( service_event
); /* notify the main loop */
823 LeaveCriticalSection( &service_cs
);
830 /******************************************************************************
831 * OpenSCManagerA [ADVAPI32.@]
833 * Establish a connection to the service control manager and open its database.
836 * lpMachineName [I] Pointer to machine name string
837 * lpDatabaseName [I] Pointer to database name string
838 * dwDesiredAccess [I] Type of access
841 * Success: A Handle to the service control manager database
844 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
845 DWORD dwDesiredAccess
)
847 LPWSTR machineW
, databaseW
;
850 machineW
= SERV_dup(lpMachineName
);
851 databaseW
= SERV_dup(lpDatabaseName
);
852 ret
= OpenSCManagerW(machineW
, databaseW
, dwDesiredAccess
);
853 heap_free(databaseW
);
858 /******************************************************************************
859 * OpenSCManagerW [ADVAPI32.@]
861 * See OpenSCManagerA.
863 DWORD
SERV_OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
864 DWORD dwDesiredAccess
, SC_HANDLE
*handle
)
868 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
869 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
873 r
= svcctl_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)handle
);
877 r
= map_exception_code(GetExceptionCode());
881 if (r
!=ERROR_SUCCESS
)
884 TRACE("returning %p\n", *handle
);
888 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
889 DWORD dwDesiredAccess
)
891 SC_HANDLE handle
= 0;
894 r
= SERV_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, &handle
);
895 if (r
!=ERROR_SUCCESS
)
900 /******************************************************************************
901 * ControlService [ADVAPI32.@]
903 * Send a control code to a service.
906 * hService [I] Handle of the service control manager database
907 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
908 * lpServiceStatus [O] Destination for the status of the service, if available
915 * Unlike M$' implementation, control requests are not serialized and may be
916 * processed asynchronously.
918 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
919 LPSERVICE_STATUS lpServiceStatus
)
923 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
927 err
= svcctl_ControlService(hService
, dwControl
, lpServiceStatus
);
931 err
= map_exception_code(GetExceptionCode());
934 if (err
!= ERROR_SUCCESS
)
943 /******************************************************************************
944 * CloseServiceHandle [ADVAPI32.@]
946 * Close a handle to a service or the service control manager database.
949 * hSCObject [I] Handle to service or service control manager database
956 CloseServiceHandle( SC_HANDLE hSCObject
)
960 TRACE("%p\n", hSCObject
);
964 err
= svcctl_CloseServiceHandle((SC_RPC_HANDLE
*)&hSCObject
);
968 err
= map_exception_code(GetExceptionCode());
972 if (err
!= ERROR_SUCCESS
)
981 /******************************************************************************
982 * OpenServiceA [ADVAPI32.@]
984 * Open a handle to a service.
987 * hSCManager [I] Handle of the service control manager database
988 * lpServiceName [I] Name of the service to open
989 * dwDesiredAccess [I] Access required to the service
992 * Success: Handle to the service
995 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
996 DWORD dwDesiredAccess
)
998 LPWSTR lpServiceNameW
;
1001 TRACE("%p %s 0x%08x\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1003 lpServiceNameW
= SERV_dup(lpServiceName
);
1004 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1005 heap_free(lpServiceNameW
);
1010 /******************************************************************************
1011 * OpenServiceW [ADVAPI32.@]
1015 DWORD
SERV_OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1016 DWORD dwDesiredAccess
, SC_HANDLE
*handle
)
1020 TRACE("%p %s 0x%08x\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1023 return ERROR_INVALID_HANDLE
;
1027 err
= svcctl_OpenServiceW(hSCManager
, lpServiceName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)handle
);
1029 __EXCEPT(rpc_filter
)
1031 err
= map_exception_code(GetExceptionCode());
1035 if (err
!= ERROR_SUCCESS
)
1038 TRACE("returning %p\n", *handle
);
1042 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1043 DWORD dwDesiredAccess
)
1045 SC_HANDLE handle
= 0;
1048 err
= SERV_OpenServiceW(hSCManager
, lpServiceName
, dwDesiredAccess
, &handle
);
1049 if (err
!= ERROR_SUCCESS
)
1054 /******************************************************************************
1055 * CreateServiceW [ADVAPI32.@]
1058 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1059 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1060 DWORD dwServiceType
, DWORD dwStartType
,
1061 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1062 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1063 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1064 LPCWSTR lpPassword
)
1066 SC_HANDLE handle
= 0;
1070 TRACE("%p %s %s\n", hSCManager
,
1071 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1075 SetLastError( ERROR_INVALID_HANDLE
);
1080 passwdlen
= (strlenW(lpPassword
) + 1) * sizeof(WCHAR
);
1088 IsWow64Process(GetCurrentProcess(), &is_wow64
);
1091 err
= svcctl_CreateServiceWOW64W(hSCManager
, lpServiceName
,
1092 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1093 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (const BYTE
*)lpDependencies
,
1094 multisz_cb(lpDependencies
), lpServiceStartName
, (const BYTE
*)lpPassword
, passwdlen
,
1095 (SC_RPC_HANDLE
*)&handle
);
1097 err
= svcctl_CreateServiceW(hSCManager
, lpServiceName
,
1098 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1099 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (const BYTE
*)lpDependencies
,
1100 multisz_cb(lpDependencies
), lpServiceStartName
, (const BYTE
*)lpPassword
, passwdlen
,
1101 (SC_RPC_HANDLE
*)&handle
);
1103 __EXCEPT(rpc_filter
)
1105 err
= map_exception_code(GetExceptionCode());
1109 if (err
!= ERROR_SUCCESS
)
1118 /******************************************************************************
1119 * CreateServiceA [ADVAPI32.@]
1122 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1123 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1124 DWORD dwServiceType
, DWORD dwStartType
,
1125 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1126 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1127 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1130 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1131 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1134 TRACE("%p %s %s\n", hSCManager
,
1135 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1137 lpServiceNameW
= SERV_dup( lpServiceName
);
1138 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1139 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1140 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1141 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1142 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1143 lpPasswordW
= SERV_dup( lpPassword
);
1145 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1146 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1147 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1148 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1150 heap_free( lpServiceNameW
);
1151 heap_free( lpDisplayNameW
);
1152 heap_free( lpBinaryPathNameW
);
1153 heap_free( lpLoadOrderGroupW
);
1154 heap_free( lpDependenciesW
);
1155 heap_free( lpServiceStartNameW
);
1156 heap_free( lpPasswordW
);
1162 /******************************************************************************
1163 * DeleteService [ADVAPI32.@]
1165 * Delete a service from the service control manager database.
1168 * hService [I] Handle of the service to delete
1174 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1178 TRACE("%p\n", hService
);
1182 err
= svcctl_DeleteService(hService
);
1184 __EXCEPT(rpc_filter
)
1186 err
= map_exception_code(GetExceptionCode());
1199 /******************************************************************************
1200 * StartServiceA [ADVAPI32.@]
1205 * hService [I] Handle of service
1206 * dwNumServiceArgs [I] Number of arguments
1207 * lpServiceArgVectors [I] Address of array of argument strings
1210 * - NT implements this function using an obscure RPC call.
1211 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1212 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1213 * - This will only work for shared address space. How should the service
1214 * args be transferred when address spaces are separated?
1215 * - Can only start one service at a time.
1216 * - Has no concept of privilege.
1222 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1223 LPCSTR
*lpServiceArgVectors
)
1225 LPWSTR
*lpwstr
=NULL
;
1229 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1231 if (dwNumServiceArgs
)
1232 lpwstr
= heap_alloc( dwNumServiceArgs
*sizeof(LPWSTR
) );
1234 for(i
=0; i
<dwNumServiceArgs
; i
++)
1235 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1237 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1239 if (dwNumServiceArgs
)
1241 for(i
=0; i
<dwNumServiceArgs
; i
++)
1242 heap_free(lpwstr
[i
]);
1250 /******************************************************************************
1251 * StartServiceW [ADVAPI32.@]
1253 * See StartServiceA.
1255 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1256 LPCWSTR
*lpServiceArgVectors
)
1260 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1264 err
= svcctl_StartServiceW(hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1266 __EXCEPT(rpc_filter
)
1268 err
= map_exception_code(GetExceptionCode());
1271 if (err
!= ERROR_SUCCESS
)
1280 /******************************************************************************
1281 * QueryServiceStatus [ADVAPI32.@]
1284 * hService [I] Handle to service to get information about
1285 * lpservicestatus [O] buffer to receive the status information for the service
1288 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1289 LPSERVICE_STATUS lpservicestatus
)
1291 SERVICE_STATUS_PROCESS SvcStatusData
;
1295 TRACE("%p %p\n", hService
, lpservicestatus
);
1299 SetLastError(ERROR_INVALID_HANDLE
);
1302 if (!lpservicestatus
)
1304 SetLastError(ERROR_INVALID_ADDRESS
);
1308 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1309 sizeof(SERVICE_STATUS_PROCESS
), &dummy
);
1310 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1315 /******************************************************************************
1316 * QueryServiceStatusEx [ADVAPI32.@]
1318 * Get information about a service.
1321 * hService [I] Handle to service to get information about
1322 * InfoLevel [I] Level of information to get
1323 * lpBuffer [O] Destination for requested information
1324 * cbBufSize [I] Size of lpBuffer in bytes
1325 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1331 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1332 LPBYTE lpBuffer
, DWORD cbBufSize
,
1333 LPDWORD pcbBytesNeeded
)
1337 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1339 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1341 err
= ERROR_INVALID_LEVEL
;
1343 else if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1345 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1346 err
= ERROR_INSUFFICIENT_BUFFER
;
1352 err
= svcctl_QueryServiceStatusEx(hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1354 __EXCEPT(rpc_filter
)
1356 err
= map_exception_code(GetExceptionCode());
1360 if (err
!= ERROR_SUCCESS
)
1368 /******************************************************************************
1369 * QueryServiceConfigA [ADVAPI32.@]
1371 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1372 DWORD size
, LPDWORD needed
)
1377 QUERY_SERVICE_CONFIGW
*configW
;
1379 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1381 if (!(buffer
= heap_alloc( 2 * size
)))
1383 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1386 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1387 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1388 if (!ret
) goto done
;
1390 config
->dwServiceType
= configW
->dwServiceType
;
1391 config
->dwStartType
= configW
->dwStartType
;
1392 config
->dwErrorControl
= configW
->dwErrorControl
;
1393 config
->lpBinaryPathName
= NULL
;
1394 config
->lpLoadOrderGroup
= NULL
;
1395 config
->dwTagId
= configW
->dwTagId
;
1396 config
->lpDependencies
= NULL
;
1397 config
->lpServiceStartName
= NULL
;
1398 config
->lpDisplayName
= NULL
;
1400 p
= (LPSTR
)(config
+ 1);
1401 n
= size
- sizeof(*config
);
1404 #define MAP_STR(str) \
1408 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1409 if (!sz) goto done; \
1416 MAP_STR( lpBinaryPathName
);
1417 MAP_STR( lpLoadOrderGroup
);
1418 MAP_STR( lpDependencies
);
1419 MAP_STR( lpServiceStartName
);
1420 MAP_STR( lpDisplayName
);
1423 *needed
= p
- (LPSTR
)config
;
1427 heap_free( buffer
);
1431 static DWORD
move_string_to_buffer(BYTE
**buf
, LPWSTR
*string_ptr
)
1438 memset(*buf
, 0, cb
);
1442 cb
= (strlenW(*string_ptr
) + 1)*sizeof(WCHAR
);
1443 memcpy(*buf
, *string_ptr
, cb
);
1444 MIDL_user_free(*string_ptr
);
1447 *string_ptr
= (LPWSTR
)*buf
;
1453 static DWORD
size_string(LPCWSTR string
)
1455 return (string
? (strlenW(string
) + 1)*sizeof(WCHAR
) : sizeof(WCHAR
));
1458 /******************************************************************************
1459 * QueryServiceConfigW [ADVAPI32.@]
1462 QueryServiceConfigW( SC_HANDLE hService
,
1463 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1464 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1466 QUERY_SERVICE_CONFIGW config
;
1471 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1472 cbBufSize
, pcbBytesNeeded
);
1474 memset(&config
, 0, sizeof(config
));
1478 err
= svcctl_QueryServiceConfigW(hService
, &config
, cbBufSize
, pcbBytesNeeded
);
1480 __EXCEPT(rpc_filter
)
1482 err
= map_exception_code(GetExceptionCode());
1486 if (err
!= ERROR_SUCCESS
)
1488 TRACE("services.exe: error %u\n", err
);
1493 /* calculate the size required first */
1494 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1495 total
+= size_string(config
.lpBinaryPathName
);
1496 total
+= size_string(config
.lpLoadOrderGroup
);
1497 total
+= size_string(config
.lpDependencies
);
1498 total
+= size_string(config
.lpServiceStartName
);
1499 total
+= size_string(config
.lpDisplayName
);
1501 *pcbBytesNeeded
= total
;
1503 /* if there's not enough memory, return an error */
1504 if( total
> cbBufSize
)
1506 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1507 MIDL_user_free(config
.lpBinaryPathName
);
1508 MIDL_user_free(config
.lpLoadOrderGroup
);
1509 MIDL_user_free(config
.lpDependencies
);
1510 MIDL_user_free(config
.lpServiceStartName
);
1511 MIDL_user_free(config
.lpDisplayName
);
1515 *lpServiceConfig
= config
;
1516 bufpos
= ((BYTE
*)lpServiceConfig
) + sizeof(QUERY_SERVICE_CONFIGW
);
1517 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpBinaryPathName
);
1518 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpLoadOrderGroup
);
1519 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDependencies
);
1520 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpServiceStartName
);
1521 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDisplayName
);
1523 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1524 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1525 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
1526 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
1527 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
1532 /******************************************************************************
1533 * QueryServiceConfig2A [ADVAPI32.@]
1536 * observed under win2k:
1537 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1538 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1540 BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1541 DWORD size
, LPDWORD needed
)
1544 LPBYTE bufferW
= NULL
;
1546 TRACE("%p %u %p %u %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1549 bufferW
= heap_alloc(size
);
1551 ret
= QueryServiceConfig2W(hService
, dwLevel
, bufferW
, size
, needed
);
1552 if(!ret
) goto cleanup
;
1555 case SERVICE_CONFIG_DESCRIPTION
:
1556 if (buffer
&& bufferW
) {
1557 LPSERVICE_DESCRIPTIONA configA
= (LPSERVICE_DESCRIPTIONA
) buffer
;
1558 LPSERVICE_DESCRIPTIONW configW
= (LPSERVICE_DESCRIPTIONW
) bufferW
;
1559 if (configW
->lpDescription
&& (size
> sizeof(SERVICE_DESCRIPTIONA
))) {
1561 configA
->lpDescription
= (LPSTR
)(configA
+ 1);
1562 sz
= WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1,
1563 configA
->lpDescription
, size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
1565 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1567 configA
->lpDescription
= NULL
;
1570 else configA
->lpDescription
= NULL
;
1573 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
1574 if (buffer
&& bufferW
&& *needed
<=size
)
1575 memcpy(buffer
, bufferW
, *needed
);
1578 FIXME("conversation W->A not implemented for level %d\n", dwLevel
);
1584 heap_free( bufferW
);
1588 /******************************************************************************
1589 * QueryServiceConfig2W [ADVAPI32.@]
1591 * See QueryServiceConfig2A.
1593 BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1594 DWORD size
, LPDWORD needed
)
1599 TRACE("%p %u %p %u %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1601 if (!buffer
&& size
)
1603 SetLastError(ERROR_INVALID_ADDRESS
);
1609 case SERVICE_CONFIG_DESCRIPTION
:
1610 if (!(bufptr
= heap_alloc( size
)))
1612 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1617 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
1622 FIXME("Level %d not implemented\n", dwLevel
);
1623 SetLastError(ERROR_INVALID_LEVEL
);
1629 SetLastError(ERROR_INVALID_ADDRESS
);
1635 err
= svcctl_QueryServiceConfig2W(hService
, dwLevel
, bufptr
, size
, needed
);
1637 __EXCEPT(rpc_filter
)
1639 err
= map_exception_code(GetExceptionCode());
1645 case SERVICE_CONFIG_DESCRIPTION
:
1647 SERVICE_DESCRIPTIONW
*desc
= (SERVICE_DESCRIPTIONW
*)buffer
;
1648 struct service_description
*s
= (struct service_description
*)bufptr
;
1650 if (err
!= ERROR_SUCCESS
&& err
!= ERROR_INSUFFICIENT_BUFFER
)
1652 heap_free( bufptr
);
1653 SetLastError( err
);
1657 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
1658 if (*needed
== sizeof(*s
)) *needed
= sizeof(*desc
);
1660 *needed
= *needed
- FIELD_OFFSET(struct service_description
, description
) + sizeof(*desc
);
1664 heap_free( bufptr
);
1665 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1670 if (!s
->size
) desc
->lpDescription
= NULL
;
1673 desc
->lpDescription
= (WCHAR
*)(desc
+ 1);
1674 memcpy( desc
->lpDescription
, s
->description
, s
->size
);
1677 heap_free( bufptr
);
1680 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
1681 if (err
!= ERROR_SUCCESS
)
1683 SetLastError( err
);
1695 /******************************************************************************
1696 * EnumServicesStatusA [ADVAPI32.@]
1699 EnumServicesStatusA( SC_HANDLE hmngr
, DWORD type
, DWORD state
, LPENUM_SERVICE_STATUSA
1700 services
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1701 LPDWORD resume_handle
)
1705 ENUM_SERVICE_STATUSW
*servicesW
= NULL
;
1709 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr
, type
, state
, services
, size
, needed
,
1710 returned
, resume_handle
);
1714 SetLastError( ERROR_INVALID_HANDLE
);
1717 if (!needed
|| !returned
)
1719 SetLastError( ERROR_INVALID_ADDRESS
);
1723 sz
= max( 2 * size
, sizeof(*servicesW
) );
1724 if (!(servicesW
= heap_alloc( sz
)))
1726 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1730 ret
= EnumServicesStatusW( hmngr
, type
, state
, servicesW
, sz
, needed
, returned
, resume_handle
);
1731 if (!ret
) goto done
;
1733 p
= (char *)services
+ *returned
* sizeof(ENUM_SERVICE_STATUSA
);
1734 n
= size
- (p
- (char *)services
);
1736 for (i
= 0; i
< *returned
; i
++)
1738 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpServiceName
, -1, p
, n
, NULL
, NULL
);
1740 services
[i
].lpServiceName
= p
;
1743 if (servicesW
[i
].lpDisplayName
)
1745 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpDisplayName
, -1, p
, n
, NULL
, NULL
);
1747 services
[i
].lpDisplayName
= p
;
1751 else services
[i
].lpDisplayName
= NULL
;
1752 services
[i
].ServiceStatus
= servicesW
[i
].ServiceStatus
;
1758 heap_free( servicesW
);
1762 /******************************************************************************
1763 * EnumServicesStatusW [ADVAPI32.@]
1766 EnumServicesStatusW( SC_HANDLE hmngr
, DWORD type
, DWORD state
, LPENUM_SERVICE_STATUSW
1767 services
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1768 LPDWORD resume_handle
)
1770 DWORD err
, i
, offset
, buflen
, count
, total_size
= 0;
1771 struct enum_service_status
*entry
;
1775 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr
, type
, state
, services
, size
, needed
,
1776 returned
, resume_handle
);
1780 SetLastError( ERROR_INVALID_HANDLE
);
1783 if (!needed
|| !returned
)
1785 SetLastError( ERROR_INVALID_ADDRESS
);
1789 /* make sure we pass a valid pointer */
1790 buflen
= max( size
, sizeof(*services
) );
1791 if (!(buf
= heap_alloc( buflen
)))
1793 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1799 err
= svcctl_EnumServicesStatusW( hmngr
, type
, state
, buf
, buflen
, needed
, &count
, resume_handle
);
1801 __EXCEPT(rpc_filter
)
1803 err
= map_exception_code( GetExceptionCode() );
1808 if (err
!= ERROR_SUCCESS
)
1810 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUSW */
1811 if (err
== ERROR_MORE_DATA
) *needed
*= 2;
1813 SetLastError( err
);
1817 entry
= (struct enum_service_status
*)buf
;
1818 for (i
= 0; i
< count
; i
++)
1820 total_size
+= sizeof(*services
);
1821 if (entry
->service_name
)
1823 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
1824 total_size
+= (strlenW( str
) + 1) * sizeof(WCHAR
);
1826 if (entry
->display_name
)
1828 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
1829 total_size
+= (strlenW( str
) + 1) * sizeof(WCHAR
);
1834 if (total_size
> size
)
1837 *needed
= total_size
;
1838 SetLastError( ERROR_MORE_DATA
);
1842 offset
= count
* sizeof(*services
);
1843 entry
= (struct enum_service_status
*)buf
;
1844 for (i
= 0; i
< count
; i
++)
1847 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
1848 str_size
= (strlenW( str
) + 1) * sizeof(WCHAR
);
1849 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ offset
);
1850 memcpy( services
[i
].lpServiceName
, str
, str_size
);
1853 if (!entry
->display_name
) services
[i
].lpDisplayName
= NULL
;
1856 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
1857 str_size
= (strlenW( str
) + 1) * sizeof(WCHAR
);
1858 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ offset
);
1859 memcpy( services
[i
].lpDisplayName
, str
, str_size
);
1862 services
[i
].ServiceStatus
= entry
->service_status
;
1872 /******************************************************************************
1873 * EnumServicesStatusExA [ADVAPI32.@]
1876 EnumServicesStatusExA( SC_HANDLE hmngr
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1877 LPBYTE buffer
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1878 LPDWORD resume_handle
, LPCSTR group
)
1882 ENUM_SERVICE_STATUS_PROCESSA
*services
= (ENUM_SERVICE_STATUS_PROCESSA
*)buffer
;
1883 ENUM_SERVICE_STATUS_PROCESSW
*servicesW
= NULL
;
1884 WCHAR
*groupW
= NULL
;
1888 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr
, level
, type
, state
, buffer
,
1889 size
, needed
, returned
, resume_handle
, debugstr_a(group
));
1891 sz
= max( 2 * size
, sizeof(*servicesW
) );
1892 if (!(servicesW
= heap_alloc( sz
)))
1894 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1899 int len
= MultiByteToWideChar( CP_ACP
, 0, group
, -1, NULL
, 0 );
1900 if (!(groupW
= heap_alloc( len
* sizeof(WCHAR
) )))
1902 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1903 heap_free( servicesW
);
1906 MultiByteToWideChar( CP_ACP
, 0, group
, -1, groupW
, len
* sizeof(WCHAR
) );
1909 ret
= EnumServicesStatusExW( hmngr
, level
, type
, state
, (BYTE
*)servicesW
, sz
,
1910 needed
, returned
, resume_handle
, groupW
);
1911 if (!ret
) goto done
;
1913 p
= (char *)services
+ *returned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
);
1914 n
= size
- (p
- (char *)services
);
1916 for (i
= 0; i
< *returned
; i
++)
1918 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpServiceName
, -1, p
, n
, NULL
, NULL
);
1920 services
[i
].lpServiceName
= p
;
1923 if (servicesW
[i
].lpDisplayName
)
1925 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpDisplayName
, -1, p
, n
, NULL
, NULL
);
1927 services
[i
].lpDisplayName
= p
;
1931 else services
[i
].lpDisplayName
= NULL
;
1932 services
[i
].ServiceStatusProcess
= servicesW
[i
].ServiceStatusProcess
;
1938 heap_free( servicesW
);
1939 heap_free( groupW
);
1943 /******************************************************************************
1944 * EnumServicesStatusExW [ADVAPI32.@]
1947 EnumServicesStatusExW( SC_HANDLE hmngr
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1948 LPBYTE buffer
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1949 LPDWORD resume_handle
, LPCWSTR group
)
1951 DWORD err
, i
, offset
, buflen
, count
, total_size
= 0;
1952 ENUM_SERVICE_STATUS_PROCESSW
*services
= (ENUM_SERVICE_STATUS_PROCESSW
*)buffer
;
1953 struct enum_service_status_process
*entry
;
1957 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr
, level
, type
, state
, buffer
,
1958 size
, needed
, returned
, resume_handle
, debugstr_w(group
));
1960 if (level
!= SC_ENUM_PROCESS_INFO
)
1962 SetLastError( ERROR_INVALID_LEVEL
);
1967 SetLastError( ERROR_INVALID_HANDLE
);
1970 if (!needed
|| !returned
)
1972 SetLastError( ERROR_INVALID_ADDRESS
);
1976 /* make sure we pass a valid pointer */
1977 buflen
= max( size
, sizeof(*services
) );
1978 if (!(buf
= heap_alloc( buflen
)))
1980 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1986 err
= svcctl_EnumServicesStatusExW( hmngr
, SC_ENUM_PROCESS_INFO
, type
, state
, buf
, buflen
, needed
,
1987 &count
, resume_handle
, group
);
1989 __EXCEPT(rpc_filter
)
1991 err
= map_exception_code( GetExceptionCode() );
1996 if (err
!= ERROR_SUCCESS
)
1998 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
1999 if (err
== ERROR_MORE_DATA
) *needed
*= 2;
2001 SetLastError( err
);
2005 entry
= (struct enum_service_status_process
*)buf
;
2006 for (i
= 0; i
< count
; i
++)
2008 total_size
+= sizeof(*services
);
2009 if (entry
->service_name
)
2011 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
2012 total_size
+= (strlenW( str
) + 1) * sizeof(WCHAR
);
2014 if (entry
->display_name
)
2016 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
2017 total_size
+= (strlenW( str
) + 1) * sizeof(WCHAR
);
2022 if (total_size
> size
)
2025 *needed
= total_size
;
2026 SetLastError( ERROR_MORE_DATA
);
2030 offset
= count
* sizeof(*services
);
2031 entry
= (struct enum_service_status_process
*)buf
;
2032 for (i
= 0; i
< count
; i
++)
2035 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
2036 str_size
= (strlenW( str
) + 1) * sizeof(WCHAR
);
2037 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ offset
);
2038 memcpy( services
[i
].lpServiceName
, str
, str_size
);
2041 if (!entry
->display_name
) services
[i
].lpDisplayName
= NULL
;
2044 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
2045 str_size
= (strlenW( str
) + 1) * sizeof(WCHAR
);
2046 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ offset
);
2047 memcpy( services
[i
].lpDisplayName
, str
, str_size
);
2050 services
[i
].ServiceStatusProcess
= entry
->service_status_process
;
2060 /******************************************************************************
2061 * GetServiceKeyNameA [ADVAPI32.@]
2063 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2064 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2066 LPWSTR lpDisplayNameW
, lpServiceNameW
;
2070 TRACE("%p %s %p %p\n", hSCManager
,
2071 debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2073 lpDisplayNameW
= SERV_dup(lpDisplayName
);
2075 lpServiceNameW
= heap_alloc(*lpcchBuffer
* sizeof(WCHAR
));
2077 lpServiceNameW
= NULL
;
2079 sizeW
= *lpcchBuffer
;
2080 if (!GetServiceKeyNameW(hSCManager
, lpDisplayNameW
, lpServiceNameW
, &sizeW
))
2082 if (lpServiceName
&& *lpcchBuffer
)
2083 lpServiceName
[0] = 0;
2084 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
2088 if (!WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, (sizeW
+ 1), lpServiceName
,
2089 *lpcchBuffer
, NULL
, NULL
))
2091 if (*lpcchBuffer
&& lpServiceName
)
2092 lpServiceName
[0] = 0;
2093 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, -1, NULL
, 0, NULL
, NULL
);
2097 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
2101 heap_free(lpServiceNameW
);
2102 heap_free(lpDisplayNameW
);
2106 /******************************************************************************
2107 * GetServiceKeyNameW [ADVAPI32.@]
2109 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2110 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2116 TRACE("%p %s %p %p\n", hSCManager
,
2117 debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2121 SetLastError( ERROR_INVALID_HANDLE
);
2125 /* provide a buffer if the caller didn't */
2126 if (!lpServiceName
|| *lpcchBuffer
< 2)
2128 lpServiceName
= buffer
;
2129 /* A size of 1 would be enough, but tests show that Windows returns 2,
2130 * probably because of a WCHAR/bytes mismatch in their code.
2135 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2136 * includes the nul-terminator on input. */
2137 size
= *lpcchBuffer
- 1;
2141 err
= svcctl_GetServiceKeyNameW(hSCManager
, lpDisplayName
, lpServiceName
,
2144 __EXCEPT(rpc_filter
)
2146 err
= map_exception_code(GetExceptionCode());
2150 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2151 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
2152 *lpcchBuffer
= size
;
2156 return err
== ERROR_SUCCESS
;
2159 /******************************************************************************
2160 * QueryServiceLockStatusA [ADVAPI32.@]
2162 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2163 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2164 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2166 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2171 /******************************************************************************
2172 * QueryServiceLockStatusW [ADVAPI32.@]
2174 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2175 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2176 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2178 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2183 /******************************************************************************
2184 * GetServiceDisplayNameA [ADVAPI32.@]
2186 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2187 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2189 LPWSTR lpServiceNameW
, lpDisplayNameW
;
2193 TRACE("%p %s %p %p\n", hSCManager
,
2194 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2196 lpServiceNameW
= SERV_dup(lpServiceName
);
2198 lpDisplayNameW
= heap_alloc(*lpcchBuffer
* sizeof(WCHAR
));
2200 lpDisplayNameW
= NULL
;
2202 sizeW
= *lpcchBuffer
;
2203 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
2205 if (lpDisplayName
&& *lpcchBuffer
)
2206 lpDisplayName
[0] = 0;
2207 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
2211 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
2212 *lpcchBuffer
, NULL
, NULL
))
2214 if (*lpcchBuffer
&& lpDisplayName
)
2215 lpDisplayName
[0] = 0;
2216 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
2220 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2221 * (but if the function succeeded it means that is a good upper estimation of the size) */
2225 heap_free(lpDisplayNameW
);
2226 heap_free(lpServiceNameW
);
2230 /******************************************************************************
2231 * GetServiceDisplayNameW [ADVAPI32.@]
2233 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2234 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2240 TRACE("%p %s %p %p\n", hSCManager
,
2241 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2245 SetLastError( ERROR_INVALID_HANDLE
);
2249 /* provide a buffer if the caller didn't */
2250 if (!lpDisplayName
|| *lpcchBuffer
< 2)
2252 lpDisplayName
= buffer
;
2253 /* A size of 1 would be enough, but tests show that Windows returns 2,
2254 * probably because of a WCHAR/bytes mismatch in their code.
2259 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2260 * includes the nul-terminator on input. */
2261 size
= *lpcchBuffer
- 1;
2265 err
= svcctl_GetServiceDisplayNameW(hSCManager
, lpServiceName
, lpDisplayName
,
2268 __EXCEPT(rpc_filter
)
2270 err
= map_exception_code(GetExceptionCode());
2274 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2275 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
2276 *lpcchBuffer
= size
;
2280 return err
== ERROR_SUCCESS
;
2283 /******************************************************************************
2284 * ChangeServiceConfigW [ADVAPI32.@]
2286 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2287 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2288 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2289 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2294 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2295 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2296 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2297 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2298 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2300 cb_pwd
= lpPassword
? (strlenW(lpPassword
) + 1)*sizeof(WCHAR
) : 0;
2304 err
= svcctl_ChangeServiceConfigW(hService
, dwServiceType
,
2305 dwStartType
, dwErrorControl
, lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
,
2306 (const BYTE
*)lpDependencies
, multisz_cb(lpDependencies
), lpServiceStartName
,
2307 (const BYTE
*)lpPassword
, cb_pwd
, lpDisplayName
);
2309 __EXCEPT(rpc_filter
)
2311 err
= map_exception_code(GetExceptionCode());
2315 if (err
!= ERROR_SUCCESS
)
2318 return err
== ERROR_SUCCESS
;
2321 /******************************************************************************
2322 * ChangeServiceConfigA [ADVAPI32.@]
2324 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2325 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2326 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2327 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2329 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2330 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2333 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2334 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2335 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2336 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2337 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2339 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2340 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2341 wDependencies
= SERV_dupmulti( lpDependencies
);
2342 wServiceStartName
= SERV_dup( lpServiceStartName
);
2343 wPassword
= SERV_dup( lpPassword
);
2344 wDisplayName
= SERV_dup( lpDisplayName
);
2346 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2347 dwStartType
, dwErrorControl
, wBinaryPathName
,
2348 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2349 wServiceStartName
, wPassword
, wDisplayName
);
2351 heap_free( wBinaryPathName
);
2352 heap_free( wLoadOrderGroup
);
2353 heap_free( wDependencies
);
2354 heap_free( wServiceStartName
);
2355 heap_free( wPassword
);
2356 heap_free( wDisplayName
);
2361 /******************************************************************************
2362 * ChangeServiceConfig2A [ADVAPI32.@]
2364 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2369 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2371 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2373 LPSERVICE_DESCRIPTIONA sd
= lpInfo
;
2374 SERVICE_DESCRIPTIONW sdw
;
2376 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2378 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2380 heap_free( sdw
.lpDescription
);
2382 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2384 LPSERVICE_FAILURE_ACTIONSA fa
= lpInfo
;
2385 SERVICE_FAILURE_ACTIONSW faw
;
2387 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2388 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2389 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2390 faw
.cActions
= fa
->cActions
;
2391 faw
.lpsaActions
= fa
->lpsaActions
;
2393 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2395 heap_free( faw
.lpRebootMsg
);
2396 heap_free( faw
.lpCommand
);
2398 else if (dwInfoLevel
== SERVICE_CONFIG_PRESHUTDOWN_INFO
)
2400 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, lpInfo
);
2403 SetLastError( ERROR_INVALID_PARAMETER
);
2408 /******************************************************************************
2409 * ChangeServiceConfig2W [ADVAPI32.@]
2411 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2418 SC_RPC_CONFIG_INFOW info
;
2420 info
.dwInfoLevel
= dwInfoLevel
;
2421 info
.u
.descr
= lpInfo
;
2422 err
= svcctl_ChangeServiceConfig2W( hService
, info
);
2424 __EXCEPT(rpc_filter
)
2426 err
= map_exception_code(GetExceptionCode());
2430 if (err
!= ERROR_SUCCESS
)
2433 return err
== ERROR_SUCCESS
;
2436 NTSTATUS
SERV_QueryServiceObjectSecurity(SC_HANDLE hService
,
2437 SECURITY_INFORMATION dwSecurityInformation
,
2438 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2439 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2441 SECURITY_DESCRIPTOR descriptor
;
2446 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2447 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2449 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2450 FIXME("information %d not supported\n", dwSecurityInformation
);
2452 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2454 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2455 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2458 status
= RtlMakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2459 *pcbBytesNeeded
= size
;
2463 /******************************************************************************
2464 * QueryServiceObjectSecurity [ADVAPI32.@]
2466 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2467 SECURITY_INFORMATION dwSecurityInformation
,
2468 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2469 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2471 NTSTATUS status
= SERV_QueryServiceObjectSecurity(hService
, dwSecurityInformation
, lpSecurityDescriptor
,
2472 cbBufSize
, pcbBytesNeeded
);
2473 if (status
!= STATUS_SUCCESS
)
2475 SetLastError(RtlNtStatusToDosError(status
));
2481 /******************************************************************************
2482 * SetServiceObjectSecurity [ADVAPI32.@]
2485 * - SetSecurityInfo should be updated to call this function once it's implemented.
2487 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2488 SECURITY_INFORMATION dwSecurityInformation
,
2489 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2491 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2495 /******************************************************************************
2496 * SetServiceBits [ADVAPI32.@]
2498 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2499 DWORD dwServiceBits
,
2501 BOOL bUpdateImmediately
)
2503 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2504 bSetBitsOn
, bUpdateImmediately
);
2508 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2509 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
2511 LPHANDLER_FUNCTION func
= context
;
2514 return ERROR_SUCCESS
;
2517 /******************************************************************************
2518 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2520 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
2522 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
2525 /******************************************************************************
2526 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2528 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
2530 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
2533 /******************************************************************************
2534 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2536 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
2539 SERVICE_STATUS_HANDLE ret
;
2541 nameW
= SERV_dup(name
);
2542 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
2547 /******************************************************************************
2548 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2550 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2551 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2553 service_data
*service
;
2554 SC_HANDLE hService
= 0;
2556 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2558 EnterCriticalSection( &service_cs
);
2559 if ((service
= find_service_by_name( lpServiceName
)))
2561 service
->handler
= lpHandlerProc
;
2562 service
->context
= lpContext
;
2563 hService
= service
->handle
;
2565 LeaveCriticalSection( &service_cs
);
2567 if (!hService
) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
2568 return (SERVICE_STATUS_HANDLE
)hService
;
2571 /******************************************************************************
2572 * EnumDependentServicesA [ADVAPI32.@]
2574 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2575 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2576 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2578 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2579 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2581 *lpServicesReturned
= 0;
2585 /******************************************************************************
2586 * EnumDependentServicesW [ADVAPI32.@]
2588 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2589 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2590 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2592 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2593 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2595 *lpServicesReturned
= 0;
2599 /******************************************************************************
2600 * NotifyServiceStatusChangeW [ADVAPI32.@]
2602 DWORD WINAPI
NotifyServiceStatusChangeW(SC_HANDLE hService
, DWORD dwNotifyMask
,
2603 SERVICE_NOTIFYW
*pNotifyBuffer
)
2607 SERVICE_STATUS_PROCESS st
;
2610 if (!once
++) FIXME("%p 0x%x %p - semi-stub\n", hService
, dwNotifyMask
, pNotifyBuffer
);
2612 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (void*)&st
, sizeof(st
), &dummy
);
2615 /* dwNotifyMask is a set of bitflags in same order as SERVICE_ statuses */
2616 if (dwNotifyMask
& (1 << (st
.dwCurrentState
- SERVICE_STOPPED
)))
2618 pNotifyBuffer
->dwNotificationStatus
= ERROR_SUCCESS
;
2619 memcpy(&pNotifyBuffer
->ServiceStatus
, &st
, sizeof(pNotifyBuffer
->ServiceStatus
));
2620 pNotifyBuffer
->dwNotificationTriggered
= 1 << (st
.dwCurrentState
- SERVICE_STOPPED
);
2621 pNotifyBuffer
->pszServiceNames
= NULL
;
2622 TRACE("Queueing notification: 0x%x\n", pNotifyBuffer
->dwNotificationTriggered
);
2623 QueueUserAPC((PAPCFUNC
)pNotifyBuffer
->pfnNotifyCallback
,
2624 GetCurrentThread(), (ULONG_PTR
)pNotifyBuffer
);
2628 /* TODO: If the service is not currently in a matching state, we should
2629 * tell `services` to monitor it. */
2631 return ERROR_SUCCESS
;