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;
390 info->proc.w(0, NULL);
392 info->proc.a(0, NULL);
400 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
401 for (argc=0, p=str; *p; p += strlenW(p) + 1)
405 info->proc.w(argc, argv);
406 HeapFree(GetProcessHeap(), 0, argv);
410 LPSTR strA, *argv, p;
413 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
414 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
415 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
417 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
418 for (argc=0, p=strA; *p; p += strlen(p) + 1)
422 info->proc.a(argc, argv);
423 HeapFree(GetProcessHeap(), 0, argv);
424 HeapFree(GetProcessHeap(), 0, strA);
429 /******************************************************************************
430 * service_handle_start
432 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
434 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
438 WARN("service is not stopped\n");
439 return ERROR_SERVICE_ALREADY_RUNNING;
442 HeapFree(GetProcessHeap(), 0, service->args);
443 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
444 memcpy( service->args, data, count * sizeof(WCHAR) );
445 service->thread = CreateThread( NULL, 0, service_thread,
447 SetEvent( service_event ); /* notify the main loop */
451 /******************************************************************************
452 * service_handle_control
454 static DWORD service_handle_control(service_data *service, DWORD dwControl)
456 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
458 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
460 if (service->handler)
461 ret = service->handler(dwControl, 0, NULL, service->context);
465 /******************************************************************************
466 * service_control_dispatcher
468 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
473 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
475 ERR("failed to open service manager error %u\n", GetLastError());
479 pipe = service_open_pipe();
481 if (pipe==INVALID_HANDLE_VALUE)
483 ERR("failed to create control pipe error = %d\n", GetLastError());
487 /* dispatcher loop */
490 service_data *service;
491 service_start_info info;
494 DWORD data_size = 0, count, result;
496 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
499 if (GetLastError() != ERROR_BROKEN_PIPE)
500 ERR( "pipe read failed error %u\n", GetLastError() );
503 if (count != FIELD_OFFSET(service_start_info,data))
505 ERR( "partial pipe read %u\n", count );
508 if (count < info.total_size)
510 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
511 data = HeapAlloc( GetProcessHeap(), 0, data_size );
512 r = ReadFile( pipe, data, data_size, &count, NULL );
515 if (GetLastError() != ERROR_BROKEN_PIPE)
516 ERR( "pipe read failed error %u\n", GetLastError() );
519 if (count != data_size)
521 ERR( "partial pipe read %u/%u\n", count, data_size );
526 /* find the service */
528 if (!(service = find_service_by_name( data )))
530 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
531 result = ERROR_INVALID_PARAMETER;
535 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
537 /* handle the request */
540 case WINESERV_STARTINFO:
541 if (!service->handle)
543 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )))
544 FIXME( "failed to open service %s\n", debugstr_w(data) );
546 result = service_handle_start(service, data + info.name_size,
547 data_size / sizeof(WCHAR) - info.name_size );
549 case WINESERV_SENDCONTROL:
550 result = service_handle_control(service, info.control);
553 ERR("received invalid command %u\n", info.cmd);
554 result = ERROR_INVALID_PARAMETER;
559 WriteFile(pipe, &result, sizeof(result), &count, NULL);
560 HeapFree( GetProcessHeap(), 0, data );
564 CloseServiceHandle( manager );
568 /******************************************************************************
569 * service_run_main_thread
571 static BOOL service_run_main_thread(void)
574 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
575 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
577 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
579 /* FIXME: service_control_dispatcher should be merged into the main thread */
580 wait_handles[0] = __wine_make_process_system();
581 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
582 wait_handles[2] = service_event;
584 TRACE("Starting %d services running as process %d\n",
585 nb_services, GetCurrentProcessId());
587 /* wait for all the threads to pack up and exit */
590 EnterCriticalSection( &service_cs );
591 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
593 if (!services[i]->thread) continue;
594 wait_services[n] = i;
595 wait_handles[n++] = services[i]->thread;
597 LeaveCriticalSection( &service_cs );
599 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
600 if (!ret) /* system process event */
602 TRACE( "last user process exited, shutting down\n" );
603 /* FIXME: we should maybe send a shutdown control to running services */
608 TRACE( "control dispatcher exited, shutting down\n" );
609 /* FIXME: we should maybe send a shutdown control to running services */
614 continue; /* rebuild the list */
618 services[wait_services[ret]]->thread = 0;
619 CloseHandle( wait_handles[ret] );
620 if (n == 4) return TRUE; /* it was the last running thread */
626 /******************************************************************************
627 * StartServiceCtrlDispatcherA [ADVAPI32.@]
629 * See StartServiceCtrlDispatcherW.
631 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
637 TRACE("%p\n", servent);
641 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
644 while (servent[nb_services].lpServiceName) nb_services++;
645 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
647 for (i = 0; i < nb_services; i++)
649 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
650 DWORD sz = FIELD_OFFSET( service_data, name[len] );
651 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
652 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
653 info->proc.a = servent[i].lpServiceProc;
654 info->unicode = FALSE;
658 service_run_main_thread();
663 /******************************************************************************
664 * StartServiceCtrlDispatcherW [ADVAPI32.@]
666 * Connects a process containing one or more services to the service control
670 * servent [I] A list of the service names and service procedures
676 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
682 TRACE("%p\n", servent);
686 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
689 while (servent[nb_services].lpServiceName) nb_services++;
690 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
692 for (i = 0; i < nb_services; i++)
694 DWORD len = strlenW(servent[i].lpServiceName) + 1;
695 DWORD sz = FIELD_OFFSET( service_data, name[len] );
696 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
697 strcpyW(info->name, servent[i].lpServiceName);
698 info->proc.w = servent[i].lpServiceProc;
699 info->unicode = TRUE;
703 service_run_main_thread();
708 /******************************************************************************
709 * LockServiceDatabase [ADVAPI32.@]
711 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
713 struct sc_manager *hscm;
714 SC_RPC_LOCK hLock = NULL;
717 TRACE("%p\n",hSCManager);
719 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
722 SetLastError( ERROR_INVALID_HANDLE );
728 err = svcctl_LockServiceDatabase(hscm->hdr.server_handle, &hLock);
732 err = map_exception_code(GetExceptionCode());
735 if (err != ERROR_SUCCESS)
743 /******************************************************************************
744 * UnlockServiceDatabase [ADVAPI32.@]
746 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
749 SC_RPC_LOCK hRpcLock = ScLock;
751 TRACE("%p\n",ScLock);
755 err = svcctl_UnlockServiceDatabase(&hRpcLock);
759 err = map_exception_code(GetExceptionCode());
762 if (err != ERROR_SUCCESS)
770 /******************************************************************************
771 * SetServiceStatus [ADVAPI32.@]
778 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
780 struct sc_service *hsvc;
783 TRACE("%p %x %x %x %x %x %x %x\n", hService,
784 lpStatus->dwServiceType, lpStatus->dwCurrentState,
785 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
786 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
787 lpStatus->dwWaitHint);
789 hsvc = sc_handle_get_handle_data((SC_HANDLE)hService, SC_HTYPE_SERVICE);
792 SetLastError( ERROR_INVALID_HANDLE );
798 err = svcctl_SetServiceStatus( hsvc->hdr.server_handle, lpStatus );
802 err = map_exception_code(GetExceptionCode());
805 if (err != ERROR_SUCCESS)
811 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
812 CloseServiceHandle((SC_HANDLE)hService);
818 /******************************************************************************
819 * OpenSCManagerA [ADVAPI32.@]
821 * Establish a connection to the service control manager and open its database.
824 * lpMachineName [I] Pointer to machine name string
825 * lpDatabaseName [I] Pointer to database name string
826 * dwDesiredAccess [I] Type of access
829 * Success: A Handle to the service control manager database
832 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
833 DWORD dwDesiredAccess )
835 LPWSTR lpMachineNameW, lpDatabaseNameW;
838 lpMachineNameW = SERV_dup(lpMachineName);
839 lpDatabaseNameW = SERV_dup(lpDatabaseName);
840 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
841 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
842 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
846 /******************************************************************************
847 * OpenSCManagerW [ADVAPI32.@]
849 * See OpenSCManagerA.
851 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
852 DWORD dwDesiredAccess )
854 struct sc_manager *manager;
857 DWORD new_mask = dwDesiredAccess;
859 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
860 debugstr_w(lpDatabaseName), dwDesiredAccess);
862 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
863 sc_handle_destroy_manager );
869 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
873 r = map_exception_code(GetExceptionCode());
876 if (r!=ERROR_SUCCESS)
879 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
880 if (r!=ERROR_SUCCESS)
883 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
885 if (r!=ERROR_SUCCESS)
888 RtlMapGenericMask(&new_mask, &scm_generic);
889 manager->dwAccess = new_mask;
890 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
892 return (SC_HANDLE) &manager->hdr;
895 sc_handle_free( &manager->hdr );
900 /******************************************************************************
901 * ControlService [ADVAPI32.@]
903 * Send a control code to a service.
906 * hService [I] Handle of the service control manager database
907 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
908 * lpServiceStatus [O] Destination for the status of the service, if available
915 * Unlike M$' implementation, control requests are not serialized and may be
916 * processed asynchronously.
918 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
919 LPSERVICE_STATUS lpServiceStatus )
921 struct sc_service *hsvc;
924 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
926 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
929 SetLastError( ERROR_INVALID_HANDLE );
935 err = svcctl_ControlService(hsvc->hdr.server_handle, dwControl, lpServiceStatus);
939 err = map_exception_code(GetExceptionCode());
942 if (err != ERROR_SUCCESS)
951 /******************************************************************************
952 * CloseServiceHandle [ADVAPI32.@]
954 * Close a handle to a service or the service control manager database.
957 * hSCObject [I] Handle to service or service control manager database
964 CloseServiceHandle( SC_HANDLE hSCObject )
966 struct sc_handle *obj;
969 TRACE("%p\n", hSCObject);
970 if (hSCObject == NULL)
972 SetLastError(ERROR_INVALID_HANDLE);
976 obj = (struct sc_handle *)hSCObject;
979 err = svcctl_CloseServiceHandle(&obj->server_handle);
983 err = map_exception_code(GetExceptionCode());
986 sc_handle_free( obj );
988 if (err != ERROR_SUCCESS)
997 /******************************************************************************
998 * OpenServiceA [ADVAPI32.@]
1000 * Open a handle to a service.
1003 * hSCManager [I] Handle of the service control manager database
1004 * lpServiceName [I] Name of the service to open
1005 * dwDesiredAccess [I] Access required to the service
1008 * Success: Handle to the service
1011 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1012 DWORD dwDesiredAccess )
1014 LPWSTR lpServiceNameW;
1017 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1019 lpServiceNameW = SERV_dup(lpServiceName);
1020 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1021 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1026 /******************************************************************************
1027 * OpenServiceW [ADVAPI32.@]
1031 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1032 DWORD dwDesiredAccess)
1034 struct sc_manager *hscm;
1035 struct sc_service *hsvc;
1038 DWORD new_mask = dwDesiredAccess;
1040 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1042 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1045 SetLastError( ERROR_INVALID_HANDLE );
1051 SetLastError(ERROR_INVALID_ADDRESS);
1055 len = strlenW(lpServiceName)+1;
1056 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1057 sizeof (struct sc_service) + len*sizeof(WCHAR),
1058 sc_handle_destroy_service );
1061 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1064 strcpyW( hsvc->name, lpServiceName );
1066 /* add reference to SCM handle */
1067 hscm->hdr.ref_count++;
1072 err = svcctl_OpenServiceW(hscm->hdr.server_handle, lpServiceName, dwDesiredAccess, &hsvc->hdr.server_handle);
1074 __EXCEPT(rpc_filter)
1076 err = map_exception_code(GetExceptionCode());
1080 if (err != ERROR_SUCCESS)
1082 sc_handle_free(&hsvc->hdr);
1087 /* for parts of advapi32 not using services.exe yet */
1088 RtlMapGenericMask(&new_mask, &svc_generic);
1089 hsvc->dwAccess = new_mask;
1091 err = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hsvc->hkey );
1092 if (err != ERROR_SUCCESS)
1093 ERR("Shouldn't hapen - service key for service validated by services.exe doesn't exist\n");
1095 TRACE("returning %p\n",hsvc);
1097 return (SC_HANDLE) &hsvc->hdr;
1100 /******************************************************************************
1101 * CreateServiceW [ADVAPI32.@]
1104 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1105 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1106 DWORD dwServiceType, DWORD dwStartType,
1107 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1108 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1109 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1110 LPCWSTR lpPassword )
1112 struct sc_manager *hscm;
1113 struct sc_service *hsvc = NULL;
1114 DWORD new_mask = dwDesiredAccess;
1118 TRACE("%p %s %s\n", hSCManager,
1119 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1121 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1124 SetLastError( ERROR_INVALID_HANDLE );
1128 if (!lpServiceName || !lpBinaryPathName)
1130 SetLastError(ERROR_INVALID_ADDRESS);
1135 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1139 len = strlenW(lpServiceName)+1;
1140 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1141 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1144 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1147 lstrcpyW( hsvc->name, lpServiceName );
1150 hscm->hdr.ref_count++;
1154 err = svcctl_CreateServiceW(hscm->hdr.server_handle, lpServiceName,
1155 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1156 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies,
1157 multisz_cb(lpDependencies), lpServiceStartName, (LPBYTE)lpPassword, passwdlen,
1158 &hsvc->hdr.server_handle);
1160 __EXCEPT(rpc_filter)
1162 err = map_exception_code(GetExceptionCode());
1166 if (err != ERROR_SUCCESS)
1169 sc_handle_free(&hsvc->hdr);
1173 /* for parts of advapi32 not using services.exe yet */
1174 err = RegOpenKeyW(hscm->hkey, lpServiceName, &hsvc->hkey);
1175 if (err != ERROR_SUCCESS)
1176 WINE_ERR("Couldn't open key that should have been created by services.exe\n");
1178 RtlMapGenericMask(&new_mask, &svc_generic);
1179 hsvc->dwAccess = new_mask;
1181 return (SC_HANDLE) &hsvc->hdr;
1185 /******************************************************************************
1186 * CreateServiceA [ADVAPI32.@]
1189 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1190 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1191 DWORD dwServiceType, DWORD dwStartType,
1192 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1193 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1194 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1197 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1198 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1201 TRACE("%p %s %s\n", hSCManager,
1202 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1204 lpServiceNameW = SERV_dup( lpServiceName );
1205 lpDisplayNameW = SERV_dup( lpDisplayName );
1206 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1207 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1208 lpDependenciesW = SERV_dupmulti( lpDependencies );
1209 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1210 lpPasswordW = SERV_dup( lpPassword );
1212 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1213 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1214 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1215 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1217 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1218 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1219 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1220 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1221 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1222 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1223 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1229 /******************************************************************************
1230 * DeleteService [ADVAPI32.@]
1232 * Delete a service from the service control manager database.
1235 * hService [I] Handle of the service to delete
1241 BOOL WINAPI DeleteService( SC_HANDLE hService )
1243 struct sc_service *hsvc;
1246 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1249 SetLastError( ERROR_INVALID_HANDLE );
1255 err = svcctl_DeleteService(hsvc->hdr.server_handle);
1257 __EXCEPT(rpc_filter)
1259 err = map_exception_code(GetExceptionCode());
1268 /* Close the key to the service */
1269 RegCloseKey(hsvc->hkey);
1275 /******************************************************************************
1276 * StartServiceA [ADVAPI32.@]
1281 * hService [I] Handle of service
1282 * dwNumServiceArgs [I] Number of arguments
1283 * lpServiceArgVectors [I] Address of array of argument strings
1286 * - NT implements this function using an obscure RPC call.
1287 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1288 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1289 * - This will only work for shared address space. How should the service
1290 * args be transferred when address spaces are separated?
1291 * - Can only start one service at a time.
1292 * - Has no concept of privilege.
1298 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1299 LPCSTR *lpServiceArgVectors )
1301 LPWSTR *lpwstr=NULL;
1305 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1307 if (dwNumServiceArgs)
1308 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1309 dwNumServiceArgs*sizeof(LPWSTR) );
1311 for(i=0; i<dwNumServiceArgs; i++)
1312 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1314 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1316 if (dwNumServiceArgs)
1318 for(i=0; i<dwNumServiceArgs; i++)
1319 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1320 HeapFree(GetProcessHeap(), 0, lpwstr);
1327 /******************************************************************************
1328 * StartServiceW [ADVAPI32.@]
1330 * See StartServiceA.
1332 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1333 LPCWSTR *lpServiceArgVectors)
1335 struct sc_service *hsvc;
1338 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1340 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1343 SetLastError(ERROR_INVALID_HANDLE);
1349 err = svcctl_StartServiceW(hsvc->hdr.server_handle, dwNumServiceArgs, lpServiceArgVectors);
1351 __EXCEPT(rpc_filter)
1353 err = map_exception_code(GetExceptionCode());
1356 if (err != ERROR_SUCCESS)
1365 /******************************************************************************
1366 * QueryServiceStatus [ADVAPI32.@]
1369 * hService [I] Handle to service to get information about
1370 * lpservicestatus [O] buffer to receive the status information for the service
1373 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1374 LPSERVICE_STATUS lpservicestatus)
1376 SERVICE_STATUS_PROCESS SvcStatusData;
1380 TRACE("%p %p\n", hService, lpservicestatus);
1382 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1383 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1384 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1389 /******************************************************************************
1390 * QueryServiceStatusEx [ADVAPI32.@]
1392 * Get information about a service.
1395 * hService [I] Handle to service to get information about
1396 * InfoLevel [I] Level of information to get
1397 * lpBuffer [O] Destination for requested information
1398 * cbBufSize [I] Size of lpBuffer in bytes
1399 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1405 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1406 LPBYTE lpBuffer, DWORD cbBufSize,
1407 LPDWORD pcbBytesNeeded)
1409 struct sc_service *hsvc;
1412 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1414 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1417 SetLastError( ERROR_INVALID_HANDLE );
1423 err = svcctl_QueryServiceStatusEx(hsvc->hdr.server_handle, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1425 __EXCEPT(rpc_filter)
1427 err = map_exception_code(GetExceptionCode());
1430 if (err != ERROR_SUCCESS)
1439 /******************************************************************************
1440 * QueryServiceConfigA [ADVAPI32.@]
1442 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1443 DWORD size, LPDWORD needed )
1448 QUERY_SERVICE_CONFIGW *configW;
1450 TRACE("%p %p %d %p\n", hService, config, size, needed);
1452 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1454 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1457 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1458 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1459 if (!ret) goto done;
1461 config->dwServiceType = configW->dwServiceType;
1462 config->dwStartType = configW->dwStartType;
1463 config->dwErrorControl = configW->dwErrorControl;
1464 config->lpBinaryPathName = NULL;
1465 config->lpLoadOrderGroup = NULL;
1466 config->dwTagId = configW->dwTagId;
1467 config->lpDependencies = NULL;
1468 config->lpServiceStartName = NULL;
1469 config->lpDisplayName = NULL;
1471 p = (LPSTR)(config + 1);
1472 n = size - sizeof(*config);
1475 #define MAP_STR(str) \
1479 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1480 if (!sz) goto done; \
1487 MAP_STR( lpBinaryPathName );
1488 MAP_STR( lpLoadOrderGroup );
1489 MAP_STR( lpDependencies );
1490 MAP_STR( lpServiceStartName );
1491 MAP_STR( lpDisplayName );
1494 *needed = p - (LPSTR)config;
1498 HeapFree( GetProcessHeap(), 0, buffer );
1502 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1509 memset(*buf, 0, cb);
1513 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1514 memcpy(*buf, *string_ptr, cb);
1515 MIDL_user_free(*string_ptr);
1518 *string_ptr = (LPWSTR)*buf;
1524 static DWORD size_string(LPWSTR string)
1526 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1529 /******************************************************************************
1530 * QueryServiceConfigW [ADVAPI32.@]
1533 QueryServiceConfigW( SC_HANDLE hService,
1534 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1535 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1537 QUERY_SERVICE_CONFIGW config;
1538 struct sc_service *hsvc;
1543 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1544 cbBufSize, pcbBytesNeeded);
1546 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1549 SetLastError( ERROR_INVALID_HANDLE );
1553 memset(&config, 0, sizeof(config));
1557 err = svcctl_QueryServiceConfigW(hsvc->hdr.server_handle, &config);
1559 __EXCEPT(rpc_filter)
1561 err = map_exception_code(GetExceptionCode());
1565 if (err != ERROR_SUCCESS)
1567 TRACE("services.exe: error %u\n", err);
1572 /* calculate the size required first */
1573 total = sizeof (QUERY_SERVICE_CONFIGW);
1574 total += size_string(config.lpBinaryPathName);
1575 total += size_string(config.lpLoadOrderGroup);
1576 total += size_string(config.lpDependencies);
1577 total += size_string(config.lpServiceStartName);
1578 total += size_string(config.lpDisplayName);
1580 *pcbBytesNeeded = total;
1582 /* if there's not enough memory, return an error */
1583 if( total > cbBufSize )
1585 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1586 MIDL_user_free(config.lpBinaryPathName);
1587 MIDL_user_free(config.lpLoadOrderGroup);
1588 MIDL_user_free(config.lpDependencies);
1589 MIDL_user_free(config.lpServiceStartName);
1590 MIDL_user_free(config.lpDisplayName);
1594 *lpServiceConfig = config;
1595 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1596 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1597 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1598 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1599 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1600 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1602 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1603 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1604 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1605 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1606 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1611 /******************************************************************************
1612 * QueryServiceConfig2A [ADVAPI32.@]
1615 * observed under win2k:
1616 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1617 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1619 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1620 DWORD size, LPDWORD needed)
1623 LPBYTE bufferW = NULL;
1626 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1628 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1629 if(!ret) goto cleanup;
1632 case SERVICE_CONFIG_DESCRIPTION:
1633 { LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1634 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1635 if (configW->lpDescription) {
1637 configA->lpDescription = (LPSTR)(configA + 1);
1638 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1639 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1641 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1643 configA->lpDescription = NULL;
1646 else configA->lpDescription = NULL;
1650 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1655 HeapFree( GetProcessHeap(), 0, bufferW);
1659 /******************************************************************************
1660 * QueryServiceConfig2W [ADVAPI32.@]
1662 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1663 DWORD size, LPDWORD needed)
1668 struct sc_service *hsvc;
1670 if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1671 if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
1672 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
1673 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
1674 (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
1675 (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
1676 (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
1677 FIXME("Level %d not implemented\n", dwLevel);
1678 SetLastError(ERROR_INVALID_LEVEL);
1681 if(!needed || (!buffer && size)) {
1682 SetLastError(ERROR_INVALID_ADDRESS);
1686 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1688 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1691 SetLastError(ERROR_INVALID_HANDLE);
1697 case SERVICE_CONFIG_DESCRIPTION: {
1698 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1699 LPSERVICE_DESCRIPTIONW config = (LPSERVICE_DESCRIPTIONW) buffer;
1700 LPBYTE strbuf = NULL;
1701 *needed = sizeof (SERVICE_DESCRIPTIONW);
1702 sz = size - *needed;
1703 if(config && (*needed <= size))
1704 strbuf = (LPBYTE) (config + 1);
1705 r = RegQueryValueExW( hKey, szDescription, 0, &type, strbuf, &sz );
1706 if((r == ERROR_SUCCESS) && ( type != REG_SZ)) {
1707 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type);
1712 if(r == ERROR_SUCCESS)
1713 config->lpDescription = (LPWSTR) (config + 1);
1715 config->lpDescription = NULL;
1721 SetLastError(ERROR_INSUFFICIENT_BUFFER);
1723 return (*needed <= size);
1726 /******************************************************************************
1727 * EnumServicesStatusA [ADVAPI32.@]
1730 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1731 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1732 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1733 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1735 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1736 dwServiceType, dwServiceState, lpServices, cbBufSize,
1737 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1738 SetLastError (ERROR_ACCESS_DENIED);
1742 /******************************************************************************
1743 * EnumServicesStatusW [ADVAPI32.@]
1746 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1747 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1748 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1749 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1751 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1752 dwServiceType, dwServiceState, lpServices, cbBufSize,
1753 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1754 SetLastError (ERROR_ACCESS_DENIED);
1758 /******************************************************************************
1759 * EnumServicesStatusExA [ADVAPI32.@]
1762 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1763 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1764 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1766 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1767 dwServiceType, dwServiceState, lpServices, cbBufSize,
1768 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1769 if (lpServicesReturned) *lpServicesReturned = 0;
1770 SetLastError (ERROR_ACCESS_DENIED);
1774 /******************************************************************************
1775 * EnumServicesStatusExW [ADVAPI32.@]
1778 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1779 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1780 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1782 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1783 dwServiceType, dwServiceState, lpServices, cbBufSize,
1784 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
1785 SetLastError (ERROR_ACCESS_DENIED);
1789 /******************************************************************************
1790 * GetServiceKeyNameA [ADVAPI32.@]
1792 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1793 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1795 LPWSTR lpDisplayNameW, lpServiceNameW;
1799 TRACE("%p %s %p %p\n", hSCManager,
1800 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1802 lpDisplayNameW = SERV_dup(lpDisplayName);
1804 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1806 lpServiceNameW = NULL;
1808 sizeW = *lpcchBuffer;
1809 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1811 if (lpServiceName && *lpcchBuffer)
1812 lpServiceName[0] = 0;
1813 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1817 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1818 *lpcchBuffer, NULL, NULL ))
1820 if (*lpcchBuffer && lpServiceName)
1821 lpServiceName[0] = 0;
1822 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1826 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1830 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1831 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1835 /******************************************************************************
1836 * GetServiceKeyNameW [ADVAPI32.@]
1838 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1839 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1841 struct sc_manager *hscm;
1844 TRACE("%p %s %p %p\n", hSCManager,
1845 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1847 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1850 SetLastError(ERROR_INVALID_HANDLE);
1856 SetLastError(ERROR_INVALID_ADDRESS);
1862 err = svcctl_GetServiceKeyNameW(hscm->hdr.server_handle,
1863 lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
1865 __EXCEPT(rpc_filter)
1867 err = map_exception_code(GetExceptionCode());
1873 return err == ERROR_SUCCESS;
1876 /******************************************************************************
1877 * QueryServiceLockStatusA [ADVAPI32.@]
1879 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1880 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1881 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1883 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1888 /******************************************************************************
1889 * QueryServiceLockStatusW [ADVAPI32.@]
1891 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1892 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1893 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1895 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1900 /******************************************************************************
1901 * GetServiceDisplayNameA [ADVAPI32.@]
1903 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1904 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1906 LPWSTR lpServiceNameW, lpDisplayNameW;
1910 TRACE("%p %s %p %p\n", hSCManager,
1911 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1913 lpServiceNameW = SERV_dup(lpServiceName);
1915 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1917 lpDisplayNameW = NULL;
1919 sizeW = *lpcchBuffer;
1920 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1922 if (lpDisplayName && *lpcchBuffer)
1923 lpDisplayName[0] = 0;
1924 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1928 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1929 *lpcchBuffer, NULL, NULL ))
1931 if (*lpcchBuffer && lpDisplayName)
1932 lpDisplayName[0] = 0;
1933 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1937 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1938 * (but if the function succeeded it means that is a good upper estimation of the size) */
1942 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1943 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1947 /******************************************************************************
1948 * GetServiceDisplayNameW [ADVAPI32.@]
1950 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1951 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1953 struct sc_manager *hscm;
1956 TRACE("%p %s %p %p\n", hSCManager,
1957 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1959 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1962 SetLastError(ERROR_INVALID_HANDLE);
1968 SetLastError(ERROR_INVALID_ADDRESS);
1974 err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
1975 lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
1977 __EXCEPT(rpc_filter)
1979 err = map_exception_code(GetExceptionCode());
1985 return err == ERROR_SUCCESS;
1988 /******************************************************************************
1989 * ChangeServiceConfigW [ADVAPI32.@]
1991 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1992 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1993 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1994 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1996 struct sc_service *hsvc;
2000 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2001 hService, dwServiceType, dwStartType, dwErrorControl,
2002 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2003 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2004 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2006 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2009 SetLastError( ERROR_INVALID_HANDLE );
2013 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2017 err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
2018 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2019 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2020 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2022 __EXCEPT(rpc_filter)
2024 err = map_exception_code(GetExceptionCode());
2028 if (err != ERROR_SUCCESS)
2031 return err == ERROR_SUCCESS;
2034 /******************************************************************************
2035 * ChangeServiceConfigA [ADVAPI32.@]
2037 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2038 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2039 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2040 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2042 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2043 LPWSTR wServiceStartName, wPassword, wDisplayName;
2046 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2047 hService, dwServiceType, dwStartType, dwErrorControl,
2048 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2049 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2050 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2052 wBinaryPathName = SERV_dup( lpBinaryPathName );
2053 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2054 wDependencies = SERV_dupmulti( lpDependencies );
2055 wServiceStartName = SERV_dup( lpServiceStartName );
2056 wPassword = SERV_dup( lpPassword );
2057 wDisplayName = SERV_dup( lpDisplayName );
2059 r = ChangeServiceConfigW( hService, dwServiceType,
2060 dwStartType, dwErrorControl, wBinaryPathName,
2061 wLoadOrderGroup, lpdwTagId, wDependencies,
2062 wServiceStartName, wPassword, wDisplayName);
2064 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2065 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2066 HeapFree( GetProcessHeap(), 0, wDependencies );
2067 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2068 HeapFree( GetProcessHeap(), 0, wPassword );
2069 HeapFree( GetProcessHeap(), 0, wDisplayName );
2074 /******************************************************************************
2075 * ChangeServiceConfig2A [ADVAPI32.@]
2077 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2082 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2084 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2086 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2087 SERVICE_DESCRIPTIONW sdw;
2089 sdw.lpDescription = SERV_dup( sd->lpDescription );
2091 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2093 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2095 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2097 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2098 SERVICE_FAILURE_ACTIONSW faw;
2100 faw.dwResetPeriod = fa->dwResetPeriod;
2101 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2102 faw.lpCommand = SERV_dup( fa->lpCommand );
2103 faw.cActions = fa->cActions;
2104 faw.lpsaActions = fa->lpsaActions;
2106 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2108 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2109 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2112 SetLastError( ERROR_INVALID_PARAMETER );
2117 /******************************************************************************
2118 * ChangeServiceConfig2W [ADVAPI32.@]
2120 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2124 struct sc_service *hsvc;
2126 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2129 SetLastError( ERROR_INVALID_HANDLE );
2134 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2136 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2137 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2138 if (sd->lpDescription)
2140 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2141 if (sd->lpDescription[0] == 0)
2142 RegDeleteValueW(hKey,szDescription);
2144 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2145 (LPVOID)sd->lpDescription,
2146 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2150 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2154 /******************************************************************************
2155 * QueryServiceObjectSecurity [ADVAPI32.@]
2157 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2158 SECURITY_INFORMATION dwSecurityInformation,
2159 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2160 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2162 SECURITY_DESCRIPTOR descriptor;
2167 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2168 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2170 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2171 FIXME("information %d not supported\n", dwSecurityInformation);
2173 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2175 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2176 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2179 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2180 *pcbBytesNeeded = size;
2184 /******************************************************************************
2185 * SetServiceObjectSecurity [ADVAPI32.@]
2187 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2188 SECURITY_INFORMATION dwSecurityInformation,
2189 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2191 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2195 /******************************************************************************
2196 * SetServiceBits [ADVAPI32.@]
2198 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2199 DWORD dwServiceBits,
2201 BOOL bUpdateImmediately)
2203 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2204 bSetBitsOn, bUpdateImmediately);
2208 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2209 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2211 LPHANDLER_FUNCTION func = context;
2214 return ERROR_SUCCESS;
2217 /******************************************************************************
2218 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2220 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2222 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2225 /******************************************************************************
2226 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2228 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2230 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2233 /******************************************************************************
2234 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2236 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2239 SERVICE_STATUS_HANDLE ret;
2241 nameW = SERV_dup(name);
2242 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2243 HeapFree( GetProcessHeap(), 0, nameW );
2247 /******************************************************************************
2248 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2250 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2251 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2253 service_data *service;
2254 SC_HANDLE hService = 0;
2257 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2259 EnterCriticalSection( &service_cs );
2260 if ((service = find_service_by_name( lpServiceName )))
2262 service->handler = lpHandlerProc;
2263 service->context = lpContext;
2264 hService = service->handle;
2267 LeaveCriticalSection( &service_cs );
2269 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2271 return (SERVICE_STATUS_HANDLE)hService;
2274 /******************************************************************************
2275 * EnumDependentServicesA [ADVAPI32.@]
2277 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2278 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2279 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2281 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2282 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2284 *lpServicesReturned = 0;
2288 /******************************************************************************
2289 * EnumDependentServicesW [ADVAPI32.@]
2291 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2292 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2293 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2295 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2296 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2298 *lpServicesReturned = 0;