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 "wine/exception.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(service);
48 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
49 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
50 'S','e','r','v','i','c','e','s',0 };
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 static const GENERIC_MAPPING scm_generic = {
63 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
64 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
65 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
69 static const GENERIC_MAPPING svc_generic = {
70 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
71 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
72 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
76 typedef struct service_data_t
78 LPHANDLER_FUNCTION_EX handler;
84 LPSERVICE_MAIN_FUNCTIONA a;
85 LPSERVICE_MAIN_FUNCTIONW w;
91 static CRITICAL_SECTION service_cs;
92 static CRITICAL_SECTION_DEBUG service_cs_debug =
95 { &service_cs_debug.ProcessLocksList,
96 &service_cs_debug.ProcessLocksList },
97 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
99 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
101 static service_data **services;
102 static unsigned int nb_services;
103 static HANDLE service_event;
105 extern HANDLE __wine_make_process_system(void);
107 /******************************************************************************
111 #define MAX_SERVICE_NAME 256
113 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
116 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
120 SC_HANDLE_TYPE htype;
122 sc_handle_destructor destroy;
123 SC_RPC_HANDLE server_handle; /* server-side handle */
126 struct sc_manager /* service control manager handle */
128 struct sc_handle hdr;
129 HKEY hkey; /* handle to services database in the registry */
133 struct sc_service /* service handle */
135 struct sc_handle hdr;
136 HKEY hkey; /* handle to service entry in the registry (under hkey) */
138 struct sc_manager *scm; /* pointer to SCM handle */
142 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
143 sc_handle_destructor destroy)
145 struct sc_handle *hdr;
147 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
152 hdr->destroy = destroy;
154 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
158 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
160 struct sc_handle *hdr = (struct sc_handle *) handle;
164 if (hdr->htype != htype)
169 static void sc_handle_free(struct sc_handle* hdr)
173 if (--hdr->ref_count)
176 HeapFree(GetProcessHeap(), 0, hdr);
179 static void sc_handle_destroy_manager(struct sc_handle *handle)
181 struct sc_manager *mgr = (struct sc_manager*) handle;
183 TRACE("destroying SC Manager %p\n", mgr);
185 RegCloseKey(mgr->hkey);
188 static void sc_handle_destroy_service(struct sc_handle *handle)
190 struct sc_service *svc = (struct sc_service*) handle;
192 TRACE("destroying service %p\n", svc);
194 RegCloseKey(svc->hkey);
196 sc_handle_free(&svc->scm->hdr);
200 /******************************************************************************
201 * String management functions (same behaviour as strdup)
202 * NOTE: the caller of those functions is responsible for calling HeapFree
203 * in order to release the memory allocated by those functions.
205 static inline LPWSTR SERV_dup( LPCSTR str )
212 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
213 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
214 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
218 static inline LPWSTR SERV_dupmulti(LPCSTR str)
226 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
227 n += (strlen( &str[n] ) + 1);
232 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
233 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
237 static inline DWORD multisz_cb(LPCWSTR wmultisz)
239 const WCHAR *wptr = wmultisz;
241 if (wmultisz == NULL)
245 wptr += lstrlenW(wptr)+1;
246 return (wptr - wmultisz + 1)*sizeof(WCHAR);
249 /******************************************************************************
250 * RPC connection with services.exe
253 handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
255 WCHAR transport[] = SVCCTL_TRANSPORT;
256 WCHAR endpoint[] = SVCCTL_ENDPOINT;
257 RPC_WSTR binding_str;
261 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
262 if (status != RPC_S_OK)
264 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
268 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
269 RpcStringFreeW(&binding_str);
271 if (status != RPC_S_OK)
273 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
280 void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
285 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
287 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
290 static DWORD map_exception_code(DWORD exception_code)
292 switch (exception_code)
294 case RPC_X_NULL_REF_POINTER:
295 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
296 case RPC_X_BYTE_COUNT_TOO_SMALL:
297 return ERROR_INVALID_PARAMETER;
299 return exception_code;
303 /******************************************************************************
304 * Service IPC functions
306 static LPWSTR service_get_pipe_name(void)
308 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
309 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
310 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
311 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
312 'C','o','n','t','r','o','l','\\',
313 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
316 HKEY service_current_key;
317 DWORD service_current;
321 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
322 KEY_QUERY_VALUE, &service_current_key);
323 if (ret != ERROR_SUCCESS)
325 len = sizeof(service_current);
326 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
327 (BYTE *)&service_current, &len);
328 RegCloseKey(service_current_key);
329 if (ret != ERROR_SUCCESS || type != REG_DWORD)
331 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
332 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
335 snprintfW(name, len, format, service_current);
339 static HANDLE service_open_pipe(void)
341 LPWSTR szPipe = service_get_pipe_name();
342 HANDLE handle = INVALID_HANDLE_VALUE;
345 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
346 0, NULL, OPEN_ALWAYS, 0, NULL);
347 if (handle != INVALID_HANDLE_VALUE)
349 if (GetLastError() != ERROR_PIPE_BUSY)
351 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
352 HeapFree(GetProcessHeap(), 0, szPipe);
357 static service_data *find_service_by_name( const WCHAR *name )
361 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
363 for (i = 0; i < nb_services; i++)
364 if (!strcmpiW( name, services[i]->name )) return services[i];
368 /******************************************************************************
371 * Call into the main service routine provided by StartServiceCtrlDispatcher.
373 static DWORD WINAPI service_thread(LPVOID arg)
375 service_data *info = arg;
376 LPWSTR str = info->args;
377 DWORD argc = 0, len = 0;
383 len += strlenW(&str[len]) + 1;
392 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
393 for (argc=0, p=str; *p; p += strlenW(p) + 1)
397 info->proc.w(argc, argv);
398 HeapFree(GetProcessHeap(), 0, argv);
402 LPSTR strA, *argv, p;
405 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
406 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
407 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
409 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
410 for (argc=0, p=strA; *p; p += strlen(p) + 1)
414 info->proc.a(argc, argv);
415 HeapFree(GetProcessHeap(), 0, argv);
416 HeapFree(GetProcessHeap(), 0, strA);
421 /******************************************************************************
422 * service_handle_start
424 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
426 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
430 WARN("service is not stopped\n");
431 return ERROR_SERVICE_ALREADY_RUNNING;
434 HeapFree(GetProcessHeap(), 0, service->args);
435 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
436 memcpy( service->args, data, count * sizeof(WCHAR) );
437 service->thread = CreateThread( NULL, 0, service_thread,
439 SetEvent( service_event ); /* notify the main loop */
443 /******************************************************************************
444 * service_handle_control
446 static DWORD service_handle_control(service_data *service, DWORD dwControl)
448 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
450 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
452 if (service->handler)
453 ret = service->handler(dwControl, 0, NULL, service->context);
457 /******************************************************************************
458 * service_control_dispatcher
460 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
465 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
467 ERR("failed to open service manager error %u\n", GetLastError());
471 pipe = service_open_pipe();
473 if (pipe==INVALID_HANDLE_VALUE)
475 ERR("failed to create control pipe error = %d\n", GetLastError());
479 /* dispatcher loop */
482 service_data *service;
483 service_start_info info;
486 DWORD data_size = 0, count, result;
488 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
491 if (GetLastError() != ERROR_BROKEN_PIPE)
492 ERR( "pipe read failed error %u\n", GetLastError() );
495 if (count != FIELD_OFFSET(service_start_info,data))
497 ERR( "partial pipe read %u\n", count );
500 if (count < info.total_size)
502 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
503 data = HeapAlloc( GetProcessHeap(), 0, data_size );
504 r = ReadFile( pipe, data, data_size, &count, NULL );
507 if (GetLastError() != ERROR_BROKEN_PIPE)
508 ERR( "pipe read failed error %u\n", GetLastError() );
511 if (count != data_size)
513 ERR( "partial pipe read %u/%u\n", count, data_size );
518 /* find the service */
520 if (!(service = find_service_by_name( data )))
522 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
523 result = ERROR_INVALID_PARAMETER;
527 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
529 /* handle the request */
532 case WINESERV_STARTINFO:
533 if (!service->handle)
535 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )))
536 FIXME( "failed to open service %s\n", debugstr_w(data) );
538 result = service_handle_start(service, data + info.name_size,
539 data_size / sizeof(WCHAR) - info.name_size );
541 case WINESERV_SENDCONTROL:
542 result = service_handle_control(service, info.control);
545 ERR("received invalid command %u\n", info.cmd);
546 result = ERROR_INVALID_PARAMETER;
551 WriteFile(pipe, &result, sizeof(result), &count, NULL);
552 HeapFree( GetProcessHeap(), 0, data );
556 CloseServiceHandle( manager );
560 /******************************************************************************
561 * service_run_main_thread
563 static BOOL service_run_main_thread(void)
566 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
567 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
569 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
571 /* FIXME: service_control_dispatcher should be merged into the main thread */
572 wait_handles[0] = __wine_make_process_system();
573 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
574 wait_handles[2] = service_event;
576 TRACE("Starting %d services running as process %d\n",
577 nb_services, GetCurrentProcessId());
579 /* wait for all the threads to pack up and exit */
582 EnterCriticalSection( &service_cs );
583 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
585 if (!services[i]->thread) continue;
586 wait_services[n] = i;
587 wait_handles[n++] = services[i]->thread;
589 LeaveCriticalSection( &service_cs );
591 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
592 if (!ret) /* system process event */
594 TRACE( "last user process exited, shutting down\n" );
595 /* FIXME: we should maybe send a shutdown control to running services */
600 TRACE( "control dispatcher exited, shutting down\n" );
601 /* FIXME: we should maybe send a shutdown control to running services */
606 continue; /* rebuild the list */
610 services[wait_services[ret]]->thread = 0;
611 CloseHandle( wait_handles[ret] );
612 if (n == 4) return TRUE; /* it was the last running thread */
618 /******************************************************************************
619 * StartServiceCtrlDispatcherA [ADVAPI32.@]
621 * See StartServiceCtrlDispatcherW.
623 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
629 TRACE("%p\n", servent);
633 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
636 while (servent[nb_services].lpServiceName) nb_services++;
637 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
639 for (i = 0; i < nb_services; i++)
641 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
642 DWORD sz = FIELD_OFFSET( service_data, name[len] );
643 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
644 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
645 info->proc.a = servent[i].lpServiceProc;
646 info->unicode = FALSE;
650 service_run_main_thread();
655 /******************************************************************************
656 * StartServiceCtrlDispatcherW [ADVAPI32.@]
658 * Connects a process containing one or more services to the service control
662 * servent [I] A list of the service names and service procedures
668 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
674 TRACE("%p\n", servent);
678 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
681 while (servent[nb_services].lpServiceName) nb_services++;
682 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
684 for (i = 0; i < nb_services; i++)
686 DWORD len = strlenW(servent[i].lpServiceName) + 1;
687 DWORD sz = FIELD_OFFSET( service_data, name[len] );
688 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
689 strcpyW(info->name, servent[i].lpServiceName);
690 info->proc.w = servent[i].lpServiceProc;
691 info->unicode = TRUE;
695 service_run_main_thread();
700 /******************************************************************************
701 * LockServiceDatabase [ADVAPI32.@]
703 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
705 struct sc_manager *hscm;
706 SC_RPC_LOCK hLock = NULL;
709 TRACE("%p\n",hSCManager);
711 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
714 SetLastError( ERROR_INVALID_HANDLE );
720 err = svcctl_LockServiceDatabase(hscm->hdr.server_handle, &hLock);
724 err = map_exception_code(GetExceptionCode());
727 if (err != ERROR_SUCCESS)
735 /******************************************************************************
736 * UnlockServiceDatabase [ADVAPI32.@]
738 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
741 SC_RPC_LOCK hRpcLock = ScLock;
743 TRACE("%p\n",ScLock);
747 err = svcctl_UnlockServiceDatabase(&hRpcLock);
751 err = map_exception_code(GetExceptionCode());
754 if (err != ERROR_SUCCESS)
762 /******************************************************************************
763 * SetServiceStatus [ADVAPI32.@]
770 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
772 struct sc_service *hsvc;
775 TRACE("%p %x %x %x %x %x %x %x\n", hService,
776 lpStatus->dwServiceType, lpStatus->dwCurrentState,
777 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
778 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
779 lpStatus->dwWaitHint);
781 hsvc = sc_handle_get_handle_data((SC_HANDLE)hService, SC_HTYPE_SERVICE);
784 SetLastError( ERROR_INVALID_HANDLE );
790 err = svcctl_SetServiceStatus( hsvc->hdr.server_handle, lpStatus );
794 err = map_exception_code(GetExceptionCode());
797 if (err != ERROR_SUCCESS)
803 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
804 CloseServiceHandle((SC_HANDLE)hService);
810 /******************************************************************************
811 * OpenSCManagerA [ADVAPI32.@]
813 * Establish a connection to the service control manager and open its database.
816 * lpMachineName [I] Pointer to machine name string
817 * lpDatabaseName [I] Pointer to database name string
818 * dwDesiredAccess [I] Type of access
821 * Success: A Handle to the service control manager database
824 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
825 DWORD dwDesiredAccess )
827 LPWSTR lpMachineNameW, lpDatabaseNameW;
830 lpMachineNameW = SERV_dup(lpMachineName);
831 lpDatabaseNameW = SERV_dup(lpDatabaseName);
832 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
833 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
834 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
838 /******************************************************************************
839 * OpenSCManagerW [ADVAPI32.@]
841 * See OpenSCManagerA.
843 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
844 DWORD dwDesiredAccess )
846 struct sc_manager *manager;
849 DWORD new_mask = dwDesiredAccess;
851 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
852 debugstr_w(lpDatabaseName), dwDesiredAccess);
854 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
855 sc_handle_destroy_manager );
861 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
865 r = map_exception_code(GetExceptionCode());
868 if (r!=ERROR_SUCCESS)
871 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
872 if (r!=ERROR_SUCCESS)
875 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
877 if (r!=ERROR_SUCCESS)
880 RtlMapGenericMask(&new_mask, &scm_generic);
881 manager->dwAccess = new_mask;
882 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
884 return (SC_HANDLE) &manager->hdr;
887 sc_handle_free( &manager->hdr );
892 /******************************************************************************
893 * ControlService [ADVAPI32.@]
895 * Send a control code to a service.
898 * hService [I] Handle of the service control manager database
899 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
900 * lpServiceStatus [O] Destination for the status of the service, if available
907 * Unlike M$' implementation, control requests are not serialized and may be
908 * processed asynchronously.
910 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
911 LPSERVICE_STATUS lpServiceStatus )
913 struct sc_service *hsvc;
916 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
918 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
921 SetLastError( ERROR_INVALID_HANDLE );
927 err = svcctl_ControlService(hsvc->hdr.server_handle, dwControl, lpServiceStatus);
931 err = map_exception_code(GetExceptionCode());
934 if (err != ERROR_SUCCESS)
943 /******************************************************************************
944 * CloseServiceHandle [ADVAPI32.@]
946 * Close a handle to a service or the service control manager database.
949 * hSCObject [I] Handle to service or service control manager database
956 CloseServiceHandle( SC_HANDLE hSCObject )
958 struct sc_handle *obj;
961 TRACE("%p\n", hSCObject);
962 if (hSCObject == NULL)
964 SetLastError(ERROR_INVALID_HANDLE);
968 obj = (struct sc_handle *)hSCObject;
971 err = svcctl_CloseServiceHandle(&obj->server_handle);
975 err = map_exception_code(GetExceptionCode());
978 sc_handle_free( obj );
980 if (err != ERROR_SUCCESS)
989 /******************************************************************************
990 * OpenServiceA [ADVAPI32.@]
992 * Open a handle to a service.
995 * hSCManager [I] Handle of the service control manager database
996 * lpServiceName [I] Name of the service to open
997 * dwDesiredAccess [I] Access required to the service
1000 * Success: Handle to the service
1003 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1004 DWORD dwDesiredAccess )
1006 LPWSTR lpServiceNameW;
1009 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1011 lpServiceNameW = SERV_dup(lpServiceName);
1012 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1013 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1018 /******************************************************************************
1019 * OpenServiceW [ADVAPI32.@]
1023 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1024 DWORD dwDesiredAccess)
1026 struct sc_manager *hscm;
1027 struct sc_service *hsvc;
1030 DWORD new_mask = dwDesiredAccess;
1032 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1034 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1037 SetLastError( ERROR_INVALID_HANDLE );
1043 SetLastError(ERROR_INVALID_ADDRESS);
1047 len = strlenW(lpServiceName)+1;
1048 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1049 sizeof (struct sc_service) + len*sizeof(WCHAR),
1050 sc_handle_destroy_service );
1053 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1056 strcpyW( hsvc->name, lpServiceName );
1058 /* add reference to SCM handle */
1059 hscm->hdr.ref_count++;
1064 err = svcctl_OpenServiceW(hscm->hdr.server_handle, lpServiceName, dwDesiredAccess, &hsvc->hdr.server_handle);
1066 __EXCEPT(rpc_filter)
1068 err = map_exception_code(GetExceptionCode());
1072 if (err != ERROR_SUCCESS)
1074 sc_handle_free(&hsvc->hdr);
1079 /* for parts of advapi32 not using services.exe yet */
1080 RtlMapGenericMask(&new_mask, &svc_generic);
1081 hsvc->dwAccess = new_mask;
1083 err = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hsvc->hkey );
1084 if (err != ERROR_SUCCESS)
1085 ERR("Shouldn't hapen - service key for service validated by services.exe doesn't exist\n");
1087 TRACE("returning %p\n",hsvc);
1089 return (SC_HANDLE) &hsvc->hdr;
1092 /******************************************************************************
1093 * CreateServiceW [ADVAPI32.@]
1096 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1097 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1098 DWORD dwServiceType, DWORD dwStartType,
1099 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1100 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1101 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1102 LPCWSTR lpPassword )
1104 struct sc_manager *hscm;
1105 struct sc_service *hsvc = NULL;
1106 DWORD new_mask = dwDesiredAccess;
1110 TRACE("%p %s %s\n", hSCManager,
1111 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1113 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1116 SetLastError( ERROR_INVALID_HANDLE );
1120 if (!lpServiceName || !lpBinaryPathName)
1122 SetLastError(ERROR_INVALID_ADDRESS);
1127 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1131 len = strlenW(lpServiceName)+1;
1132 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1133 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1136 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1139 lstrcpyW( hsvc->name, lpServiceName );
1142 hscm->hdr.ref_count++;
1146 err = svcctl_CreateServiceW(hscm->hdr.server_handle, lpServiceName,
1147 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1148 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies,
1149 multisz_cb(lpDependencies), lpServiceStartName, (LPBYTE)lpPassword, passwdlen,
1150 &hsvc->hdr.server_handle);
1152 __EXCEPT(rpc_filter)
1154 err = map_exception_code(GetExceptionCode());
1158 if (err != ERROR_SUCCESS)
1161 sc_handle_free(&hsvc->hdr);
1165 /* for parts of advapi32 not using services.exe yet */
1166 err = RegOpenKeyW(hscm->hkey, lpServiceName, &hsvc->hkey);
1167 if (err != ERROR_SUCCESS)
1168 WINE_ERR("Couldn't open key that should have been created by services.exe\n");
1170 RtlMapGenericMask(&new_mask, &svc_generic);
1171 hsvc->dwAccess = new_mask;
1173 return (SC_HANDLE) &hsvc->hdr;
1177 /******************************************************************************
1178 * CreateServiceA [ADVAPI32.@]
1181 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1182 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1183 DWORD dwServiceType, DWORD dwStartType,
1184 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1185 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1186 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1189 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1190 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1193 TRACE("%p %s %s\n", hSCManager,
1194 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1196 lpServiceNameW = SERV_dup( lpServiceName );
1197 lpDisplayNameW = SERV_dup( lpDisplayName );
1198 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1199 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1200 lpDependenciesW = SERV_dupmulti( lpDependencies );
1201 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1202 lpPasswordW = SERV_dup( lpPassword );
1204 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1205 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1206 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1207 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1209 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1210 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1211 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1212 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1213 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1214 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1215 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1221 /******************************************************************************
1222 * DeleteService [ADVAPI32.@]
1224 * Delete a service from the service control manager database.
1227 * hService [I] Handle of the service to delete
1233 BOOL WINAPI DeleteService( SC_HANDLE hService )
1235 struct sc_service *hsvc;
1238 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1241 SetLastError( ERROR_INVALID_HANDLE );
1247 err = svcctl_DeleteService(hsvc->hdr.server_handle);
1249 __EXCEPT(rpc_filter)
1251 err = map_exception_code(GetExceptionCode());
1260 /* Close the key to the service */
1261 RegCloseKey(hsvc->hkey);
1267 /******************************************************************************
1268 * StartServiceA [ADVAPI32.@]
1273 * hService [I] Handle of service
1274 * dwNumServiceArgs [I] Number of arguments
1275 * lpServiceArgVectors [I] Address of array of argument strings
1278 * - NT implements this function using an obscure RPC call.
1279 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1280 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1281 * - This will only work for shared address space. How should the service
1282 * args be transferred when address spaces are separated?
1283 * - Can only start one service at a time.
1284 * - Has no concept of privilege.
1290 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1291 LPCSTR *lpServiceArgVectors )
1293 LPWSTR *lpwstr=NULL;
1297 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1299 if (dwNumServiceArgs)
1300 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1301 dwNumServiceArgs*sizeof(LPWSTR) );
1303 for(i=0; i<dwNumServiceArgs; i++)
1304 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1306 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1308 if (dwNumServiceArgs)
1310 for(i=0; i<dwNumServiceArgs; i++)
1311 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1312 HeapFree(GetProcessHeap(), 0, lpwstr);
1319 /******************************************************************************
1320 * StartServiceW [ADVAPI32.@]
1322 * See StartServiceA.
1324 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1325 LPCWSTR *lpServiceArgVectors)
1327 struct sc_service *hsvc;
1330 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1332 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1335 SetLastError(ERROR_INVALID_HANDLE);
1341 err = svcctl_StartServiceW(hsvc->hdr.server_handle, dwNumServiceArgs, lpServiceArgVectors);
1343 __EXCEPT(rpc_filter)
1345 err = map_exception_code(GetExceptionCode());
1348 if (err != ERROR_SUCCESS)
1357 /******************************************************************************
1358 * QueryServiceStatus [ADVAPI32.@]
1361 * hService [I] Handle to service to get information about
1362 * lpservicestatus [O] buffer to receive the status information for the service
1365 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1366 LPSERVICE_STATUS lpservicestatus)
1368 SERVICE_STATUS_PROCESS SvcStatusData;
1372 TRACE("%p %p\n", hService, lpservicestatus);
1374 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1375 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1376 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1381 /******************************************************************************
1382 * QueryServiceStatusEx [ADVAPI32.@]
1384 * Get information about a service.
1387 * hService [I] Handle to service to get information about
1388 * InfoLevel [I] Level of information to get
1389 * lpBuffer [O] Destination for requested information
1390 * cbBufSize [I] Size of lpBuffer in bytes
1391 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1397 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1398 LPBYTE lpBuffer, DWORD cbBufSize,
1399 LPDWORD pcbBytesNeeded)
1401 struct sc_service *hsvc;
1404 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1406 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1409 SetLastError( ERROR_INVALID_HANDLE );
1415 err = svcctl_QueryServiceStatusEx(hsvc->hdr.server_handle, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1417 __EXCEPT(rpc_filter)
1419 err = map_exception_code(GetExceptionCode());
1422 if (err != ERROR_SUCCESS)
1431 /******************************************************************************
1432 * QueryServiceConfigA [ADVAPI32.@]
1434 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1435 DWORD size, LPDWORD needed )
1440 QUERY_SERVICE_CONFIGW *configW;
1442 TRACE("%p %p %d %p\n", hService, config, size, needed);
1444 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1446 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1449 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1450 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1451 if (!ret) goto done;
1453 config->dwServiceType = configW->dwServiceType;
1454 config->dwStartType = configW->dwStartType;
1455 config->dwErrorControl = configW->dwErrorControl;
1456 config->lpBinaryPathName = NULL;
1457 config->lpLoadOrderGroup = NULL;
1458 config->dwTagId = configW->dwTagId;
1459 config->lpDependencies = NULL;
1460 config->lpServiceStartName = NULL;
1461 config->lpDisplayName = NULL;
1463 p = (LPSTR)(config + 1);
1464 n = size - sizeof(*config);
1467 #define MAP_STR(str) \
1471 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1472 if (!sz) goto done; \
1479 MAP_STR( lpBinaryPathName );
1480 MAP_STR( lpLoadOrderGroup );
1481 MAP_STR( lpDependencies );
1482 MAP_STR( lpServiceStartName );
1483 MAP_STR( lpDisplayName );
1486 *needed = p - (LPSTR)config;
1490 HeapFree( GetProcessHeap(), 0, buffer );
1494 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1501 memset(*buf, 0, cb);
1505 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1506 memcpy(*buf, *string_ptr, cb);
1507 MIDL_user_free(*string_ptr);
1510 *string_ptr = (LPWSTR)*buf;
1516 static DWORD size_string(LPWSTR string)
1518 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1521 /******************************************************************************
1522 * QueryServiceConfigW [ADVAPI32.@]
1525 QueryServiceConfigW( SC_HANDLE hService,
1526 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1527 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1529 QUERY_SERVICE_CONFIGW config;
1530 struct sc_service *hsvc;
1535 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1536 cbBufSize, pcbBytesNeeded);
1538 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1541 SetLastError( ERROR_INVALID_HANDLE );
1545 memset(&config, 0, sizeof(config));
1549 err = svcctl_QueryServiceConfigW(hsvc->hdr.server_handle, &config);
1551 __EXCEPT(rpc_filter)
1553 err = map_exception_code(GetExceptionCode());
1557 if (err != ERROR_SUCCESS)
1559 TRACE("services.exe: error %u\n", err);
1564 /* calculate the size required first */
1565 total = sizeof (QUERY_SERVICE_CONFIGW);
1566 total += size_string(config.lpBinaryPathName);
1567 total += size_string(config.lpLoadOrderGroup);
1568 total += size_string(config.lpDependencies);
1569 total += size_string(config.lpServiceStartName);
1570 total += size_string(config.lpDisplayName);
1572 *pcbBytesNeeded = total;
1574 /* if there's not enough memory, return an error */
1575 if( total > cbBufSize )
1577 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1578 MIDL_user_free(config.lpBinaryPathName);
1579 MIDL_user_free(config.lpLoadOrderGroup);
1580 MIDL_user_free(config.lpDependencies);
1581 MIDL_user_free(config.lpServiceStartName);
1582 MIDL_user_free(config.lpDisplayName);
1586 *lpServiceConfig = config;
1587 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1588 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1589 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1590 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1591 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1592 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1594 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1595 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1596 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1597 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1598 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1603 /******************************************************************************
1604 * QueryServiceConfig2A [ADVAPI32.@]
1607 * observed under win2k:
1608 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1609 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1611 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1612 DWORD size, LPDWORD needed)
1615 LPBYTE bufferW = NULL;
1618 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1620 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1621 if(!ret) goto cleanup;
1624 case SERVICE_CONFIG_DESCRIPTION:
1625 { LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1626 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1627 if (configW->lpDescription) {
1629 configA->lpDescription = (LPSTR)(configA + 1);
1630 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1631 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1633 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1635 configA->lpDescription = NULL;
1638 else configA->lpDescription = NULL;
1642 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1647 HeapFree( GetProcessHeap(), 0, bufferW);
1651 /******************************************************************************
1652 * QueryServiceConfig2W [ADVAPI32.@]
1654 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1655 DWORD size, LPDWORD needed)
1660 struct sc_service *hsvc;
1662 if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1663 if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
1664 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
1665 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
1666 (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
1667 (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
1668 (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
1669 FIXME("Level %d not implemented\n", dwLevel);
1670 SetLastError(ERROR_INVALID_LEVEL);
1673 if(!needed || (!buffer && size)) {
1674 SetLastError(ERROR_INVALID_ADDRESS);
1678 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1680 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1683 SetLastError(ERROR_INVALID_HANDLE);
1689 case SERVICE_CONFIG_DESCRIPTION: {
1690 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1691 LPSERVICE_DESCRIPTIONW config = (LPSERVICE_DESCRIPTIONW) buffer;
1692 LPBYTE strbuf = NULL;
1693 *needed = sizeof (SERVICE_DESCRIPTIONW);
1694 sz = size - *needed;
1695 if(config && (*needed <= size))
1696 strbuf = (LPBYTE) (config + 1);
1697 r = RegQueryValueExW( hKey, szDescription, 0, &type, strbuf, &sz );
1698 if((r == ERROR_SUCCESS) && ( type != REG_SZ)) {
1699 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type);
1704 if(r == ERROR_SUCCESS)
1705 config->lpDescription = (LPWSTR) (config + 1);
1707 config->lpDescription = NULL;
1713 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1715 return (*needed <= size);
1718 /******************************************************************************
1719 * EnumServicesStatusA [ADVAPI32.@]
1722 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1723 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1724 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1725 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1727 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1728 dwServiceType, dwServiceState, lpServices, cbBufSize,
1729 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1730 SetLastError (ERROR_ACCESS_DENIED);
1734 /******************************************************************************
1735 * EnumServicesStatusW [ADVAPI32.@]
1738 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1739 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1740 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1741 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1743 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1744 dwServiceType, dwServiceState, lpServices, cbBufSize,
1745 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1746 SetLastError (ERROR_ACCESS_DENIED);
1750 /******************************************************************************
1751 * EnumServicesStatusExA [ADVAPI32.@]
1754 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1755 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1756 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1758 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1759 dwServiceType, dwServiceState, lpServices, cbBufSize,
1760 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1761 if (lpServicesReturned) *lpServicesReturned = 0;
1762 SetLastError (ERROR_ACCESS_DENIED);
1766 /******************************************************************************
1767 * EnumServicesStatusExW [ADVAPI32.@]
1770 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1771 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1772 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1774 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1775 dwServiceType, dwServiceState, lpServices, cbBufSize,
1776 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
1777 SetLastError (ERROR_ACCESS_DENIED);
1781 /******************************************************************************
1782 * GetServiceKeyNameA [ADVAPI32.@]
1784 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1785 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1787 LPWSTR lpDisplayNameW, lpServiceNameW;
1791 TRACE("%p %s %p %p\n", hSCManager,
1792 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1794 lpDisplayNameW = SERV_dup(lpDisplayName);
1796 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1798 lpServiceNameW = NULL;
1800 sizeW = *lpcchBuffer;
1801 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1803 if (lpServiceName && *lpcchBuffer)
1804 lpServiceName[0] = 0;
1805 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1809 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1810 *lpcchBuffer, NULL, NULL ))
1812 if (*lpcchBuffer && lpServiceName)
1813 lpServiceName[0] = 0;
1814 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1818 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1822 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1823 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1827 /******************************************************************************
1828 * GetServiceKeyNameW [ADVAPI32.@]
1830 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1831 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1833 struct sc_manager *hscm;
1836 TRACE("%p %s %p %p\n", hSCManager,
1837 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1839 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1842 SetLastError(ERROR_INVALID_HANDLE);
1848 SetLastError(ERROR_INVALID_ADDRESS);
1854 err = svcctl_GetServiceKeyNameW(hscm->hdr.server_handle,
1855 lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
1857 __EXCEPT(rpc_filter)
1859 err = map_exception_code(GetExceptionCode());
1865 return err == ERROR_SUCCESS;
1868 /******************************************************************************
1869 * QueryServiceLockStatusA [ADVAPI32.@]
1871 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1872 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1873 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1875 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1880 /******************************************************************************
1881 * QueryServiceLockStatusW [ADVAPI32.@]
1883 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1884 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1885 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1887 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1892 /******************************************************************************
1893 * GetServiceDisplayNameA [ADVAPI32.@]
1895 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1896 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1898 LPWSTR lpServiceNameW, lpDisplayNameW;
1902 TRACE("%p %s %p %p\n", hSCManager,
1903 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1905 lpServiceNameW = SERV_dup(lpServiceName);
1907 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1909 lpDisplayNameW = NULL;
1911 sizeW = *lpcchBuffer;
1912 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1914 if (lpDisplayName && *lpcchBuffer)
1915 lpDisplayName[0] = 0;
1916 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1920 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1921 *lpcchBuffer, NULL, NULL ))
1923 if (*lpcchBuffer && lpDisplayName)
1924 lpDisplayName[0] = 0;
1925 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1929 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1930 * (but if the function succeeded it means that is a good upper estimation of the size) */
1934 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1935 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1939 /******************************************************************************
1940 * GetServiceDisplayNameW [ADVAPI32.@]
1942 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1943 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1945 struct sc_manager *hscm;
1948 TRACE("%p %s %p %p\n", hSCManager,
1949 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1951 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1954 SetLastError(ERROR_INVALID_HANDLE);
1960 SetLastError(ERROR_INVALID_ADDRESS);
1966 err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
1967 lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
1969 __EXCEPT(rpc_filter)
1971 err = map_exception_code(GetExceptionCode());
1977 return err == ERROR_SUCCESS;
1980 /******************************************************************************
1981 * ChangeServiceConfigW [ADVAPI32.@]
1983 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1984 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1985 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1986 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1988 struct sc_service *hsvc;
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 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2001 SetLastError( ERROR_INVALID_HANDLE );
2005 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2009 err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
2010 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2011 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2012 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2014 __EXCEPT(rpc_filter)
2016 err = map_exception_code(GetExceptionCode());
2020 if (err != ERROR_SUCCESS)
2023 return err == ERROR_SUCCESS;
2026 /******************************************************************************
2027 * ChangeServiceConfigA [ADVAPI32.@]
2029 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2030 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2031 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2032 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2034 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2035 LPWSTR wServiceStartName, wPassword, wDisplayName;
2038 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2039 hService, dwServiceType, dwStartType, dwErrorControl,
2040 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2041 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2042 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2044 wBinaryPathName = SERV_dup( lpBinaryPathName );
2045 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2046 wDependencies = SERV_dupmulti( lpDependencies );
2047 wServiceStartName = SERV_dup( lpServiceStartName );
2048 wPassword = SERV_dup( lpPassword );
2049 wDisplayName = SERV_dup( lpDisplayName );
2051 r = ChangeServiceConfigW( hService, dwServiceType,
2052 dwStartType, dwErrorControl, wBinaryPathName,
2053 wLoadOrderGroup, lpdwTagId, wDependencies,
2054 wServiceStartName, wPassword, wDisplayName);
2056 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2057 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2058 HeapFree( GetProcessHeap(), 0, wDependencies );
2059 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2060 HeapFree( GetProcessHeap(), 0, wPassword );
2061 HeapFree( GetProcessHeap(), 0, wDisplayName );
2066 /******************************************************************************
2067 * ChangeServiceConfig2A [ADVAPI32.@]
2069 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2074 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2076 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2078 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2079 SERVICE_DESCRIPTIONW sdw;
2081 sdw.lpDescription = SERV_dup( sd->lpDescription );
2083 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2085 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2087 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2089 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2090 SERVICE_FAILURE_ACTIONSW faw;
2092 faw.dwResetPeriod = fa->dwResetPeriod;
2093 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2094 faw.lpCommand = SERV_dup( fa->lpCommand );
2095 faw.cActions = fa->cActions;
2096 faw.lpsaActions = fa->lpsaActions;
2098 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2100 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2101 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2104 SetLastError( ERROR_INVALID_PARAMETER );
2109 /******************************************************************************
2110 * ChangeServiceConfig2W [ADVAPI32.@]
2112 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2116 struct sc_service *hsvc;
2118 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2121 SetLastError( ERROR_INVALID_HANDLE );
2126 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2128 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2129 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2130 if (sd->lpDescription)
2132 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2133 if (sd->lpDescription[0] == 0)
2134 RegDeleteValueW(hKey,szDescription);
2136 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2137 (LPVOID)sd->lpDescription,
2138 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2142 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2146 /******************************************************************************
2147 * QueryServiceObjectSecurity [ADVAPI32.@]
2149 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2150 SECURITY_INFORMATION dwSecurityInformation,
2151 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2152 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2154 SECURITY_DESCRIPTOR descriptor;
2159 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2160 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2162 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2163 FIXME("information %d not supported\n", dwSecurityInformation);
2165 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2167 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2168 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2171 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2172 *pcbBytesNeeded = size;
2176 /******************************************************************************
2177 * SetServiceObjectSecurity [ADVAPI32.@]
2179 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2180 SECURITY_INFORMATION dwSecurityInformation,
2181 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2183 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2187 /******************************************************************************
2188 * SetServiceBits [ADVAPI32.@]
2190 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2191 DWORD dwServiceBits,
2193 BOOL bUpdateImmediately)
2195 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2196 bSetBitsOn, bUpdateImmediately);
2200 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2201 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2203 LPHANDLER_FUNCTION func = context;
2206 return ERROR_SUCCESS;
2209 /******************************************************************************
2210 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2212 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2214 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2217 /******************************************************************************
2218 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2220 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2222 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2225 /******************************************************************************
2226 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2228 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2231 SERVICE_STATUS_HANDLE ret;
2233 nameW = SERV_dup(name);
2234 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2235 HeapFree( GetProcessHeap(), 0, nameW );
2239 /******************************************************************************
2240 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2242 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2243 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2245 service_data *service;
2246 SC_HANDLE hService = 0;
2249 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2251 EnterCriticalSection( &service_cs );
2252 if ((service = find_service_by_name( lpServiceName )))
2254 service->handler = lpHandlerProc;
2255 service->context = lpContext;
2256 hService = service->handle;
2259 LeaveCriticalSection( &service_cs );
2261 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2263 return (SERVICE_STATUS_HANDLE)hService;
2266 /******************************************************************************
2267 * EnumDependentServicesA [ADVAPI32.@]
2269 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2270 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2271 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2273 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2274 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2276 *lpServicesReturned = 0;
2280 /******************************************************************************
2281 * EnumDependentServicesW [ADVAPI32.@]
2283 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2284 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2285 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2287 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2288 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2290 *lpServicesReturned = 0;