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"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
44 #include "advapi32_misc.h"
46 #include "wine/exception.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(service);
50 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
52 return HeapAlloc(GetProcessHeap(), 0, len);
55 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
57 HeapFree(GetProcessHeap(), 0, ptr);
60 typedef struct service_data_t
62 LPHANDLER_FUNCTION_EX handler;
66 SC_HANDLE full_access_handle;
69 LPSERVICE_MAIN_FUNCTIONA a;
70 LPSERVICE_MAIN_FUNCTIONW w;
76 static CRITICAL_SECTION service_cs;
77 static CRITICAL_SECTION_DEBUG service_cs_debug =
80 { &service_cs_debug.ProcessLocksList,
81 &service_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
84 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
86 static service_data **services;
87 static unsigned int nb_services;
88 static HANDLE service_event;
90 extern HANDLE CDECL __wine_make_process_system(void);
92 /******************************************************************************
93 * String management functions (same behaviour as strdup)
94 * NOTE: the caller of those functions is responsible for calling HeapFree
95 * in order to release the memory allocated by those functions.
97 LPWSTR SERV_dup( LPCSTR str )
104 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
105 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
106 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
110 static inline LPWSTR SERV_dupmulti(LPCSTR str)
118 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
119 n += (strlen( &str[n] ) + 1);
124 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
125 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
129 static inline DWORD multisz_cb(LPCWSTR wmultisz)
131 const WCHAR *wptr = wmultisz;
133 if (wmultisz == NULL)
137 wptr += lstrlenW(wptr)+1;
138 return (wptr - wmultisz + 1)*sizeof(WCHAR);
141 /******************************************************************************
142 * RPC connection with services.exe
145 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
147 WCHAR transport[] = SVCCTL_TRANSPORT;
148 WCHAR endpoint[] = SVCCTL_ENDPOINT;
149 RPC_WSTR binding_str;
153 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
154 if (status != RPC_S_OK)
156 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
160 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
161 RpcStringFreeW(&binding_str);
163 if (status != RPC_S_OK)
165 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
172 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
177 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
179 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
182 static DWORD map_exception_code(DWORD exception_code)
184 switch (exception_code)
186 case RPC_X_NULL_REF_POINTER:
187 return ERROR_INVALID_ADDRESS;
188 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
189 case RPC_X_BYTE_COUNT_TOO_SMALL:
190 return ERROR_INVALID_PARAMETER;
191 case RPC_S_INVALID_BINDING:
192 case RPC_X_SS_IN_NULL_CONTEXT:
193 return ERROR_INVALID_HANDLE;
195 return exception_code;
199 /******************************************************************************
200 * Service IPC functions
202 static LPWSTR service_get_pipe_name(void)
204 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
205 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
206 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
207 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
208 'C','o','n','t','r','o','l','\\',
209 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
212 HKEY service_current_key;
213 DWORD service_current;
217 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
218 KEY_QUERY_VALUE, &service_current_key);
219 if (ret != ERROR_SUCCESS)
221 len = sizeof(service_current);
222 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
223 (BYTE *)&service_current, &len);
224 RegCloseKey(service_current_key);
225 if (ret != ERROR_SUCCESS || type != REG_DWORD)
227 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
228 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
231 snprintfW(name, len, format, service_current);
235 static HANDLE service_open_pipe(void)
237 LPWSTR szPipe = service_get_pipe_name();
238 HANDLE handle = INVALID_HANDLE_VALUE;
241 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
242 0, NULL, OPEN_ALWAYS, 0, NULL);
243 if (handle != INVALID_HANDLE_VALUE)
245 if (GetLastError() != ERROR_PIPE_BUSY)
247 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
248 HeapFree(GetProcessHeap(), 0, szPipe);
253 static service_data *find_service_by_name( const WCHAR *name )
257 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
259 for (i = 0; i < nb_services; i++)
260 if (!strcmpiW( name, services[i]->name )) return services[i];
264 /******************************************************************************
267 * Call into the main service routine provided by StartServiceCtrlDispatcher.
269 static DWORD WINAPI service_thread(LPVOID arg)
271 service_data *info = arg;
272 LPWSTR str = info->args;
273 DWORD argc = 0, len = 0;
279 len += strlenW(&str[len]) + 1;
288 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
289 for (argc=0, p=str; *p; p += strlenW(p) + 1)
293 info->proc.w(argc, argv);
294 HeapFree(GetProcessHeap(), 0, argv);
298 LPSTR strA, *argv, p;
301 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
302 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
303 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
305 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
306 for (argc=0, p=strA; *p; p += strlen(p) + 1)
310 info->proc.a(argc, argv);
311 HeapFree(GetProcessHeap(), 0, argv);
312 HeapFree(GetProcessHeap(), 0, strA);
317 /******************************************************************************
318 * service_handle_start
320 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
322 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
326 WARN("service is not stopped\n");
327 return ERROR_SERVICE_ALREADY_RUNNING;
330 HeapFree(GetProcessHeap(), 0, service->args);
331 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
332 memcpy( service->args, data, count * sizeof(WCHAR) );
333 service->thread = CreateThread( NULL, 0, service_thread,
335 SetEvent( service_event ); /* notify the main loop */
339 /******************************************************************************
340 * service_handle_control
342 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
344 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
346 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
348 if (service->handler)
349 ret = service->handler(dwControl, 0, NULL, service->context);
353 /******************************************************************************
354 * service_control_dispatcher
356 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
361 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
363 ERR("failed to open service manager error %u\n", GetLastError());
367 pipe = service_open_pipe();
369 if (pipe==INVALID_HANDLE_VALUE)
371 WARN("failed to create control pipe error = %d\n", GetLastError());
375 /* dispatcher loop */
378 service_data *service;
379 service_start_info info;
382 DWORD data_size = 0, count, result;
384 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
387 if (GetLastError() != ERROR_BROKEN_PIPE)
388 ERR( "pipe read failed error %u\n", GetLastError() );
391 if (count != FIELD_OFFSET(service_start_info,data))
393 ERR( "partial pipe read %u\n", count );
396 if (count < info.total_size)
398 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
399 data = HeapAlloc( GetProcessHeap(), 0, data_size );
400 r = ReadFile( pipe, data, data_size, &count, NULL );
403 if (GetLastError() != ERROR_BROKEN_PIPE)
404 ERR( "pipe read failed error %u\n", GetLastError() );
405 HeapFree( GetProcessHeap(), 0, data );
408 if (count != data_size)
410 ERR( "partial pipe read %u/%u\n", count, data_size );
411 HeapFree( GetProcessHeap(), 0, data );
416 /* find the service */
418 if (!(service = find_service_by_name( data )))
420 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
421 result = ERROR_INVALID_PARAMETER;
425 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
427 /* handle the request */
430 case WINESERV_STARTINFO:
431 if (!service->handle)
433 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )) ||
434 !(service->full_access_handle = OpenServiceW( manager, data, GENERIC_READ|GENERIC_WRITE )))
435 FIXME( "failed to open service %s\n", debugstr_w(data) );
437 result = service_handle_start(service, data, data_size / sizeof(WCHAR));
439 case WINESERV_SENDCONTROL:
440 result = service_handle_control(service, info.control);
443 ERR("received invalid command %u\n", info.cmd);
444 result = ERROR_INVALID_PARAMETER;
449 WriteFile(pipe, &result, sizeof(result), &count, NULL);
450 HeapFree( GetProcessHeap(), 0, data );
454 CloseServiceHandle( manager );
458 /******************************************************************************
459 * service_run_main_thread
461 static BOOL service_run_main_thread(void)
464 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
465 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
467 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
469 /* FIXME: service_control_dispatcher should be merged into the main thread */
470 wait_handles[0] = __wine_make_process_system();
471 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
472 wait_handles[2] = service_event;
474 TRACE("Starting %d services running as process %d\n",
475 nb_services, GetCurrentProcessId());
477 /* wait for all the threads to pack up and exit */
480 EnterCriticalSection( &service_cs );
481 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
483 if (!services[i]->thread) continue;
484 wait_services[n] = i;
485 wait_handles[n++] = services[i]->thread;
487 LeaveCriticalSection( &service_cs );
489 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
490 if (!ret) /* system process event */
493 SERVICE_PRESHUTDOWN_INFO spi;
494 DWORD timeout = 5000;
497 EnterCriticalSection( &service_cs );
499 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
501 if (!services[i]->thread) continue;
503 res = QueryServiceStatus(services[i]->full_access_handle, &st);
505 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
507 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
508 (LPBYTE)&spi, sizeof(spi), &i );
511 FIXME("service should be able to delay shutdown\n");
512 timeout += spi.dwPreshutdownTimeout;
513 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN );
514 wait_handles[n++] = services[i]->thread;
517 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
519 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN );
520 wait_handles[n++] = services[i]->thread;
523 LeaveCriticalSection( &service_cs );
525 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
526 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
531 TRACE( "control dispatcher exited, shutting down\n" );
532 /* FIXME: we should maybe send a shutdown control to running services */
537 continue; /* rebuild the list */
541 services[wait_services[ret]]->thread = 0;
542 CloseHandle( wait_handles[ret] );
543 if (n == 4) return TRUE; /* it was the last running thread */
549 /******************************************************************************
550 * StartServiceCtrlDispatcherA [ADVAPI32.@]
552 * See StartServiceCtrlDispatcherW.
554 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
560 TRACE("%p\n", servent);
564 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
567 while (servent[nb_services].lpServiceName) nb_services++;
568 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
570 for (i = 0; i < nb_services; i++)
572 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
573 DWORD sz = FIELD_OFFSET( service_data, name[len] );
574 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
575 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
576 info->proc.a = servent[i].lpServiceProc;
577 info->unicode = FALSE;
581 service_run_main_thread();
586 /******************************************************************************
587 * StartServiceCtrlDispatcherW [ADVAPI32.@]
589 * Connects a process containing one or more services to the service control
593 * servent [I] A list of the service names and service procedures
599 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
605 TRACE("%p\n", servent);
609 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
612 while (servent[nb_services].lpServiceName) nb_services++;
613 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
615 for (i = 0; i < nb_services; i++)
617 DWORD len = strlenW(servent[i].lpServiceName) + 1;
618 DWORD sz = FIELD_OFFSET( service_data, name[len] );
619 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
620 strcpyW(info->name, servent[i].lpServiceName);
621 info->proc.w = servent[i].lpServiceProc;
622 info->unicode = TRUE;
626 service_run_main_thread();
631 /******************************************************************************
632 * LockServiceDatabase [ADVAPI32.@]
634 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
636 SC_RPC_LOCK hLock = NULL;
639 TRACE("%p\n",hSCManager);
643 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
647 err = map_exception_code(GetExceptionCode());
650 if (err != ERROR_SUCCESS)
658 /******************************************************************************
659 * UnlockServiceDatabase [ADVAPI32.@]
661 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
664 SC_RPC_LOCK hRpcLock = ScLock;
666 TRACE("%p\n",ScLock);
670 err = svcctl_UnlockServiceDatabase(&hRpcLock);
674 err = map_exception_code(GetExceptionCode());
677 if (err != ERROR_SUCCESS)
685 /******************************************************************************
686 * SetServiceStatus [ADVAPI32.@]
693 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
697 TRACE("%p %x %x %x %x %x %x %x\n", hService,
698 lpStatus->dwServiceType, lpStatus->dwCurrentState,
699 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
700 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
701 lpStatus->dwWaitHint);
705 err = svcctl_SetServiceStatus( hService, lpStatus );
709 err = map_exception_code(GetExceptionCode());
712 if (err != ERROR_SUCCESS)
718 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
719 CloseServiceHandle((SC_HANDLE)hService);
725 /******************************************************************************
726 * OpenSCManagerA [ADVAPI32.@]
728 * Establish a connection to the service control manager and open its database.
731 * lpMachineName [I] Pointer to machine name string
732 * lpDatabaseName [I] Pointer to database name string
733 * dwDesiredAccess [I] Type of access
736 * Success: A Handle to the service control manager database
739 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
740 DWORD dwDesiredAccess )
742 LPWSTR lpMachineNameW, lpDatabaseNameW;
745 lpMachineNameW = SERV_dup(lpMachineName);
746 lpDatabaseNameW = SERV_dup(lpDatabaseName);
747 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
748 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
749 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
753 /******************************************************************************
754 * OpenSCManagerW [ADVAPI32.@]
756 * See OpenSCManagerA.
758 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
759 DWORD dwDesiredAccess )
761 SC_HANDLE handle = 0;
764 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
765 debugstr_w(lpDatabaseName), dwDesiredAccess);
769 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
773 r = map_exception_code(GetExceptionCode());
777 if (r!=ERROR_SUCCESS)
783 TRACE("returning %p\n", handle);
787 /******************************************************************************
788 * ControlService [ADVAPI32.@]
790 * Send a control code to a service.
793 * hService [I] Handle of the service control manager database
794 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
795 * lpServiceStatus [O] Destination for the status of the service, if available
802 * Unlike M$' implementation, control requests are not serialized and may be
803 * processed asynchronously.
805 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
806 LPSERVICE_STATUS lpServiceStatus )
810 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
814 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
818 err = map_exception_code(GetExceptionCode());
821 if (err != ERROR_SUCCESS)
830 /******************************************************************************
831 * CloseServiceHandle [ADVAPI32.@]
833 * Close a handle to a service or the service control manager database.
836 * hSCObject [I] Handle to service or service control manager database
843 CloseServiceHandle( SC_HANDLE hSCObject )
847 TRACE("%p\n", hSCObject);
851 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
855 err = map_exception_code(GetExceptionCode());
859 if (err != ERROR_SUCCESS)
868 /******************************************************************************
869 * OpenServiceA [ADVAPI32.@]
871 * Open a handle to a service.
874 * hSCManager [I] Handle of the service control manager database
875 * lpServiceName [I] Name of the service to open
876 * dwDesiredAccess [I] Access required to the service
879 * Success: Handle to the service
882 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
883 DWORD dwDesiredAccess )
885 LPWSTR lpServiceNameW;
888 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
890 lpServiceNameW = SERV_dup(lpServiceName);
891 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
892 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
897 /******************************************************************************
898 * OpenServiceW [ADVAPI32.@]
902 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
903 DWORD dwDesiredAccess)
905 SC_HANDLE handle = 0;
908 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
912 SetLastError( ERROR_INVALID_HANDLE );
918 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
922 err = map_exception_code(GetExceptionCode());
926 if (err != ERROR_SUCCESS)
932 TRACE("returning %p\n",handle);
936 /******************************************************************************
937 * CreateServiceW [ADVAPI32.@]
940 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
941 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
942 DWORD dwServiceType, DWORD dwStartType,
943 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
944 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
945 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
948 SC_HANDLE handle = 0;
952 TRACE("%p %s %s\n", hSCManager,
953 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
957 SetLastError( ERROR_INVALID_HANDLE );
962 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
968 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
969 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
970 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
971 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
972 (SC_RPC_HANDLE *)&handle);
976 err = map_exception_code(GetExceptionCode());
980 if (err != ERROR_SUCCESS)
989 /******************************************************************************
990 * CreateServiceA [ADVAPI32.@]
993 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
994 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
995 DWORD dwServiceType, DWORD dwStartType,
996 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
997 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
998 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1001 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1002 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1005 TRACE("%p %s %s\n", hSCManager,
1006 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1008 lpServiceNameW = SERV_dup( lpServiceName );
1009 lpDisplayNameW = SERV_dup( lpDisplayName );
1010 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1011 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1012 lpDependenciesW = SERV_dupmulti( lpDependencies );
1013 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1014 lpPasswordW = SERV_dup( lpPassword );
1016 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1017 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1018 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1019 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1021 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1022 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1023 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1024 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1025 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1026 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1027 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1033 /******************************************************************************
1034 * DeleteService [ADVAPI32.@]
1036 * Delete a service from the service control manager database.
1039 * hService [I] Handle of the service to delete
1045 BOOL WINAPI DeleteService( SC_HANDLE hService )
1051 err = svcctl_DeleteService(hService);
1053 __EXCEPT(rpc_filter)
1055 err = map_exception_code(GetExceptionCode());
1068 /******************************************************************************
1069 * StartServiceA [ADVAPI32.@]
1074 * hService [I] Handle of service
1075 * dwNumServiceArgs [I] Number of arguments
1076 * lpServiceArgVectors [I] Address of array of argument strings
1079 * - NT implements this function using an obscure RPC call.
1080 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1081 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1082 * - This will only work for shared address space. How should the service
1083 * args be transferred when address spaces are separated?
1084 * - Can only start one service at a time.
1085 * - Has no concept of privilege.
1091 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1092 LPCSTR *lpServiceArgVectors )
1094 LPWSTR *lpwstr=NULL;
1098 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1100 if (dwNumServiceArgs)
1101 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1102 dwNumServiceArgs*sizeof(LPWSTR) );
1104 for(i=0; i<dwNumServiceArgs; i++)
1105 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1107 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1109 if (dwNumServiceArgs)
1111 for(i=0; i<dwNumServiceArgs; i++)
1112 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1113 HeapFree(GetProcessHeap(), 0, lpwstr);
1120 /******************************************************************************
1121 * StartServiceW [ADVAPI32.@]
1123 * See StartServiceA.
1125 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1126 LPCWSTR *lpServiceArgVectors)
1130 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1134 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1136 __EXCEPT(rpc_filter)
1138 err = map_exception_code(GetExceptionCode());
1141 if (err != ERROR_SUCCESS)
1150 /******************************************************************************
1151 * QueryServiceStatus [ADVAPI32.@]
1154 * hService [I] Handle to service to get information about
1155 * lpservicestatus [O] buffer to receive the status information for the service
1158 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1159 LPSERVICE_STATUS lpservicestatus)
1161 SERVICE_STATUS_PROCESS SvcStatusData;
1165 TRACE("%p %p\n", hService, lpservicestatus);
1169 SetLastError(ERROR_INVALID_HANDLE);
1172 if (!lpservicestatus)
1174 SetLastError(ERROR_INVALID_ADDRESS);
1178 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1179 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1180 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1185 /******************************************************************************
1186 * QueryServiceStatusEx [ADVAPI32.@]
1188 * Get information about a service.
1191 * hService [I] Handle to service to get information about
1192 * InfoLevel [I] Level of information to get
1193 * lpBuffer [O] Destination for requested information
1194 * cbBufSize [I] Size of lpBuffer in bytes
1195 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1201 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1202 LPBYTE lpBuffer, DWORD cbBufSize,
1203 LPDWORD pcbBytesNeeded)
1207 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1209 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1211 err = ERROR_INVALID_LEVEL;
1213 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1215 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1216 err = ERROR_INSUFFICIENT_BUFFER;
1222 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1224 __EXCEPT(rpc_filter)
1226 err = map_exception_code(GetExceptionCode());
1230 if (err != ERROR_SUCCESS)
1238 /******************************************************************************
1239 * QueryServiceConfigA [ADVAPI32.@]
1241 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1242 DWORD size, LPDWORD needed )
1247 QUERY_SERVICE_CONFIGW *configW;
1249 TRACE("%p %p %d %p\n", hService, config, size, needed);
1251 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1253 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1256 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1257 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1258 if (!ret) goto done;
1260 config->dwServiceType = configW->dwServiceType;
1261 config->dwStartType = configW->dwStartType;
1262 config->dwErrorControl = configW->dwErrorControl;
1263 config->lpBinaryPathName = NULL;
1264 config->lpLoadOrderGroup = NULL;
1265 config->dwTagId = configW->dwTagId;
1266 config->lpDependencies = NULL;
1267 config->lpServiceStartName = NULL;
1268 config->lpDisplayName = NULL;
1270 p = (LPSTR)(config + 1);
1271 n = size - sizeof(*config);
1274 #define MAP_STR(str) \
1278 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1279 if (!sz) goto done; \
1286 MAP_STR( lpBinaryPathName );
1287 MAP_STR( lpLoadOrderGroup );
1288 MAP_STR( lpDependencies );
1289 MAP_STR( lpServiceStartName );
1290 MAP_STR( lpDisplayName );
1293 *needed = p - (LPSTR)config;
1297 HeapFree( GetProcessHeap(), 0, buffer );
1301 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1308 memset(*buf, 0, cb);
1312 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1313 memcpy(*buf, *string_ptr, cb);
1314 MIDL_user_free(*string_ptr);
1317 *string_ptr = (LPWSTR)*buf;
1323 static DWORD size_string(LPCWSTR string)
1325 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1328 /******************************************************************************
1329 * QueryServiceConfigW [ADVAPI32.@]
1332 QueryServiceConfigW( SC_HANDLE hService,
1333 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1334 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1336 QUERY_SERVICE_CONFIGW config;
1341 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1342 cbBufSize, pcbBytesNeeded);
1344 memset(&config, 0, sizeof(config));
1348 err = svcctl_QueryServiceConfigW(hService, &config);
1350 __EXCEPT(rpc_filter)
1352 err = map_exception_code(GetExceptionCode());
1356 if (err != ERROR_SUCCESS)
1358 TRACE("services.exe: error %u\n", err);
1363 /* calculate the size required first */
1364 total = sizeof (QUERY_SERVICE_CONFIGW);
1365 total += size_string(config.lpBinaryPathName);
1366 total += size_string(config.lpLoadOrderGroup);
1367 total += size_string(config.lpDependencies);
1368 total += size_string(config.lpServiceStartName);
1369 total += size_string(config.lpDisplayName);
1371 *pcbBytesNeeded = total;
1373 /* if there's not enough memory, return an error */
1374 if( total > cbBufSize )
1376 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1377 MIDL_user_free(config.lpBinaryPathName);
1378 MIDL_user_free(config.lpLoadOrderGroup);
1379 MIDL_user_free(config.lpDependencies);
1380 MIDL_user_free(config.lpServiceStartName);
1381 MIDL_user_free(config.lpDisplayName);
1385 *lpServiceConfig = config;
1386 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1387 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1388 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1389 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1390 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1391 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1393 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1394 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1395 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1396 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1397 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1402 /******************************************************************************
1403 * QueryServiceConfig2A [ADVAPI32.@]
1406 * observed under win2k:
1407 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1408 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1410 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1411 DWORD size, LPDWORD needed)
1414 LPBYTE bufferW = NULL;
1417 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1419 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1420 if(!ret) goto cleanup;
1423 case SERVICE_CONFIG_DESCRIPTION:
1424 if (buffer && bufferW) {
1425 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1426 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1427 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1429 configA->lpDescription = (LPSTR)(configA + 1);
1430 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1431 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1433 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1435 configA->lpDescription = NULL;
1438 else configA->lpDescription = NULL;
1441 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1442 if (buffer && bufferW && *needed<=size)
1443 memcpy(buffer, bufferW, *needed);
1446 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1452 HeapFree( GetProcessHeap(), 0, bufferW);
1456 /******************************************************************************
1457 * QueryServiceConfig2W [ADVAPI32.@]
1459 * See QueryServiceConfig2A.
1461 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1462 DWORD size, LPDWORD needed)
1466 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1467 FIXME("Level %d not implemented\n", dwLevel);
1468 SetLastError(ERROR_INVALID_LEVEL);
1472 if(!buffer && size) {
1473 SetLastError(ERROR_INVALID_ADDRESS);
1477 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1481 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1483 __EXCEPT(rpc_filter)
1485 err = map_exception_code(GetExceptionCode());
1489 if (err != ERROR_SUCCESS)
1491 SetLastError( err );
1497 case SERVICE_CONFIG_DESCRIPTION:
1500 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1501 if (descr->lpDescription) /* make it an absolute pointer */
1502 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1510 /******************************************************************************
1511 * EnumServicesStatusA [ADVAPI32.@]
1514 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1515 services, DWORD size, LPDWORD needed, LPDWORD returned,
1516 LPDWORD resume_handle )
1520 ENUM_SERVICE_STATUSW *servicesW = NULL;
1524 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1525 returned, resume_handle);
1527 sz = max( 2 * size, sizeof(*servicesW) );
1528 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1530 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1534 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1535 if (!ret) goto done;
1537 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1538 n = size - (p - (char *)services);
1540 for (i = 0; i < *returned; i++)
1542 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1544 services[i].lpServiceName = p;
1547 if (servicesW[i].lpDisplayName)
1549 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1551 services[i].lpDisplayName = p;
1555 else services[i].lpDisplayName = NULL;
1556 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1562 HeapFree( GetProcessHeap(), 0, servicesW );
1566 /******************************************************************************
1567 * EnumServicesStatusW [ADVAPI32.@]
1570 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1571 services, DWORD size, LPDWORD needed, LPDWORD returned,
1572 LPDWORD resume_handle )
1575 ENUM_SERVICE_STATUSW dummy_status;
1577 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1578 returned, resume_handle);
1581 FIXME("resume handle not supported\n");
1585 SetLastError( ERROR_INVALID_HANDLE );
1589 /* make sure we pass a valid pointer */
1590 if (!services || size < sizeof(*services))
1592 services = &dummy_status;
1593 size = sizeof(dummy_status);
1598 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1600 __EXCEPT(rpc_filter)
1602 err = map_exception_code( GetExceptionCode() );
1606 if (err != ERROR_SUCCESS)
1608 SetLastError( err );
1612 for (i = 0; i < *returned; i++)
1614 /* convert buffer offsets into pointers */
1615 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1616 if (services[i].lpDisplayName)
1617 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1623 /******************************************************************************
1624 * EnumServicesStatusExA [ADVAPI32.@]
1627 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1628 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1629 LPDWORD resume_handle, LPCSTR group )
1633 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1634 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1635 WCHAR *groupW = NULL;
1639 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1640 size, needed, returned, resume_handle, debugstr_a(group));
1642 sz = max( 2 * size, sizeof(*servicesW) );
1643 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1645 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1650 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1651 if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1653 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1654 HeapFree( GetProcessHeap(), 0, servicesW );
1657 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1660 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1661 needed, returned, resume_handle, groupW );
1662 if (!ret) goto done;
1664 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1665 n = size - (p - (char *)services);
1667 for (i = 0; i < *returned; i++)
1669 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1671 services[i].lpServiceName = p;
1674 if (servicesW[i].lpDisplayName)
1676 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1678 services[i].lpDisplayName = p;
1682 else services[i].lpDisplayName = NULL;
1683 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1689 HeapFree( GetProcessHeap(), 0, servicesW );
1690 HeapFree( GetProcessHeap(), 0, groupW );
1694 /******************************************************************************
1695 * EnumServicesStatusExW [ADVAPI32.@]
1698 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1699 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1700 LPDWORD resume_handle, LPCWSTR group )
1703 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1704 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1706 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1707 size, needed, returned, resume_handle, debugstr_w(group));
1710 FIXME("resume handle not supported\n");
1712 if (level != SC_ENUM_PROCESS_INFO)
1714 SetLastError( ERROR_INVALID_LEVEL );
1719 SetLastError( ERROR_INVALID_HANDLE );
1723 /* make sure we pass a valid buffer pointer */
1724 if (!services || size < sizeof(*services))
1726 buffer = (BYTE *)&dummy_status;
1727 size = sizeof(dummy_status);
1732 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1735 __EXCEPT(rpc_filter)
1737 err = map_exception_code( GetExceptionCode() );
1741 if (err != ERROR_SUCCESS)
1743 SetLastError( err );
1747 for (i = 0; i < *returned; i++)
1749 /* convert buffer offsets into pointers */
1750 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1751 if (services[i].lpDisplayName)
1752 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1758 /******************************************************************************
1759 * GetServiceKeyNameA [ADVAPI32.@]
1761 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1762 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1764 LPWSTR lpDisplayNameW, lpServiceNameW;
1768 TRACE("%p %s %p %p\n", hSCManager,
1769 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1771 lpDisplayNameW = SERV_dup(lpDisplayName);
1773 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1775 lpServiceNameW = NULL;
1777 sizeW = *lpcchBuffer;
1778 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1780 if (lpServiceName && *lpcchBuffer)
1781 lpServiceName[0] = 0;
1782 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1786 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1787 *lpcchBuffer, NULL, NULL ))
1789 if (*lpcchBuffer && lpServiceName)
1790 lpServiceName[0] = 0;
1791 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1795 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1799 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1800 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1804 /******************************************************************************
1805 * GetServiceKeyNameW [ADVAPI32.@]
1807 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1808 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1814 TRACE("%p %s %p %p\n", hSCManager,
1815 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1819 SetLastError( ERROR_INVALID_HANDLE );
1823 /* provide a buffer if the caller didn't */
1824 if (!lpServiceName || *lpcchBuffer < 2)
1826 lpServiceName = buffer;
1827 /* A size of 1 would be enough, but tests show that Windows returns 2,
1828 * probably because of a WCHAR/bytes mismatch in their code.
1833 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1834 * includes the nul-terminator on input. */
1835 size = *lpcchBuffer - 1;
1839 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1842 __EXCEPT(rpc_filter)
1844 err = map_exception_code(GetExceptionCode());
1848 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1849 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1850 *lpcchBuffer = size;
1854 return err == ERROR_SUCCESS;
1857 /******************************************************************************
1858 * QueryServiceLockStatusA [ADVAPI32.@]
1860 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1861 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1862 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1864 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1869 /******************************************************************************
1870 * QueryServiceLockStatusW [ADVAPI32.@]
1872 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1873 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1874 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1876 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1881 /******************************************************************************
1882 * GetServiceDisplayNameA [ADVAPI32.@]
1884 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1885 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1887 LPWSTR lpServiceNameW, lpDisplayNameW;
1891 TRACE("%p %s %p %p\n", hSCManager,
1892 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1894 lpServiceNameW = SERV_dup(lpServiceName);
1896 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1898 lpDisplayNameW = NULL;
1900 sizeW = *lpcchBuffer;
1901 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1903 if (lpDisplayName && *lpcchBuffer)
1904 lpDisplayName[0] = 0;
1905 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1909 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1910 *lpcchBuffer, NULL, NULL ))
1912 if (*lpcchBuffer && lpDisplayName)
1913 lpDisplayName[0] = 0;
1914 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1918 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1919 * (but if the function succeeded it means that is a good upper estimation of the size) */
1923 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1924 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1928 /******************************************************************************
1929 * GetServiceDisplayNameW [ADVAPI32.@]
1931 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1932 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1938 TRACE("%p %s %p %p\n", hSCManager,
1939 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1943 SetLastError( ERROR_INVALID_HANDLE );
1947 /* provide a buffer if the caller didn't */
1948 if (!lpDisplayName || *lpcchBuffer < 2)
1950 lpDisplayName = buffer;
1951 /* A size of 1 would be enough, but tests show that Windows returns 2,
1952 * probably because of a WCHAR/bytes mismatch in their code.
1957 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1958 * includes the nul-terminator on input. */
1959 size = *lpcchBuffer - 1;
1963 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
1966 __EXCEPT(rpc_filter)
1968 err = map_exception_code(GetExceptionCode());
1972 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1973 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1974 *lpcchBuffer = size;
1978 return err == ERROR_SUCCESS;
1981 /******************************************************************************
1982 * ChangeServiceConfigW [ADVAPI32.@]
1984 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1985 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1986 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1987 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1992 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1993 hService, dwServiceType, dwStartType, dwErrorControl,
1994 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1995 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1996 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1998 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2002 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2003 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2004 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2005 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2007 __EXCEPT(rpc_filter)
2009 err = map_exception_code(GetExceptionCode());
2013 if (err != ERROR_SUCCESS)
2016 return err == ERROR_SUCCESS;
2019 /******************************************************************************
2020 * ChangeServiceConfigA [ADVAPI32.@]
2022 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2023 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2024 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2025 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2027 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2028 LPWSTR wServiceStartName, wPassword, wDisplayName;
2031 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2032 hService, dwServiceType, dwStartType, dwErrorControl,
2033 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2034 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2035 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2037 wBinaryPathName = SERV_dup( lpBinaryPathName );
2038 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2039 wDependencies = SERV_dupmulti( lpDependencies );
2040 wServiceStartName = SERV_dup( lpServiceStartName );
2041 wPassword = SERV_dup( lpPassword );
2042 wDisplayName = SERV_dup( lpDisplayName );
2044 r = ChangeServiceConfigW( hService, dwServiceType,
2045 dwStartType, dwErrorControl, wBinaryPathName,
2046 wLoadOrderGroup, lpdwTagId, wDependencies,
2047 wServiceStartName, wPassword, wDisplayName);
2049 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2050 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2051 HeapFree( GetProcessHeap(), 0, wDependencies );
2052 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2053 HeapFree( GetProcessHeap(), 0, wPassword );
2054 HeapFree( GetProcessHeap(), 0, wDisplayName );
2059 /******************************************************************************
2060 * ChangeServiceConfig2A [ADVAPI32.@]
2062 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2067 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2069 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2071 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2072 SERVICE_DESCRIPTIONW sdw;
2074 sdw.lpDescription = SERV_dup( sd->lpDescription );
2076 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2078 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2080 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2082 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2083 SERVICE_FAILURE_ACTIONSW faw;
2085 faw.dwResetPeriod = fa->dwResetPeriod;
2086 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2087 faw.lpCommand = SERV_dup( fa->lpCommand );
2088 faw.cActions = fa->cActions;
2089 faw.lpsaActions = fa->lpsaActions;
2091 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2093 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2094 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2096 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2098 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2101 SetLastError( ERROR_INVALID_PARAMETER );
2106 /******************************************************************************
2107 * ChangeServiceConfig2W [ADVAPI32.@]
2109 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2116 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2118 __EXCEPT(rpc_filter)
2120 err = map_exception_code(GetExceptionCode());
2124 if (err != ERROR_SUCCESS)
2127 return err == ERROR_SUCCESS;
2130 /******************************************************************************
2131 * QueryServiceObjectSecurity [ADVAPI32.@]
2133 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2134 SECURITY_INFORMATION dwSecurityInformation,
2135 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2136 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2138 SECURITY_DESCRIPTOR descriptor;
2143 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2144 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2146 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2147 FIXME("information %d not supported\n", dwSecurityInformation);
2149 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2151 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2152 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2155 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2156 *pcbBytesNeeded = size;
2160 /******************************************************************************
2161 * SetServiceObjectSecurity [ADVAPI32.@]
2163 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2164 SECURITY_INFORMATION dwSecurityInformation,
2165 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2167 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2171 /******************************************************************************
2172 * SetServiceBits [ADVAPI32.@]
2174 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2175 DWORD dwServiceBits,
2177 BOOL bUpdateImmediately)
2179 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2180 bSetBitsOn, bUpdateImmediately);
2184 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2185 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2187 LPHANDLER_FUNCTION func = context;
2190 return ERROR_SUCCESS;
2193 /******************************************************************************
2194 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2196 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2198 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2201 /******************************************************************************
2202 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2204 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2206 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2209 /******************************************************************************
2210 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2212 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2215 SERVICE_STATUS_HANDLE ret;
2217 nameW = SERV_dup(name);
2218 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2219 HeapFree( GetProcessHeap(), 0, nameW );
2223 /******************************************************************************
2224 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2226 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2227 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2229 service_data *service;
2230 SC_HANDLE hService = 0;
2233 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2235 EnterCriticalSection( &service_cs );
2236 if ((service = find_service_by_name( lpServiceName )))
2238 service->handler = lpHandlerProc;
2239 service->context = lpContext;
2240 hService = service->handle;
2243 LeaveCriticalSection( &service_cs );
2245 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2247 return (SERVICE_STATUS_HANDLE)hService;
2250 /******************************************************************************
2251 * EnumDependentServicesA [ADVAPI32.@]
2253 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2254 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2255 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2257 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2258 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2260 *lpServicesReturned = 0;
2264 /******************************************************************************
2265 * EnumDependentServicesW [ADVAPI32.@]
2267 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2268 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2269 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2271 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2272 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2274 *lpServicesReturned = 0;