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"
51 #include "wine/list.h"
53 WINE_DEFAULT_DEBUG_CHANNEL(service
);
55 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(SIZE_T len
)
57 return heap_alloc(len
);
60 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
65 typedef struct service_data_t
67 LPHANDLER_FUNCTION_EX handler
;
71 SC_HANDLE full_access_handle
;
74 LPSERVICE_MAIN_FUNCTIONA a
;
75 LPSERVICE_MAIN_FUNCTIONW w
;
81 typedef struct dispatcher_data_t
87 typedef struct notify_data_t
{
89 SC_RPC_NOTIFY_PARAMS params
;
90 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams
;
91 SC_NOTIFY_RPC_HANDLE notify_handle
;
92 SERVICE_NOTIFYW
*notify_buffer
;
93 HANDLE calling_thread
, ready_evt
;
97 static struct list notify_list
= LIST_INIT(notify_list
);
99 static CRITICAL_SECTION service_cs
;
100 static CRITICAL_SECTION_DEBUG service_cs_debug
=
103 { &service_cs_debug
.ProcessLocksList
,
104 &service_cs_debug
.ProcessLocksList
},
105 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
107 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
109 static service_data
**services
;
110 static unsigned int nb_services
;
111 static HANDLE service_event
;
112 static BOOL stop_service
;
114 extern HANDLE CDECL
__wine_make_process_system(void);
116 /******************************************************************************
117 * String management functions (same behaviour as strdup)
118 * NOTE: the caller of those functions is responsible for calling HeapFree
119 * in order to release the memory allocated by those functions.
121 LPWSTR
SERV_dup( LPCSTR str
)
128 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
129 wstr
= heap_alloc( len
*sizeof (WCHAR
) );
130 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
134 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
142 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
143 n
+= (strlen( &str
[n
] ) + 1);
148 wstr
= heap_alloc( len
*sizeof (WCHAR
) );
149 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
153 static inline DWORD
multisz_cb(LPCWSTR wmultisz
)
155 const WCHAR
*wptr
= wmultisz
;
157 if (wmultisz
== NULL
)
161 wptr
+= lstrlenW(wptr
)+1;
162 return (wptr
- wmultisz
+ 1)*sizeof(WCHAR
);
165 /******************************************************************************
166 * RPC connection with services.exe
168 static handle_t
rpc_wstr_bind(RPC_WSTR str
)
170 WCHAR transport
[] = SVCCTL_TRANSPORT
;
171 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
172 RPC_WSTR binding_str
;
176 status
= RpcStringBindingComposeW(NULL
, transport
, str
, endpoint
, NULL
, &binding_str
);
177 if (status
!= RPC_S_OK
)
179 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
183 status
= RpcBindingFromStringBindingW(binding_str
, &rpc_handle
);
184 RpcStringFreeW(&binding_str
);
186 if (status
!= RPC_S_OK
)
188 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
195 static handle_t
rpc_cstr_bind(RPC_CSTR str
)
197 RPC_CSTR transport
= (RPC_CSTR
)SVCCTL_TRANSPORTA
;
198 RPC_CSTR endpoint
= (RPC_CSTR
)SVCCTL_ENDPOINTA
;
199 RPC_CSTR binding_str
;
203 status
= RpcStringBindingComposeA(NULL
, transport
, str
, endpoint
, NULL
, &binding_str
);
204 if (status
!= RPC_S_OK
)
206 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
210 status
= RpcBindingFromStringBindingA(binding_str
, &rpc_handle
);
211 RpcStringFreeA(&binding_str
);
213 if (status
!= RPC_S_OK
)
215 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
222 DECLSPEC_HIDDEN handle_t __RPC_USER
MACHINE_HANDLEA_bind(MACHINE_HANDLEA MachineName
)
224 return rpc_cstr_bind((RPC_CSTR
)MachineName
);
227 DECLSPEC_HIDDEN
void __RPC_USER
MACHINE_HANDLEA_unbind(MACHINE_HANDLEA MachineName
, handle_t h
)
232 DECLSPEC_HIDDEN handle_t __RPC_USER
MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName
)
234 return rpc_wstr_bind((RPC_WSTR
)MachineName
);
237 DECLSPEC_HIDDEN
void __RPC_USER
MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName
, handle_t h
)
242 DECLSPEC_HIDDEN handle_t __RPC_USER
SVCCTL_HANDLEW_bind(SVCCTL_HANDLEW MachineName
)
244 return rpc_wstr_bind((RPC_WSTR
)MachineName
);
247 DECLSPEC_HIDDEN
void __RPC_USER
SVCCTL_HANDLEW_unbind(SVCCTL_HANDLEW MachineName
, handle_t h
)
252 static LONG WINAPI
rpc_filter(EXCEPTION_POINTERS
*eptr
)
254 return I_RpcExceptionFilter(eptr
->ExceptionRecord
->ExceptionCode
);
257 static DWORD
map_exception_code(DWORD exception_code
)
259 switch (exception_code
)
261 case RPC_X_NULL_REF_POINTER
:
262 return ERROR_INVALID_ADDRESS
;
263 case RPC_X_ENUM_VALUE_OUT_OF_RANGE
:
264 case RPC_X_BYTE_COUNT_TOO_SMALL
:
265 return ERROR_INVALID_PARAMETER
;
266 case RPC_S_INVALID_BINDING
:
267 case RPC_X_SS_IN_NULL_CONTEXT
:
268 return ERROR_INVALID_HANDLE
;
270 return exception_code
;
274 /******************************************************************************
275 * Service IPC functions
277 static LPWSTR
service_get_pipe_name(void)
279 static const WCHAR format
[] = { '\\','\\','.','\\','p','i','p','e','\\',
280 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
281 static const WCHAR service_current_key_str
[] = { 'S','Y','S','T','E','M','\\',
282 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
283 'C','o','n','t','r','o','l','\\',
284 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
287 HKEY service_current_key
;
288 DWORD service_current
;
292 ret
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
, service_current_key_str
, 0,
293 KEY_QUERY_VALUE
, &service_current_key
);
294 if (ret
!= ERROR_SUCCESS
)
296 len
= sizeof(service_current
);
297 ret
= RegQueryValueExW(service_current_key
, NULL
, NULL
, &type
,
298 (BYTE
*)&service_current
, &len
);
299 RegCloseKey(service_current_key
);
300 if (ret
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
302 len
= ARRAY_SIZE(format
) + 10 /* strlenW("4294967295") */;
303 name
= heap_alloc(len
* sizeof(WCHAR
));
306 snprintfW(name
, len
, format
, service_current
);
310 static HANDLE
service_open_pipe(void)
312 LPWSTR szPipe
= service_get_pipe_name();
313 HANDLE handle
= INVALID_HANDLE_VALUE
;
316 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
317 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
318 if (handle
!= INVALID_HANDLE_VALUE
)
320 if (GetLastError() != ERROR_PIPE_BUSY
)
322 } while (WaitNamedPipeW(szPipe
, NMPWAIT_USE_DEFAULT_WAIT
));
328 static service_data
*find_service_by_name( const WCHAR
*name
)
332 if (nb_services
== 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
334 for (i
= 0; i
< nb_services
; i
++)
335 if (!strcmpiW( name
, services
[i
]->name
)) return services
[i
];
339 /******************************************************************************
342 * Call into the main service routine provided by StartServiceCtrlDispatcher.
344 static DWORD WINAPI
service_thread(LPVOID arg
)
346 service_data
*info
= arg
;
347 LPWSTR str
= info
->args
;
348 DWORD argc
= 0, len
= 0;
354 len
+= strlenW(&str
[len
]) + 1;
363 argv
= heap_alloc((argc
+1)*sizeof(LPWSTR
));
364 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
368 info
->proc
.w(argc
, argv
);
373 LPSTR strA
, *argv
, p
;
376 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
377 strA
= heap_alloc(lenA
);
378 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
380 argv
= heap_alloc((argc
+1)*sizeof(LPSTR
));
381 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
385 info
->proc
.a(argc
, argv
);
392 /******************************************************************************
393 * service_handle_start
395 static DWORD
service_handle_start(service_data
*service
, const void *data
, DWORD data_size
)
397 DWORD count
= data_size
/ sizeof(WCHAR
);
401 WARN("service is not stopped\n");
402 return ERROR_SERVICE_ALREADY_RUNNING
;
405 heap_free(service
->args
);
406 service
->args
= heap_alloc((count
+ 2) * sizeof(WCHAR
));
407 if (count
) memcpy( service
->args
, data
, count
* sizeof(WCHAR
) );
408 service
->args
[count
++] = 0;
409 service
->args
[count
++] = 0;
411 service
->thread
= CreateThread( NULL
, 0, service_thread
,
413 SetEvent( service_event
); /* notify the main loop */
417 /******************************************************************************
418 * service_handle_control
420 static DWORD
service_handle_control(service_data
*service
, DWORD control
, const void *data
, DWORD data_size
)
422 DWORD ret
= ERROR_INVALID_SERVICE_CONTROL
;
424 TRACE("%s control %u data %p data_size %u\n", debugstr_w(service
->name
), control
, data
, data_size
);
426 if (control
== SERVICE_CONTROL_START
)
427 ret
= service_handle_start(service
, data
, data_size
);
428 else if (service
->handler
)
429 ret
= service
->handler(control
, 0, (void *)data
, service
->context
);
433 /******************************************************************************
434 * service_control_dispatcher
436 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
438 dispatcher_data
*disp
= arg
;
440 /* dispatcher loop */
443 service_data
*service
;
444 service_start_info info
;
448 DWORD data_size
= 0, count
, result
;
450 r
= ReadFile( disp
->pipe
, &info
, FIELD_OFFSET(service_start_info
,data
), &count
, NULL
);
453 if (GetLastError() != ERROR_BROKEN_PIPE
)
454 ERR( "pipe read failed error %u\n", GetLastError() );
457 if (count
!= FIELD_OFFSET(service_start_info
,data
))
459 ERR( "partial pipe read %u\n", count
);
462 if (count
< info
.total_size
)
464 data_size
= info
.total_size
- FIELD_OFFSET(service_start_info
,data
);
465 data
= heap_alloc( data_size
);
466 r
= ReadFile( disp
->pipe
, data
, data_size
, &count
, NULL
);
469 if (GetLastError() != ERROR_BROKEN_PIPE
)
470 ERR( "pipe read failed error %u\n", GetLastError() );
474 if (count
!= data_size
)
476 ERR( "partial pipe read %u/%u\n", count
, data_size
);
482 EnterCriticalSection( &service_cs
);
484 /* validate service name */
485 name
= (WCHAR
*)data
;
486 if (!info
.name_size
|| data_size
< info
.name_size
* sizeof(WCHAR
) || name
[info
.name_size
- 1])
488 ERR( "got request without valid service name\n" );
489 result
= ERROR_INVALID_PARAMETER
;
493 if (info
.magic
!= SERVICE_PROTOCOL_MAGIC
)
495 ERR( "received invalid request for service %s\n", debugstr_w(name
) );
496 result
= ERROR_INVALID_PARAMETER
;
500 /* find the service */
501 if (!(service
= find_service_by_name( name
)))
503 FIXME( "got request for unknown service %s\n", debugstr_w(name
) );
504 result
= ERROR_INVALID_PARAMETER
;
508 if (!service
->handle
)
510 if (!(service
->handle
= OpenServiceW( disp
->manager
, name
, SERVICE_SET_STATUS
)) ||
511 !(service
->full_access_handle
= OpenServiceW( disp
->manager
, name
,
512 GENERIC_READ
|GENERIC_WRITE
)))
513 FIXME( "failed to open service %s\n", debugstr_w(name
) );
516 data_size
-= info
.name_size
* sizeof(WCHAR
);
517 result
= service_handle_control(service
, info
.control
, data_size
?
518 &data
[info
.name_size
* sizeof(WCHAR
)] : NULL
, data_size
);
521 LeaveCriticalSection( &service_cs
);
522 WriteFile( disp
->pipe
, &result
, sizeof(result
), &count
, NULL
);
526 CloseHandle( disp
->pipe
);
527 CloseServiceHandle( disp
->manager
);
532 /* wait for services which accept this type of message to become STOPPED */
533 static void handle_shutdown_msg(DWORD msg
, DWORD accept
)
536 SERVICE_PRESHUTDOWN_INFO spi
;
537 DWORD i
, n
= 0, sz
, timeout
= 2000;
539 BOOL res
, done
= TRUE
;
540 SC_HANDLE
*wait_handles
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(SC_HANDLE
) * nb_services
);
542 EnterCriticalSection( &service_cs
);
543 for (i
= 0; i
< nb_services
; i
++)
545 res
= QueryServiceStatus( services
[i
]->full_access_handle
, &st
);
546 if (!res
|| st
.dwCurrentState
== SERVICE_STOPPED
|| !(st
.dwControlsAccepted
& accept
))
551 if (accept
== SERVICE_ACCEPT_PRESHUTDOWN
)
553 res
= QueryServiceConfig2W( services
[i
]->full_access_handle
, SERVICE_CONFIG_PRESHUTDOWN_INFO
,
554 (LPBYTE
)&spi
, sizeof(spi
), &sz
);
557 FIXME( "service should be able to delay shutdown\n" );
558 timeout
= max( spi
.dwPreshutdownTimeout
, timeout
);
562 service_handle_control( services
[i
], msg
, NULL
, 0 );
563 wait_handles
[n
++] = services
[i
]->full_access_handle
;
565 LeaveCriticalSection( &service_cs
);
567 /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
568 timeout
= min( timeout
, 3000 );
569 stop_time
= GetTickCount64() + timeout
;
571 while (!done
&& GetTickCount64() < stop_time
)
574 for (i
= 0; i
< n
; i
++)
576 res
= QueryServiceStatus( wait_handles
[i
], &st
);
577 if (!res
|| st
.dwCurrentState
== SERVICE_STOPPED
)
586 HeapFree( GetProcessHeap(), 0, wait_handles
);
589 /******************************************************************************
590 * service_run_main_thread
592 static BOOL
service_run_main_thread(void)
595 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
596 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
597 dispatcher_data
*disp
= heap_alloc( sizeof(*disp
) );
599 disp
->manager
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
602 ERR("failed to open service manager error %u\n", GetLastError());
607 disp
->pipe
= service_open_pipe();
608 if (disp
->pipe
== INVALID_HANDLE_VALUE
)
610 WARN("failed to create control pipe error %u\n", GetLastError());
611 CloseServiceHandle( disp
->manager
);
613 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
);
617 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
618 stop_service
= FALSE
;
620 /* FIXME: service_control_dispatcher should be merged into the main thread */
621 wait_handles
[0] = __wine_make_process_system();
622 wait_handles
[1] = CreateThread( NULL
, 0, service_control_dispatcher
, disp
, 0, NULL
);
623 wait_handles
[2] = service_event
;
625 TRACE("Starting %d services running as process %d\n",
626 nb_services
, GetCurrentProcessId());
628 /* wait for all the threads to pack up and exit */
629 while (!stop_service
)
631 EnterCriticalSection( &service_cs
);
632 for (i
= 0, n
= 3; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
634 if (!services
[i
]->thread
) continue;
635 wait_services
[n
] = i
;
636 wait_handles
[n
++] = services
[i
]->thread
;
638 LeaveCriticalSection( &service_cs
);
640 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
641 if (!ret
) /* system process event */
643 handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN
, SERVICE_ACCEPT_PRESHUTDOWN
);
644 handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN
, SERVICE_ACCEPT_SHUTDOWN
);
649 TRACE( "control dispatcher exited, shutting down\n" );
650 /* FIXME: we should maybe send a shutdown control to running services */
655 continue; /* rebuild the list */
659 i
= wait_services
[ret
];
660 EnterCriticalSection( &service_cs
);
661 CloseHandle( services
[i
]->thread
);
662 services
[i
]->thread
= NULL
;
663 LeaveCriticalSection( &service_cs
);
671 /******************************************************************************
672 * StartServiceCtrlDispatcherA [ADVAPI32.@]
674 * See StartServiceCtrlDispatcherW.
676 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
681 TRACE("%p\n", servent
);
685 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
688 while (servent
[nb_services
].lpServiceName
) nb_services
++;
691 SetLastError( ERROR_INVALID_PARAMETER
);
695 services
= heap_alloc( nb_services
* sizeof(*services
) );
697 for (i
= 0; i
< nb_services
; i
++)
699 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
700 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
701 info
= heap_alloc_zero( sz
);
702 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
703 info
->proc
.a
= servent
[i
].lpServiceProc
;
704 info
->unicode
= FALSE
;
708 return service_run_main_thread();
711 /******************************************************************************
712 * StartServiceCtrlDispatcherW [ADVAPI32.@]
714 * Connects a process containing one or more services to the service control
718 * servent [I] A list of the service names and service procedures
724 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
729 TRACE("%p\n", servent
);
733 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
736 while (servent
[nb_services
].lpServiceName
) nb_services
++;
739 SetLastError( ERROR_INVALID_PARAMETER
);
743 services
= heap_alloc( nb_services
* sizeof(*services
) );
745 for (i
= 0; i
< nb_services
; i
++)
747 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
748 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
749 info
= heap_alloc_zero( sz
);
750 strcpyW(info
->name
, servent
[i
].lpServiceName
);
751 info
->proc
.w
= servent
[i
].lpServiceProc
;
752 info
->unicode
= TRUE
;
756 return service_run_main_thread();
759 /******************************************************************************
760 * LockServiceDatabase [ADVAPI32.@]
762 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
764 SC_RPC_LOCK hLock
= NULL
;
767 TRACE("%p\n",hSCManager
);
771 err
= svcctl_LockServiceDatabase(hSCManager
, &hLock
);
775 err
= map_exception_code(GetExceptionCode());
778 if (err
!= ERROR_SUCCESS
)
786 /******************************************************************************
787 * UnlockServiceDatabase [ADVAPI32.@]
789 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
792 SC_RPC_LOCK hRpcLock
= ScLock
;
794 TRACE("%p\n",ScLock
);
798 err
= svcctl_UnlockServiceDatabase(&hRpcLock
);
802 err
= map_exception_code(GetExceptionCode());
805 if (err
!= ERROR_SUCCESS
)
813 /******************************************************************************
814 * SetServiceStatus [ADVAPI32.@]
821 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
825 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
826 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
827 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
828 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
829 lpStatus
->dwWaitHint
);
833 err
= svcctl_SetServiceStatus( hService
, lpStatus
);
837 err
= map_exception_code(GetExceptionCode());
840 if (err
!= ERROR_SUCCESS
)
846 if (lpStatus
->dwCurrentState
== SERVICE_STOPPED
)
848 unsigned int i
, count
= 0;
849 EnterCriticalSection( &service_cs
);
850 for (i
= 0; i
< nb_services
; i
++)
852 if (services
[i
]->handle
== (SC_HANDLE
)hService
) continue;
853 if (services
[i
]->thread
) count
++;
858 SetEvent( service_event
); /* notify the main loop */
860 LeaveCriticalSection( &service_cs
);
867 /******************************************************************************
868 * OpenSCManagerA [ADVAPI32.@]
870 * Establish a connection to the service control manager and open its database.
873 * lpMachineName [I] Pointer to machine name string
874 * lpDatabaseName [I] Pointer to database name string
875 * dwDesiredAccess [I] Type of access
878 * Success: A Handle to the service control manager database
881 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
882 DWORD dwDesiredAccess
)
884 LPWSTR machineW
, databaseW
;
887 machineW
= SERV_dup(lpMachineName
);
888 databaseW
= SERV_dup(lpDatabaseName
);
889 ret
= OpenSCManagerW(machineW
, databaseW
, dwDesiredAccess
);
890 heap_free(databaseW
);
895 /******************************************************************************
896 * OpenSCManagerW [ADVAPI32.@]
898 * See OpenSCManagerA.
900 DWORD
SERV_OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
901 DWORD dwDesiredAccess
, SC_HANDLE
*handle
)
905 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
906 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
910 r
= svcctl_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)handle
);
914 r
= map_exception_code(GetExceptionCode());
918 if (r
!=ERROR_SUCCESS
)
921 TRACE("returning %p\n", *handle
);
925 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
926 DWORD dwDesiredAccess
)
928 SC_HANDLE handle
= 0;
931 r
= SERV_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, &handle
);
932 if (r
!=ERROR_SUCCESS
)
937 /******************************************************************************
938 * ControlService [ADVAPI32.@]
940 * Send a control code to a service.
943 * hService [I] Handle of the service control manager database
944 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
945 * lpServiceStatus [O] Destination for the status of the service, if available
952 * Unlike M$' implementation, control requests are not serialized and may be
953 * processed asynchronously.
955 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
956 LPSERVICE_STATUS lpServiceStatus
)
960 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
964 err
= svcctl_ControlService(hService
, dwControl
, lpServiceStatus
);
968 err
= map_exception_code(GetExceptionCode());
971 if (err
!= ERROR_SUCCESS
)
980 /******************************************************************************
981 * CloseServiceHandle [ADVAPI32.@]
983 * Close a handle to a service or the service control manager database.
986 * hSCObject [I] Handle to service or service control manager database
993 CloseServiceHandle( SC_HANDLE hSCObject
)
997 TRACE("%p\n", hSCObject
);
1001 err
= svcctl_CloseServiceHandle((SC_RPC_HANDLE
*)&hSCObject
);
1003 __EXCEPT(rpc_filter
)
1005 err
= map_exception_code(GetExceptionCode());
1009 if (err
!= ERROR_SUCCESS
)
1018 /******************************************************************************
1019 * OpenServiceA [ADVAPI32.@]
1021 * Open a handle to a service.
1024 * hSCManager [I] Handle of the service control manager database
1025 * lpServiceName [I] Name of the service to open
1026 * dwDesiredAccess [I] Access required to the service
1029 * Success: Handle to the service
1032 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1033 DWORD dwDesiredAccess
)
1035 LPWSTR lpServiceNameW
;
1038 TRACE("%p %s 0x%08x\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1040 lpServiceNameW
= SERV_dup(lpServiceName
);
1041 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1042 heap_free(lpServiceNameW
);
1047 /******************************************************************************
1048 * OpenServiceW [ADVAPI32.@]
1052 DWORD
SERV_OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1053 DWORD dwDesiredAccess
, SC_HANDLE
*handle
)
1057 TRACE("%p %s 0x%08x\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1060 return ERROR_INVALID_HANDLE
;
1064 err
= svcctl_OpenServiceW(hSCManager
, lpServiceName
, dwDesiredAccess
, (SC_RPC_HANDLE
*)handle
);
1066 __EXCEPT(rpc_filter
)
1068 err
= map_exception_code(GetExceptionCode());
1072 if (err
!= ERROR_SUCCESS
)
1075 TRACE("returning %p\n", *handle
);
1079 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1080 DWORD dwDesiredAccess
)
1082 SC_HANDLE handle
= 0;
1085 err
= SERV_OpenServiceW(hSCManager
, lpServiceName
, dwDesiredAccess
, &handle
);
1086 if (err
!= ERROR_SUCCESS
)
1091 /******************************************************************************
1092 * CreateServiceW [ADVAPI32.@]
1095 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1096 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1097 DWORD dwServiceType
, DWORD dwStartType
,
1098 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1099 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1100 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1101 LPCWSTR lpPassword
)
1103 SC_HANDLE handle
= 0;
1107 TRACE("%p %s %s\n", hSCManager
,
1108 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1112 SetLastError( ERROR_INVALID_HANDLE
);
1117 passwdlen
= (strlenW(lpPassword
) + 1) * sizeof(WCHAR
);
1125 IsWow64Process(GetCurrentProcess(), &is_wow64
);
1128 err
= svcctl_CreateServiceWOW64W(hSCManager
, lpServiceName
,
1129 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1130 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (const BYTE
*)lpDependencies
,
1131 multisz_cb(lpDependencies
), lpServiceStartName
, (const BYTE
*)lpPassword
, passwdlen
,
1132 (SC_RPC_HANDLE
*)&handle
);
1134 err
= svcctl_CreateServiceW(hSCManager
, lpServiceName
,
1135 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1136 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (const BYTE
*)lpDependencies
,
1137 multisz_cb(lpDependencies
), lpServiceStartName
, (const BYTE
*)lpPassword
, passwdlen
,
1138 (SC_RPC_HANDLE
*)&handle
);
1140 __EXCEPT(rpc_filter
)
1142 err
= map_exception_code(GetExceptionCode());
1146 if (err
!= ERROR_SUCCESS
)
1155 /******************************************************************************
1156 * CreateServiceA [ADVAPI32.@]
1159 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1160 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1161 DWORD dwServiceType
, DWORD dwStartType
,
1162 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1163 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1164 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1167 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1168 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1171 TRACE("%p %s %s\n", hSCManager
,
1172 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1174 lpServiceNameW
= SERV_dup( lpServiceName
);
1175 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1176 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1177 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1178 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1179 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1180 lpPasswordW
= SERV_dup( lpPassword
);
1182 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1183 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1184 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1185 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1187 heap_free( lpServiceNameW
);
1188 heap_free( lpDisplayNameW
);
1189 heap_free( lpBinaryPathNameW
);
1190 heap_free( lpLoadOrderGroupW
);
1191 heap_free( lpDependenciesW
);
1192 heap_free( lpServiceStartNameW
);
1193 heap_free( lpPasswordW
);
1199 /******************************************************************************
1200 * DeleteService [ADVAPI32.@]
1202 * Delete a service from the service control manager database.
1205 * hService [I] Handle of the service to delete
1211 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1215 TRACE("%p\n", hService
);
1219 err
= svcctl_DeleteService(hService
);
1221 __EXCEPT(rpc_filter
)
1223 err
= map_exception_code(GetExceptionCode());
1236 /******************************************************************************
1237 * StartServiceA [ADVAPI32.@]
1242 * hService [I] Handle of service
1243 * dwNumServiceArgs [I] Number of arguments
1244 * lpServiceArgVectors [I] Address of array of argument strings
1247 * - NT implements this function using an obscure RPC call.
1248 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1249 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1250 * - This will only work for shared address space. How should the service
1251 * args be transferred when address spaces are separated?
1252 * - Can only start one service at a time.
1253 * - Has no concept of privilege.
1259 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1260 LPCSTR
*lpServiceArgVectors
)
1262 LPWSTR
*lpwstr
=NULL
;
1266 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1268 if (dwNumServiceArgs
)
1269 lpwstr
= heap_alloc( dwNumServiceArgs
*sizeof(LPWSTR
) );
1271 for(i
=0; i
<dwNumServiceArgs
; i
++)
1272 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1274 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1276 if (dwNumServiceArgs
)
1278 for(i
=0; i
<dwNumServiceArgs
; i
++)
1279 heap_free(lpwstr
[i
]);
1287 /******************************************************************************
1288 * StartServiceW [ADVAPI32.@]
1290 * See StartServiceA.
1292 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1293 LPCWSTR
*lpServiceArgVectors
)
1297 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1301 err
= svcctl_StartServiceW(hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1303 __EXCEPT(rpc_filter
)
1305 err
= map_exception_code(GetExceptionCode());
1308 if (err
!= ERROR_SUCCESS
)
1317 /******************************************************************************
1318 * QueryServiceStatus [ADVAPI32.@]
1321 * hService [I] Handle to service to get information about
1322 * lpservicestatus [O] buffer to receive the status information for the service
1325 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1326 LPSERVICE_STATUS lpservicestatus
)
1328 SERVICE_STATUS_PROCESS SvcStatusData
;
1332 TRACE("%p %p\n", hService
, lpservicestatus
);
1336 SetLastError(ERROR_INVALID_HANDLE
);
1339 if (!lpservicestatus
)
1341 SetLastError(ERROR_INVALID_ADDRESS
);
1345 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1346 sizeof(SERVICE_STATUS_PROCESS
), &dummy
);
1347 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1352 /******************************************************************************
1353 * QueryServiceStatusEx [ADVAPI32.@]
1355 * Get information about a service.
1358 * hService [I] Handle to service to get information about
1359 * InfoLevel [I] Level of information to get
1360 * lpBuffer [O] Destination for requested information
1361 * cbBufSize [I] Size of lpBuffer in bytes
1362 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1368 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1369 LPBYTE lpBuffer
, DWORD cbBufSize
,
1370 LPDWORD pcbBytesNeeded
)
1374 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1376 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1378 err
= ERROR_INVALID_LEVEL
;
1380 else if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1382 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1383 err
= ERROR_INSUFFICIENT_BUFFER
;
1389 err
= svcctl_QueryServiceStatusEx(hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1391 __EXCEPT(rpc_filter
)
1393 err
= map_exception_code(GetExceptionCode());
1397 if (err
!= ERROR_SUCCESS
)
1405 /******************************************************************************
1406 * QueryServiceConfigA [ADVAPI32.@]
1408 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1409 DWORD size
, LPDWORD needed
)
1414 QUERY_SERVICE_CONFIGW
*configW
;
1416 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1418 if (!(buffer
= heap_alloc( 2 * size
)))
1420 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1423 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1424 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1425 if (!ret
) goto done
;
1427 config
->dwServiceType
= configW
->dwServiceType
;
1428 config
->dwStartType
= configW
->dwStartType
;
1429 config
->dwErrorControl
= configW
->dwErrorControl
;
1430 config
->lpBinaryPathName
= NULL
;
1431 config
->lpLoadOrderGroup
= NULL
;
1432 config
->dwTagId
= configW
->dwTagId
;
1433 config
->lpDependencies
= NULL
;
1434 config
->lpServiceStartName
= NULL
;
1435 config
->lpDisplayName
= NULL
;
1437 p
= (LPSTR
)(config
+ 1);
1438 n
= size
- sizeof(*config
);
1441 #define MAP_STR(str) \
1445 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1446 if (!sz) goto done; \
1453 MAP_STR( lpBinaryPathName
);
1454 MAP_STR( lpLoadOrderGroup
);
1455 MAP_STR( lpDependencies
);
1456 MAP_STR( lpServiceStartName
);
1457 MAP_STR( lpDisplayName
);
1460 *needed
= p
- (LPSTR
)config
;
1464 heap_free( buffer
);
1468 static DWORD
move_string_to_buffer(BYTE
**buf
, LPWSTR
*string_ptr
)
1475 memset(*buf
, 0, cb
);
1479 cb
= (strlenW(*string_ptr
) + 1)*sizeof(WCHAR
);
1480 memcpy(*buf
, *string_ptr
, cb
);
1481 MIDL_user_free(*string_ptr
);
1484 *string_ptr
= (LPWSTR
)*buf
;
1490 static DWORD
size_string(LPCWSTR string
)
1492 return (string
? (strlenW(string
) + 1)*sizeof(WCHAR
) : sizeof(WCHAR
));
1495 /******************************************************************************
1496 * QueryServiceConfigW [ADVAPI32.@]
1499 QueryServiceConfigW( SC_HANDLE hService
,
1500 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1501 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1503 QUERY_SERVICE_CONFIGW config
;
1508 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1509 cbBufSize
, pcbBytesNeeded
);
1511 memset(&config
, 0, sizeof(config
));
1515 err
= svcctl_QueryServiceConfigW(hService
, &config
, cbBufSize
, pcbBytesNeeded
);
1517 __EXCEPT(rpc_filter
)
1519 err
= map_exception_code(GetExceptionCode());
1523 if (err
!= ERROR_SUCCESS
)
1525 TRACE("services.exe: error %u\n", err
);
1530 /* calculate the size required first */
1531 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1532 total
+= size_string(config
.lpBinaryPathName
);
1533 total
+= size_string(config
.lpLoadOrderGroup
);
1534 total
+= size_string(config
.lpDependencies
);
1535 total
+= size_string(config
.lpServiceStartName
);
1536 total
+= size_string(config
.lpDisplayName
);
1538 *pcbBytesNeeded
= total
;
1540 /* if there's not enough memory, return an error */
1541 if( total
> cbBufSize
)
1543 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1544 MIDL_user_free(config
.lpBinaryPathName
);
1545 MIDL_user_free(config
.lpLoadOrderGroup
);
1546 MIDL_user_free(config
.lpDependencies
);
1547 MIDL_user_free(config
.lpServiceStartName
);
1548 MIDL_user_free(config
.lpDisplayName
);
1552 *lpServiceConfig
= config
;
1553 bufpos
= ((BYTE
*)lpServiceConfig
) + sizeof(QUERY_SERVICE_CONFIGW
);
1554 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpBinaryPathName
);
1555 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpLoadOrderGroup
);
1556 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDependencies
);
1557 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpServiceStartName
);
1558 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDisplayName
);
1560 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1561 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1562 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
1563 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
1564 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
1569 /******************************************************************************
1570 * QueryServiceConfig2A [ADVAPI32.@]
1573 * observed under win2k:
1574 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1575 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1577 BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1578 DWORD size
, LPDWORD needed
)
1581 LPBYTE bufferW
= NULL
;
1583 TRACE("%p %u %p %u %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1586 bufferW
= heap_alloc(size
);
1588 ret
= QueryServiceConfig2W(hService
, dwLevel
, bufferW
, size
, needed
);
1589 if(!ret
) goto cleanup
;
1592 case SERVICE_CONFIG_DESCRIPTION
:
1593 if (buffer
&& bufferW
) {
1594 LPSERVICE_DESCRIPTIONA configA
= (LPSERVICE_DESCRIPTIONA
) buffer
;
1595 LPSERVICE_DESCRIPTIONW configW
= (LPSERVICE_DESCRIPTIONW
) bufferW
;
1596 if (configW
->lpDescription
&& (size
> sizeof(SERVICE_DESCRIPTIONA
))) {
1598 configA
->lpDescription
= (LPSTR
)(configA
+ 1);
1599 sz
= WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1,
1600 configA
->lpDescription
, size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
1602 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1604 configA
->lpDescription
= NULL
;
1607 else configA
->lpDescription
= NULL
;
1610 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
1611 if (buffer
&& bufferW
&& *needed
<=size
)
1612 memcpy(buffer
, bufferW
, *needed
);
1615 FIXME("conversation W->A not implemented for level %d\n", dwLevel
);
1621 heap_free( bufferW
);
1625 /******************************************************************************
1626 * QueryServiceConfig2W [ADVAPI32.@]
1628 * See QueryServiceConfig2A.
1630 BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1631 DWORD size
, LPDWORD needed
)
1636 TRACE("%p %u %p %u %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1638 if (!buffer
&& size
)
1640 SetLastError(ERROR_INVALID_ADDRESS
);
1646 case SERVICE_CONFIG_DESCRIPTION
:
1647 if (!(bufptr
= heap_alloc( size
)))
1649 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1654 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
1659 FIXME("Level %d not implemented\n", dwLevel
);
1660 SetLastError(ERROR_INVALID_LEVEL
);
1666 if (dwLevel
== SERVICE_CONFIG_DESCRIPTION
) heap_free(bufptr
);
1667 SetLastError(ERROR_INVALID_ADDRESS
);
1673 err
= svcctl_QueryServiceConfig2W(hService
, dwLevel
, bufptr
, size
, needed
);
1675 __EXCEPT(rpc_filter
)
1677 err
= map_exception_code(GetExceptionCode());
1683 case SERVICE_CONFIG_DESCRIPTION
:
1685 SERVICE_DESCRIPTIONW
*desc
= (SERVICE_DESCRIPTIONW
*)buffer
;
1686 struct service_description
*s
= (struct service_description
*)bufptr
;
1688 if (err
!= ERROR_SUCCESS
&& err
!= ERROR_INSUFFICIENT_BUFFER
)
1690 heap_free( bufptr
);
1691 SetLastError( err
);
1695 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
1696 if (*needed
== sizeof(*s
)) *needed
= sizeof(*desc
);
1698 *needed
= *needed
- FIELD_OFFSET(struct service_description
, description
) + sizeof(*desc
);
1702 heap_free( bufptr
);
1703 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1708 if (!s
->size
) desc
->lpDescription
= NULL
;
1711 desc
->lpDescription
= (WCHAR
*)(desc
+ 1);
1712 memcpy( desc
->lpDescription
, s
->description
, s
->size
);
1715 heap_free( bufptr
);
1718 case SERVICE_CONFIG_PRESHUTDOWN_INFO
:
1719 if (err
!= ERROR_SUCCESS
)
1721 SetLastError( err
);
1733 /******************************************************************************
1734 * EnumServicesStatusA [ADVAPI32.@]
1737 EnumServicesStatusA( SC_HANDLE hmngr
, DWORD type
, DWORD state
, LPENUM_SERVICE_STATUSA
1738 services
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1739 LPDWORD resume_handle
)
1743 ENUM_SERVICE_STATUSW
*servicesW
= NULL
;
1747 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr
, type
, state
, services
, size
, needed
,
1748 returned
, resume_handle
);
1752 SetLastError( ERROR_INVALID_HANDLE
);
1755 if (!needed
|| !returned
)
1757 SetLastError( ERROR_INVALID_ADDRESS
);
1761 sz
= max( 2 * size
, sizeof(*servicesW
) );
1762 if (!(servicesW
= heap_alloc( sz
)))
1764 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1768 ret
= EnumServicesStatusW( hmngr
, type
, state
, servicesW
, sz
, needed
, returned
, resume_handle
);
1769 if (!ret
) goto done
;
1771 p
= (char *)services
+ *returned
* sizeof(ENUM_SERVICE_STATUSA
);
1772 n
= size
- (p
- (char *)services
);
1774 for (i
= 0; i
< *returned
; i
++)
1776 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpServiceName
, -1, p
, n
, NULL
, NULL
);
1778 services
[i
].lpServiceName
= p
;
1781 if (servicesW
[i
].lpDisplayName
)
1783 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpDisplayName
, -1, p
, n
, NULL
, NULL
);
1785 services
[i
].lpDisplayName
= p
;
1789 else services
[i
].lpDisplayName
= NULL
;
1790 services
[i
].ServiceStatus
= servicesW
[i
].ServiceStatus
;
1796 heap_free( servicesW
);
1800 /******************************************************************************
1801 * EnumServicesStatusW [ADVAPI32.@]
1804 EnumServicesStatusW( SC_HANDLE hmngr
, DWORD type
, DWORD state
, LPENUM_SERVICE_STATUSW
1805 services
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1806 LPDWORD resume_handle
)
1808 DWORD err
, i
, offset
, buflen
, count
, total_size
= 0;
1809 struct enum_service_status
*entry
;
1813 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr
, type
, state
, services
, size
, needed
,
1814 returned
, resume_handle
);
1818 SetLastError( ERROR_INVALID_HANDLE
);
1821 if (!needed
|| !returned
)
1823 SetLastError( ERROR_INVALID_ADDRESS
);
1827 /* make sure we pass a valid pointer */
1828 buflen
= max( size
, sizeof(*services
) );
1829 if (!(buf
= heap_alloc( buflen
)))
1831 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1837 err
= svcctl_EnumServicesStatusW( hmngr
, type
, state
, buf
, buflen
, needed
, &count
, resume_handle
);
1839 __EXCEPT(rpc_filter
)
1841 err
= map_exception_code( GetExceptionCode() );
1846 if (err
!= ERROR_SUCCESS
)
1848 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUSW */
1849 if (err
== ERROR_MORE_DATA
) *needed
*= 2;
1851 SetLastError( err
);
1855 entry
= (struct enum_service_status
*)buf
;
1856 for (i
= 0; i
< count
; i
++)
1858 total_size
+= sizeof(*services
);
1859 if (entry
->service_name
)
1861 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
1862 total_size
+= (strlenW( str
) + 1) * sizeof(WCHAR
);
1864 if (entry
->display_name
)
1866 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
1867 total_size
+= (strlenW( str
) + 1) * sizeof(WCHAR
);
1872 if (total_size
> size
)
1875 *needed
= total_size
;
1876 SetLastError( ERROR_MORE_DATA
);
1880 offset
= count
* sizeof(*services
);
1881 entry
= (struct enum_service_status
*)buf
;
1882 for (i
= 0; i
< count
; i
++)
1885 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
1886 str_size
= (strlenW( str
) + 1) * sizeof(WCHAR
);
1887 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ offset
);
1888 memcpy( services
[i
].lpServiceName
, str
, str_size
);
1891 if (!entry
->display_name
) services
[i
].lpDisplayName
= NULL
;
1894 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
1895 str_size
= (strlenW( str
) + 1) * sizeof(WCHAR
);
1896 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ offset
);
1897 memcpy( services
[i
].lpDisplayName
, str
, str_size
);
1900 services
[i
].ServiceStatus
= entry
->service_status
;
1910 /******************************************************************************
1911 * EnumServicesStatusExA [ADVAPI32.@]
1914 EnumServicesStatusExA( SC_HANDLE hmngr
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1915 LPBYTE buffer
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1916 LPDWORD resume_handle
, LPCSTR group
)
1920 ENUM_SERVICE_STATUS_PROCESSA
*services
= (ENUM_SERVICE_STATUS_PROCESSA
*)buffer
;
1921 ENUM_SERVICE_STATUS_PROCESSW
*servicesW
= NULL
;
1922 WCHAR
*groupW
= NULL
;
1926 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr
, level
, type
, state
, buffer
,
1927 size
, needed
, returned
, resume_handle
, debugstr_a(group
));
1929 sz
= max( 2 * size
, sizeof(*servicesW
) );
1930 if (!(servicesW
= heap_alloc( sz
)))
1932 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1937 int len
= MultiByteToWideChar( CP_ACP
, 0, group
, -1, NULL
, 0 );
1938 if (!(groupW
= heap_alloc( len
* sizeof(WCHAR
) )))
1940 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1941 heap_free( servicesW
);
1944 MultiByteToWideChar( CP_ACP
, 0, group
, -1, groupW
, len
* sizeof(WCHAR
) );
1947 ret
= EnumServicesStatusExW( hmngr
, level
, type
, state
, (BYTE
*)servicesW
, sz
,
1948 needed
, returned
, resume_handle
, groupW
);
1949 if (!ret
) goto done
;
1951 p
= (char *)services
+ *returned
* sizeof(ENUM_SERVICE_STATUS_PROCESSA
);
1952 n
= size
- (p
- (char *)services
);
1954 for (i
= 0; i
< *returned
; i
++)
1956 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpServiceName
, -1, p
, n
, NULL
, NULL
);
1958 services
[i
].lpServiceName
= p
;
1961 if (servicesW
[i
].lpDisplayName
)
1963 sz
= WideCharToMultiByte( CP_ACP
, 0, servicesW
[i
].lpDisplayName
, -1, p
, n
, NULL
, NULL
);
1965 services
[i
].lpDisplayName
= p
;
1969 else services
[i
].lpDisplayName
= NULL
;
1970 services
[i
].ServiceStatusProcess
= servicesW
[i
].ServiceStatusProcess
;
1976 heap_free( servicesW
);
1977 heap_free( groupW
);
1981 /******************************************************************************
1982 * EnumServicesStatusExW [ADVAPI32.@]
1985 EnumServicesStatusExW( SC_HANDLE hmngr
, SC_ENUM_TYPE level
, DWORD type
, DWORD state
,
1986 LPBYTE buffer
, DWORD size
, LPDWORD needed
, LPDWORD returned
,
1987 LPDWORD resume_handle
, LPCWSTR group
)
1989 DWORD err
, i
, offset
, buflen
, count
, total_size
= 0;
1990 ENUM_SERVICE_STATUS_PROCESSW
*services
= (ENUM_SERVICE_STATUS_PROCESSW
*)buffer
;
1991 struct enum_service_status_process
*entry
;
1995 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr
, level
, type
, state
, buffer
,
1996 size
, needed
, returned
, resume_handle
, debugstr_w(group
));
1998 if (level
!= SC_ENUM_PROCESS_INFO
)
2000 SetLastError( ERROR_INVALID_LEVEL
);
2005 SetLastError( ERROR_INVALID_HANDLE
);
2008 if (!needed
|| !returned
)
2010 SetLastError( ERROR_INVALID_ADDRESS
);
2014 /* make sure we pass a valid pointer */
2015 buflen
= max( size
, sizeof(*services
) );
2016 if (!(buf
= heap_alloc( buflen
)))
2018 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
2024 err
= svcctl_EnumServicesStatusExW( hmngr
, SC_ENUM_PROCESS_INFO
, type
, state
, buf
, buflen
, needed
,
2025 &count
, resume_handle
, group
);
2027 __EXCEPT(rpc_filter
)
2029 err
= map_exception_code( GetExceptionCode() );
2034 if (err
!= ERROR_SUCCESS
)
2036 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
2037 if (err
== ERROR_MORE_DATA
) *needed
*= 2;
2039 SetLastError( err
);
2043 entry
= (struct enum_service_status_process
*)buf
;
2044 for (i
= 0; i
< count
; i
++)
2046 total_size
+= sizeof(*services
);
2047 if (entry
->service_name
)
2049 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
2050 total_size
+= (strlenW( str
) + 1) * sizeof(WCHAR
);
2052 if (entry
->display_name
)
2054 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
2055 total_size
+= (strlenW( str
) + 1) * sizeof(WCHAR
);
2060 if (total_size
> size
)
2063 *needed
= total_size
;
2064 SetLastError( ERROR_MORE_DATA
);
2068 offset
= count
* sizeof(*services
);
2069 entry
= (struct enum_service_status_process
*)buf
;
2070 for (i
= 0; i
< count
; i
++)
2073 str
= (const WCHAR
*)(buf
+ entry
->service_name
);
2074 str_size
= (strlenW( str
) + 1) * sizeof(WCHAR
);
2075 services
[i
].lpServiceName
= (WCHAR
*)((char *)services
+ offset
);
2076 memcpy( services
[i
].lpServiceName
, str
, str_size
);
2079 if (!entry
->display_name
) services
[i
].lpDisplayName
= NULL
;
2082 str
= (const WCHAR
*)(buf
+ entry
->display_name
);
2083 str_size
= (strlenW( str
) + 1) * sizeof(WCHAR
);
2084 services
[i
].lpDisplayName
= (WCHAR
*)((char *)services
+ offset
);
2085 memcpy( services
[i
].lpDisplayName
, str
, str_size
);
2088 services
[i
].ServiceStatusProcess
= entry
->service_status_process
;
2098 /******************************************************************************
2099 * GetServiceKeyNameA [ADVAPI32.@]
2101 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2102 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2104 LPWSTR lpDisplayNameW
, lpServiceNameW
;
2108 TRACE("%p %s %p %p\n", hSCManager
,
2109 debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2111 lpDisplayNameW
= SERV_dup(lpDisplayName
);
2113 lpServiceNameW
= heap_alloc(*lpcchBuffer
* sizeof(WCHAR
));
2115 lpServiceNameW
= NULL
;
2117 sizeW
= *lpcchBuffer
;
2118 if (!GetServiceKeyNameW(hSCManager
, lpDisplayNameW
, lpServiceNameW
, &sizeW
))
2120 if (lpServiceName
&& *lpcchBuffer
)
2121 lpServiceName
[0] = 0;
2122 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
2126 if (!WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, (sizeW
+ 1), lpServiceName
,
2127 *lpcchBuffer
, NULL
, NULL
))
2129 if (*lpcchBuffer
&& lpServiceName
)
2130 lpServiceName
[0] = 0;
2131 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, -1, NULL
, 0, NULL
, NULL
);
2135 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
2139 heap_free(lpServiceNameW
);
2140 heap_free(lpDisplayNameW
);
2144 /******************************************************************************
2145 * GetServiceKeyNameW [ADVAPI32.@]
2147 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2148 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2154 TRACE("%p %s %p %p\n", hSCManager
,
2155 debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2159 SetLastError( ERROR_INVALID_HANDLE
);
2163 /* provide a buffer if the caller didn't */
2164 if (!lpServiceName
|| *lpcchBuffer
< 2)
2166 lpServiceName
= buffer
;
2167 /* A size of 1 would be enough, but tests show that Windows returns 2,
2168 * probably because of a WCHAR/bytes mismatch in their code.
2173 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2174 * includes the nul-terminator on input. */
2175 size
= *lpcchBuffer
- 1;
2179 err
= svcctl_GetServiceKeyNameW(hSCManager
, lpDisplayName
, lpServiceName
,
2182 __EXCEPT(rpc_filter
)
2184 err
= map_exception_code(GetExceptionCode());
2188 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2189 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
2190 *lpcchBuffer
= size
;
2194 return err
== ERROR_SUCCESS
;
2197 /******************************************************************************
2198 * QueryServiceLockStatusA [ADVAPI32.@]
2200 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2201 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2202 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2204 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2209 /******************************************************************************
2210 * QueryServiceLockStatusW [ADVAPI32.@]
2212 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2213 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2214 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2216 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2221 /******************************************************************************
2222 * GetServiceDisplayNameA [ADVAPI32.@]
2224 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2225 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2227 LPWSTR lpServiceNameW
, lpDisplayNameW
;
2231 TRACE("%p %s %p %p\n", hSCManager
,
2232 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2234 lpServiceNameW
= SERV_dup(lpServiceName
);
2236 lpDisplayNameW
= heap_alloc(*lpcchBuffer
* sizeof(WCHAR
));
2238 lpDisplayNameW
= NULL
;
2240 sizeW
= *lpcchBuffer
;
2241 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
2243 if (lpDisplayName
&& *lpcchBuffer
)
2244 lpDisplayName
[0] = 0;
2245 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
2249 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
2250 *lpcchBuffer
, NULL
, NULL
))
2252 if (*lpcchBuffer
&& lpDisplayName
)
2253 lpDisplayName
[0] = 0;
2254 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
2258 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2259 * (but if the function succeeded it means that is a good upper estimation of the size) */
2263 heap_free(lpDisplayNameW
);
2264 heap_free(lpServiceNameW
);
2268 /******************************************************************************
2269 * GetServiceDisplayNameW [ADVAPI32.@]
2271 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2272 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2278 TRACE("%p %s %p %p\n", hSCManager
,
2279 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2283 SetLastError( ERROR_INVALID_HANDLE
);
2287 /* provide a buffer if the caller didn't */
2288 if (!lpDisplayName
|| *lpcchBuffer
< 2)
2290 lpDisplayName
= buffer
;
2291 /* A size of 1 would be enough, but tests show that Windows returns 2,
2292 * probably because of a WCHAR/bytes mismatch in their code.
2297 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
2298 * includes the nul-terminator on input. */
2299 size
= *lpcchBuffer
- 1;
2303 err
= svcctl_GetServiceDisplayNameW(hSCManager
, lpServiceName
, lpDisplayName
,
2306 __EXCEPT(rpc_filter
)
2308 err
= map_exception_code(GetExceptionCode());
2312 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2313 if (err
== ERROR_SUCCESS
|| err
== ERROR_INSUFFICIENT_BUFFER
)
2314 *lpcchBuffer
= size
;
2318 return err
== ERROR_SUCCESS
;
2321 /******************************************************************************
2322 * ChangeServiceConfigW [ADVAPI32.@]
2324 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2325 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2326 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2327 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2332 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2333 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2334 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2335 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2336 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2338 cb_pwd
= lpPassword
? (strlenW(lpPassword
) + 1)*sizeof(WCHAR
) : 0;
2342 err
= svcctl_ChangeServiceConfigW(hService
, dwServiceType
,
2343 dwStartType
, dwErrorControl
, lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
,
2344 (const BYTE
*)lpDependencies
, multisz_cb(lpDependencies
), lpServiceStartName
,
2345 (const BYTE
*)lpPassword
, cb_pwd
, lpDisplayName
);
2347 __EXCEPT(rpc_filter
)
2349 err
= map_exception_code(GetExceptionCode());
2353 if (err
!= ERROR_SUCCESS
)
2356 return err
== ERROR_SUCCESS
;
2359 /******************************************************************************
2360 * ChangeServiceConfigA [ADVAPI32.@]
2362 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2363 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2364 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2365 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2367 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2368 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2371 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2372 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2373 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2374 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2375 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2377 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2378 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2379 wDependencies
= SERV_dupmulti( lpDependencies
);
2380 wServiceStartName
= SERV_dup( lpServiceStartName
);
2381 wPassword
= SERV_dup( lpPassword
);
2382 wDisplayName
= SERV_dup( lpDisplayName
);
2384 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2385 dwStartType
, dwErrorControl
, wBinaryPathName
,
2386 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2387 wServiceStartName
, wPassword
, wDisplayName
);
2389 heap_free( wBinaryPathName
);
2390 heap_free( wLoadOrderGroup
);
2391 heap_free( wDependencies
);
2392 heap_free( wServiceStartName
);
2393 heap_free( wPassword
);
2394 heap_free( wDisplayName
);
2399 /******************************************************************************
2400 * ChangeServiceConfig2A [ADVAPI32.@]
2402 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2407 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2409 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2411 LPSERVICE_DESCRIPTIONA sd
= lpInfo
;
2412 SERVICE_DESCRIPTIONW sdw
;
2414 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2416 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2418 heap_free( sdw
.lpDescription
);
2420 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2422 LPSERVICE_FAILURE_ACTIONSA fa
= lpInfo
;
2423 SERVICE_FAILURE_ACTIONSW faw
;
2425 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2426 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2427 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2428 faw
.cActions
= fa
->cActions
;
2429 faw
.lpsaActions
= fa
->lpsaActions
;
2431 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2433 heap_free( faw
.lpRebootMsg
);
2434 heap_free( faw
.lpCommand
);
2436 else if (dwInfoLevel
== SERVICE_CONFIG_PRESHUTDOWN_INFO
)
2438 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, lpInfo
);
2441 SetLastError( ERROR_INVALID_PARAMETER
);
2446 /******************************************************************************
2447 * ChangeServiceConfig2W [ADVAPI32.@]
2449 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2452 SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo
;
2457 SC_RPC_CONFIG_INFOW info
;
2459 info
.dwInfoLevel
= dwInfoLevel
;
2460 if (dwInfoLevel
== SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO
)
2462 SERVICE_REQUIRED_PRIVILEGES_INFOW
*privinfo
= lpInfo
;
2465 for (p
= privinfo
->pmszRequiredPrivileges
; *p
; p
+= strlenW(p
) + 1);
2466 rpc_privinfo
.cbRequiredPrivileges
=
2467 (p
- privinfo
->pmszRequiredPrivileges
+ 1) * sizeof(WCHAR
);
2468 rpc_privinfo
.pRequiredPrivileges
= (BYTE
*)privinfo
->pmszRequiredPrivileges
;
2469 info
.u
.privinfo
= &rpc_privinfo
;
2472 info
.u
.descr
= lpInfo
;
2473 err
= svcctl_ChangeServiceConfig2W( hService
, info
);
2475 __EXCEPT(rpc_filter
)
2477 err
= map_exception_code(GetExceptionCode());
2481 if (err
!= ERROR_SUCCESS
)
2484 return err
== ERROR_SUCCESS
;
2487 NTSTATUS
SERV_QueryServiceObjectSecurity(SC_HANDLE hService
,
2488 SECURITY_INFORMATION dwSecurityInformation
,
2489 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2490 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2492 SECURITY_DESCRIPTOR descriptor
;
2497 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2498 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2500 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2501 FIXME("information %d not supported\n", dwSecurityInformation
);
2503 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2505 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2506 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2509 status
= RtlMakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2510 *pcbBytesNeeded
= size
;
2514 /******************************************************************************
2515 * QueryServiceObjectSecurity [ADVAPI32.@]
2517 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2518 SECURITY_INFORMATION dwSecurityInformation
,
2519 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2520 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2522 NTSTATUS status
= SERV_QueryServiceObjectSecurity(hService
, dwSecurityInformation
, lpSecurityDescriptor
,
2523 cbBufSize
, pcbBytesNeeded
);
2524 if (status
!= STATUS_SUCCESS
)
2526 SetLastError(RtlNtStatusToDosError(status
));
2532 /******************************************************************************
2533 * SetServiceObjectSecurity [ADVAPI32.@]
2536 * - SetSecurityInfo should be updated to call this function once it's implemented.
2538 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2539 SECURITY_INFORMATION dwSecurityInformation
,
2540 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2542 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2546 /******************************************************************************
2547 * SetServiceBits [ADVAPI32.@]
2549 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2550 DWORD dwServiceBits
,
2552 BOOL bUpdateImmediately
)
2554 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2555 bSetBitsOn
, bUpdateImmediately
);
2559 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2560 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
2562 LPHANDLER_FUNCTION func
= context
;
2565 return ERROR_SUCCESS
;
2568 /******************************************************************************
2569 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2571 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
2573 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
2576 /******************************************************************************
2577 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2579 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
2581 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
2584 /******************************************************************************
2585 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2587 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
2590 SERVICE_STATUS_HANDLE ret
;
2592 nameW
= SERV_dup(name
);
2593 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
2598 /******************************************************************************
2599 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2601 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2602 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2604 service_data
*service
;
2605 SC_HANDLE hService
= 0;
2607 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2609 EnterCriticalSection( &service_cs
);
2610 if ((service
= find_service_by_name( lpServiceName
)))
2612 service
->handler
= lpHandlerProc
;
2613 service
->context
= lpContext
;
2614 hService
= service
->handle
;
2616 LeaveCriticalSection( &service_cs
);
2618 if (!hService
) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
2619 return (SERVICE_STATUS_HANDLE
)hService
;
2622 /******************************************************************************
2623 * EnumDependentServicesA [ADVAPI32.@]
2625 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2626 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2627 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2629 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2630 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2632 *lpServicesReturned
= 0;
2636 /******************************************************************************
2637 * EnumDependentServicesW [ADVAPI32.@]
2639 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2640 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2641 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2643 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2644 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2646 *lpServicesReturned
= 0;
2650 static DWORD WINAPI
notify_thread(void *user
)
2653 notify_data
*data
= user
;
2654 SC_RPC_NOTIFY_PARAMS_LIST
*list
= NULL
;
2655 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2
*cparams
;
2660 /* GetNotifyResults blocks until there is an event */
2661 err
= svcctl_GetNotifyResults(data
->notify_handle
, &list
);
2663 __EXCEPT(rpc_filter
)
2665 err
= map_exception_code(GetExceptionCode());
2669 EnterCriticalSection( &service_cs
);
2671 list_remove(&data
->entry
);
2673 LeaveCriticalSection( &service_cs
);
2675 if (err
== ERROR_SUCCESS
&& list
)
2677 cparams
= list
->NotifyParamsArray
[0].u
.params
;
2679 data
->notify_buffer
->dwNotificationStatus
= cparams
->dwNotificationStatus
;
2680 memcpy(&data
->notify_buffer
->ServiceStatus
, &cparams
->ServiceStatus
,
2681 sizeof(SERVICE_STATUS_PROCESS
));
2682 data
->notify_buffer
->dwNotificationTriggered
= cparams
->dwNotificationTriggered
;
2683 data
->notify_buffer
->pszServiceNames
= NULL
;
2685 QueueUserAPC((PAPCFUNC
)data
->notify_buffer
->pfnNotifyCallback
,
2686 data
->calling_thread
, (ULONG_PTR
)data
->notify_buffer
);
2688 HeapFree(GetProcessHeap(), 0, list
);
2691 WARN("GetNotifyResults server call failed: %u\n", err
);
2696 err
= svcctl_CloseNotifyHandle(&data
->notify_handle
, &dummy
);
2698 __EXCEPT(rpc_filter
)
2700 err
= map_exception_code(GetExceptionCode());
2704 if (err
!= ERROR_SUCCESS
)
2705 WARN("CloseNotifyHandle server call failed: %u\n", err
);
2707 CloseHandle(data
->calling_thread
);
2708 HeapFree(GetProcessHeap(), 0, data
);
2713 /******************************************************************************
2714 * NotifyServiceStatusChangeW [ADVAPI32.@]
2716 DWORD WINAPI
NotifyServiceStatusChangeW(SC_HANDLE hService
, DWORD dwNotifyMask
,
2717 SERVICE_NOTIFYW
*pNotifyBuffer
)
2720 BOOL b_dummy
= FALSE
;
2724 TRACE("%p 0x%x %p\n", hService
, dwNotifyMask
, pNotifyBuffer
);
2726 data
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*data
));
2728 return ERROR_NOT_ENOUGH_MEMORY
;
2730 data
->service
= hService
;
2731 data
->notify_buffer
= pNotifyBuffer
;
2732 if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
2733 GetCurrentProcess(), &data
->calling_thread
, 0, FALSE
,
2734 DUPLICATE_SAME_ACCESS
))
2736 ERR("DuplicateHandle failed: %u\n", GetLastError());
2737 HeapFree(GetProcessHeap(), 0, data
);
2738 return ERROR_NOT_ENOUGH_MEMORY
;
2741 data
->params
.dwInfoLevel
= 2;
2742 data
->params
.u
.params
= &data
->cparams
;
2744 data
->cparams
.dwNotifyMask
= dwNotifyMask
;
2746 EnterCriticalSection( &service_cs
);
2750 err
= svcctl_NotifyServiceStatusChange(hService
, data
->params
,
2751 &g_dummy
, &g_dummy
, &b_dummy
, &data
->notify_handle
);
2753 __EXCEPT(rpc_filter
)
2755 err
= map_exception_code(GetExceptionCode());
2759 if (err
!= ERROR_SUCCESS
)
2761 WARN("NotifyServiceStatusChange server call failed: %u\n", err
);
2762 LeaveCriticalSection( &service_cs
);
2763 CloseHandle(data
->calling_thread
);
2764 CloseHandle(data
->ready_evt
);
2765 HeapFree(GetProcessHeap(), 0, data
);
2769 CloseHandle(CreateThread(NULL
, 0, ¬ify_thread
, data
, 0, NULL
));
2771 list_add_tail(¬ify_list
, &data
->entry
);
2773 LeaveCriticalSection( &service_cs
);
2775 return ERROR_SUCCESS
;