2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include "wine/port.h"
32 #define WIN32_NO_STATUS
38 #include "wine/unicode.h"
39 #include "wine/debug.h"
46 #include "advapi32_misc.h"
48 #include "wine/exception.h"
50 WINE_DEFAULT_DEBUG_CHANNEL(service);
52 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
54 return HeapAlloc(GetProcessHeap(), 0, len);
57 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
59 HeapFree(GetProcessHeap(), 0, ptr);
62 typedef struct service_data_t
64 LPHANDLER_FUNCTION_EX handler;
68 SC_HANDLE full_access_handle;
71 LPSERVICE_MAIN_FUNCTIONA a;
72 LPSERVICE_MAIN_FUNCTIONW w;
78 typedef struct dispatcher_data_t
84 static CRITICAL_SECTION service_cs;
85 static CRITICAL_SECTION_DEBUG service_cs_debug =
88 { &service_cs_debug.ProcessLocksList,
89 &service_cs_debug.ProcessLocksList },
90 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
92 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
94 static service_data **services;
95 static unsigned int nb_services;
96 static HANDLE service_event;
97 static HANDLE stop_event;
99 extern HANDLE CDECL __wine_make_process_system(void);
101 /******************************************************************************
102 * String management functions (same behaviour as strdup)
103 * NOTE: the caller of those functions is responsible for calling HeapFree
104 * in order to release the memory allocated by those functions.
106 LPWSTR SERV_dup( LPCSTR str )
113 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
114 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
115 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
119 static inline LPWSTR SERV_dupmulti(LPCSTR str)
127 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
128 n += (strlen( &str[n] ) + 1);
133 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
134 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
138 static inline DWORD multisz_cb(LPCWSTR wmultisz)
140 const WCHAR *wptr = wmultisz;
142 if (wmultisz == NULL)
146 wptr += lstrlenW(wptr)+1;
147 return (wptr - wmultisz + 1)*sizeof(WCHAR);
150 /******************************************************************************
151 * RPC connection with services.exe
154 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
156 WCHAR transport[] = SVCCTL_TRANSPORT;
157 WCHAR endpoint[] = SVCCTL_ENDPOINT;
158 RPC_WSTR binding_str;
162 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
163 if (status != RPC_S_OK)
165 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
169 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
170 RpcStringFreeW(&binding_str);
172 if (status != RPC_S_OK)
174 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
181 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
186 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
188 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
191 static DWORD map_exception_code(DWORD exception_code)
193 switch (exception_code)
195 case RPC_X_NULL_REF_POINTER:
196 return ERROR_INVALID_ADDRESS;
197 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
198 case RPC_X_BYTE_COUNT_TOO_SMALL:
199 return ERROR_INVALID_PARAMETER;
200 case RPC_S_INVALID_BINDING:
201 case RPC_X_SS_IN_NULL_CONTEXT:
202 return ERROR_INVALID_HANDLE;
204 return exception_code;
208 /******************************************************************************
209 * Service IPC functions
211 static LPWSTR service_get_pipe_name(void)
213 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
214 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
215 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
216 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
217 'C','o','n','t','r','o','l','\\',
218 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
221 HKEY service_current_key;
222 DWORD service_current;
226 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
227 KEY_QUERY_VALUE, &service_current_key);
228 if (ret != ERROR_SUCCESS)
230 len = sizeof(service_current);
231 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
232 (BYTE *)&service_current, &len);
233 RegCloseKey(service_current_key);
234 if (ret != ERROR_SUCCESS || type != REG_DWORD)
236 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
237 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
240 snprintfW(name, len, format, service_current);
244 static HANDLE service_open_pipe(void)
246 LPWSTR szPipe = service_get_pipe_name();
247 HANDLE handle = INVALID_HANDLE_VALUE;
250 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
251 0, NULL, OPEN_ALWAYS, 0, NULL);
252 if (handle != INVALID_HANDLE_VALUE)
254 if (GetLastError() != ERROR_PIPE_BUSY)
256 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
257 HeapFree(GetProcessHeap(), 0, szPipe);
262 static service_data *find_service_by_name( const WCHAR *name )
266 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
268 for (i = 0; i < nb_services; i++)
269 if (!strcmpiW( name, services[i]->name )) return services[i];
273 /******************************************************************************
276 * Call into the main service routine provided by StartServiceCtrlDispatcher.
278 static DWORD WINAPI service_thread(LPVOID arg)
280 service_data *info = arg;
281 LPWSTR str = info->args;
282 DWORD argc = 0, len = 0;
288 len += strlenW(&str[len]) + 1;
297 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
298 for (argc=0, p=str; *p; p += strlenW(p) + 1)
302 info->proc.w(argc, argv);
303 HeapFree(GetProcessHeap(), 0, argv);
307 LPSTR strA, *argv, p;
310 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
311 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
312 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
314 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
315 for (argc=0, p=strA; *p; p += strlen(p) + 1)
319 info->proc.a(argc, argv);
320 HeapFree(GetProcessHeap(), 0, argv);
321 HeapFree(GetProcessHeap(), 0, strA);
326 /******************************************************************************
327 * service_handle_start
329 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
331 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
335 WARN("service is not stopped\n");
336 return ERROR_SERVICE_ALREADY_RUNNING;
339 HeapFree(GetProcessHeap(), 0, service->args);
340 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
341 memcpy( service->args, data, count * sizeof(WCHAR) );
342 service->thread = CreateThread( NULL, 0, service_thread,
344 SetEvent( service_event ); /* notify the main loop */
348 /******************************************************************************
349 * service_handle_control
351 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
353 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
355 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
357 if (service->handler)
358 ret = service->handler(dwControl, 0, NULL, service->context);
362 /******************************************************************************
363 * service_control_dispatcher
365 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
367 dispatcher_data *disp = arg;
369 /* dispatcher loop */
372 service_data *service;
373 service_start_info info;
376 DWORD data_size = 0, count, result;
378 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
381 if (GetLastError() != ERROR_BROKEN_PIPE)
382 ERR( "pipe read failed error %u\n", GetLastError() );
385 if (count != FIELD_OFFSET(service_start_info,data))
387 ERR( "partial pipe read %u\n", count );
390 if (count < info.total_size)
392 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
393 data = HeapAlloc( GetProcessHeap(), 0, data_size );
394 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
397 if (GetLastError() != ERROR_BROKEN_PIPE)
398 ERR( "pipe read failed error %u\n", GetLastError() );
399 HeapFree( GetProcessHeap(), 0, data );
402 if (count != data_size)
404 ERR( "partial pipe read %u/%u\n", count, data_size );
405 HeapFree( GetProcessHeap(), 0, data );
410 /* find the service */
412 if (!(service = find_service_by_name( data )))
414 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
415 result = ERROR_INVALID_PARAMETER;
419 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
421 /* handle the request */
424 case WINESERV_STARTINFO:
425 if (!service->handle)
427 if (!(service->handle = OpenServiceW( disp->manager, data, SERVICE_SET_STATUS )) ||
428 !(service->full_access_handle = OpenServiceW( disp->manager, data,
429 GENERIC_READ|GENERIC_WRITE )))
430 FIXME( "failed to open service %s\n", debugstr_w(data) );
432 result = service_handle_start(service, data, data_size / sizeof(WCHAR));
434 case WINESERV_SENDCONTROL:
435 result = service_handle_control(service, info.control);
438 ERR("received invalid command %u\n", info.cmd);
439 result = ERROR_INVALID_PARAMETER;
444 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
445 HeapFree( GetProcessHeap(), 0, data );
448 CloseHandle( disp->pipe );
449 CloseServiceHandle( disp->manager );
450 HeapFree( GetProcessHeap(), 0, disp );
454 /******************************************************************************
455 * service_run_main_thread
457 static BOOL service_run_main_thread(void)
460 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
461 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
462 dispatcher_data *disp = HeapAlloc( GetProcessHeap(), 0, sizeof(*disp) );
464 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
467 ERR("failed to open service manager error %u\n", GetLastError());
468 HeapFree( GetProcessHeap(), 0, disp );
472 disp->pipe = service_open_pipe();
473 if (disp->pipe == INVALID_HANDLE_VALUE)
475 WARN("failed to create control pipe error %u\n", GetLastError());
476 CloseServiceHandle( disp->manager );
477 HeapFree( GetProcessHeap(), 0, disp );
478 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
482 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
483 stop_event = CreateEventW( NULL, FALSE, FALSE, NULL );
485 /* FIXME: service_control_dispatcher should be merged into the main thread */
486 wait_handles[0] = __wine_make_process_system();
487 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
488 wait_handles[2] = service_event;
489 wait_handles[3] = stop_event;
491 TRACE("Starting %d services running as process %d\n",
492 nb_services, GetCurrentProcessId());
494 /* wait for all the threads to pack up and exit */
497 EnterCriticalSection( &service_cs );
498 for (i = 0, n = 4; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
500 if (!services[i]->thread) continue;
501 wait_services[n] = i;
502 wait_handles[n++] = services[i]->thread;
504 LeaveCriticalSection( &service_cs );
506 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
507 if (!ret) /* system process event */
510 SERVICE_PRESHUTDOWN_INFO spi;
511 DWORD timeout = 5000;
514 EnterCriticalSection( &service_cs );
516 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
518 if (!services[i]->thread) continue;
520 res = QueryServiceStatus(services[i]->full_access_handle, &st);
522 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
524 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
525 (LPBYTE)&spi, sizeof(spi), &i );
528 FIXME("service should be able to delay shutdown\n");
529 timeout += spi.dwPreshutdownTimeout;
530 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN );
531 wait_handles[n++] = services[i]->thread;
534 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
536 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN );
537 wait_handles[n++] = services[i]->thread;
540 LeaveCriticalSection( &service_cs );
542 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
543 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
548 TRACE( "control dispatcher exited, shutting down\n" );
549 /* FIXME: we should maybe send a shutdown control to running services */
554 continue; /* rebuild the list */
562 services[wait_services[ret]]->thread = 0;
563 CloseHandle( wait_handles[ret] );
569 /******************************************************************************
570 * StartServiceCtrlDispatcherA [ADVAPI32.@]
572 * See StartServiceCtrlDispatcherW.
574 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
579 TRACE("%p\n", servent);
583 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
586 while (servent[nb_services].lpServiceName) nb_services++;
589 SetLastError( ERROR_INVALID_PARAMETER );
593 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
595 for (i = 0; i < nb_services; i++)
597 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
598 DWORD sz = FIELD_OFFSET( service_data, name[len] );
599 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
600 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
601 info->proc.a = servent[i].lpServiceProc;
602 info->unicode = FALSE;
606 return service_run_main_thread();
609 /******************************************************************************
610 * StartServiceCtrlDispatcherW [ADVAPI32.@]
612 * Connects a process containing one or more services to the service control
616 * servent [I] A list of the service names and service procedures
622 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
627 TRACE("%p\n", servent);
631 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
634 while (servent[nb_services].lpServiceName) nb_services++;
637 SetLastError( ERROR_INVALID_PARAMETER );
641 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
643 for (i = 0; i < nb_services; i++)
645 DWORD len = strlenW(servent[i].lpServiceName) + 1;
646 DWORD sz = FIELD_OFFSET( service_data, name[len] );
647 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
648 strcpyW(info->name, servent[i].lpServiceName);
649 info->proc.w = servent[i].lpServiceProc;
650 info->unicode = TRUE;
654 return service_run_main_thread();
657 /******************************************************************************
658 * LockServiceDatabase [ADVAPI32.@]
660 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
662 SC_RPC_LOCK hLock = NULL;
665 TRACE("%p\n",hSCManager);
669 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
673 err = map_exception_code(GetExceptionCode());
676 if (err != ERROR_SUCCESS)
684 /******************************************************************************
685 * UnlockServiceDatabase [ADVAPI32.@]
687 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
690 SC_RPC_LOCK hRpcLock = ScLock;
692 TRACE("%p\n",ScLock);
696 err = svcctl_UnlockServiceDatabase(&hRpcLock);
700 err = map_exception_code(GetExceptionCode());
703 if (err != ERROR_SUCCESS)
711 /******************************************************************************
712 * SetServiceStatus [ADVAPI32.@]
719 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
723 TRACE("%p %x %x %x %x %x %x %x\n", hService,
724 lpStatus->dwServiceType, lpStatus->dwCurrentState,
725 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
726 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
727 lpStatus->dwWaitHint);
731 err = svcctl_SetServiceStatus( hService, lpStatus );
735 err = map_exception_code(GetExceptionCode());
738 if (err != ERROR_SUCCESS)
744 if (lpStatus->dwCurrentState == SERVICE_STOPPED) {
745 SetEvent(stop_event);
746 CloseServiceHandle((SC_HANDLE)hService);
753 /******************************************************************************
754 * OpenSCManagerA [ADVAPI32.@]
756 * Establish a connection to the service control manager and open its database.
759 * lpMachineName [I] Pointer to machine name string
760 * lpDatabaseName [I] Pointer to database name string
761 * dwDesiredAccess [I] Type of access
764 * Success: A Handle to the service control manager database
767 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
768 DWORD dwDesiredAccess )
770 LPWSTR lpMachineNameW, lpDatabaseNameW;
773 lpMachineNameW = SERV_dup(lpMachineName);
774 lpDatabaseNameW = SERV_dup(lpDatabaseName);
775 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
776 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
777 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
781 /******************************************************************************
782 * OpenSCManagerW [ADVAPI32.@]
784 * See OpenSCManagerA.
786 DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
787 DWORD dwDesiredAccess, SC_HANDLE *handle )
791 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
792 debugstr_w(lpDatabaseName), dwDesiredAccess);
796 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
800 r = map_exception_code(GetExceptionCode());
804 if (r!=ERROR_SUCCESS)
807 TRACE("returning %p\n", *handle);
811 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
812 DWORD dwDesiredAccess )
814 SC_HANDLE handle = 0;
817 r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle);
818 if (r!=ERROR_SUCCESS)
823 /******************************************************************************
824 * ControlService [ADVAPI32.@]
826 * Send a control code to a service.
829 * hService [I] Handle of the service control manager database
830 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
831 * lpServiceStatus [O] Destination for the status of the service, if available
838 * Unlike M$' implementation, control requests are not serialized and may be
839 * processed asynchronously.
841 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
842 LPSERVICE_STATUS lpServiceStatus )
846 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
850 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
854 err = map_exception_code(GetExceptionCode());
857 if (err != ERROR_SUCCESS)
866 /******************************************************************************
867 * CloseServiceHandle [ADVAPI32.@]
869 * Close a handle to a service or the service control manager database.
872 * hSCObject [I] Handle to service or service control manager database
879 CloseServiceHandle( SC_HANDLE hSCObject )
883 TRACE("%p\n", hSCObject);
887 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
891 err = map_exception_code(GetExceptionCode());
895 if (err != ERROR_SUCCESS)
904 /******************************************************************************
905 * OpenServiceA [ADVAPI32.@]
907 * Open a handle to a service.
910 * hSCManager [I] Handle of the service control manager database
911 * lpServiceName [I] Name of the service to open
912 * dwDesiredAccess [I] Access required to the service
915 * Success: Handle to the service
918 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
919 DWORD dwDesiredAccess )
921 LPWSTR lpServiceNameW;
924 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
926 lpServiceNameW = SERV_dup(lpServiceName);
927 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
928 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
933 /******************************************************************************
934 * OpenServiceW [ADVAPI32.@]
938 DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
939 DWORD dwDesiredAccess, SC_HANDLE *handle )
943 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
946 return ERROR_INVALID_HANDLE;
950 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
954 err = map_exception_code(GetExceptionCode());
958 if (err != ERROR_SUCCESS)
961 TRACE("returning %p\n", *handle);
965 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
966 DWORD dwDesiredAccess)
968 SC_HANDLE handle = 0;
971 err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle);
972 if (err != ERROR_SUCCESS)
977 /******************************************************************************
978 * CreateServiceW [ADVAPI32.@]
981 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
982 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
983 DWORD dwServiceType, DWORD dwStartType,
984 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
985 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
986 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
989 SC_HANDLE handle = 0;
993 TRACE("%p %s %s\n", hSCManager,
994 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
998 SetLastError( ERROR_INVALID_HANDLE );
1003 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1009 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
1010 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1011 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1012 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1013 (SC_RPC_HANDLE *)&handle);
1015 __EXCEPT(rpc_filter)
1017 err = map_exception_code(GetExceptionCode());
1021 if (err != ERROR_SUCCESS)
1030 /******************************************************************************
1031 * CreateServiceA [ADVAPI32.@]
1034 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1035 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1036 DWORD dwServiceType, DWORD dwStartType,
1037 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1038 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1039 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1042 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1043 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1046 TRACE("%p %s %s\n", hSCManager,
1047 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1049 lpServiceNameW = SERV_dup( lpServiceName );
1050 lpDisplayNameW = SERV_dup( lpDisplayName );
1051 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1052 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1053 lpDependenciesW = SERV_dupmulti( lpDependencies );
1054 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1055 lpPasswordW = SERV_dup( lpPassword );
1057 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1058 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1059 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1060 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1062 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1063 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1064 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1065 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1066 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1067 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1068 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1074 /******************************************************************************
1075 * DeleteService [ADVAPI32.@]
1077 * Delete a service from the service control manager database.
1080 * hService [I] Handle of the service to delete
1086 BOOL WINAPI DeleteService( SC_HANDLE hService )
1092 err = svcctl_DeleteService(hService);
1094 __EXCEPT(rpc_filter)
1096 err = map_exception_code(GetExceptionCode());
1109 /******************************************************************************
1110 * StartServiceA [ADVAPI32.@]
1115 * hService [I] Handle of service
1116 * dwNumServiceArgs [I] Number of arguments
1117 * lpServiceArgVectors [I] Address of array of argument strings
1120 * - NT implements this function using an obscure RPC call.
1121 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1122 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1123 * - This will only work for shared address space. How should the service
1124 * args be transferred when address spaces are separated?
1125 * - Can only start one service at a time.
1126 * - Has no concept of privilege.
1132 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1133 LPCSTR *lpServiceArgVectors )
1135 LPWSTR *lpwstr=NULL;
1139 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1141 if (dwNumServiceArgs)
1142 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1143 dwNumServiceArgs*sizeof(LPWSTR) );
1145 for(i=0; i<dwNumServiceArgs; i++)
1146 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1148 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1150 if (dwNumServiceArgs)
1152 for(i=0; i<dwNumServiceArgs; i++)
1153 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1154 HeapFree(GetProcessHeap(), 0, lpwstr);
1161 /******************************************************************************
1162 * StartServiceW [ADVAPI32.@]
1164 * See StartServiceA.
1166 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1167 LPCWSTR *lpServiceArgVectors)
1171 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1175 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1177 __EXCEPT(rpc_filter)
1179 err = map_exception_code(GetExceptionCode());
1182 if (err != ERROR_SUCCESS)
1191 /******************************************************************************
1192 * QueryServiceStatus [ADVAPI32.@]
1195 * hService [I] Handle to service to get information about
1196 * lpservicestatus [O] buffer to receive the status information for the service
1199 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1200 LPSERVICE_STATUS lpservicestatus)
1202 SERVICE_STATUS_PROCESS SvcStatusData;
1206 TRACE("%p %p\n", hService, lpservicestatus);
1210 SetLastError(ERROR_INVALID_HANDLE);
1213 if (!lpservicestatus)
1215 SetLastError(ERROR_INVALID_ADDRESS);
1219 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1220 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1221 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1226 /******************************************************************************
1227 * QueryServiceStatusEx [ADVAPI32.@]
1229 * Get information about a service.
1232 * hService [I] Handle to service to get information about
1233 * InfoLevel [I] Level of information to get
1234 * lpBuffer [O] Destination for requested information
1235 * cbBufSize [I] Size of lpBuffer in bytes
1236 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1242 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1243 LPBYTE lpBuffer, DWORD cbBufSize,
1244 LPDWORD pcbBytesNeeded)
1248 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1250 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1252 err = ERROR_INVALID_LEVEL;
1254 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1256 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1257 err = ERROR_INSUFFICIENT_BUFFER;
1263 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1265 __EXCEPT(rpc_filter)
1267 err = map_exception_code(GetExceptionCode());
1271 if (err != ERROR_SUCCESS)
1279 /******************************************************************************
1280 * QueryServiceConfigA [ADVAPI32.@]
1282 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1283 DWORD size, LPDWORD needed )
1288 QUERY_SERVICE_CONFIGW *configW;
1290 TRACE("%p %p %d %p\n", hService, config, size, needed);
1292 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1294 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1297 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1298 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1299 if (!ret) goto done;
1301 config->dwServiceType = configW->dwServiceType;
1302 config->dwStartType = configW->dwStartType;
1303 config->dwErrorControl = configW->dwErrorControl;
1304 config->lpBinaryPathName = NULL;
1305 config->lpLoadOrderGroup = NULL;
1306 config->dwTagId = configW->dwTagId;
1307 config->lpDependencies = NULL;
1308 config->lpServiceStartName = NULL;
1309 config->lpDisplayName = NULL;
1311 p = (LPSTR)(config + 1);
1312 n = size - sizeof(*config);
1315 #define MAP_STR(str) \
1319 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1320 if (!sz) goto done; \
1327 MAP_STR( lpBinaryPathName );
1328 MAP_STR( lpLoadOrderGroup );
1329 MAP_STR( lpDependencies );
1330 MAP_STR( lpServiceStartName );
1331 MAP_STR( lpDisplayName );
1334 *needed = p - (LPSTR)config;
1338 HeapFree( GetProcessHeap(), 0, buffer );
1342 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1349 memset(*buf, 0, cb);
1353 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1354 memcpy(*buf, *string_ptr, cb);
1355 MIDL_user_free(*string_ptr);
1358 *string_ptr = (LPWSTR)*buf;
1364 static DWORD size_string(LPCWSTR string)
1366 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1369 /******************************************************************************
1370 * QueryServiceConfigW [ADVAPI32.@]
1373 QueryServiceConfigW( SC_HANDLE hService,
1374 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1375 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1377 QUERY_SERVICE_CONFIGW config;
1382 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1383 cbBufSize, pcbBytesNeeded);
1385 memset(&config, 0, sizeof(config));
1389 err = svcctl_QueryServiceConfigW(hService, &config);
1391 __EXCEPT(rpc_filter)
1393 err = map_exception_code(GetExceptionCode());
1397 if (err != ERROR_SUCCESS)
1399 TRACE("services.exe: error %u\n", err);
1404 /* calculate the size required first */
1405 total = sizeof (QUERY_SERVICE_CONFIGW);
1406 total += size_string(config.lpBinaryPathName);
1407 total += size_string(config.lpLoadOrderGroup);
1408 total += size_string(config.lpDependencies);
1409 total += size_string(config.lpServiceStartName);
1410 total += size_string(config.lpDisplayName);
1412 *pcbBytesNeeded = total;
1414 /* if there's not enough memory, return an error */
1415 if( total > cbBufSize )
1417 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1418 MIDL_user_free(config.lpBinaryPathName);
1419 MIDL_user_free(config.lpLoadOrderGroup);
1420 MIDL_user_free(config.lpDependencies);
1421 MIDL_user_free(config.lpServiceStartName);
1422 MIDL_user_free(config.lpDisplayName);
1426 *lpServiceConfig = config;
1427 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1428 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1429 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1430 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1431 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1432 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1434 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1435 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1436 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1437 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1438 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1443 /******************************************************************************
1444 * QueryServiceConfig2A [ADVAPI32.@]
1447 * observed under win2k:
1448 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1449 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1451 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1452 DWORD size, LPDWORD needed)
1455 LPBYTE bufferW = NULL;
1458 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1460 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1461 if(!ret) goto cleanup;
1464 case SERVICE_CONFIG_DESCRIPTION:
1465 if (buffer && bufferW) {
1466 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1467 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1468 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1470 configA->lpDescription = (LPSTR)(configA + 1);
1471 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1472 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1474 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1476 configA->lpDescription = NULL;
1479 else configA->lpDescription = NULL;
1482 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1483 if (buffer && bufferW && *needed<=size)
1484 memcpy(buffer, bufferW, *needed);
1487 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1493 HeapFree( GetProcessHeap(), 0, bufferW);
1497 /******************************************************************************
1498 * QueryServiceConfig2W [ADVAPI32.@]
1500 * See QueryServiceConfig2A.
1502 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1503 DWORD size, LPDWORD needed)
1507 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1508 FIXME("Level %d not implemented\n", dwLevel);
1509 SetLastError(ERROR_INVALID_LEVEL);
1513 if(!buffer && size) {
1514 SetLastError(ERROR_INVALID_ADDRESS);
1518 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1522 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1524 __EXCEPT(rpc_filter)
1526 err = map_exception_code(GetExceptionCode());
1530 if (err != ERROR_SUCCESS)
1532 SetLastError( err );
1538 case SERVICE_CONFIG_DESCRIPTION:
1541 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1542 if (descr->lpDescription) /* make it an absolute pointer */
1543 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1551 /******************************************************************************
1552 * EnumServicesStatusA [ADVAPI32.@]
1555 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1556 services, DWORD size, LPDWORD needed, LPDWORD returned,
1557 LPDWORD resume_handle )
1561 ENUM_SERVICE_STATUSW *servicesW = NULL;
1565 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1566 returned, resume_handle);
1568 sz = max( 2 * size, sizeof(*servicesW) );
1569 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1571 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1575 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1576 if (!ret) goto done;
1578 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1579 n = size - (p - (char *)services);
1581 for (i = 0; i < *returned; i++)
1583 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1585 services[i].lpServiceName = p;
1588 if (servicesW[i].lpDisplayName)
1590 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1592 services[i].lpDisplayName = p;
1596 else services[i].lpDisplayName = NULL;
1597 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1603 HeapFree( GetProcessHeap(), 0, servicesW );
1607 /******************************************************************************
1608 * EnumServicesStatusW [ADVAPI32.@]
1611 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1612 services, DWORD size, LPDWORD needed, LPDWORD returned,
1613 LPDWORD resume_handle )
1616 ENUM_SERVICE_STATUSW dummy_status;
1618 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1619 returned, resume_handle);
1622 FIXME("resume handle not supported\n");
1626 SetLastError( ERROR_INVALID_HANDLE );
1630 /* make sure we pass a valid pointer */
1631 if (!services || size < sizeof(*services))
1633 services = &dummy_status;
1634 size = sizeof(dummy_status);
1639 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1641 __EXCEPT(rpc_filter)
1643 err = map_exception_code( GetExceptionCode() );
1647 if (err != ERROR_SUCCESS)
1649 SetLastError( err );
1653 for (i = 0; i < *returned; i++)
1655 /* convert buffer offsets into pointers */
1656 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1657 if (services[i].lpDisplayName)
1658 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1664 /******************************************************************************
1665 * EnumServicesStatusExA [ADVAPI32.@]
1668 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1669 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1670 LPDWORD resume_handle, LPCSTR group )
1674 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1675 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1676 WCHAR *groupW = NULL;
1680 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1681 size, needed, returned, resume_handle, debugstr_a(group));
1683 sz = max( 2 * size, sizeof(*servicesW) );
1684 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1686 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1691 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1692 if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1694 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1695 HeapFree( GetProcessHeap(), 0, servicesW );
1698 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1701 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1702 needed, returned, resume_handle, groupW );
1703 if (!ret) goto done;
1705 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1706 n = size - (p - (char *)services);
1708 for (i = 0; i < *returned; i++)
1710 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1712 services[i].lpServiceName = p;
1715 if (servicesW[i].lpDisplayName)
1717 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1719 services[i].lpDisplayName = p;
1723 else services[i].lpDisplayName = NULL;
1724 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1730 HeapFree( GetProcessHeap(), 0, servicesW );
1731 HeapFree( GetProcessHeap(), 0, groupW );
1735 /******************************************************************************
1736 * EnumServicesStatusExW [ADVAPI32.@]
1739 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1740 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1741 LPDWORD resume_handle, LPCWSTR group )
1744 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1745 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1747 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1748 size, needed, returned, resume_handle, debugstr_w(group));
1751 FIXME("resume handle not supported\n");
1753 if (level != SC_ENUM_PROCESS_INFO)
1755 SetLastError( ERROR_INVALID_LEVEL );
1760 SetLastError( ERROR_INVALID_HANDLE );
1764 /* make sure we pass a valid buffer pointer */
1765 if (!services || size < sizeof(*services))
1767 buffer = (BYTE *)&dummy_status;
1768 size = sizeof(dummy_status);
1773 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1776 __EXCEPT(rpc_filter)
1778 err = map_exception_code( GetExceptionCode() );
1782 if (err != ERROR_SUCCESS)
1784 SetLastError( err );
1788 for (i = 0; i < *returned; i++)
1790 /* convert buffer offsets into pointers */
1791 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1792 if (services[i].lpDisplayName)
1793 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1799 /******************************************************************************
1800 * GetServiceKeyNameA [ADVAPI32.@]
1802 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1803 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1805 LPWSTR lpDisplayNameW, lpServiceNameW;
1809 TRACE("%p %s %p %p\n", hSCManager,
1810 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1812 lpDisplayNameW = SERV_dup(lpDisplayName);
1814 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1816 lpServiceNameW = NULL;
1818 sizeW = *lpcchBuffer;
1819 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1821 if (lpServiceName && *lpcchBuffer)
1822 lpServiceName[0] = 0;
1823 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1827 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1828 *lpcchBuffer, NULL, NULL ))
1830 if (*lpcchBuffer && lpServiceName)
1831 lpServiceName[0] = 0;
1832 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1836 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1840 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1841 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1845 /******************************************************************************
1846 * GetServiceKeyNameW [ADVAPI32.@]
1848 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1849 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1855 TRACE("%p %s %p %p\n", hSCManager,
1856 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1860 SetLastError( ERROR_INVALID_HANDLE );
1864 /* provide a buffer if the caller didn't */
1865 if (!lpServiceName || *lpcchBuffer < 2)
1867 lpServiceName = buffer;
1868 /* A size of 1 would be enough, but tests show that Windows returns 2,
1869 * probably because of a WCHAR/bytes mismatch in their code.
1874 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1875 * includes the nul-terminator on input. */
1876 size = *lpcchBuffer - 1;
1880 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1883 __EXCEPT(rpc_filter)
1885 err = map_exception_code(GetExceptionCode());
1889 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1890 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1891 *lpcchBuffer = size;
1895 return err == ERROR_SUCCESS;
1898 /******************************************************************************
1899 * QueryServiceLockStatusA [ADVAPI32.@]
1901 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1902 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1903 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1905 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1910 /******************************************************************************
1911 * QueryServiceLockStatusW [ADVAPI32.@]
1913 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1914 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1915 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1917 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1922 /******************************************************************************
1923 * GetServiceDisplayNameA [ADVAPI32.@]
1925 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1926 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1928 LPWSTR lpServiceNameW, lpDisplayNameW;
1932 TRACE("%p %s %p %p\n", hSCManager,
1933 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1935 lpServiceNameW = SERV_dup(lpServiceName);
1937 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1939 lpDisplayNameW = NULL;
1941 sizeW = *lpcchBuffer;
1942 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1944 if (lpDisplayName && *lpcchBuffer)
1945 lpDisplayName[0] = 0;
1946 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1950 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1951 *lpcchBuffer, NULL, NULL ))
1953 if (*lpcchBuffer && lpDisplayName)
1954 lpDisplayName[0] = 0;
1955 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1959 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1960 * (but if the function succeeded it means that is a good upper estimation of the size) */
1964 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1965 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1969 /******************************************************************************
1970 * GetServiceDisplayNameW [ADVAPI32.@]
1972 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1973 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1979 TRACE("%p %s %p %p\n", hSCManager,
1980 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1984 SetLastError( ERROR_INVALID_HANDLE );
1988 /* provide a buffer if the caller didn't */
1989 if (!lpDisplayName || *lpcchBuffer < 2)
1991 lpDisplayName = buffer;
1992 /* A size of 1 would be enough, but tests show that Windows returns 2,
1993 * probably because of a WCHAR/bytes mismatch in their code.
1998 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1999 * includes the nul-terminator on input. */
2000 size = *lpcchBuffer - 1;
2004 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
2007 __EXCEPT(rpc_filter)
2009 err = map_exception_code(GetExceptionCode());
2013 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2014 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2015 *lpcchBuffer = size;
2019 return err == ERROR_SUCCESS;
2022 /******************************************************************************
2023 * ChangeServiceConfigW [ADVAPI32.@]
2025 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2026 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2027 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2028 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2033 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2034 hService, dwServiceType, dwStartType, dwErrorControl,
2035 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2036 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2037 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2039 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2043 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2044 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2045 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2046 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2048 __EXCEPT(rpc_filter)
2050 err = map_exception_code(GetExceptionCode());
2054 if (err != ERROR_SUCCESS)
2057 return err == ERROR_SUCCESS;
2060 /******************************************************************************
2061 * ChangeServiceConfigA [ADVAPI32.@]
2063 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2064 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2065 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2066 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2068 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2069 LPWSTR wServiceStartName, wPassword, wDisplayName;
2072 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2073 hService, dwServiceType, dwStartType, dwErrorControl,
2074 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2075 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2076 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2078 wBinaryPathName = SERV_dup( lpBinaryPathName );
2079 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2080 wDependencies = SERV_dupmulti( lpDependencies );
2081 wServiceStartName = SERV_dup( lpServiceStartName );
2082 wPassword = SERV_dup( lpPassword );
2083 wDisplayName = SERV_dup( lpDisplayName );
2085 r = ChangeServiceConfigW( hService, dwServiceType,
2086 dwStartType, dwErrorControl, wBinaryPathName,
2087 wLoadOrderGroup, lpdwTagId, wDependencies,
2088 wServiceStartName, wPassword, wDisplayName);
2090 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2091 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2092 HeapFree( GetProcessHeap(), 0, wDependencies );
2093 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2094 HeapFree( GetProcessHeap(), 0, wPassword );
2095 HeapFree( GetProcessHeap(), 0, wDisplayName );
2100 /******************************************************************************
2101 * ChangeServiceConfig2A [ADVAPI32.@]
2103 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2108 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2110 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2112 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2113 SERVICE_DESCRIPTIONW sdw;
2115 sdw.lpDescription = SERV_dup( sd->lpDescription );
2117 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2119 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2121 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2123 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2124 SERVICE_FAILURE_ACTIONSW faw;
2126 faw.dwResetPeriod = fa->dwResetPeriod;
2127 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2128 faw.lpCommand = SERV_dup( fa->lpCommand );
2129 faw.cActions = fa->cActions;
2130 faw.lpsaActions = fa->lpsaActions;
2132 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2134 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2135 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2137 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2139 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2142 SetLastError( ERROR_INVALID_PARAMETER );
2147 /******************************************************************************
2148 * ChangeServiceConfig2W [ADVAPI32.@]
2150 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2157 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2159 __EXCEPT(rpc_filter)
2161 err = map_exception_code(GetExceptionCode());
2165 if (err != ERROR_SUCCESS)
2168 return err == ERROR_SUCCESS;
2171 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2172 SECURITY_INFORMATION dwSecurityInformation,
2173 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2174 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2176 SECURITY_DESCRIPTOR descriptor;
2181 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2182 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2184 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2185 FIXME("information %d not supported\n", dwSecurityInformation);
2187 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2189 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2190 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2193 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2194 *pcbBytesNeeded = size;
2198 /******************************************************************************
2199 * QueryServiceObjectSecurity [ADVAPI32.@]
2201 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2202 SECURITY_INFORMATION dwSecurityInformation,
2203 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2204 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2206 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2207 cbBufSize, pcbBytesNeeded);
2208 if (status != STATUS_SUCCESS)
2210 SetLastError(RtlNtStatusToDosError(status));
2216 /******************************************************************************
2217 * SetServiceObjectSecurity [ADVAPI32.@]
2220 * - SetSecurityInfo should be updated to call this function once it's implemented.
2222 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2223 SECURITY_INFORMATION dwSecurityInformation,
2224 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2226 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2230 /******************************************************************************
2231 * SetServiceBits [ADVAPI32.@]
2233 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2234 DWORD dwServiceBits,
2236 BOOL bUpdateImmediately)
2238 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2239 bSetBitsOn, bUpdateImmediately);
2243 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2244 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2246 LPHANDLER_FUNCTION func = context;
2249 return ERROR_SUCCESS;
2252 /******************************************************************************
2253 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2255 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2257 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2260 /******************************************************************************
2261 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2263 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2265 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2268 /******************************************************************************
2269 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2271 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2274 SERVICE_STATUS_HANDLE ret;
2276 nameW = SERV_dup(name);
2277 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2278 HeapFree( GetProcessHeap(), 0, nameW );
2282 /******************************************************************************
2283 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2285 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2286 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2288 service_data *service;
2289 SC_HANDLE hService = 0;
2292 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2294 EnterCriticalSection( &service_cs );
2295 if ((service = find_service_by_name( lpServiceName )))
2297 service->handler = lpHandlerProc;
2298 service->context = lpContext;
2299 hService = service->handle;
2302 LeaveCriticalSection( &service_cs );
2304 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2306 return (SERVICE_STATUS_HANDLE)hService;
2309 /******************************************************************************
2310 * EnumDependentServicesA [ADVAPI32.@]
2312 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2313 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2314 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2316 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2317 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2319 *lpServicesReturned = 0;
2323 /******************************************************************************
2324 * EnumDependentServicesW [ADVAPI32.@]
2326 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2327 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2328 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2330 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2331 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2333 *lpServicesReturned = 0;