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
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
41 static const WCHAR szLocalSystem[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
42 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
43 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
44 'S','e','r','v','i','c','e','s',0 };
45 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
48 static const GENERIC_MAPPING scm_generic = {
49 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
50 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
51 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
55 static const GENERIC_MAPPING svc_generic = {
56 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
57 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
58 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
62 typedef struct service_start_info_t
69 #define WINESERV_STARTINFO 1
70 #define WINESERV_GETSTATUS 2
71 #define WINESERV_SENDCONTROL 3
73 typedef struct service_data_t
75 LPHANDLER_FUNCTION_EX handler;
77 SERVICE_STATUS_PROCESS status;
81 LPSERVICE_MAIN_FUNCTIONA a;
82 LPSERVICE_MAIN_FUNCTIONW w;
88 static CRITICAL_SECTION service_cs;
89 static CRITICAL_SECTION_DEBUG service_cs_debug =
92 { &service_cs_debug.ProcessLocksList,
93 &service_cs_debug.ProcessLocksList },
94 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
96 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
98 static service_data **services;
99 static unsigned int nb_services;
100 static HANDLE service_event;
102 extern HANDLE __wine_make_process_system(void);
104 /******************************************************************************
108 #define MAX_SERVICE_NAME 256
110 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
113 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
117 SC_HANDLE_TYPE htype;
119 sc_handle_destructor destroy;
122 struct sc_manager /* service control manager handle */
124 struct sc_handle hdr;
125 HKEY hkey; /* handle to services database in the registry */
129 struct sc_service /* service handle */
131 struct sc_handle hdr;
132 HKEY hkey; /* handle to service entry in the registry (under hkey) */
134 struct sc_manager *scm; /* pointer to SCM handle */
138 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
139 sc_handle_destructor destroy)
141 struct sc_handle *hdr;
143 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
148 hdr->destroy = destroy;
150 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
154 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
156 struct sc_handle *hdr = (struct sc_handle *) handle;
160 if (hdr->htype != htype)
165 static void sc_handle_free(struct sc_handle* hdr)
169 if (--hdr->ref_count)
172 HeapFree(GetProcessHeap(), 0, hdr);
175 static void sc_handle_destroy_manager(struct sc_handle *handle)
177 struct sc_manager *mgr = (struct sc_manager*) handle;
179 TRACE("destroying SC Manager %p\n", mgr);
181 RegCloseKey(mgr->hkey);
184 static void sc_handle_destroy_service(struct sc_handle *handle)
186 struct sc_service *svc = (struct sc_service*) handle;
188 TRACE("destroying service %p\n", svc);
190 RegCloseKey(svc->hkey);
192 sc_handle_free(&svc->scm->hdr);
196 /******************************************************************************
197 * String management functions (same behaviour as strdup)
198 * NOTE: the caller of those functions is responsible for calling HeapFree
199 * in order to release the memory allocated by those functions.
201 static inline LPWSTR SERV_dup( LPCSTR str )
208 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
209 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
210 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
214 static inline LPWSTR SERV_dupmulti(LPCSTR str)
222 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
223 n += (strlen( &str[n] ) + 1);
228 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
229 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
233 /******************************************************************************
234 * registry access functions and data
236 static const WCHAR szDisplayName[] = {
237 'D','i','s','p','l','a','y','N','a','m','e', 0 };
238 static const WCHAR szType[] = {'T','y','p','e',0};
239 static const WCHAR szStart[] = {'S','t','a','r','t',0};
240 static const WCHAR szError[] = {
241 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
242 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
243 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
244 static const WCHAR szDependencies[] = {
245 'D','e','p','e','n','d','e','n','c','i','e','s',0};
246 static const WCHAR szDependOnService[] = {
247 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
248 static const WCHAR szObjectName[] = {
249 'O','b','j','e','c','t','N','a','m','e',0};
250 static const WCHAR szTag[] = {
260 static inline void service_set_value( struct reg_value *val,
261 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
269 static inline void service_set_dword( struct reg_value *val,
270 LPCWSTR name, const DWORD *data )
272 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
275 static inline void service_set_string( struct reg_value *val,
276 LPCWSTR name, LPCWSTR string )
278 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
279 service_set_value( val, REG_SZ, name, string, len );
282 static inline void service_set_multi_string( struct reg_value *val,
283 LPCWSTR name, LPCWSTR string )
287 /* determine the length of a double null terminated multi string */
289 len += (lstrlenW( &string[ len ] )+1);
290 } while ( string[ len++ ] );
292 len *= sizeof (WCHAR);
293 service_set_value( val, REG_MULTI_SZ, name, string, len );
296 static inline LONG service_write_values( HKEY hKey,
297 const struct reg_value *val, int n )
299 LONG r = ERROR_SUCCESS;
304 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
305 (const BYTE*)val[i].data, val[i].size );
306 if( r != ERROR_SUCCESS )
312 /******************************************************************************
313 * Service IPC functions
315 static LPWSTR service_get_pipe_name(LPCWSTR service)
317 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
318 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
322 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
323 name = HeapAlloc(GetProcessHeap(), 0, len);
324 strcpyW(name, prefix);
325 strcatW(name, service);
329 static HANDLE service_open_pipe(LPCWSTR service)
331 LPWSTR szPipe = service_get_pipe_name( service );
332 HANDLE handle = INVALID_HANDLE_VALUE;
335 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
336 0, NULL, OPEN_ALWAYS, 0, NULL);
337 if (handle != INVALID_HANDLE_VALUE)
339 if (GetLastError() != ERROR_PIPE_BUSY)
341 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
342 HeapFree(GetProcessHeap(), 0, szPipe);
347 /******************************************************************************
348 * service_get_event_handle
350 static HANDLE service_get_event_handle(LPCWSTR service)
352 static const WCHAR prefix[] = {
353 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
358 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
359 name = HeapAlloc(GetProcessHeap(), 0, len);
360 strcpyW(name, prefix);
361 strcatW(name, service);
362 handle = CreateEventW(NULL, TRUE, FALSE, name);
363 HeapFree(GetProcessHeap(), 0, name);
367 /******************************************************************************
370 * Call into the main service routine provided by StartServiceCtrlDispatcher.
372 static DWORD WINAPI service_thread(LPVOID arg)
374 service_data *info = arg;
375 LPWSTR str = info->args;
376 DWORD argc = 0, len = 0;
382 len += strlenW(&str[len]) + 1;
389 info->proc.w(0, NULL);
391 info->proc.a(0, NULL);
399 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
400 for (argc=0, p=str; *p; p += strlenW(p) + 1)
404 info->proc.w(argc, argv);
405 HeapFree(GetProcessHeap(), 0, argv);
409 LPSTR strA, *argv, p;
412 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
413 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
414 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
416 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
417 for (argc=0, p=strA; *p; p += strlen(p) + 1)
421 info->proc.a(argc, argv);
422 HeapFree(GetProcessHeap(), 0, argv);
423 HeapFree(GetProcessHeap(), 0, strA);
428 /******************************************************************************
429 * service_handle_start
431 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
433 DWORD read = 0, result = 0;
437 TRACE("%p %p %d\n", pipe, service, count);
439 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
440 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
441 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
443 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
444 r, count, read, debugstr_wn(args, count));
450 WARN("service is not stopped\n");
451 result = ERROR_SERVICE_ALREADY_RUNNING;
455 HeapFree(GetProcessHeap(), 0, service->args);
456 service->args = args;
458 service->thread = CreateThread( NULL, 0, service_thread,
460 SetEvent( service_event ); /* notify the main loop */
463 HeapFree(GetProcessHeap(), 0, args);
464 WriteFile( pipe, &result, sizeof result, &read, NULL );
469 /******************************************************************************
470 * service_send_start_message
472 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
474 DWORD i, len, count, result;
475 service_start_info *ssi;
479 TRACE("%p %p %d\n", pipe, argv, argc);
481 /* calculate how much space do we need to send the startup info */
483 for (i=0; i<argc; i++)
484 len += strlenW(argv[i])+1;
486 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
487 ssi->cmd = WINESERV_STARTINFO;
490 /* copy service args into a single buffer*/
492 for (i=0; i<argc; i++)
499 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
502 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
505 SetLastError(result);
510 HeapFree(GetProcessHeap(),0,ssi);
515 /******************************************************************************
516 * service_handle_get_status
518 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
522 return WriteFile(pipe, &service->status,
523 sizeof service->status, &count, NULL);
526 /******************************************************************************
529 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
531 DWORD cmd[2], count = 0;
534 cmd[0] = WINESERV_GETSTATUS;
536 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
537 if (!r || count != sizeof cmd)
539 ERR("service protocol error - failed to write pipe!\n");
542 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
543 if (!r || count != sizeof *status)
544 ERR("service protocol error - failed to read pipe "
545 "r = %d count = %d!\n", r, count);
549 /******************************************************************************
550 * service_send_control
552 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
554 DWORD cmd[2], count = 0;
557 cmd[0] = WINESERV_SENDCONTROL;
559 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
560 if (!r || count != sizeof cmd)
562 ERR("service protocol error - failed to write pipe!\n");
565 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
566 if (!r || count != sizeof *result)
567 ERR("service protocol error - failed to read pipe "
568 "r = %d count = %d!\n", r, count);
572 /******************************************************************************
573 * service_accepts_control
575 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
577 DWORD a = service->status.dwControlsAccepted;
581 case SERVICE_CONTROL_INTERROGATE:
583 case SERVICE_CONTROL_STOP:
584 if (a&SERVICE_ACCEPT_STOP)
587 case SERVICE_CONTROL_SHUTDOWN:
588 if (a&SERVICE_ACCEPT_SHUTDOWN)
591 case SERVICE_CONTROL_PAUSE:
592 case SERVICE_CONTROL_CONTINUE:
593 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
596 case SERVICE_CONTROL_PARAMCHANGE:
597 if (a&SERVICE_ACCEPT_PARAMCHANGE)
600 case SERVICE_CONTROL_NETBINDADD:
601 case SERVICE_CONTROL_NETBINDREMOVE:
602 case SERVICE_CONTROL_NETBINDENABLE:
603 case SERVICE_CONTROL_NETBINDDISABLE:
604 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
606 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
607 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
610 case SERVICE_CONTROL_POWEREVENT:
611 if (a&SERVICE_ACCEPT_POWEREVENT)
614 case SERVICE_CONTROL_SESSIONCHANGE:
615 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
622 /******************************************************************************
623 * service_handle_control
625 static BOOL service_handle_control(HANDLE pipe, service_data *service,
628 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
630 TRACE("received control %d\n", dwControl);
632 if (service_accepts_control(service, dwControl))
634 if (service->handler)
635 ret = service->handler(dwControl, 0, NULL, service->context);
637 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
640 /******************************************************************************
641 * service_control_dispatcher
643 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
645 service_data *service = arg;
649 TRACE("%p %s\n", service, debugstr_w(service->name));
651 /* create a pipe to talk to the rest of the world with */
652 name = service_get_pipe_name(service->name);
653 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
654 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
656 if (pipe==INVALID_HANDLE_VALUE)
657 ERR("failed to create pipe for %s, error = %d\n",
658 debugstr_w(service->name), GetLastError());
660 HeapFree(GetProcessHeap(), 0, name);
662 /* let the process who started us know we've tried to create a pipe */
663 event = service_get_event_handle(service->name);
667 if (pipe==INVALID_HANDLE_VALUE) return 0;
669 /* dispatcher loop */
673 DWORD count, req[2] = {0,0};
675 r = ConnectNamedPipe(pipe, NULL);
676 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
678 ERR("pipe connect failed\n");
682 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
683 if (!r || count!=sizeof req)
685 ERR("pipe read failed\n");
689 /* handle the request */
692 case WINESERV_STARTINFO:
693 service_handle_start(pipe, service, req[1]);
695 case WINESERV_GETSTATUS:
696 service_handle_get_status(pipe, service);
698 case WINESERV_SENDCONTROL:
699 service_handle_control(pipe, service, req[1]);
702 ERR("received invalid command %d length %d\n", req[0], req[1]);
705 FlushFileBuffers(pipe);
706 DisconnectNamedPipe(pipe);
713 /******************************************************************************
714 * service_run_threads
716 static BOOL service_run_threads(void)
719 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
720 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
722 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
724 wait_handles[0] = __wine_make_process_system();
725 wait_handles[1] = service_event;
727 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
728 nb_services, GetCurrentProcessId());
730 EnterCriticalSection( &service_cs );
731 for (i = 0; i < nb_services; i++)
733 services[i]->status.dwProcessId = GetCurrentProcessId();
734 CloseHandle( CreateThread( NULL, 0, service_control_dispatcher, services[i], 0, NULL ));
736 LeaveCriticalSection( &service_cs );
738 /* wait for all the threads to pack up and exit */
741 EnterCriticalSection( &service_cs );
742 for (i = 0, n = 2; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
744 if (!services[i]->thread) continue;
745 wait_services[n] = i;
746 wait_handles[n++] = services[i]->thread;
748 LeaveCriticalSection( &service_cs );
750 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
751 if (!ret) /* system process event */
753 TRACE( "last user process exited, shutting down\n" );
754 /* FIXME: we should maybe send a shutdown control to running services */
759 continue; /* rebuild the list */
763 services[wait_services[ret]]->thread = 0;
764 CloseHandle( wait_handles[ret] );
765 if (n == 3) return TRUE; /* it was the last running thread */
771 /******************************************************************************
772 * StartServiceCtrlDispatcherA [ADVAPI32.@]
774 * See StartServiceCtrlDispatcherW.
776 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
782 TRACE("%p\n", servent);
786 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
789 while (servent[nb_services].lpServiceName) nb_services++;
790 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
792 for (i = 0; i < nb_services; i++)
794 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
795 DWORD sz = FIELD_OFFSET( service_data, name[len] );
796 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
797 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
798 info->proc.a = servent[i].lpServiceProc;
799 info->unicode = FALSE;
803 service_run_threads();
808 /******************************************************************************
809 * StartServiceCtrlDispatcherW [ADVAPI32.@]
811 * Connects a process containing one or more services to the service control
815 * servent [I] A list of the service names and service procedures
821 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
827 TRACE("%p\n", servent);
831 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
834 while (servent[nb_services].lpServiceName) nb_services++;
835 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
837 for (i = 0; i < nb_services; i++)
839 DWORD len = strlenW(servent[i].lpServiceName) + 1;
840 DWORD sz = FIELD_OFFSET( service_data, name[len] );
841 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
842 strcpyW(info->name, servent[i].lpServiceName);
843 info->proc.w = servent[i].lpServiceProc;
844 info->unicode = TRUE;
848 service_run_threads();
853 /******************************************************************************
854 * LockServiceDatabase [ADVAPI32.@]
856 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
860 TRACE("%p\n",hSCManager);
862 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
863 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
867 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
870 TRACE("returning %p\n", ret);
875 /******************************************************************************
876 * UnlockServiceDatabase [ADVAPI32.@]
878 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
880 TRACE("%p\n",ScLock);
882 return CloseHandle( ScLock );
885 /******************************************************************************
886 * SetServiceStatus [ADVAPI32.@]
893 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
895 ULONG_PTR index = HandleToULong(hService) - 1;
898 TRACE("%p %x %x %x %x %x %x %x\n", hService,
899 lpStatus->dwServiceType, lpStatus->dwCurrentState,
900 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
901 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
902 lpStatus->dwWaitHint);
904 EnterCriticalSection( &service_cs );
905 if (index < nb_services)
907 memcpy( &services[index]->status, lpStatus, sizeof(SERVICE_STATUS) );
908 TRACE("Set service status to %d\n",services[index]->status.dwCurrentState);
911 LeaveCriticalSection( &service_cs );
917 /******************************************************************************
918 * OpenSCManagerA [ADVAPI32.@]
920 * Establish a connection to the service control manager and open its database.
923 * lpMachineName [I] Pointer to machine name string
924 * lpDatabaseName [I] Pointer to database name string
925 * dwDesiredAccess [I] Type of access
928 * Success: A Handle to the service control manager database
931 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
932 DWORD dwDesiredAccess )
934 LPWSTR lpMachineNameW, lpDatabaseNameW;
937 lpMachineNameW = SERV_dup(lpMachineName);
938 lpDatabaseNameW = SERV_dup(lpDatabaseName);
939 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
940 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
941 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
945 /******************************************************************************
946 * OpenSCManagerW [ADVAPI32.@]
948 * See OpenSCManagerA.
950 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
951 DWORD dwDesiredAccess )
953 struct sc_manager *manager;
956 DWORD new_mask = dwDesiredAccess;
958 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
959 debugstr_w(lpDatabaseName), dwDesiredAccess);
961 if( lpDatabaseName && lpDatabaseName[0] )
963 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
965 /* noop, all right */
967 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
969 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
974 SetLastError( ERROR_INVALID_NAME );
979 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
980 sc_handle_destroy_manager );
984 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
985 if (r!=ERROR_SUCCESS)
988 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
990 if (r!=ERROR_SUCCESS)
993 RtlMapGenericMask(&new_mask, &scm_generic);
994 manager->dwAccess = new_mask;
995 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
997 return (SC_HANDLE) &manager->hdr;
1000 sc_handle_free( &manager->hdr );
1005 /******************************************************************************
1006 * ControlService [ADVAPI32.@]
1008 * Send a control code to a service.
1011 * hService [I] Handle of the service control manager database
1012 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1013 * lpServiceStatus [O] Destination for the status of the service, if available
1020 * Unlike M$' implementation, control requests are not serialized and may be
1021 * processed asynchronously.
1023 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1024 LPSERVICE_STATUS lpServiceStatus )
1026 struct sc_service *hsvc;
1030 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1032 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1035 SetLastError( ERROR_INVALID_HANDLE );
1039 ret = QueryServiceStatus(hService, lpServiceStatus);
1042 ERR("failed to query service status\n");
1043 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1047 switch (lpServiceStatus->dwCurrentState)
1049 case SERVICE_STOPPED:
1050 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1052 case SERVICE_START_PENDING:
1053 if (dwControl==SERVICE_CONTROL_STOP)
1056 case SERVICE_STOP_PENDING:
1057 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1061 handle = service_open_pipe(hsvc->name);
1062 if (handle!=INVALID_HANDLE_VALUE)
1064 DWORD result = ERROR_SUCCESS;
1065 ret = service_send_control(handle, dwControl, &result);
1066 CloseHandle(handle);
1067 if (result!=ERROR_SUCCESS)
1069 SetLastError(result);
1077 /******************************************************************************
1078 * CloseServiceHandle [ADVAPI32.@]
1080 * Close a handle to a service or the service control manager database.
1083 * hSCObject [I] Handle to service or service control manager database
1090 CloseServiceHandle( SC_HANDLE hSCObject )
1092 TRACE("%p\n", hSCObject);
1094 sc_handle_free( (struct sc_handle*) hSCObject );
1100 /******************************************************************************
1101 * OpenServiceA [ADVAPI32.@]
1103 * Open a handle to a service.
1106 * hSCManager [I] Handle of the service control manager database
1107 * lpServiceName [I] Name of the service to open
1108 * dwDesiredAccess [I] Access required to the service
1111 * Success: Handle to the service
1114 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1115 DWORD dwDesiredAccess )
1117 LPWSTR lpServiceNameW;
1120 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1122 lpServiceNameW = SERV_dup(lpServiceName);
1123 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1124 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1129 /******************************************************************************
1130 * OpenServiceW [ADVAPI32.@]
1134 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1135 DWORD dwDesiredAccess)
1137 struct sc_manager *hscm;
1138 struct sc_service *hsvc;
1142 DWORD new_mask = dwDesiredAccess;
1144 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1146 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1149 SetLastError( ERROR_INVALID_HANDLE );
1155 SetLastError(ERROR_INVALID_ADDRESS);
1159 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1160 if (r!=ERROR_SUCCESS)
1162 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1166 len = strlenW(lpServiceName)+1;
1167 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1168 sizeof (struct sc_service) + len*sizeof(WCHAR),
1169 sc_handle_destroy_service );
1175 strcpyW( hsvc->name, lpServiceName );
1178 RtlMapGenericMask(&new_mask, &svc_generic);
1179 hsvc->dwAccess = new_mask;
1181 /* add reference to SCM handle */
1182 hscm->hdr.ref_count++;
1185 TRACE("returning %p\n",hsvc);
1187 return (SC_HANDLE) &hsvc->hdr;
1190 /******************************************************************************
1191 * CreateServiceW [ADVAPI32.@]
1194 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1195 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1196 DWORD dwServiceType, DWORD dwStartType,
1197 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1198 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1199 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1200 LPCWSTR lpPassword )
1202 struct sc_manager *hscm;
1203 struct sc_service *hsvc = NULL;
1207 struct reg_value val[10];
1209 DWORD new_mask = dwDesiredAccess;
1211 WCHAR buffer[MAX_PATH];
1212 BOOL displayname_exists = FALSE;
1214 TRACE("%p %s %s\n", hSCManager,
1215 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1217 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1220 SetLastError( ERROR_INVALID_HANDLE );
1224 if (!lpServiceName || !lpBinaryPathName)
1226 SetLastError(ERROR_INVALID_ADDRESS);
1230 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1232 SetLastError(ERROR_ACCESS_DENIED);
1236 if (!lpServiceName[0])
1238 SetLastError(ERROR_INVALID_NAME);
1242 if (!lpBinaryPathName[0])
1244 SetLastError(ERROR_INVALID_PARAMETER);
1248 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1249 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1250 * runs under the LocalSystem account)
1252 switch (dwServiceType)
1254 case SERVICE_KERNEL_DRIVER:
1255 case SERVICE_FILE_SYSTEM_DRIVER:
1256 case SERVICE_WIN32_OWN_PROCESS:
1257 case SERVICE_WIN32_SHARE_PROCESS:
1260 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1261 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1262 /* FIXME : Do we need a more thorough check? */
1263 if (lpServiceStartName)
1265 SetLastError(ERROR_INVALID_PARAMETER);
1270 SetLastError(ERROR_INVALID_PARAMETER);
1274 if (!lpServiceStartName && (dwServiceType & SERVICE_WIN32))
1275 lpServiceStartName = szLocalSystem;
1277 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1278 if (dwStartType > SERVICE_DISABLED)
1280 SetLastError(ERROR_INVALID_PARAMETER);
1284 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1285 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1286 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1288 SetLastError(ERROR_INVALID_PARAMETER);
1292 /* Loop through the registry to check if the service already exists and to
1293 * check if we can use the given displayname.
1294 * FIXME: Should we use EnumServicesStatusEx?
1296 len = sizeof(buffer);
1297 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1301 /* The service already exists, so bail out */
1302 if(!lstrcmpiW(lpServiceName, buffer))
1304 SetLastError(ERROR_SERVICE_EXISTS);
1308 /* The given displayname matches the found servicename. We don't bail out
1309 * as servicename is checked before a duplicate displayname
1311 if(!lstrcmpiW(lpDisplayName, buffer))
1312 displayname_exists = TRUE;
1314 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1316 WCHAR name[MAX_PATH];
1317 DWORD size = sizeof(name);
1319 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1321 /* The given displayname matches the found displayname */
1322 if (!lstrcmpiW(lpDisplayName, name))
1323 displayname_exists = TRUE;
1325 RegCloseKey(service_key);
1328 len = sizeof(buffer);
1331 if (lpDisplayName && displayname_exists)
1333 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1337 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1338 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1339 if (r!=ERROR_SUCCESS)
1341 /* FIXME: Should we set an error? */
1346 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1348 service_set_dword( &val[n++], szType, &dwServiceType );
1349 service_set_dword( &val[n++], szStart, &dwStartType );
1350 service_set_dword( &val[n++], szError, &dwErrorControl );
1352 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1354 if( lpLoadOrderGroup )
1355 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1357 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1358 * There is no such key as what szDependencies refers to */
1359 if( lpDependencies )
1360 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1363 FIXME("Don't know how to add a Password for a service.\n");
1365 if( lpServiceStartName )
1366 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1368 r = service_write_values( hKey, val, n );
1369 if( r != ERROR_SUCCESS )
1372 len = strlenW(lpServiceName)+1;
1373 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1374 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1377 lstrcpyW( hsvc->name, lpServiceName );
1380 RtlMapGenericMask(&new_mask, &svc_generic);
1381 hsvc->dwAccess = new_mask;
1384 hscm->hdr.ref_count++;
1386 return (SC_HANDLE) &hsvc->hdr;
1389 RegCloseKey( hKey );
1394 /******************************************************************************
1395 * CreateServiceA [ADVAPI32.@]
1398 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1399 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1400 DWORD dwServiceType, DWORD dwStartType,
1401 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1402 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1403 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1406 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1407 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1410 TRACE("%p %s %s\n", hSCManager,
1411 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1413 lpServiceNameW = SERV_dup( lpServiceName );
1414 lpDisplayNameW = SERV_dup( lpDisplayName );
1415 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1416 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1417 lpDependenciesW = SERV_dupmulti( lpDependencies );
1418 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1419 lpPasswordW = SERV_dup( lpPassword );
1421 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1422 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1423 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1424 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1426 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1427 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1428 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1429 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1430 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1431 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1432 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1438 /******************************************************************************
1439 * DeleteService [ADVAPI32.@]
1441 * Delete a service from the service control manager database.
1444 * hService [I] Handle of the service to delete
1450 BOOL WINAPI DeleteService( SC_HANDLE hService )
1452 struct sc_service *hsvc;
1454 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1457 SetLastError( ERROR_INVALID_HANDLE );
1461 if (!(hsvc->dwAccess & DELETE))
1463 SetLastError(ERROR_ACCESS_DENIED);
1467 /* Close the key to the service */
1468 RegCloseKey(hsvc->hkey);
1470 /* Delete the service under the Service Control Manager key */
1471 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1479 /******************************************************************************
1480 * StartServiceA [ADVAPI32.@]
1485 * hService [I] Handle of service
1486 * dwNumServiceArgs [I] Number of arguments
1487 * lpServiceArgVectors [I] Address of array of argument strings
1490 * - NT implements this function using an obscure RPC call.
1491 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1492 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1493 * - This will only work for shared address space. How should the service
1494 * args be transferred when address spaces are separated?
1495 * - Can only start one service at a time.
1496 * - Has no concept of privilege.
1502 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1503 LPCSTR *lpServiceArgVectors )
1505 LPWSTR *lpwstr=NULL;
1509 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1511 if (dwNumServiceArgs)
1512 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1513 dwNumServiceArgs*sizeof(LPWSTR) );
1515 for(i=0; i<dwNumServiceArgs; i++)
1516 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1518 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1520 if (dwNumServiceArgs)
1522 for(i=0; i<dwNumServiceArgs; i++)
1523 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1524 HeapFree(GetProcessHeap(), 0, lpwstr);
1530 /******************************************************************************
1531 * service_start_process [INTERNAL]
1533 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1535 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1536 PROCESS_INFORMATION pi;
1538 LPWSTR path = NULL, str;
1539 DWORD type, size, ret, svc_type;
1543 size = sizeof(svc_type);
1544 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1547 if (svc_type == SERVICE_KERNEL_DRIVER)
1549 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1550 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1552 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1553 GetSystemDirectoryW( path, len );
1554 lstrcatW( path, winedeviceW );
1555 lstrcatW( path, hsvc->name );
1559 /* read the executable path from the registry */
1561 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1562 if (ret!=ERROR_SUCCESS)
1564 str = HeapAlloc(GetProcessHeap(),0,size);
1565 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1566 if (ret==ERROR_SUCCESS)
1568 size = ExpandEnvironmentStringsW(str,NULL,0);
1569 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1570 ExpandEnvironmentStringsW(str,path,size);
1572 HeapFree(GetProcessHeap(),0,str);
1577 /* wait for the process to start and set an event or terminate */
1578 handles[0] = service_get_event_handle( hsvc->name );
1579 ZeroMemory(&si, sizeof(STARTUPINFOW));
1580 si.cb = sizeof(STARTUPINFOW);
1581 if (!(svc_type & SERVICE_INTERACTIVE_PROCESS))
1583 static WCHAR desktopW[] = {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n','\\','D','e','f','a','u','l','t',0};
1584 si.lpDesktop = desktopW;
1587 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1590 if (ppid) *ppid = pi.dwProcessId;
1592 handles[1] = pi.hProcess;
1593 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1594 if(ret != WAIT_OBJECT_0)
1596 SetLastError(ERROR_IO_PENDING);
1600 CloseHandle( pi.hThread );
1601 CloseHandle( pi.hProcess );
1603 CloseHandle( handles[0] );
1604 HeapFree(GetProcessHeap(),0,path);
1608 static BOOL service_wait_for_startup(SC_HANDLE hService)
1611 SERVICE_STATUS status;
1614 TRACE("%p\n", hService);
1616 for (i=0; i<20; i++)
1618 status.dwCurrentState = 0;
1619 r = QueryServiceStatus(hService, &status);
1622 if (status.dwCurrentState == SERVICE_RUNNING)
1624 TRACE("Service started successfully\n");
1633 /******************************************************************************
1634 * StartServiceW [ADVAPI32.@]
1636 * See StartServiceA.
1638 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1639 LPCWSTR *lpServiceArgVectors)
1641 struct sc_service *hsvc;
1644 HANDLE handle = INVALID_HANDLE_VALUE;
1646 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1648 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1651 SetLastError(ERROR_INVALID_HANDLE);
1655 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1659 handle = service_open_pipe(hsvc->name);
1660 if (handle==INVALID_HANDLE_VALUE)
1662 /* start the service process */
1663 if (service_start_process(hsvc, NULL))
1664 handle = service_open_pipe(hsvc->name);
1667 if (handle != INVALID_HANDLE_VALUE)
1669 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1670 CloseHandle(handle);
1673 UnlockServiceDatabase( hLock );
1675 TRACE("returning %d\n", r);
1678 service_wait_for_startup(hService);
1683 /******************************************************************************
1684 * QueryServiceStatus [ADVAPI32.@]
1687 * hService [I] Handle to service to get information about
1688 * lpservicestatus [O] buffer to receive the status information for the service
1691 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1692 LPSERVICE_STATUS lpservicestatus)
1694 SERVICE_STATUS_PROCESS SvcStatusData;
1697 TRACE("%p %p\n", hService, lpservicestatus);
1699 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1700 sizeof(SERVICE_STATUS_PROCESS), NULL);
1701 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1706 /******************************************************************************
1707 * QueryServiceStatusEx [ADVAPI32.@]
1709 * Get information about a service.
1712 * hService [I] Handle to service to get information about
1713 * InfoLevel [I] Level of information to get
1714 * lpBuffer [O] Destination for requested information
1715 * cbBufSize [I] Size of lpBuffer in bytes
1716 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1722 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1723 LPBYTE lpBuffer, DWORD cbBufSize,
1724 LPDWORD pcbBytesNeeded)
1726 struct sc_service *hsvc;
1727 DWORD size, type, val;
1730 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1732 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1734 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1736 SetLastError( ERROR_INVALID_LEVEL);
1740 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1741 if (pSvcStatusData == NULL)
1743 SetLastError( ERROR_INVALID_PARAMETER);
1747 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1749 if( pcbBytesNeeded != NULL)
1750 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1752 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1756 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1759 SetLastError( ERROR_INVALID_HANDLE );
1763 pipe = service_open_pipe(hsvc->name);
1764 if (pipe != INVALID_HANDLE_VALUE)
1766 r = service_get_status(pipe, pSvcStatusData);
1772 TRACE("Failed to read service status\n");
1774 /* read the service type from the registry */
1776 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1777 if (r != ERROR_SUCCESS || type != REG_DWORD)
1780 pSvcStatusData->dwServiceType = val;
1781 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1782 pSvcStatusData->dwControlsAccepted = 0;
1783 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1784 pSvcStatusData->dwServiceSpecificExitCode = 0;
1785 pSvcStatusData->dwCheckPoint = 0;
1786 pSvcStatusData->dwWaitHint = 0;
1791 /******************************************************************************
1792 * QueryServiceConfigA [ADVAPI32.@]
1794 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1795 DWORD size, LPDWORD needed )
1800 QUERY_SERVICE_CONFIGW *configW;
1802 TRACE("%p %p %d %p\n", hService, config, size, needed);
1804 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1806 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1809 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1810 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1811 if (!ret) goto done;
1813 config->dwServiceType = configW->dwServiceType;
1814 config->dwStartType = configW->dwStartType;
1815 config->dwErrorControl = configW->dwErrorControl;
1816 config->lpBinaryPathName = NULL;
1817 config->lpLoadOrderGroup = NULL;
1818 config->dwTagId = configW->dwTagId;
1819 config->lpDependencies = NULL;
1820 config->lpServiceStartName = NULL;
1821 config->lpDisplayName = NULL;
1823 p = (LPSTR)(config + 1);
1824 n = size - sizeof(*config);
1827 #define MAP_STR(str) \
1831 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1832 if (!sz) goto done; \
1839 MAP_STR( lpBinaryPathName );
1840 MAP_STR( lpLoadOrderGroup );
1841 MAP_STR( lpDependencies );
1842 MAP_STR( lpServiceStartName );
1843 MAP_STR( lpDisplayName );
1846 *needed = p - (LPSTR)config;
1850 HeapFree( GetProcessHeap(), 0, buffer );
1854 /******************************************************************************
1855 * QueryServiceConfigW [ADVAPI32.@]
1858 QueryServiceConfigW( SC_HANDLE hService,
1859 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1860 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1862 WCHAR str_buffer[ MAX_PATH ];
1864 DWORD type, val, sz, total, n;
1867 struct sc_service *hsvc;
1869 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1870 cbBufSize, pcbBytesNeeded);
1872 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1875 SetLastError( ERROR_INVALID_HANDLE );
1880 /* TODO: Check which members are mandatory and what the registry types
1881 * should be. This should of course also be tested when a service is
1885 /* calculate the size required first */
1886 total = sizeof (QUERY_SERVICE_CONFIGW);
1888 sz = sizeof(str_buffer);
1889 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1890 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1892 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1893 if( 0 == sz ) return FALSE;
1895 total += sizeof(WCHAR) * sz;
1899 /* FIXME: set last error */
1904 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1905 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1908 total += sizeof(WCHAR);
1911 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1912 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1915 total += sizeof(WCHAR);
1918 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1919 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1922 total += sizeof(WCHAR);
1925 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1926 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1929 total += sizeof(WCHAR);
1931 *pcbBytesNeeded = total;
1933 /* if there's not enough memory, return an error */
1934 if( total > cbBufSize )
1936 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1940 ZeroMemory( lpServiceConfig, total );
1943 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1944 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1945 lpServiceConfig->dwServiceType = val;
1948 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1949 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1950 lpServiceConfig->dwStartType = val;
1953 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1954 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1955 lpServiceConfig->dwErrorControl = val;
1958 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
1959 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1960 lpServiceConfig->dwTagId = val;
1962 /* now do the strings */
1963 p = (LPBYTE) &lpServiceConfig[1];
1964 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1966 sz = sizeof(str_buffer);
1967 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1968 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1970 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1971 sz *= sizeof(WCHAR);
1972 if( 0 == sz || sz > n ) return FALSE;
1974 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1980 /* FIXME: set last error */
1985 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1986 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1987 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2000 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2001 lpServiceConfig->lpDependencies = (LPWSTR) p;
2002 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2015 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2016 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2017 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2030 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2031 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2032 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2044 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2045 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2046 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2047 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2048 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2053 /******************************************************************************
2054 * EnumServicesStatusA [ADVAPI32.@]
2057 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2058 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2059 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2060 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2062 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2063 dwServiceType, dwServiceState, lpServices, cbBufSize,
2064 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2065 SetLastError (ERROR_ACCESS_DENIED);
2069 /******************************************************************************
2070 * EnumServicesStatusW [ADVAPI32.@]
2073 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2074 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2075 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2076 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2078 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2079 dwServiceType, dwServiceState, lpServices, cbBufSize,
2080 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2081 SetLastError (ERROR_ACCESS_DENIED);
2085 /******************************************************************************
2086 * EnumServicesStatusExA [ADVAPI32.@]
2089 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2090 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2091 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2093 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2094 dwServiceType, dwServiceState, lpServices, cbBufSize,
2095 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2096 *lpServicesReturned = 0;
2097 SetLastError (ERROR_ACCESS_DENIED);
2101 /******************************************************************************
2102 * EnumServicesStatusExW [ADVAPI32.@]
2105 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2106 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2107 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2109 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2110 dwServiceType, dwServiceState, lpServices, cbBufSize,
2111 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2112 SetLastError (ERROR_ACCESS_DENIED);
2116 /******************************************************************************
2117 * GetServiceKeyNameA [ADVAPI32.@]
2119 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2120 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2122 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2126 /******************************************************************************
2127 * GetServiceKeyNameW [ADVAPI32.@]
2129 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2130 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2132 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2136 /******************************************************************************
2137 * QueryServiceLockStatusA [ADVAPI32.@]
2139 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2140 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2141 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2143 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2148 /******************************************************************************
2149 * QueryServiceLockStatusW [ADVAPI32.@]
2151 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2152 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2153 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2155 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2160 /******************************************************************************
2161 * GetServiceDisplayNameA [ADVAPI32.@]
2163 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2164 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2166 LPWSTR lpServiceNameW, lpDisplayNameW;
2170 TRACE("%p %s %p %p\n", hSCManager,
2171 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2173 lpServiceNameW = SERV_dup(lpServiceName);
2175 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2177 lpDisplayNameW = NULL;
2179 sizeW = *lpcchBuffer;
2180 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2182 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2186 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2187 *lpcchBuffer, NULL, NULL ))
2189 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2193 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2194 * (but if the function succeeded it means that is a good upper estimation of the size) */
2198 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2199 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2203 /******************************************************************************
2204 * GetServiceDisplayNameW [ADVAPI32.@]
2206 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2207 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2209 struct sc_manager *hscm;
2213 TRACE("%p %s %p %p\n", hSCManager,
2214 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2216 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2219 SetLastError(ERROR_INVALID_HANDLE);
2225 SetLastError(ERROR_INVALID_ADDRESS);
2229 size = *lpcchBuffer * sizeof(WCHAR);
2230 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2231 if (!ret && !lpDisplayName && size)
2232 ret = ERROR_MORE_DATA;
2236 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2238 if (ret == ERROR_MORE_DATA)
2240 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2241 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2243 else if (ret == ERROR_FILE_NOT_FOUND)
2247 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2249 UINT len = lstrlenW(lpServiceName);
2252 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2253 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2254 else if (lpDisplayName && *lpcchBuffer)
2256 /* No displayname, but the service exists and the buffer
2257 * is big enough. We should return the servicename.
2259 lstrcpyW(lpDisplayName, lpServiceName);
2268 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2275 /* Always return the correct needed size on success */
2276 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2281 /******************************************************************************
2282 * ChangeServiceConfigW [ADVAPI32.@]
2284 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2285 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2286 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2287 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2289 struct reg_value val[10];
2290 struct sc_service *hsvc;
2291 DWORD r = ERROR_SUCCESS;
2295 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2296 hService, dwServiceType, dwStartType, dwErrorControl,
2297 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2298 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2299 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2301 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2304 SetLastError( ERROR_INVALID_HANDLE );
2309 if( dwServiceType != SERVICE_NO_CHANGE )
2310 service_set_dword( &val[n++], szType, &dwServiceType );
2312 if( dwStartType != SERVICE_NO_CHANGE )
2313 service_set_dword( &val[n++], szStart, &dwStartType );
2315 if( dwErrorControl != SERVICE_NO_CHANGE )
2316 service_set_dword( &val[n++], szError, &dwErrorControl );
2318 if( lpBinaryPathName )
2319 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2321 if( lpLoadOrderGroup )
2322 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2324 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2325 * There is no such key as what szDependencies refers to */
2326 if( lpDependencies )
2327 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2330 FIXME("ignoring password\n");
2332 if( lpServiceStartName )
2333 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2335 r = service_write_values( hsvc->hkey, val, n );
2337 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2340 /******************************************************************************
2341 * ChangeServiceConfigA [ADVAPI32.@]
2343 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2344 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2345 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2346 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2348 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2349 LPWSTR wServiceStartName, wPassword, wDisplayName;
2352 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2353 hService, dwServiceType, dwStartType, dwErrorControl,
2354 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2355 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2356 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2358 wBinaryPathName = SERV_dup( lpBinaryPathName );
2359 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2360 wDependencies = SERV_dupmulti( lpDependencies );
2361 wServiceStartName = SERV_dup( lpServiceStartName );
2362 wPassword = SERV_dup( lpPassword );
2363 wDisplayName = SERV_dup( lpDisplayName );
2365 r = ChangeServiceConfigW( hService, dwServiceType,
2366 dwStartType, dwErrorControl, wBinaryPathName,
2367 wLoadOrderGroup, lpdwTagId, wDependencies,
2368 wServiceStartName, wPassword, wDisplayName);
2370 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2371 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2372 HeapFree( GetProcessHeap(), 0, wDependencies );
2373 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2374 HeapFree( GetProcessHeap(), 0, wPassword );
2375 HeapFree( GetProcessHeap(), 0, wDisplayName );
2380 /******************************************************************************
2381 * ChangeServiceConfig2A [ADVAPI32.@]
2383 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2388 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2390 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2392 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2393 SERVICE_DESCRIPTIONW sdw;
2395 sdw.lpDescription = SERV_dup( sd->lpDescription );
2397 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2399 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2401 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2403 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2404 SERVICE_FAILURE_ACTIONSW faw;
2406 faw.dwResetPeriod = fa->dwResetPeriod;
2407 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2408 faw.lpCommand = SERV_dup( fa->lpCommand );
2409 faw.cActions = fa->cActions;
2410 faw.lpsaActions = fa->lpsaActions;
2412 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2414 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2415 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2418 SetLastError( ERROR_INVALID_PARAMETER );
2423 /******************************************************************************
2424 * ChangeServiceConfig2W [ADVAPI32.@]
2426 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2430 struct sc_service *hsvc;
2432 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2435 SetLastError( ERROR_INVALID_HANDLE );
2440 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2442 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2443 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2444 if (sd->lpDescription)
2446 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2447 if (sd->lpDescription[0] == 0)
2448 RegDeleteValueW(hKey,szDescription);
2450 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2451 (LPVOID)sd->lpDescription,
2452 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2456 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2460 /******************************************************************************
2461 * QueryServiceObjectSecurity [ADVAPI32.@]
2463 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2464 SECURITY_INFORMATION dwSecurityInformation,
2465 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2466 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2468 SECURITY_DESCRIPTOR descriptor;
2473 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2474 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2476 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2477 FIXME("information %d not supported\n", dwSecurityInformation);
2479 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2481 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2482 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2485 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2486 *pcbBytesNeeded = size;
2490 /******************************************************************************
2491 * SetServiceObjectSecurity [ADVAPI32.@]
2493 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2494 SECURITY_INFORMATION dwSecurityInformation,
2495 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2497 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2501 /******************************************************************************
2502 * SetServiceBits [ADVAPI32.@]
2504 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2505 DWORD dwServiceBits,
2507 BOOL bUpdateImmediately)
2509 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2510 bSetBitsOn, bUpdateImmediately);
2514 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2515 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2517 LPHANDLER_FUNCTION func = context;
2520 return ERROR_SUCCESS;
2523 /******************************************************************************
2524 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2526 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2528 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2531 /******************************************************************************
2532 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2534 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2536 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2539 /******************************************************************************
2540 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2542 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2545 SERVICE_STATUS_HANDLE ret;
2547 nameW = SERV_dup(name);
2548 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2549 HeapFree( GetProcessHeap(), 0, nameW );
2553 /******************************************************************************
2554 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2556 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2557 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2559 SERVICE_STATUS_HANDLE handle = 0;
2562 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2564 EnterCriticalSection( &service_cs );
2565 for (i = 0; i < nb_services; i++)
2567 if(!strcmpW(lpServiceName, services[i]->name))
2569 services[i]->handler = lpHandlerProc;
2570 services[i]->context = lpContext;
2571 handle = ULongToHandle( i + 1 );
2575 LeaveCriticalSection( &service_cs );
2580 /******************************************************************************
2581 * EnumDependentServicesA [ADVAPI32.@]
2583 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2584 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2585 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2587 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2588 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2590 *lpServicesReturned = 0;
2594 /******************************************************************************
2595 * EnumDependentServicesW [ADVAPI32.@]
2597 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2598 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2599 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2601 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2602 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2604 *lpServicesReturned = 0;