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 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
781 DWORD dwDesiredAccess )
783 SC_HANDLE handle = 0;
786 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
787 debugstr_w(lpDatabaseName), dwDesiredAccess);
791 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
795 r = map_exception_code(GetExceptionCode());
799 if (r!=ERROR_SUCCESS)
805 TRACE("returning %p\n", handle);
809 /******************************************************************************
810 * ControlService [ADVAPI32.@]
812 * Send a control code to a service.
815 * hService [I] Handle of the service control manager database
816 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
817 * lpServiceStatus [O] Destination for the status of the service, if available
824 * Unlike M$' implementation, control requests are not serialized and may be
825 * processed asynchronously.
827 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
828 LPSERVICE_STATUS lpServiceStatus )
832 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
836 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
840 err = map_exception_code(GetExceptionCode());
843 if (err != ERROR_SUCCESS)
852 /******************************************************************************
853 * CloseServiceHandle [ADVAPI32.@]
855 * Close a handle to a service or the service control manager database.
858 * hSCObject [I] Handle to service or service control manager database
865 CloseServiceHandle( SC_HANDLE hSCObject )
869 TRACE("%p\n", hSCObject);
873 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
877 err = map_exception_code(GetExceptionCode());
881 if (err != ERROR_SUCCESS)
890 /******************************************************************************
891 * OpenServiceA [ADVAPI32.@]
893 * Open a handle to a service.
896 * hSCManager [I] Handle of the service control manager database
897 * lpServiceName [I] Name of the service to open
898 * dwDesiredAccess [I] Access required to the service
901 * Success: Handle to the service
904 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
905 DWORD dwDesiredAccess )
907 LPWSTR lpServiceNameW;
910 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
912 lpServiceNameW = SERV_dup(lpServiceName);
913 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
914 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
919 /******************************************************************************
920 * OpenServiceW [ADVAPI32.@]
924 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
925 DWORD dwDesiredAccess)
927 SC_HANDLE handle = 0;
930 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
934 SetLastError( ERROR_INVALID_HANDLE );
940 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
944 err = map_exception_code(GetExceptionCode());
948 if (err != ERROR_SUCCESS)
954 TRACE("returning %p\n",handle);
958 /******************************************************************************
959 * CreateServiceW [ADVAPI32.@]
962 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
963 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
964 DWORD dwServiceType, DWORD dwStartType,
965 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
966 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
967 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
970 SC_HANDLE handle = 0;
974 TRACE("%p %s %s\n", hSCManager,
975 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
979 SetLastError( ERROR_INVALID_HANDLE );
984 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
990 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
991 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
992 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
993 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
994 (SC_RPC_HANDLE *)&handle);
998 err = map_exception_code(GetExceptionCode());
1002 if (err != ERROR_SUCCESS)
1011 /******************************************************************************
1012 * CreateServiceA [ADVAPI32.@]
1015 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1016 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1017 DWORD dwServiceType, DWORD dwStartType,
1018 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1019 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1020 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1023 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1024 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1027 TRACE("%p %s %s\n", hSCManager,
1028 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1030 lpServiceNameW = SERV_dup( lpServiceName );
1031 lpDisplayNameW = SERV_dup( lpDisplayName );
1032 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1033 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1034 lpDependenciesW = SERV_dupmulti( lpDependencies );
1035 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1036 lpPasswordW = SERV_dup( lpPassword );
1038 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1039 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1040 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1041 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1043 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1044 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1045 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1046 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1047 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1048 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1049 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1055 /******************************************************************************
1056 * DeleteService [ADVAPI32.@]
1058 * Delete a service from the service control manager database.
1061 * hService [I] Handle of the service to delete
1067 BOOL WINAPI DeleteService( SC_HANDLE hService )
1073 err = svcctl_DeleteService(hService);
1075 __EXCEPT(rpc_filter)
1077 err = map_exception_code(GetExceptionCode());
1090 /******************************************************************************
1091 * StartServiceA [ADVAPI32.@]
1096 * hService [I] Handle of service
1097 * dwNumServiceArgs [I] Number of arguments
1098 * lpServiceArgVectors [I] Address of array of argument strings
1101 * - NT implements this function using an obscure RPC call.
1102 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1103 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1104 * - This will only work for shared address space. How should the service
1105 * args be transferred when address spaces are separated?
1106 * - Can only start one service at a time.
1107 * - Has no concept of privilege.
1113 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1114 LPCSTR *lpServiceArgVectors )
1116 LPWSTR *lpwstr=NULL;
1120 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1122 if (dwNumServiceArgs)
1123 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1124 dwNumServiceArgs*sizeof(LPWSTR) );
1126 for(i=0; i<dwNumServiceArgs; i++)
1127 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1129 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1131 if (dwNumServiceArgs)
1133 for(i=0; i<dwNumServiceArgs; i++)
1134 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1135 HeapFree(GetProcessHeap(), 0, lpwstr);
1142 /******************************************************************************
1143 * StartServiceW [ADVAPI32.@]
1145 * See StartServiceA.
1147 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1148 LPCWSTR *lpServiceArgVectors)
1152 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1156 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1158 __EXCEPT(rpc_filter)
1160 err = map_exception_code(GetExceptionCode());
1163 if (err != ERROR_SUCCESS)
1172 /******************************************************************************
1173 * QueryServiceStatus [ADVAPI32.@]
1176 * hService [I] Handle to service to get information about
1177 * lpservicestatus [O] buffer to receive the status information for the service
1180 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1181 LPSERVICE_STATUS lpservicestatus)
1183 SERVICE_STATUS_PROCESS SvcStatusData;
1187 TRACE("%p %p\n", hService, lpservicestatus);
1191 SetLastError(ERROR_INVALID_HANDLE);
1194 if (!lpservicestatus)
1196 SetLastError(ERROR_INVALID_ADDRESS);
1200 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1201 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1202 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1207 /******************************************************************************
1208 * QueryServiceStatusEx [ADVAPI32.@]
1210 * Get information about a service.
1213 * hService [I] Handle to service to get information about
1214 * InfoLevel [I] Level of information to get
1215 * lpBuffer [O] Destination for requested information
1216 * cbBufSize [I] Size of lpBuffer in bytes
1217 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1223 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1224 LPBYTE lpBuffer, DWORD cbBufSize,
1225 LPDWORD pcbBytesNeeded)
1229 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1231 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1233 err = ERROR_INVALID_LEVEL;
1235 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1237 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1238 err = ERROR_INSUFFICIENT_BUFFER;
1244 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1246 __EXCEPT(rpc_filter)
1248 err = map_exception_code(GetExceptionCode());
1252 if (err != ERROR_SUCCESS)
1260 /******************************************************************************
1261 * QueryServiceConfigA [ADVAPI32.@]
1263 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1264 DWORD size, LPDWORD needed )
1269 QUERY_SERVICE_CONFIGW *configW;
1271 TRACE("%p %p %d %p\n", hService, config, size, needed);
1273 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1275 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1278 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1279 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1280 if (!ret) goto done;
1282 config->dwServiceType = configW->dwServiceType;
1283 config->dwStartType = configW->dwStartType;
1284 config->dwErrorControl = configW->dwErrorControl;
1285 config->lpBinaryPathName = NULL;
1286 config->lpLoadOrderGroup = NULL;
1287 config->dwTagId = configW->dwTagId;
1288 config->lpDependencies = NULL;
1289 config->lpServiceStartName = NULL;
1290 config->lpDisplayName = NULL;
1292 p = (LPSTR)(config + 1);
1293 n = size - sizeof(*config);
1296 #define MAP_STR(str) \
1300 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1301 if (!sz) goto done; \
1308 MAP_STR( lpBinaryPathName );
1309 MAP_STR( lpLoadOrderGroup );
1310 MAP_STR( lpDependencies );
1311 MAP_STR( lpServiceStartName );
1312 MAP_STR( lpDisplayName );
1315 *needed = p - (LPSTR)config;
1319 HeapFree( GetProcessHeap(), 0, buffer );
1323 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1330 memset(*buf, 0, cb);
1334 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1335 memcpy(*buf, *string_ptr, cb);
1336 MIDL_user_free(*string_ptr);
1339 *string_ptr = (LPWSTR)*buf;
1345 static DWORD size_string(LPCWSTR string)
1347 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1350 /******************************************************************************
1351 * QueryServiceConfigW [ADVAPI32.@]
1354 QueryServiceConfigW( SC_HANDLE hService,
1355 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1356 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1358 QUERY_SERVICE_CONFIGW config;
1363 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1364 cbBufSize, pcbBytesNeeded);
1366 memset(&config, 0, sizeof(config));
1370 err = svcctl_QueryServiceConfigW(hService, &config);
1372 __EXCEPT(rpc_filter)
1374 err = map_exception_code(GetExceptionCode());
1378 if (err != ERROR_SUCCESS)
1380 TRACE("services.exe: error %u\n", err);
1385 /* calculate the size required first */
1386 total = sizeof (QUERY_SERVICE_CONFIGW);
1387 total += size_string(config.lpBinaryPathName);
1388 total += size_string(config.lpLoadOrderGroup);
1389 total += size_string(config.lpDependencies);
1390 total += size_string(config.lpServiceStartName);
1391 total += size_string(config.lpDisplayName);
1393 *pcbBytesNeeded = total;
1395 /* if there's not enough memory, return an error */
1396 if( total > cbBufSize )
1398 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1399 MIDL_user_free(config.lpBinaryPathName);
1400 MIDL_user_free(config.lpLoadOrderGroup);
1401 MIDL_user_free(config.lpDependencies);
1402 MIDL_user_free(config.lpServiceStartName);
1403 MIDL_user_free(config.lpDisplayName);
1407 *lpServiceConfig = config;
1408 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1409 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1410 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1411 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1412 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1413 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1415 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1416 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1417 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1418 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1419 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1424 /******************************************************************************
1425 * QueryServiceConfig2A [ADVAPI32.@]
1428 * observed under win2k:
1429 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1430 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1432 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1433 DWORD size, LPDWORD needed)
1436 LPBYTE bufferW = NULL;
1439 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1441 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1442 if(!ret) goto cleanup;
1445 case SERVICE_CONFIG_DESCRIPTION:
1446 if (buffer && bufferW) {
1447 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1448 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1449 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1451 configA->lpDescription = (LPSTR)(configA + 1);
1452 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1453 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1455 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1457 configA->lpDescription = NULL;
1460 else configA->lpDescription = NULL;
1463 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1464 if (buffer && bufferW && *needed<=size)
1465 memcpy(buffer, bufferW, *needed);
1468 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1474 HeapFree( GetProcessHeap(), 0, bufferW);
1478 /******************************************************************************
1479 * QueryServiceConfig2W [ADVAPI32.@]
1481 * See QueryServiceConfig2A.
1483 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1484 DWORD size, LPDWORD needed)
1488 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1489 FIXME("Level %d not implemented\n", dwLevel);
1490 SetLastError(ERROR_INVALID_LEVEL);
1494 if(!buffer && size) {
1495 SetLastError(ERROR_INVALID_ADDRESS);
1499 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1503 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1505 __EXCEPT(rpc_filter)
1507 err = map_exception_code(GetExceptionCode());
1511 if (err != ERROR_SUCCESS)
1513 SetLastError( err );
1519 case SERVICE_CONFIG_DESCRIPTION:
1522 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1523 if (descr->lpDescription) /* make it an absolute pointer */
1524 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1532 /******************************************************************************
1533 * EnumServicesStatusA [ADVAPI32.@]
1536 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1537 services, DWORD size, LPDWORD needed, LPDWORD returned,
1538 LPDWORD resume_handle )
1542 ENUM_SERVICE_STATUSW *servicesW = NULL;
1546 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1547 returned, resume_handle);
1549 sz = max( 2 * size, sizeof(*servicesW) );
1550 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1552 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1556 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1557 if (!ret) goto done;
1559 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1560 n = size - (p - (char *)services);
1562 for (i = 0; i < *returned; i++)
1564 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1566 services[i].lpServiceName = p;
1569 if (servicesW[i].lpDisplayName)
1571 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1573 services[i].lpDisplayName = p;
1577 else services[i].lpDisplayName = NULL;
1578 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1584 HeapFree( GetProcessHeap(), 0, servicesW );
1588 /******************************************************************************
1589 * EnumServicesStatusW [ADVAPI32.@]
1592 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1593 services, DWORD size, LPDWORD needed, LPDWORD returned,
1594 LPDWORD resume_handle )
1597 ENUM_SERVICE_STATUSW dummy_status;
1599 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1600 returned, resume_handle);
1603 FIXME("resume handle not supported\n");
1607 SetLastError( ERROR_INVALID_HANDLE );
1611 /* make sure we pass a valid pointer */
1612 if (!services || size < sizeof(*services))
1614 services = &dummy_status;
1615 size = sizeof(dummy_status);
1620 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1622 __EXCEPT(rpc_filter)
1624 err = map_exception_code( GetExceptionCode() );
1628 if (err != ERROR_SUCCESS)
1630 SetLastError( err );
1634 for (i = 0; i < *returned; i++)
1636 /* convert buffer offsets into pointers */
1637 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1638 if (services[i].lpDisplayName)
1639 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1645 /******************************************************************************
1646 * EnumServicesStatusExA [ADVAPI32.@]
1649 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1650 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1651 LPDWORD resume_handle, LPCSTR group )
1655 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1656 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1657 WCHAR *groupW = NULL;
1661 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1662 size, needed, returned, resume_handle, debugstr_a(group));
1664 sz = max( 2 * size, sizeof(*servicesW) );
1665 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1667 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1672 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1673 if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1675 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1676 HeapFree( GetProcessHeap(), 0, servicesW );
1679 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1682 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1683 needed, returned, resume_handle, groupW );
1684 if (!ret) goto done;
1686 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1687 n = size - (p - (char *)services);
1689 for (i = 0; i < *returned; i++)
1691 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1693 services[i].lpServiceName = p;
1696 if (servicesW[i].lpDisplayName)
1698 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1700 services[i].lpDisplayName = p;
1704 else services[i].lpDisplayName = NULL;
1705 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1711 HeapFree( GetProcessHeap(), 0, servicesW );
1712 HeapFree( GetProcessHeap(), 0, groupW );
1716 /******************************************************************************
1717 * EnumServicesStatusExW [ADVAPI32.@]
1720 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1721 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1722 LPDWORD resume_handle, LPCWSTR group )
1725 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1726 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1728 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1729 size, needed, returned, resume_handle, debugstr_w(group));
1732 FIXME("resume handle not supported\n");
1734 if (level != SC_ENUM_PROCESS_INFO)
1736 SetLastError( ERROR_INVALID_LEVEL );
1741 SetLastError( ERROR_INVALID_HANDLE );
1745 /* make sure we pass a valid buffer pointer */
1746 if (!services || size < sizeof(*services))
1748 buffer = (BYTE *)&dummy_status;
1749 size = sizeof(dummy_status);
1754 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1757 __EXCEPT(rpc_filter)
1759 err = map_exception_code( GetExceptionCode() );
1763 if (err != ERROR_SUCCESS)
1765 SetLastError( err );
1769 for (i = 0; i < *returned; i++)
1771 /* convert buffer offsets into pointers */
1772 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1773 if (services[i].lpDisplayName)
1774 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1780 /******************************************************************************
1781 * GetServiceKeyNameA [ADVAPI32.@]
1783 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1784 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1786 LPWSTR lpDisplayNameW, lpServiceNameW;
1790 TRACE("%p %s %p %p\n", hSCManager,
1791 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1793 lpDisplayNameW = SERV_dup(lpDisplayName);
1795 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1797 lpServiceNameW = NULL;
1799 sizeW = *lpcchBuffer;
1800 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1802 if (lpServiceName && *lpcchBuffer)
1803 lpServiceName[0] = 0;
1804 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1808 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1809 *lpcchBuffer, NULL, NULL ))
1811 if (*lpcchBuffer && lpServiceName)
1812 lpServiceName[0] = 0;
1813 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1817 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1821 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1822 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1826 /******************************************************************************
1827 * GetServiceKeyNameW [ADVAPI32.@]
1829 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1830 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1836 TRACE("%p %s %p %p\n", hSCManager,
1837 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1841 SetLastError( ERROR_INVALID_HANDLE );
1845 /* provide a buffer if the caller didn't */
1846 if (!lpServiceName || *lpcchBuffer < 2)
1848 lpServiceName = buffer;
1849 /* A size of 1 would be enough, but tests show that Windows returns 2,
1850 * probably because of a WCHAR/bytes mismatch in their code.
1855 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1856 * includes the nul-terminator on input. */
1857 size = *lpcchBuffer - 1;
1861 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1864 __EXCEPT(rpc_filter)
1866 err = map_exception_code(GetExceptionCode());
1870 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1871 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1872 *lpcchBuffer = size;
1876 return err == ERROR_SUCCESS;
1879 /******************************************************************************
1880 * QueryServiceLockStatusA [ADVAPI32.@]
1882 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1883 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1884 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1886 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1891 /******************************************************************************
1892 * QueryServiceLockStatusW [ADVAPI32.@]
1894 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1895 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1896 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1898 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1903 /******************************************************************************
1904 * GetServiceDisplayNameA [ADVAPI32.@]
1906 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1907 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1909 LPWSTR lpServiceNameW, lpDisplayNameW;
1913 TRACE("%p %s %p %p\n", hSCManager,
1914 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1916 lpServiceNameW = SERV_dup(lpServiceName);
1918 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1920 lpDisplayNameW = NULL;
1922 sizeW = *lpcchBuffer;
1923 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1925 if (lpDisplayName && *lpcchBuffer)
1926 lpDisplayName[0] = 0;
1927 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1931 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1932 *lpcchBuffer, NULL, NULL ))
1934 if (*lpcchBuffer && lpDisplayName)
1935 lpDisplayName[0] = 0;
1936 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1940 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1941 * (but if the function succeeded it means that is a good upper estimation of the size) */
1945 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1946 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1950 /******************************************************************************
1951 * GetServiceDisplayNameW [ADVAPI32.@]
1953 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1954 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1960 TRACE("%p %s %p %p\n", hSCManager,
1961 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1965 SetLastError( ERROR_INVALID_HANDLE );
1969 /* provide a buffer if the caller didn't */
1970 if (!lpDisplayName || *lpcchBuffer < 2)
1972 lpDisplayName = buffer;
1973 /* A size of 1 would be enough, but tests show that Windows returns 2,
1974 * probably because of a WCHAR/bytes mismatch in their code.
1979 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1980 * includes the nul-terminator on input. */
1981 size = *lpcchBuffer - 1;
1985 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
1988 __EXCEPT(rpc_filter)
1990 err = map_exception_code(GetExceptionCode());
1994 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1995 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1996 *lpcchBuffer = size;
2000 return err == ERROR_SUCCESS;
2003 /******************************************************************************
2004 * ChangeServiceConfigW [ADVAPI32.@]
2006 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2007 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2008 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2009 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2014 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2015 hService, dwServiceType, dwStartType, dwErrorControl,
2016 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2017 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2018 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2020 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2024 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2025 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2026 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2027 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2029 __EXCEPT(rpc_filter)
2031 err = map_exception_code(GetExceptionCode());
2035 if (err != ERROR_SUCCESS)
2038 return err == ERROR_SUCCESS;
2041 /******************************************************************************
2042 * ChangeServiceConfigA [ADVAPI32.@]
2044 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2045 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2046 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2047 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2049 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2050 LPWSTR wServiceStartName, wPassword, wDisplayName;
2053 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2054 hService, dwServiceType, dwStartType, dwErrorControl,
2055 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2056 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2057 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2059 wBinaryPathName = SERV_dup( lpBinaryPathName );
2060 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2061 wDependencies = SERV_dupmulti( lpDependencies );
2062 wServiceStartName = SERV_dup( lpServiceStartName );
2063 wPassword = SERV_dup( lpPassword );
2064 wDisplayName = SERV_dup( lpDisplayName );
2066 r = ChangeServiceConfigW( hService, dwServiceType,
2067 dwStartType, dwErrorControl, wBinaryPathName,
2068 wLoadOrderGroup, lpdwTagId, wDependencies,
2069 wServiceStartName, wPassword, wDisplayName);
2071 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2072 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2073 HeapFree( GetProcessHeap(), 0, wDependencies );
2074 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2075 HeapFree( GetProcessHeap(), 0, wPassword );
2076 HeapFree( GetProcessHeap(), 0, wDisplayName );
2081 /******************************************************************************
2082 * ChangeServiceConfig2A [ADVAPI32.@]
2084 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2089 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2091 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2093 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2094 SERVICE_DESCRIPTIONW sdw;
2096 sdw.lpDescription = SERV_dup( sd->lpDescription );
2098 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2100 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2102 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2104 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2105 SERVICE_FAILURE_ACTIONSW faw;
2107 faw.dwResetPeriod = fa->dwResetPeriod;
2108 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2109 faw.lpCommand = SERV_dup( fa->lpCommand );
2110 faw.cActions = fa->cActions;
2111 faw.lpsaActions = fa->lpsaActions;
2113 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2115 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2116 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2118 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2120 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2123 SetLastError( ERROR_INVALID_PARAMETER );
2128 /******************************************************************************
2129 * ChangeServiceConfig2W [ADVAPI32.@]
2131 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2138 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2140 __EXCEPT(rpc_filter)
2142 err = map_exception_code(GetExceptionCode());
2146 if (err != ERROR_SUCCESS)
2149 return err == ERROR_SUCCESS;
2152 NTSTATUS SERV_QueryServiceObjectSecurity(SC_HANDLE hService,
2153 SECURITY_INFORMATION dwSecurityInformation,
2154 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2155 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2157 SECURITY_DESCRIPTOR descriptor;
2162 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2163 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2165 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2166 FIXME("information %d not supported\n", dwSecurityInformation);
2168 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2170 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2171 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2174 status = RtlMakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2175 *pcbBytesNeeded = size;
2179 /******************************************************************************
2180 * QueryServiceObjectSecurity [ADVAPI32.@]
2182 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2183 SECURITY_INFORMATION dwSecurityInformation,
2184 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2185 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2187 NTSTATUS status = SERV_QueryServiceObjectSecurity(hService, dwSecurityInformation, lpSecurityDescriptor,
2188 cbBufSize, pcbBytesNeeded);
2189 if (status != STATUS_SUCCESS)
2191 SetLastError(RtlNtStatusToDosError(status));
2197 /******************************************************************************
2198 * SetServiceObjectSecurity [ADVAPI32.@]
2200 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2201 SECURITY_INFORMATION dwSecurityInformation,
2202 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2204 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2208 /******************************************************************************
2209 * SetServiceBits [ADVAPI32.@]
2211 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2212 DWORD dwServiceBits,
2214 BOOL bUpdateImmediately)
2216 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2217 bSetBitsOn, bUpdateImmediately);
2221 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2222 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2224 LPHANDLER_FUNCTION func = context;
2227 return ERROR_SUCCESS;
2230 /******************************************************************************
2231 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2233 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2235 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2238 /******************************************************************************
2239 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2241 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2243 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2246 /******************************************************************************
2247 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2249 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2252 SERVICE_STATUS_HANDLE ret;
2254 nameW = SERV_dup(name);
2255 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2256 HeapFree( GetProcessHeap(), 0, nameW );
2260 /******************************************************************************
2261 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2263 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2264 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2266 service_data *service;
2267 SC_HANDLE hService = 0;
2270 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2272 EnterCriticalSection( &service_cs );
2273 if ((service = find_service_by_name( lpServiceName )))
2275 service->handler = lpHandlerProc;
2276 service->context = lpContext;
2277 hService = service->handle;
2280 LeaveCriticalSection( &service_cs );
2282 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2284 return (SERVICE_STATUS_HANDLE)hService;
2287 /******************************************************************************
2288 * EnumDependentServicesA [ADVAPI32.@]
2290 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2291 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2292 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2294 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2295 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2297 *lpServicesReturned = 0;
2301 /******************************************************************************
2302 * EnumDependentServicesW [ADVAPI32.@]
2304 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2305 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2306 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2308 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2309 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2311 *lpServicesReturned = 0;