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 static CRITICAL_SECTION service_cs;
79 static CRITICAL_SECTION_DEBUG service_cs_debug =
82 { &service_cs_debug.ProcessLocksList,
83 &service_cs_debug.ProcessLocksList },
84 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
86 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
88 static service_data **services;
89 static unsigned int nb_services;
90 static HANDLE service_event;
91 static HANDLE stop_event;
93 extern HANDLE CDECL __wine_make_process_system(void);
95 /******************************************************************************
96 * String management functions (same behaviour as strdup)
97 * NOTE: the caller of those functions is responsible for calling HeapFree
98 * in order to release the memory allocated by those functions.
100 LPWSTR SERV_dup( LPCSTR str )
107 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
108 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
109 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
113 static inline LPWSTR SERV_dupmulti(LPCSTR str)
121 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
122 n += (strlen( &str[n] ) + 1);
127 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
128 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
132 static inline DWORD multisz_cb(LPCWSTR wmultisz)
134 const WCHAR *wptr = wmultisz;
136 if (wmultisz == NULL)
140 wptr += lstrlenW(wptr)+1;
141 return (wptr - wmultisz + 1)*sizeof(WCHAR);
144 /******************************************************************************
145 * RPC connection with services.exe
148 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
150 WCHAR transport[] = SVCCTL_TRANSPORT;
151 WCHAR endpoint[] = SVCCTL_ENDPOINT;
152 RPC_WSTR binding_str;
156 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
157 if (status != RPC_S_OK)
159 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
163 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
164 RpcStringFreeW(&binding_str);
166 if (status != RPC_S_OK)
168 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
175 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
180 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
182 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
185 static DWORD map_exception_code(DWORD exception_code)
187 switch (exception_code)
189 case RPC_X_NULL_REF_POINTER:
190 return ERROR_INVALID_ADDRESS;
191 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
192 case RPC_X_BYTE_COUNT_TOO_SMALL:
193 return ERROR_INVALID_PARAMETER;
194 case RPC_S_INVALID_BINDING:
195 case RPC_X_SS_IN_NULL_CONTEXT:
196 return ERROR_INVALID_HANDLE;
198 return exception_code;
202 /******************************************************************************
203 * Service IPC functions
205 static LPWSTR service_get_pipe_name(void)
207 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
208 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
209 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
210 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
211 'C','o','n','t','r','o','l','\\',
212 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
215 HKEY service_current_key;
216 DWORD service_current;
220 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
221 KEY_QUERY_VALUE, &service_current_key);
222 if (ret != ERROR_SUCCESS)
224 len = sizeof(service_current);
225 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
226 (BYTE *)&service_current, &len);
227 RegCloseKey(service_current_key);
228 if (ret != ERROR_SUCCESS || type != REG_DWORD)
230 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
231 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
234 snprintfW(name, len, format, service_current);
238 static HANDLE service_open_pipe(void)
240 LPWSTR szPipe = service_get_pipe_name();
241 HANDLE handle = INVALID_HANDLE_VALUE;
244 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
245 0, NULL, OPEN_ALWAYS, 0, NULL);
246 if (handle != INVALID_HANDLE_VALUE)
248 if (GetLastError() != ERROR_PIPE_BUSY)
250 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
251 HeapFree(GetProcessHeap(), 0, szPipe);
256 static service_data *find_service_by_name( const WCHAR *name )
260 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
262 for (i = 0; i < nb_services; i++)
263 if (!strcmpiW( name, services[i]->name )) return services[i];
267 /******************************************************************************
270 * Call into the main service routine provided by StartServiceCtrlDispatcher.
272 static DWORD WINAPI service_thread(LPVOID arg)
274 service_data *info = arg;
275 LPWSTR str = info->args;
276 DWORD argc = 0, len = 0;
282 len += strlenW(&str[len]) + 1;
291 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
292 for (argc=0, p=str; *p; p += strlenW(p) + 1)
296 info->proc.w(argc, argv);
297 HeapFree(GetProcessHeap(), 0, argv);
301 LPSTR strA, *argv, p;
304 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
305 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
306 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
308 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
309 for (argc=0, p=strA; *p; p += strlen(p) + 1)
313 info->proc.a(argc, argv);
314 HeapFree(GetProcessHeap(), 0, argv);
315 HeapFree(GetProcessHeap(), 0, strA);
320 /******************************************************************************
321 * service_handle_start
323 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
325 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
329 WARN("service is not stopped\n");
330 return ERROR_SERVICE_ALREADY_RUNNING;
333 HeapFree(GetProcessHeap(), 0, service->args);
334 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
335 memcpy( service->args, data, count * sizeof(WCHAR) );
336 service->thread = CreateThread( NULL, 0, service_thread,
338 SetEvent( service_event ); /* notify the main loop */
342 /******************************************************************************
343 * service_handle_control
345 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
347 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
349 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
351 if (service->handler)
352 ret = service->handler(dwControl, 0, NULL, service->context);
356 /******************************************************************************
357 * service_control_dispatcher
359 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
364 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
366 ERR("failed to open service manager error %u\n", GetLastError());
370 pipe = service_open_pipe();
372 if (pipe==INVALID_HANDLE_VALUE)
374 WARN("failed to create control pipe error = %d\n", GetLastError());
378 /* dispatcher loop */
381 service_data *service;
382 service_start_info info;
385 DWORD data_size = 0, count, result;
387 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
390 if (GetLastError() != ERROR_BROKEN_PIPE)
391 ERR( "pipe read failed error %u\n", GetLastError() );
394 if (count != FIELD_OFFSET(service_start_info,data))
396 ERR( "partial pipe read %u\n", count );
399 if (count < info.total_size)
401 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
402 data = HeapAlloc( GetProcessHeap(), 0, data_size );
403 r = ReadFile( pipe, data, data_size, &count, NULL );
406 if (GetLastError() != ERROR_BROKEN_PIPE)
407 ERR( "pipe read failed error %u\n", GetLastError() );
408 HeapFree( GetProcessHeap(), 0, data );
411 if (count != data_size)
413 ERR( "partial pipe read %u/%u\n", count, data_size );
414 HeapFree( GetProcessHeap(), 0, data );
419 /* find the service */
421 if (!(service = find_service_by_name( data )))
423 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
424 result = ERROR_INVALID_PARAMETER;
428 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
430 /* handle the request */
433 case WINESERV_STARTINFO:
434 if (!service->handle)
436 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )) ||
437 !(service->full_access_handle = OpenServiceW( manager, data, GENERIC_READ|GENERIC_WRITE )))
438 FIXME( "failed to open service %s\n", debugstr_w(data) );
440 result = service_handle_start(service, data, data_size / sizeof(WCHAR));
442 case WINESERV_SENDCONTROL:
443 result = service_handle_control(service, info.control);
446 ERR("received invalid command %u\n", info.cmd);
447 result = ERROR_INVALID_PARAMETER;
452 WriteFile(pipe, &result, sizeof(result), &count, NULL);
453 HeapFree( GetProcessHeap(), 0, data );
457 CloseServiceHandle( manager );
461 /******************************************************************************
462 * service_run_main_thread
464 static BOOL service_run_main_thread(void)
467 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
468 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
470 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
471 stop_event = CreateEventW( NULL, FALSE, FALSE, NULL );
473 /* FIXME: service_control_dispatcher should be merged into the main thread */
474 wait_handles[0] = __wine_make_process_system();
475 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
476 wait_handles[2] = service_event;
477 wait_handles[3] = stop_event;
479 TRACE("Starting %d services running as process %d\n",
480 nb_services, GetCurrentProcessId());
482 /* wait for all the threads to pack up and exit */
485 EnterCriticalSection( &service_cs );
486 for (i = 0, n = 4; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
488 if (!services[i]->thread) continue;
489 wait_services[n] = i;
490 wait_handles[n++] = services[i]->thread;
492 LeaveCriticalSection( &service_cs );
494 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
495 if (!ret) /* system process event */
498 SERVICE_PRESHUTDOWN_INFO spi;
499 DWORD timeout = 5000;
502 EnterCriticalSection( &service_cs );
504 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
506 if (!services[i]->thread) continue;
508 res = QueryServiceStatus(services[i]->full_access_handle, &st);
510 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
512 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
513 (LPBYTE)&spi, sizeof(spi), &i );
516 FIXME("service should be able to delay shutdown\n");
517 timeout += spi.dwPreshutdownTimeout;
518 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN );
519 wait_handles[n++] = services[i]->thread;
522 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
524 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN );
525 wait_handles[n++] = services[i]->thread;
528 LeaveCriticalSection( &service_cs );
530 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
531 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
536 TRACE( "control dispatcher exited, shutting down\n" );
537 /* FIXME: we should maybe send a shutdown control to running services */
542 continue; /* rebuild the list */
550 services[wait_services[ret]]->thread = 0;
551 CloseHandle( wait_handles[ret] );
557 /******************************************************************************
558 * StartServiceCtrlDispatcherA [ADVAPI32.@]
560 * See StartServiceCtrlDispatcherW.
562 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
568 TRACE("%p\n", servent);
572 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
575 while (servent[nb_services].lpServiceName) nb_services++;
578 SetLastError( ERROR_INVALID_PARAMETER );
582 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
584 for (i = 0; i < nb_services; i++)
586 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
587 DWORD sz = FIELD_OFFSET( service_data, name[len] );
588 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
589 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
590 info->proc.a = servent[i].lpServiceProc;
591 info->unicode = FALSE;
595 service_run_main_thread();
600 /******************************************************************************
601 * StartServiceCtrlDispatcherW [ADVAPI32.@]
603 * Connects a process containing one or more services to the service control
607 * servent [I] A list of the service names and service procedures
613 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
619 TRACE("%p\n", servent);
623 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
626 while (servent[nb_services].lpServiceName) nb_services++;
629 SetLastError( ERROR_INVALID_PARAMETER );
633 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
635 for (i = 0; i < nb_services; i++)
637 DWORD len = strlenW(servent[i].lpServiceName) + 1;
638 DWORD sz = FIELD_OFFSET( service_data, name[len] );
639 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
640 strcpyW(info->name, servent[i].lpServiceName);
641 info->proc.w = servent[i].lpServiceProc;
642 info->unicode = TRUE;
646 service_run_main_thread();
651 /******************************************************************************
652 * LockServiceDatabase [ADVAPI32.@]
654 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
656 SC_RPC_LOCK hLock = NULL;
659 TRACE("%p\n",hSCManager);
663 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
667 err = map_exception_code(GetExceptionCode());
670 if (err != ERROR_SUCCESS)
678 /******************************************************************************
679 * UnlockServiceDatabase [ADVAPI32.@]
681 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
684 SC_RPC_LOCK hRpcLock = ScLock;
686 TRACE("%p\n",ScLock);
690 err = svcctl_UnlockServiceDatabase(&hRpcLock);
694 err = map_exception_code(GetExceptionCode());
697 if (err != ERROR_SUCCESS)
705 /******************************************************************************
706 * SetServiceStatus [ADVAPI32.@]
713 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
717 TRACE("%p %x %x %x %x %x %x %x\n", hService,
718 lpStatus->dwServiceType, lpStatus->dwCurrentState,
719 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
720 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
721 lpStatus->dwWaitHint);
725 err = svcctl_SetServiceStatus( hService, lpStatus );
729 err = map_exception_code(GetExceptionCode());
732 if (err != ERROR_SUCCESS)
738 if (lpStatus->dwCurrentState == SERVICE_STOPPED) {
739 SetEvent(stop_event);
740 CloseServiceHandle((SC_HANDLE)hService);
747 /******************************************************************************
748 * OpenSCManagerA [ADVAPI32.@]
750 * Establish a connection to the service control manager and open its database.
753 * lpMachineName [I] Pointer to machine name string
754 * lpDatabaseName [I] Pointer to database name string
755 * dwDesiredAccess [I] Type of access
758 * Success: A Handle to the service control manager database
761 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
762 DWORD dwDesiredAccess )
764 LPWSTR lpMachineNameW, lpDatabaseNameW;
767 lpMachineNameW = SERV_dup(lpMachineName);
768 lpDatabaseNameW = SERV_dup(lpDatabaseName);
769 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
770 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
771 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
775 /******************************************************************************
776 * OpenSCManagerW [ADVAPI32.@]
778 * See OpenSCManagerA.
780 DWORD SERV_OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
781 DWORD dwDesiredAccess, SC_HANDLE *handle )
785 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
786 debugstr_w(lpDatabaseName), dwDesiredAccess);
790 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
794 r = map_exception_code(GetExceptionCode());
798 if (r!=ERROR_SUCCESS)
801 TRACE("returning %p\n", *handle);
805 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
806 DWORD dwDesiredAccess )
808 SC_HANDLE handle = 0;
811 r = SERV_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &handle);
812 if (r!=ERROR_SUCCESS)
817 /******************************************************************************
818 * ControlService [ADVAPI32.@]
820 * Send a control code to a service.
823 * hService [I] Handle of the service control manager database
824 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
825 * lpServiceStatus [O] Destination for the status of the service, if available
832 * Unlike M$' implementation, control requests are not serialized and may be
833 * processed asynchronously.
835 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
836 LPSERVICE_STATUS lpServiceStatus )
840 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
844 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
848 err = map_exception_code(GetExceptionCode());
851 if (err != ERROR_SUCCESS)
860 /******************************************************************************
861 * CloseServiceHandle [ADVAPI32.@]
863 * Close a handle to a service or the service control manager database.
866 * hSCObject [I] Handle to service or service control manager database
873 CloseServiceHandle( SC_HANDLE hSCObject )
877 TRACE("%p\n", hSCObject);
881 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
885 err = map_exception_code(GetExceptionCode());
889 if (err != ERROR_SUCCESS)
898 /******************************************************************************
899 * OpenServiceA [ADVAPI32.@]
901 * Open a handle to a service.
904 * hSCManager [I] Handle of the service control manager database
905 * lpServiceName [I] Name of the service to open
906 * dwDesiredAccess [I] Access required to the service
909 * Success: Handle to the service
912 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
913 DWORD dwDesiredAccess )
915 LPWSTR lpServiceNameW;
918 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
920 lpServiceNameW = SERV_dup(lpServiceName);
921 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
922 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
927 /******************************************************************************
928 * OpenServiceW [ADVAPI32.@]
932 DWORD SERV_OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
933 DWORD dwDesiredAccess, SC_HANDLE *handle )
937 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
940 return ERROR_INVALID_HANDLE;
944 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)handle);
948 err = map_exception_code(GetExceptionCode());
952 if (err != ERROR_SUCCESS)
955 TRACE("returning %p\n", *handle);
959 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
960 DWORD dwDesiredAccess)
962 SC_HANDLE handle = 0;
965 err = SERV_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, &handle);
966 if (err != ERROR_SUCCESS)
971 /******************************************************************************
972 * CreateServiceW [ADVAPI32.@]
975 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
976 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
977 DWORD dwServiceType, DWORD dwStartType,
978 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
979 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
980 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
983 SC_HANDLE handle = 0;
987 TRACE("%p %s %s\n", hSCManager,
988 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
992 SetLastError( ERROR_INVALID_HANDLE );
997 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1003 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
1004 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1005 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
1006 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
1007 (SC_RPC_HANDLE *)&handle);
1009 __EXCEPT(rpc_filter)
1011 err = map_exception_code(GetExceptionCode());
1015 if (err != ERROR_SUCCESS)
1024 /******************************************************************************
1025 * CreateServiceA [ADVAPI32.@]
1028 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1029 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1030 DWORD dwServiceType, DWORD dwStartType,
1031 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1032 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1033 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1036 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1037 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1040 TRACE("%p %s %s\n", hSCManager,
1041 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1043 lpServiceNameW = SERV_dup( lpServiceName );
1044 lpDisplayNameW = SERV_dup( lpDisplayName );
1045 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1046 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1047 lpDependenciesW = SERV_dupmulti( lpDependencies );
1048 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1049 lpPasswordW = SERV_dup( lpPassword );
1051 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1052 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1053 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1054 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1056 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1057 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1058 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1059 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1060 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1061 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1062 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1068 /******************************************************************************
1069 * DeleteService [ADVAPI32.@]
1071 * Delete a service from the service control manager database.
1074 * hService [I] Handle of the service to delete
1080 BOOL WINAPI DeleteService( SC_HANDLE hService )
1086 err = svcctl_DeleteService(hService);
1088 __EXCEPT(rpc_filter)
1090 err = map_exception_code(GetExceptionCode());
1103 /******************************************************************************
1104 * StartServiceA [ADVAPI32.@]
1109 * hService [I] Handle of service
1110 * dwNumServiceArgs [I] Number of arguments
1111 * lpServiceArgVectors [I] Address of array of argument strings
1114 * - NT implements this function using an obscure RPC call.
1115 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1116 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1117 * - This will only work for shared address space. How should the service
1118 * args be transferred when address spaces are separated?
1119 * - Can only start one service at a time.
1120 * - Has no concept of privilege.
1126 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1127 LPCSTR *lpServiceArgVectors )
1129 LPWSTR *lpwstr=NULL;
1133 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1135 if (dwNumServiceArgs)
1136 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1137 dwNumServiceArgs*sizeof(LPWSTR) );
1139 for(i=0; i<dwNumServiceArgs; i++)
1140 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1142 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1144 if (dwNumServiceArgs)
1146 for(i=0; i<dwNumServiceArgs; i++)
1147 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1148 HeapFree(GetProcessHeap(), 0, lpwstr);
1155 /******************************************************************************
1156 * StartServiceW [ADVAPI32.@]
1158 * See StartServiceA.
1160 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1161 LPCWSTR *lpServiceArgVectors)
1165 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1169 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1171 __EXCEPT(rpc_filter)
1173 err = map_exception_code(GetExceptionCode());
1176 if (err != ERROR_SUCCESS)
1185 /******************************************************************************
1186 * QueryServiceStatus [ADVAPI32.@]
1189 * hService [I] Handle to service to get information about
1190 * lpservicestatus [O] buffer to receive the status information for the service
1193 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1194 LPSERVICE_STATUS lpservicestatus)
1196 SERVICE_STATUS_PROCESS SvcStatusData;
1200 TRACE("%p %p\n", hService, lpservicestatus);
1204 SetLastError(ERROR_INVALID_HANDLE);
1207 if (!lpservicestatus)
1209 SetLastError(ERROR_INVALID_ADDRESS);
1213 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1214 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1215 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1220 /******************************************************************************
1221 * QueryServiceStatusEx [ADVAPI32.@]
1223 * Get information about a service.
1226 * hService [I] Handle to service to get information about
1227 * InfoLevel [I] Level of information to get
1228 * lpBuffer [O] Destination for requested information
1229 * cbBufSize [I] Size of lpBuffer in bytes
1230 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1236 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1237 LPBYTE lpBuffer, DWORD cbBufSize,
1238 LPDWORD pcbBytesNeeded)
1242 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1244 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1246 err = ERROR_INVALID_LEVEL;
1248 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1250 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1251 err = ERROR_INSUFFICIENT_BUFFER;
1257 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1259 __EXCEPT(rpc_filter)
1261 err = map_exception_code(GetExceptionCode());
1265 if (err != ERROR_SUCCESS)
1273 /******************************************************************************
1274 * QueryServiceConfigA [ADVAPI32.@]
1276 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1277 DWORD size, LPDWORD needed )
1282 QUERY_SERVICE_CONFIGW *configW;
1284 TRACE("%p %p %d %p\n", hService, config, size, needed);
1286 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1288 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1291 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1292 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1293 if (!ret) goto done;
1295 config->dwServiceType = configW->dwServiceType;
1296 config->dwStartType = configW->dwStartType;
1297 config->dwErrorControl = configW->dwErrorControl;
1298 config->lpBinaryPathName = NULL;
1299 config->lpLoadOrderGroup = NULL;
1300 config->dwTagId = configW->dwTagId;
1301 config->lpDependencies = NULL;
1302 config->lpServiceStartName = NULL;
1303 config->lpDisplayName = NULL;
1305 p = (LPSTR)(config + 1);
1306 n = size - sizeof(*config);
1309 #define MAP_STR(str) \
1313 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1314 if (!sz) goto done; \
1321 MAP_STR( lpBinaryPathName );
1322 MAP_STR( lpLoadOrderGroup );
1323 MAP_STR( lpDependencies );
1324 MAP_STR( lpServiceStartName );
1325 MAP_STR( lpDisplayName );
1328 *needed = p - (LPSTR)config;
1332 HeapFree( GetProcessHeap(), 0, buffer );
1336 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1343 memset(*buf, 0, cb);
1347 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1348 memcpy(*buf, *string_ptr, cb);
1349 MIDL_user_free(*string_ptr);
1352 *string_ptr = (LPWSTR)*buf;
1358 static DWORD size_string(LPCWSTR string)
1360 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1363 /******************************************************************************
1364 * QueryServiceConfigW [ADVAPI32.@]
1367 QueryServiceConfigW( SC_HANDLE hService,
1368 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1369 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1371 QUERY_SERVICE_CONFIGW config;
1376 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1377 cbBufSize, pcbBytesNeeded);
1379 memset(&config, 0, sizeof(config));
1383 err = svcctl_QueryServiceConfigW(hService, &config);
1385 __EXCEPT(rpc_filter)
1387 err = map_exception_code(GetExceptionCode());
1391 if (err != ERROR_SUCCESS)
1393 TRACE("services.exe: error %u\n", err);
1398 /* calculate the size required first */
1399 total = sizeof (QUERY_SERVICE_CONFIGW);
1400 total += size_string(config.lpBinaryPathName);
1401 total += size_string(config.lpLoadOrderGroup);
1402 total += size_string(config.lpDependencies);
1403 total += size_string(config.lpServiceStartName);
1404 total += size_string(config.lpDisplayName);
1406 *pcbBytesNeeded = total;
1408 /* if there's not enough memory, return an error */
1409 if( total > cbBufSize )
1411 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1412 MIDL_user_free(config.lpBinaryPathName);
1413 MIDL_user_free(config.lpLoadOrderGroup);
1414 MIDL_user_free(config.lpDependencies);
1415 MIDL_user_free(config.lpServiceStartName);
1416 MIDL_user_free(config.lpDisplayName);
1420 *lpServiceConfig = config;
1421 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1422 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1423 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1424 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1425 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1426 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1428 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1429 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1430 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1431 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1432 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1437 /******************************************************************************
1438 * QueryServiceConfig2A [ADVAPI32.@]
1441 * observed under win2k:
1442 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1443 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1445 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1446 DWORD size, LPDWORD needed)
1449 LPBYTE bufferW = NULL;
1452 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1454 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1455 if(!ret) goto cleanup;
1458 case SERVICE_CONFIG_DESCRIPTION:
1459 if (buffer && bufferW) {
1460 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1461 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1462 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1464 configA->lpDescription = (LPSTR)(configA + 1);
1465 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1466 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1468 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1470 configA->lpDescription = NULL;
1473 else configA->lpDescription = NULL;
1476 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1477 if (buffer && bufferW && *needed<=size)
1478 memcpy(buffer, bufferW, *needed);
1481 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1487 HeapFree( GetProcessHeap(), 0, bufferW);
1491 /******************************************************************************
1492 * QueryServiceConfig2W [ADVAPI32.@]
1494 * See QueryServiceConfig2A.
1496 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1497 DWORD size, LPDWORD needed)
1501 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1502 FIXME("Level %d not implemented\n", dwLevel);
1503 SetLastError(ERROR_INVALID_LEVEL);
1507 if(!buffer && size) {
1508 SetLastError(ERROR_INVALID_ADDRESS);
1512 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1516 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1518 __EXCEPT(rpc_filter)
1520 err = map_exception_code(GetExceptionCode());
1524 if (err != ERROR_SUCCESS)
1526 SetLastError( err );
1532 case SERVICE_CONFIG_DESCRIPTION:
1535 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1536 if (descr->lpDescription) /* make it an absolute pointer */
1537 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1545 /******************************************************************************
1546 * EnumServicesStatusA [ADVAPI32.@]
1549 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1550 services, DWORD size, LPDWORD needed, LPDWORD returned,
1551 LPDWORD resume_handle )
1555 ENUM_SERVICE_STATUSW *servicesW = NULL;
1559 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1560 returned, resume_handle);
1562 sz = max( 2 * size, sizeof(*servicesW) );
1563 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1565 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1569 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1570 if (!ret) goto done;
1572 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1573 n = size - (p - (char *)services);
1575 for (i = 0; i < *returned; i++)
1577 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1579 services[i].lpServiceName = p;
1582 if (servicesW[i].lpDisplayName)
1584 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1586 services[i].lpDisplayName = p;
1590 else services[i].lpDisplayName = NULL;
1591 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1597 HeapFree( GetProcessHeap(), 0, servicesW );
1601 /******************************************************************************
1602 * EnumServicesStatusW [ADVAPI32.@]
1605 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1606 services, DWORD size, LPDWORD needed, LPDWORD returned,
1607 LPDWORD resume_handle )
1610 ENUM_SERVICE_STATUSW dummy_status;
1612 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1613 returned, resume_handle);
1616 FIXME("resume handle not supported\n");
1620 SetLastError( ERROR_INVALID_HANDLE );
1624 /* make sure we pass a valid pointer */
1625 if (!services || size < sizeof(*services))
1627 services = &dummy_status;
1628 size = sizeof(dummy_status);
1633 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1635 __EXCEPT(rpc_filter)
1637 err = map_exception_code( GetExceptionCode() );
1641 if (err != ERROR_SUCCESS)
1643 SetLastError( err );
1647 for (i = 0; i < *returned; i++)
1649 /* convert buffer offsets into pointers */
1650 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1651 if (services[i].lpDisplayName)
1652 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1658 /******************************************************************************
1659 * EnumServicesStatusExA [ADVAPI32.@]
1662 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1663 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1664 LPDWORD resume_handle, LPCSTR group )
1668 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1669 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1670 WCHAR *groupW = NULL;
1674 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1675 size, needed, returned, resume_handle, debugstr_a(group));
1677 sz = max( 2 * size, sizeof(*servicesW) );
1678 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1680 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1685 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1686 if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1688 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1689 HeapFree( GetProcessHeap(), 0, servicesW );
1692 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1695 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1696 needed, returned, resume_handle, groupW );
1697 if (!ret) goto done;
1699 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1700 n = size - (p - (char *)services);
1702 for (i = 0; i < *returned; i++)
1704 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1706 services[i].lpServiceName = p;
1709 if (servicesW[i].lpDisplayName)
1711 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1713 services[i].lpDisplayName = p;
1717 else services[i].lpDisplayName = NULL;
1718 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1724 HeapFree( GetProcessHeap(), 0, servicesW );
1725 HeapFree( GetProcessHeap(), 0, groupW );
1729 /******************************************************************************
1730 * EnumServicesStatusExW [ADVAPI32.@]
1733 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1734 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1735 LPDWORD resume_handle, LPCWSTR group )
1738 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1739 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1741 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1742 size, needed, returned, resume_handle, debugstr_w(group));
1745 FIXME("resume handle not supported\n");
1747 if (level != SC_ENUM_PROCESS_INFO)
1749 SetLastError( ERROR_INVALID_LEVEL );
1754 SetLastError( ERROR_INVALID_HANDLE );
1758 /* make sure we pass a valid buffer pointer */
1759 if (!services || size < sizeof(*services))
1761 buffer = (BYTE *)&dummy_status;
1762 size = sizeof(dummy_status);
1767 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1770 __EXCEPT(rpc_filter)
1772 err = map_exception_code( GetExceptionCode() );
1776 if (err != ERROR_SUCCESS)
1778 SetLastError( err );
1782 for (i = 0; i < *returned; i++)
1784 /* convert buffer offsets into pointers */
1785 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1786 if (services[i].lpDisplayName)
1787 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1793 /******************************************************************************
1794 * GetServiceKeyNameA [ADVAPI32.@]
1796 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1797 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1799 LPWSTR lpDisplayNameW, lpServiceNameW;
1803 TRACE("%p %s %p %p\n", hSCManager,
1804 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1806 lpDisplayNameW = SERV_dup(lpDisplayName);
1808 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1810 lpServiceNameW = NULL;
1812 sizeW = *lpcchBuffer;
1813 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1815 if (lpServiceName && *lpcchBuffer)
1816 lpServiceName[0] = 0;
1817 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1821 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1822 *lpcchBuffer, NULL, NULL ))
1824 if (*lpcchBuffer && lpServiceName)
1825 lpServiceName[0] = 0;
1826 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1830 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1834 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1835 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1839 /******************************************************************************
1840 * GetServiceKeyNameW [ADVAPI32.@]
1842 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1843 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1849 TRACE("%p %s %p %p\n", hSCManager,
1850 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1854 SetLastError( ERROR_INVALID_HANDLE );
1858 /* provide a buffer if the caller didn't */
1859 if (!lpServiceName || *lpcchBuffer < 2)
1861 lpServiceName = buffer;
1862 /* A size of 1 would be enough, but tests show that Windows returns 2,
1863 * probably because of a WCHAR/bytes mismatch in their code.
1868 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1869 * includes the nul-terminator on input. */
1870 size = *lpcchBuffer - 1;
1874 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1877 __EXCEPT(rpc_filter)
1879 err = map_exception_code(GetExceptionCode());
1883 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1884 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1885 *lpcchBuffer = size;
1889 return err == ERROR_SUCCESS;
1892 /******************************************************************************
1893 * QueryServiceLockStatusA [ADVAPI32.@]
1895 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1896 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1897 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1899 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1904 /******************************************************************************
1905 * QueryServiceLockStatusW [ADVAPI32.@]
1907 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1908 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1909 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1911 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1916 /******************************************************************************
1917 * GetServiceDisplayNameA [ADVAPI32.@]
1919 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1920 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1922 LPWSTR lpServiceNameW, lpDisplayNameW;
1926 TRACE("%p %s %p %p\n", hSCManager,
1927 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1929 lpServiceNameW = SERV_dup(lpServiceName);
1931 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1933 lpDisplayNameW = NULL;
1935 sizeW = *lpcchBuffer;
1936 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1938 if (lpDisplayName && *lpcchBuffer)
1939 lpDisplayName[0] = 0;
1940 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1944 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1945 *lpcchBuffer, NULL, NULL ))
1947 if (*lpcchBuffer && lpDisplayName)
1948 lpDisplayName[0] = 0;
1949 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1953 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1954 * (but if the function succeeded it means that is a good upper estimation of the size) */
1958 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1959 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1963 /******************************************************************************
1964 * GetServiceDisplayNameW [ADVAPI32.@]
1966 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1967 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1973 TRACE("%p %s %p %p\n", hSCManager,
1974 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1978 SetLastError( ERROR_INVALID_HANDLE );
1982 /* provide a buffer if the caller didn't */
1983 if (!lpDisplayName || *lpcchBuffer < 2)
1985 lpDisplayName = buffer;
1986 /* A size of 1 would be enough, but tests show that Windows returns 2,
1987 * probably because of a WCHAR/bytes mismatch in their code.
1992 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1993 * includes the nul-terminator on input. */
1994 size = *lpcchBuffer - 1;
1998 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
2001 __EXCEPT(rpc_filter)
2003 err = map_exception_code(GetExceptionCode());
2007 /* The value of *lpcchBuffer excludes nul-terminator on output. */
2008 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
2009 *lpcchBuffer = size;
2013 return err == ERROR_SUCCESS;
2016 /******************************************************************************
2017 * ChangeServiceConfigW [ADVAPI32.@]
2019 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2020 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2021 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2022 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2027 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2028 hService, dwServiceType, dwStartType, dwErrorControl,
2029 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2030 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2031 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2033 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2037 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2038 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2039 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2040 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2042 __EXCEPT(rpc_filter)
2044 err = map_exception_code(GetExceptionCode());
2048 if (err != ERROR_SUCCESS)
2051 return err == ERROR_SUCCESS;
2054 /******************************************************************************
2055 * ChangeServiceConfigA [ADVAPI32.@]
2057 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2058 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2059 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2060 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2062 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2063 LPWSTR wServiceStartName, wPassword, wDisplayName;
2066 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2067 hService, dwServiceType, dwStartType, dwErrorControl,
2068 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2069 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2070 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2072 wBinaryPathName = SERV_dup( lpBinaryPathName );
2073 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2074 wDependencies = SERV_dupmulti( lpDependencies );
2075 wServiceStartName = SERV_dup( lpServiceStartName );
2076 wPassword = SERV_dup( lpPassword );
2077 wDisplayName = SERV_dup( lpDisplayName );
2079 r = ChangeServiceConfigW( hService, dwServiceType,
2080 dwStartType, dwErrorControl, wBinaryPathName,
2081 wLoadOrderGroup, lpdwTagId, wDependencies,
2082 wServiceStartName, wPassword, wDisplayName);
2084 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2085 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2086 HeapFree( GetProcessHeap(), 0, wDependencies );
2087 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2088 HeapFree( GetProcessHeap(), 0, wPassword );
2089 HeapFree( GetProcessHeap(), 0, wDisplayName );
2094 /******************************************************************************
2095 * ChangeServiceConfig2A [ADVAPI32.@]
2097 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2102 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2104 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2106 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2107 SERVICE_DESCRIPTIONW sdw;
2109 sdw.lpDescription = SERV_dup( sd->lpDescription );
2111 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2113 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2115 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2117 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2118 SERVICE_FAILURE_ACTIONSW faw;
2120 faw.dwResetPeriod = fa->dwResetPeriod;
2121 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2122 faw.lpCommand = SERV_dup( fa->lpCommand );
2123 faw.cActions = fa->cActions;
2124 faw.lpsaActions = fa->lpsaActions;
2126 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2128 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2129 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2131 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2133 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2136 SetLastError( ERROR_INVALID_PARAMETER );
2141 /******************************************************************************
2142 * ChangeServiceConfig2W [ADVAPI32.@]
2144 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2151 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2153 __EXCEPT(rpc_filter)
2155 err = map_exception_code(GetExceptionCode());
2159 if (err != ERROR_SUCCESS)
2162 return err == ERROR_SUCCESS;
2165 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2166 SECURITY_INFORMATION dwSecurityInformation,
2167 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2168 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2170 SECURITY_DESCRIPTOR descriptor;
2175 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2176 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2178 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2179 FIXME("information %d not supported\n", dwSecurityInformation);
2181 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2183 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2184 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2187 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2188 *pcbBytesNeeded = size;
2192 /******************************************************************************
2193 * QueryServiceObjectSecurity [ADVAPI32.@]
2195 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2196 SECURITY_INFORMATION dwSecurityInformation,
2197 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2198 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2200 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2201 cbBufSize, pcbBytesNeeded);
2202 if (status != STATUS_SUCCESS)
2204 SetLastError(RtlNtStatusToDosError(status));
2210 /******************************************************************************
2211 * SetServiceObjectSecurity [ADVAPI32.@]
2214 * - SetSecurityInfo should be updated to call this function once it's implemented.
2216 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2217 SECURITY_INFORMATION dwSecurityInformation,
2218 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2220 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2224 /******************************************************************************
2225 * SetServiceBits [ADVAPI32.@]
2227 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2228 DWORD dwServiceBits,
2230 BOOL bUpdateImmediately)
2232 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2233 bSetBitsOn, bUpdateImmediately);
2237 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2238 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2240 LPHANDLER_FUNCTION func = context;
2243 return ERROR_SUCCESS;
2246 /******************************************************************************
2247 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2249 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2251 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2254 /******************************************************************************
2255 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2257 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2259 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2262 /******************************************************************************
2263 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2265 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2268 SERVICE_STATUS_HANDLE ret;
2270 nameW = SERV_dup(name);
2271 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2272 HeapFree( GetProcessHeap(), 0, nameW );
2276 /******************************************************************************
2277 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2279 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2280 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2282 service_data *service;
2283 SC_HANDLE hService = 0;
2286 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2288 EnterCriticalSection( &service_cs );
2289 if ((service = find_service_by_name( lpServiceName )))
2291 service->handler = lpHandlerProc;
2292 service->context = lpContext;
2293 hService = service->handle;
2296 LeaveCriticalSection( &service_cs );
2298 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2300 return (SERVICE_STATUS_HANDLE)hService;
2303 /******************************************************************************
2304 * EnumDependentServicesA [ADVAPI32.@]
2306 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2307 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2308 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2310 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2311 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2313 *lpServicesReturned = 0;
2317 /******************************************************************************
2318 * EnumDependentServicesW [ADVAPI32.@]
2320 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2321 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2322 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2324 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2325 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2327 *lpServicesReturned = 0;