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->status.dwCurrentState = SERVICE_START_PENDING;
459 service->thread = CreateThread( NULL, 0, service_thread,
461 SetEvent( service_event ); /* notify the main loop */
464 HeapFree(GetProcessHeap(), 0, args);
465 WriteFile( pipe, &result, sizeof result, &read, NULL );
470 /******************************************************************************
471 * service_send_start_message
473 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
475 DWORD i, len, count, result;
476 service_start_info *ssi;
480 TRACE("%p %p %d\n", pipe, argv, argc);
482 /* calculate how much space do we need to send the startup info */
484 for (i=0; i<argc; i++)
485 len += strlenW(argv[i])+1;
487 ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, str[len]));
488 ssi->cmd = WINESERV_STARTINFO;
491 /* copy service args into a single buffer*/
493 for (i=0; i<argc; i++)
500 r = WriteFile(pipe, ssi, FIELD_OFFSET(service_start_info, str[len]), &count, NULL);
503 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
506 SetLastError(result);
511 HeapFree(GetProcessHeap(),0,ssi);
516 /******************************************************************************
517 * service_handle_get_status
519 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
523 return WriteFile(pipe, &service->status,
524 sizeof service->status, &count, NULL);
527 /******************************************************************************
530 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
532 DWORD cmd[2], count = 0;
535 cmd[0] = WINESERV_GETSTATUS;
537 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
538 if (!r || count != sizeof cmd)
540 ERR("service protocol error - failed to write pipe!\n");
543 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
544 if (!r || count != sizeof *status)
545 ERR("service protocol error - failed to read pipe "
546 "r = %d count = %d!\n", r, count);
550 /******************************************************************************
551 * service_send_control
553 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
555 DWORD cmd[2], count = 0;
558 cmd[0] = WINESERV_SENDCONTROL;
560 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
561 if (!r || count != sizeof cmd)
563 ERR("service protocol error - failed to write pipe!\n");
566 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
567 if (!r || count != sizeof *result)
568 ERR("service protocol error - failed to read pipe "
569 "r = %d count = %d!\n", r, count);
573 /******************************************************************************
574 * service_accepts_control
576 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
578 DWORD a = service->status.dwControlsAccepted;
582 case SERVICE_CONTROL_INTERROGATE:
584 case SERVICE_CONTROL_STOP:
585 if (a&SERVICE_ACCEPT_STOP)
588 case SERVICE_CONTROL_SHUTDOWN:
589 if (a&SERVICE_ACCEPT_SHUTDOWN)
592 case SERVICE_CONTROL_PAUSE:
593 case SERVICE_CONTROL_CONTINUE:
594 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
597 case SERVICE_CONTROL_PARAMCHANGE:
598 if (a&SERVICE_ACCEPT_PARAMCHANGE)
601 case SERVICE_CONTROL_NETBINDADD:
602 case SERVICE_CONTROL_NETBINDREMOVE:
603 case SERVICE_CONTROL_NETBINDENABLE:
604 case SERVICE_CONTROL_NETBINDDISABLE:
605 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
607 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
608 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
611 case SERVICE_CONTROL_POWEREVENT:
612 if (a&SERVICE_ACCEPT_POWEREVENT)
615 case SERVICE_CONTROL_SESSIONCHANGE:
616 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
623 /******************************************************************************
624 * service_handle_control
626 static BOOL service_handle_control(HANDLE pipe, service_data *service,
629 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
631 TRACE("received control %d\n", dwControl);
633 if (service_accepts_control(service, dwControl))
635 if (service->handler)
636 ret = service->handler(dwControl, 0, NULL, service->context);
638 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
641 /******************************************************************************
642 * service_control_dispatcher
644 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
646 service_data *service = arg;
650 TRACE("%p %s\n", service, debugstr_w(service->name));
652 /* create a pipe to talk to the rest of the world with */
653 name = service_get_pipe_name(service->name);
654 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
655 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
657 if (pipe==INVALID_HANDLE_VALUE)
658 ERR("failed to create pipe for %s, error = %d\n",
659 debugstr_w(service->name), GetLastError());
661 HeapFree(GetProcessHeap(), 0, name);
663 /* let the process who started us know we've tried to create a pipe */
664 event = service_get_event_handle(service->name);
668 if (pipe==INVALID_HANDLE_VALUE) return 0;
670 /* dispatcher loop */
674 DWORD count, req[2] = {0,0};
676 r = ConnectNamedPipe(pipe, NULL);
677 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
679 ERR("pipe connect failed\n");
683 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
684 if (!r || count!=sizeof req)
686 ERR("pipe read failed\n");
690 /* handle the request */
693 case WINESERV_STARTINFO:
694 service_handle_start(pipe, service, req[1]);
696 case WINESERV_GETSTATUS:
697 service_handle_get_status(pipe, service);
699 case WINESERV_SENDCONTROL:
700 service_handle_control(pipe, service, req[1]);
703 ERR("received invalid command %d length %d\n", req[0], req[1]);
706 FlushFileBuffers(pipe);
707 DisconnectNamedPipe(pipe);
714 /******************************************************************************
715 * service_run_threads
717 static BOOL service_run_threads(void)
720 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
721 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
723 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
725 wait_handles[0] = __wine_make_process_system();
726 wait_handles[1] = service_event;
728 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
729 nb_services, GetCurrentProcessId());
731 EnterCriticalSection( &service_cs );
732 for (i = 0; i < nb_services; i++)
734 services[i]->status.dwProcessId = GetCurrentProcessId();
735 CloseHandle( CreateThread( NULL, 0, service_control_dispatcher, services[i], 0, NULL ));
737 LeaveCriticalSection( &service_cs );
739 /* wait for all the threads to pack up and exit */
742 EnterCriticalSection( &service_cs );
743 for (i = 0, n = 2; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
745 if (!services[i]->thread) continue;
746 wait_services[n] = i;
747 wait_handles[n++] = services[i]->thread;
749 LeaveCriticalSection( &service_cs );
751 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
752 if (!ret) /* system process event */
754 TRACE( "last user process exited, shutting down\n" );
755 /* FIXME: we should maybe send a shutdown control to running services */
760 continue; /* rebuild the list */
764 services[wait_services[ret]]->thread = 0;
765 CloseHandle( wait_handles[ret] );
766 if (n == 3) return TRUE; /* it was the last running thread */
772 /******************************************************************************
773 * StartServiceCtrlDispatcherA [ADVAPI32.@]
775 * See StartServiceCtrlDispatcherW.
777 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
783 TRACE("%p\n", servent);
787 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
790 while (servent[nb_services].lpServiceName) nb_services++;
791 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
793 for (i = 0; i < nb_services; i++)
795 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
796 DWORD sz = FIELD_OFFSET( service_data, name[len] );
797 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
798 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
799 info->proc.a = servent[i].lpServiceProc;
800 info->unicode = FALSE;
804 service_run_threads();
809 /******************************************************************************
810 * StartServiceCtrlDispatcherW [ADVAPI32.@]
812 * Connects a process containing one or more services to the service control
816 * servent [I] A list of the service names and service procedures
822 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
828 TRACE("%p\n", servent);
832 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
835 while (servent[nb_services].lpServiceName) nb_services++;
836 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
838 for (i = 0; i < nb_services; i++)
840 DWORD len = strlenW(servent[i].lpServiceName) + 1;
841 DWORD sz = FIELD_OFFSET( service_data, name[len] );
842 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
843 strcpyW(info->name, servent[i].lpServiceName);
844 info->proc.w = servent[i].lpServiceProc;
845 info->unicode = TRUE;
849 service_run_threads();
854 /******************************************************************************
855 * LockServiceDatabase [ADVAPI32.@]
857 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
861 TRACE("%p\n",hSCManager);
863 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
864 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
868 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
871 TRACE("returning %p\n", ret);
876 /******************************************************************************
877 * UnlockServiceDatabase [ADVAPI32.@]
879 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
881 TRACE("%p\n",ScLock);
883 return CloseHandle( ScLock );
886 /******************************************************************************
887 * SetServiceStatus [ADVAPI32.@]
894 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
896 ULONG_PTR index = HandleToULong(hService) - 1;
899 TRACE("%p %x %x %x %x %x %x %x\n", hService,
900 lpStatus->dwServiceType, lpStatus->dwCurrentState,
901 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
902 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
903 lpStatus->dwWaitHint);
905 EnterCriticalSection( &service_cs );
906 if (index < nb_services)
908 memcpy( &services[index]->status, lpStatus, sizeof(SERVICE_STATUS) );
909 TRACE("Set service status to %d\n",services[index]->status.dwCurrentState);
912 LeaveCriticalSection( &service_cs );
918 /******************************************************************************
919 * OpenSCManagerA [ADVAPI32.@]
921 * Establish a connection to the service control manager and open its database.
924 * lpMachineName [I] Pointer to machine name string
925 * lpDatabaseName [I] Pointer to database name string
926 * dwDesiredAccess [I] Type of access
929 * Success: A Handle to the service control manager database
932 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
933 DWORD dwDesiredAccess )
935 LPWSTR lpMachineNameW, lpDatabaseNameW;
938 lpMachineNameW = SERV_dup(lpMachineName);
939 lpDatabaseNameW = SERV_dup(lpDatabaseName);
940 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
941 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
942 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
946 /******************************************************************************
947 * OpenSCManagerW [ADVAPI32.@]
949 * See OpenSCManagerA.
951 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
952 DWORD dwDesiredAccess )
954 struct sc_manager *manager;
957 DWORD new_mask = dwDesiredAccess;
959 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
960 debugstr_w(lpDatabaseName), dwDesiredAccess);
962 if( lpDatabaseName && lpDatabaseName[0] )
964 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
966 /* noop, all right */
968 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
970 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
975 SetLastError( ERROR_INVALID_NAME );
980 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
981 sc_handle_destroy_manager );
985 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
986 if (r!=ERROR_SUCCESS)
989 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
991 if (r!=ERROR_SUCCESS)
994 RtlMapGenericMask(&new_mask, &scm_generic);
995 manager->dwAccess = new_mask;
996 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
998 return (SC_HANDLE) &manager->hdr;
1001 sc_handle_free( &manager->hdr );
1006 /******************************************************************************
1007 * ControlService [ADVAPI32.@]
1009 * Send a control code to a service.
1012 * hService [I] Handle of the service control manager database
1013 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1014 * lpServiceStatus [O] Destination for the status of the service, if available
1021 * Unlike M$' implementation, control requests are not serialized and may be
1022 * processed asynchronously.
1024 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1025 LPSERVICE_STATUS lpServiceStatus )
1027 struct sc_service *hsvc;
1031 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1033 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1036 SetLastError( ERROR_INVALID_HANDLE );
1040 if (lpServiceStatus)
1042 ret = QueryServiceStatus(hService, lpServiceStatus);
1045 ERR("failed to query service status\n");
1046 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1050 switch (lpServiceStatus->dwCurrentState)
1052 case SERVICE_STOPPED:
1053 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1055 case SERVICE_START_PENDING:
1056 if (dwControl==SERVICE_CONTROL_STOP)
1059 case SERVICE_STOP_PENDING:
1060 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1065 handle = service_open_pipe(hsvc->name);
1066 if (handle!=INVALID_HANDLE_VALUE)
1068 DWORD result = ERROR_SUCCESS;
1069 ret = service_send_control(handle, dwControl, &result);
1070 CloseHandle(handle);
1071 if (result!=ERROR_SUCCESS)
1073 SetLastError(result);
1081 /******************************************************************************
1082 * CloseServiceHandle [ADVAPI32.@]
1084 * Close a handle to a service or the service control manager database.
1087 * hSCObject [I] Handle to service or service control manager database
1094 CloseServiceHandle( SC_HANDLE hSCObject )
1096 TRACE("%p\n", hSCObject);
1098 sc_handle_free( (struct sc_handle*) hSCObject );
1104 /******************************************************************************
1105 * OpenServiceA [ADVAPI32.@]
1107 * Open a handle to a service.
1110 * hSCManager [I] Handle of the service control manager database
1111 * lpServiceName [I] Name of the service to open
1112 * dwDesiredAccess [I] Access required to the service
1115 * Success: Handle to the service
1118 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1119 DWORD dwDesiredAccess )
1121 LPWSTR lpServiceNameW;
1124 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1126 lpServiceNameW = SERV_dup(lpServiceName);
1127 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1128 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1133 /******************************************************************************
1134 * OpenServiceW [ADVAPI32.@]
1138 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1139 DWORD dwDesiredAccess)
1141 struct sc_manager *hscm;
1142 struct sc_service *hsvc;
1146 DWORD new_mask = dwDesiredAccess;
1148 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1150 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1153 SetLastError( ERROR_INVALID_HANDLE );
1159 SetLastError(ERROR_INVALID_ADDRESS);
1163 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1164 if (r!=ERROR_SUCCESS)
1166 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1170 len = strlenW(lpServiceName)+1;
1171 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1172 sizeof (struct sc_service) + len*sizeof(WCHAR),
1173 sc_handle_destroy_service );
1179 strcpyW( hsvc->name, lpServiceName );
1182 RtlMapGenericMask(&new_mask, &svc_generic);
1183 hsvc->dwAccess = new_mask;
1185 /* add reference to SCM handle */
1186 hscm->hdr.ref_count++;
1189 TRACE("returning %p\n",hsvc);
1191 return (SC_HANDLE) &hsvc->hdr;
1194 /******************************************************************************
1195 * CreateServiceW [ADVAPI32.@]
1198 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1199 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1200 DWORD dwServiceType, DWORD dwStartType,
1201 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1202 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1203 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1204 LPCWSTR lpPassword )
1206 struct sc_manager *hscm;
1207 struct sc_service *hsvc = NULL;
1211 struct reg_value val[10];
1213 DWORD new_mask = dwDesiredAccess;
1215 WCHAR buffer[MAX_PATH];
1216 BOOL displayname_exists = FALSE;
1218 TRACE("%p %s %s\n", hSCManager,
1219 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1221 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1224 SetLastError( ERROR_INVALID_HANDLE );
1228 if (!lpServiceName || !lpBinaryPathName)
1230 SetLastError(ERROR_INVALID_ADDRESS);
1234 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1236 SetLastError(ERROR_ACCESS_DENIED);
1240 if (!lpServiceName[0])
1242 SetLastError(ERROR_INVALID_NAME);
1246 if (!lpBinaryPathName[0])
1248 SetLastError(ERROR_INVALID_PARAMETER);
1252 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1253 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1254 * runs under the LocalSystem account)
1256 switch (dwServiceType)
1258 case SERVICE_KERNEL_DRIVER:
1259 case SERVICE_FILE_SYSTEM_DRIVER:
1260 case SERVICE_WIN32_OWN_PROCESS:
1261 case SERVICE_WIN32_SHARE_PROCESS:
1264 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1265 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1266 /* FIXME : Do we need a more thorough check? */
1267 if (lpServiceStartName)
1269 SetLastError(ERROR_INVALID_PARAMETER);
1274 SetLastError(ERROR_INVALID_PARAMETER);
1278 if (!lpServiceStartName && (dwServiceType & SERVICE_WIN32))
1279 lpServiceStartName = szLocalSystem;
1281 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1282 if (dwStartType > SERVICE_DISABLED)
1284 SetLastError(ERROR_INVALID_PARAMETER);
1288 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1289 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1290 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1292 SetLastError(ERROR_INVALID_PARAMETER);
1296 /* Loop through the registry to check if the service already exists and to
1297 * check if we can use the given displayname.
1298 * FIXME: Should we use EnumServicesStatusEx?
1300 len = sizeof(buffer);
1301 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1305 /* The service already exists, so bail out */
1306 if(!lstrcmpiW(lpServiceName, buffer))
1308 SetLastError(ERROR_SERVICE_EXISTS);
1312 /* The given displayname matches the found servicename. We don't bail out
1313 * as servicename is checked before a duplicate displayname
1315 if(!lstrcmpiW(lpDisplayName, buffer))
1316 displayname_exists = TRUE;
1318 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1320 WCHAR name[MAX_PATH];
1321 DWORD size = sizeof(name);
1323 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1325 /* The given displayname matches the found displayname */
1326 if (!lstrcmpiW(lpDisplayName, name))
1327 displayname_exists = TRUE;
1329 RegCloseKey(service_key);
1332 len = sizeof(buffer);
1335 if (lpDisplayName && displayname_exists)
1337 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1341 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1342 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1343 if (r!=ERROR_SUCCESS)
1345 /* FIXME: Should we set an error? */
1350 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1352 service_set_dword( &val[n++], szType, &dwServiceType );
1353 service_set_dword( &val[n++], szStart, &dwStartType );
1354 service_set_dword( &val[n++], szError, &dwErrorControl );
1356 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1358 if( lpLoadOrderGroup )
1359 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1361 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1362 * There is no such key as what szDependencies refers to */
1363 if( lpDependencies )
1364 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1367 FIXME("Don't know how to add a Password for a service.\n");
1369 if( lpServiceStartName )
1370 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1372 r = service_write_values( hKey, val, n );
1373 if( r != ERROR_SUCCESS )
1376 len = strlenW(lpServiceName)+1;
1377 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1378 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1381 lstrcpyW( hsvc->name, lpServiceName );
1384 RtlMapGenericMask(&new_mask, &svc_generic);
1385 hsvc->dwAccess = new_mask;
1388 hscm->hdr.ref_count++;
1390 return (SC_HANDLE) &hsvc->hdr;
1393 RegCloseKey( hKey );
1398 /******************************************************************************
1399 * CreateServiceA [ADVAPI32.@]
1402 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1403 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1404 DWORD dwServiceType, DWORD dwStartType,
1405 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1406 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1407 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1410 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1411 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1414 TRACE("%p %s %s\n", hSCManager,
1415 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1417 lpServiceNameW = SERV_dup( lpServiceName );
1418 lpDisplayNameW = SERV_dup( lpDisplayName );
1419 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1420 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1421 lpDependenciesW = SERV_dupmulti( lpDependencies );
1422 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1423 lpPasswordW = SERV_dup( lpPassword );
1425 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1426 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1427 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1428 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1430 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1431 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1432 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1433 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1434 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1435 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1436 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1442 /******************************************************************************
1443 * DeleteService [ADVAPI32.@]
1445 * Delete a service from the service control manager database.
1448 * hService [I] Handle of the service to delete
1454 BOOL WINAPI DeleteService( SC_HANDLE hService )
1456 struct sc_service *hsvc;
1458 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1461 SetLastError( ERROR_INVALID_HANDLE );
1465 if (!(hsvc->dwAccess & DELETE))
1467 SetLastError(ERROR_ACCESS_DENIED);
1471 /* Close the key to the service */
1472 RegCloseKey(hsvc->hkey);
1474 /* Delete the service under the Service Control Manager key */
1475 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1483 /******************************************************************************
1484 * StartServiceA [ADVAPI32.@]
1489 * hService [I] Handle of service
1490 * dwNumServiceArgs [I] Number of arguments
1491 * lpServiceArgVectors [I] Address of array of argument strings
1494 * - NT implements this function using an obscure RPC call.
1495 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1496 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1497 * - This will only work for shared address space. How should the service
1498 * args be transferred when address spaces are separated?
1499 * - Can only start one service at a time.
1500 * - Has no concept of privilege.
1506 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1507 LPCSTR *lpServiceArgVectors )
1509 LPWSTR *lpwstr=NULL;
1513 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1515 if (dwNumServiceArgs)
1516 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1517 dwNumServiceArgs*sizeof(LPWSTR) );
1519 for(i=0; i<dwNumServiceArgs; i++)
1520 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1522 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1524 if (dwNumServiceArgs)
1526 for(i=0; i<dwNumServiceArgs; i++)
1527 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1528 HeapFree(GetProcessHeap(), 0, lpwstr);
1534 /******************************************************************************
1535 * service_start_process [INTERNAL]
1537 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1539 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1540 PROCESS_INFORMATION pi;
1542 LPWSTR path = NULL, str;
1543 DWORD type, size, ret, svc_type;
1547 size = sizeof(svc_type);
1548 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1551 if (svc_type == SERVICE_KERNEL_DRIVER)
1553 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1554 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1556 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1557 GetSystemDirectoryW( path, len );
1558 lstrcatW( path, winedeviceW );
1559 lstrcatW( path, hsvc->name );
1563 /* read the executable path from the registry */
1565 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1566 if (ret!=ERROR_SUCCESS)
1568 str = HeapAlloc(GetProcessHeap(),0,size);
1569 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1570 if (ret==ERROR_SUCCESS)
1572 size = ExpandEnvironmentStringsW(str,NULL,0);
1573 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1574 ExpandEnvironmentStringsW(str,path,size);
1576 HeapFree(GetProcessHeap(),0,str);
1581 /* wait for the process to start and set an event or terminate */
1582 handles[0] = service_get_event_handle( hsvc->name );
1583 ZeroMemory(&si, sizeof(STARTUPINFOW));
1584 si.cb = sizeof(STARTUPINFOW);
1585 if (!(svc_type & SERVICE_INTERACTIVE_PROCESS))
1587 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};
1588 si.lpDesktop = desktopW;
1591 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1594 if (ppid) *ppid = pi.dwProcessId;
1596 handles[1] = pi.hProcess;
1597 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1598 if(ret != WAIT_OBJECT_0)
1600 SetLastError(ERROR_IO_PENDING);
1604 CloseHandle( pi.hThread );
1605 CloseHandle( pi.hProcess );
1607 CloseHandle( handles[0] );
1608 HeapFree(GetProcessHeap(),0,path);
1612 static BOOL service_wait_for_startup(SC_HANDLE hService)
1615 SERVICE_STATUS status;
1618 TRACE("%p\n", hService);
1620 for (i=0; i<20; i++)
1622 status.dwCurrentState = 0;
1623 r = QueryServiceStatus(hService, &status);
1626 if (status.dwCurrentState == SERVICE_RUNNING)
1628 TRACE("Service started successfully\n");
1632 if (status.dwCurrentState != SERVICE_START_PENDING) break;
1638 /******************************************************************************
1639 * StartServiceW [ADVAPI32.@]
1641 * See StartServiceA.
1643 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1644 LPCWSTR *lpServiceArgVectors)
1646 struct sc_service *hsvc;
1649 HANDLE handle = INVALID_HANDLE_VALUE;
1651 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1653 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1656 SetLastError(ERROR_INVALID_HANDLE);
1660 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1664 handle = service_open_pipe(hsvc->name);
1665 if (handle==INVALID_HANDLE_VALUE)
1667 /* start the service process */
1668 if (service_start_process(hsvc, NULL))
1669 handle = service_open_pipe(hsvc->name);
1672 if (handle != INVALID_HANDLE_VALUE)
1674 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1675 CloseHandle(handle);
1678 UnlockServiceDatabase( hLock );
1680 TRACE("returning %d\n", r);
1683 service_wait_for_startup(hService);
1688 /******************************************************************************
1689 * QueryServiceStatus [ADVAPI32.@]
1692 * hService [I] Handle to service to get information about
1693 * lpservicestatus [O] buffer to receive the status information for the service
1696 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1697 LPSERVICE_STATUS lpservicestatus)
1699 SERVICE_STATUS_PROCESS SvcStatusData;
1702 TRACE("%p %p\n", hService, lpservicestatus);
1704 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1705 sizeof(SERVICE_STATUS_PROCESS), NULL);
1706 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1711 /******************************************************************************
1712 * QueryServiceStatusEx [ADVAPI32.@]
1714 * Get information about a service.
1717 * hService [I] Handle to service to get information about
1718 * InfoLevel [I] Level of information to get
1719 * lpBuffer [O] Destination for requested information
1720 * cbBufSize [I] Size of lpBuffer in bytes
1721 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1727 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1728 LPBYTE lpBuffer, DWORD cbBufSize,
1729 LPDWORD pcbBytesNeeded)
1731 struct sc_service *hsvc;
1732 DWORD size, type, val;
1735 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1737 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1739 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1741 SetLastError( ERROR_INVALID_LEVEL);
1745 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1746 if (pSvcStatusData == NULL)
1748 SetLastError( ERROR_INVALID_PARAMETER);
1752 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1754 if( pcbBytesNeeded != NULL)
1755 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1757 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1761 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1764 SetLastError( ERROR_INVALID_HANDLE );
1768 pipe = service_open_pipe(hsvc->name);
1769 if (pipe != INVALID_HANDLE_VALUE)
1771 r = service_get_status(pipe, pSvcStatusData);
1777 TRACE("Failed to read service status\n");
1779 /* read the service type from the registry */
1781 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1782 if (r != ERROR_SUCCESS || type != REG_DWORD)
1785 pSvcStatusData->dwServiceType = val;
1786 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1787 pSvcStatusData->dwControlsAccepted = 0;
1788 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1789 pSvcStatusData->dwServiceSpecificExitCode = 0;
1790 pSvcStatusData->dwCheckPoint = 0;
1791 pSvcStatusData->dwWaitHint = 0;
1796 /******************************************************************************
1797 * QueryServiceConfigA [ADVAPI32.@]
1799 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1800 DWORD size, LPDWORD needed )
1805 QUERY_SERVICE_CONFIGW *configW;
1807 TRACE("%p %p %d %p\n", hService, config, size, needed);
1809 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1811 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1814 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1815 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1816 if (!ret) goto done;
1818 config->dwServiceType = configW->dwServiceType;
1819 config->dwStartType = configW->dwStartType;
1820 config->dwErrorControl = configW->dwErrorControl;
1821 config->lpBinaryPathName = NULL;
1822 config->lpLoadOrderGroup = NULL;
1823 config->dwTagId = configW->dwTagId;
1824 config->lpDependencies = NULL;
1825 config->lpServiceStartName = NULL;
1826 config->lpDisplayName = NULL;
1828 p = (LPSTR)(config + 1);
1829 n = size - sizeof(*config);
1832 #define MAP_STR(str) \
1836 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1837 if (!sz) goto done; \
1844 MAP_STR( lpBinaryPathName );
1845 MAP_STR( lpLoadOrderGroup );
1846 MAP_STR( lpDependencies );
1847 MAP_STR( lpServiceStartName );
1848 MAP_STR( lpDisplayName );
1851 *needed = p - (LPSTR)config;
1855 HeapFree( GetProcessHeap(), 0, buffer );
1859 /******************************************************************************
1860 * QueryServiceConfigW [ADVAPI32.@]
1863 QueryServiceConfigW( SC_HANDLE hService,
1864 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1865 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1867 WCHAR str_buffer[ MAX_PATH ];
1869 DWORD type, val, sz, total, n;
1872 struct sc_service *hsvc;
1874 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1875 cbBufSize, pcbBytesNeeded);
1877 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1880 SetLastError( ERROR_INVALID_HANDLE );
1885 /* TODO: Check which members are mandatory and what the registry types
1886 * should be. This should of course also be tested when a service is
1890 /* calculate the size required first */
1891 total = sizeof (QUERY_SERVICE_CONFIGW);
1893 sz = sizeof(str_buffer);
1894 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1895 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1897 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1898 if( 0 == sz ) return FALSE;
1900 total += sizeof(WCHAR) * sz;
1904 /* FIXME: set last error */
1909 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1910 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1913 total += sizeof(WCHAR);
1916 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1917 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1920 total += sizeof(WCHAR);
1923 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1924 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1927 total += sizeof(WCHAR);
1930 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1931 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1934 total += sizeof(WCHAR);
1936 *pcbBytesNeeded = total;
1938 /* if there's not enough memory, return an error */
1939 if( total > cbBufSize )
1941 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1945 ZeroMemory( lpServiceConfig, total );
1948 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1949 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1950 lpServiceConfig->dwServiceType = val;
1953 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1954 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1955 lpServiceConfig->dwStartType = val;
1958 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1959 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1960 lpServiceConfig->dwErrorControl = val;
1963 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
1964 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1965 lpServiceConfig->dwTagId = val;
1967 /* now do the strings */
1968 p = (LPBYTE) &lpServiceConfig[1];
1969 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1971 sz = sizeof(str_buffer);
1972 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1973 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1975 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1976 sz *= sizeof(WCHAR);
1977 if( 0 == sz || sz > n ) return FALSE;
1979 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1985 /* FIXME: set last error */
1990 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1991 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1992 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2005 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2006 lpServiceConfig->lpDependencies = (LPWSTR) p;
2007 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2020 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2021 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2022 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2035 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2036 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2037 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2049 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2050 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2051 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2052 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2053 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2058 /******************************************************************************
2059 * EnumServicesStatusA [ADVAPI32.@]
2062 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2063 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2064 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2065 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2067 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2068 dwServiceType, dwServiceState, lpServices, cbBufSize,
2069 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2070 SetLastError (ERROR_ACCESS_DENIED);
2074 /******************************************************************************
2075 * EnumServicesStatusW [ADVAPI32.@]
2078 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2079 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2080 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2081 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2083 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2084 dwServiceType, dwServiceState, lpServices, cbBufSize,
2085 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2086 SetLastError (ERROR_ACCESS_DENIED);
2090 /******************************************************************************
2091 * EnumServicesStatusExA [ADVAPI32.@]
2094 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2095 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2096 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2098 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2099 dwServiceType, dwServiceState, lpServices, cbBufSize,
2100 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2101 *lpServicesReturned = 0;
2102 SetLastError (ERROR_ACCESS_DENIED);
2106 /******************************************************************************
2107 * EnumServicesStatusExW [ADVAPI32.@]
2110 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2111 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2112 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2114 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2115 dwServiceType, dwServiceState, lpServices, cbBufSize,
2116 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2117 SetLastError (ERROR_ACCESS_DENIED);
2121 /******************************************************************************
2122 * GetServiceKeyNameA [ADVAPI32.@]
2124 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2125 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2127 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2131 /******************************************************************************
2132 * GetServiceKeyNameW [ADVAPI32.@]
2134 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2135 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2137 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2141 /******************************************************************************
2142 * QueryServiceLockStatusA [ADVAPI32.@]
2144 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2145 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2146 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2148 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2153 /******************************************************************************
2154 * QueryServiceLockStatusW [ADVAPI32.@]
2156 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2157 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2158 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2160 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2165 /******************************************************************************
2166 * GetServiceDisplayNameA [ADVAPI32.@]
2168 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2169 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2171 LPWSTR lpServiceNameW, lpDisplayNameW;
2175 TRACE("%p %s %p %p\n", hSCManager,
2176 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2178 lpServiceNameW = SERV_dup(lpServiceName);
2180 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2182 lpDisplayNameW = NULL;
2184 sizeW = *lpcchBuffer;
2185 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2187 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2191 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2192 *lpcchBuffer, NULL, NULL ))
2194 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2198 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2199 * (but if the function succeeded it means that is a good upper estimation of the size) */
2203 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2204 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2208 /******************************************************************************
2209 * GetServiceDisplayNameW [ADVAPI32.@]
2211 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2212 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2214 struct sc_manager *hscm;
2218 TRACE("%p %s %p %p\n", hSCManager,
2219 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2221 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2224 SetLastError(ERROR_INVALID_HANDLE);
2230 SetLastError(ERROR_INVALID_ADDRESS);
2234 size = *lpcchBuffer * sizeof(WCHAR);
2235 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2236 if (!ret && !lpDisplayName && size)
2237 ret = ERROR_MORE_DATA;
2241 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2243 if (ret == ERROR_MORE_DATA)
2245 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2246 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2248 else if (ret == ERROR_FILE_NOT_FOUND)
2252 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2254 UINT len = lstrlenW(lpServiceName);
2257 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2258 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2259 else if (lpDisplayName && *lpcchBuffer)
2261 /* No displayname, but the service exists and the buffer
2262 * is big enough. We should return the servicename.
2264 lstrcpyW(lpDisplayName, lpServiceName);
2273 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2280 /* Always return the correct needed size on success */
2281 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2286 /******************************************************************************
2287 * ChangeServiceConfigW [ADVAPI32.@]
2289 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2290 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2291 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2292 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2294 struct reg_value val[10];
2295 struct sc_service *hsvc;
2296 DWORD r = ERROR_SUCCESS;
2300 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2301 hService, dwServiceType, dwStartType, dwErrorControl,
2302 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2303 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2304 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2306 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2309 SetLastError( ERROR_INVALID_HANDLE );
2314 if( dwServiceType != SERVICE_NO_CHANGE )
2315 service_set_dword( &val[n++], szType, &dwServiceType );
2317 if( dwStartType != SERVICE_NO_CHANGE )
2318 service_set_dword( &val[n++], szStart, &dwStartType );
2320 if( dwErrorControl != SERVICE_NO_CHANGE )
2321 service_set_dword( &val[n++], szError, &dwErrorControl );
2323 if( lpBinaryPathName )
2324 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2326 if( lpLoadOrderGroup )
2327 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2329 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2330 * There is no such key as what szDependencies refers to */
2331 if( lpDependencies )
2332 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2335 FIXME("ignoring password\n");
2337 if( lpServiceStartName )
2338 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2340 r = service_write_values( hsvc->hkey, val, n );
2342 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2345 /******************************************************************************
2346 * ChangeServiceConfigA [ADVAPI32.@]
2348 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2349 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2350 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2351 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2353 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2354 LPWSTR wServiceStartName, wPassword, wDisplayName;
2357 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2358 hService, dwServiceType, dwStartType, dwErrorControl,
2359 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2360 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2361 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2363 wBinaryPathName = SERV_dup( lpBinaryPathName );
2364 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2365 wDependencies = SERV_dupmulti( lpDependencies );
2366 wServiceStartName = SERV_dup( lpServiceStartName );
2367 wPassword = SERV_dup( lpPassword );
2368 wDisplayName = SERV_dup( lpDisplayName );
2370 r = ChangeServiceConfigW( hService, dwServiceType,
2371 dwStartType, dwErrorControl, wBinaryPathName,
2372 wLoadOrderGroup, lpdwTagId, wDependencies,
2373 wServiceStartName, wPassword, wDisplayName);
2375 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2376 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2377 HeapFree( GetProcessHeap(), 0, wDependencies );
2378 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2379 HeapFree( GetProcessHeap(), 0, wPassword );
2380 HeapFree( GetProcessHeap(), 0, wDisplayName );
2385 /******************************************************************************
2386 * ChangeServiceConfig2A [ADVAPI32.@]
2388 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2393 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2395 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2397 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2398 SERVICE_DESCRIPTIONW sdw;
2400 sdw.lpDescription = SERV_dup( sd->lpDescription );
2402 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2404 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2406 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2408 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2409 SERVICE_FAILURE_ACTIONSW faw;
2411 faw.dwResetPeriod = fa->dwResetPeriod;
2412 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2413 faw.lpCommand = SERV_dup( fa->lpCommand );
2414 faw.cActions = fa->cActions;
2415 faw.lpsaActions = fa->lpsaActions;
2417 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2419 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2420 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2423 SetLastError( ERROR_INVALID_PARAMETER );
2428 /******************************************************************************
2429 * ChangeServiceConfig2W [ADVAPI32.@]
2431 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2435 struct sc_service *hsvc;
2437 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2440 SetLastError( ERROR_INVALID_HANDLE );
2445 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2447 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2448 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2449 if (sd->lpDescription)
2451 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2452 if (sd->lpDescription[0] == 0)
2453 RegDeleteValueW(hKey,szDescription);
2455 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2456 (LPVOID)sd->lpDescription,
2457 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2461 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2465 /******************************************************************************
2466 * QueryServiceObjectSecurity [ADVAPI32.@]
2468 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2469 SECURITY_INFORMATION dwSecurityInformation,
2470 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2471 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2473 SECURITY_DESCRIPTOR descriptor;
2478 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2479 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2481 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2482 FIXME("information %d not supported\n", dwSecurityInformation);
2484 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2486 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2487 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2490 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2491 *pcbBytesNeeded = size;
2495 /******************************************************************************
2496 * SetServiceObjectSecurity [ADVAPI32.@]
2498 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2499 SECURITY_INFORMATION dwSecurityInformation,
2500 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2502 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2506 /******************************************************************************
2507 * SetServiceBits [ADVAPI32.@]
2509 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2510 DWORD dwServiceBits,
2512 BOOL bUpdateImmediately)
2514 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2515 bSetBitsOn, bUpdateImmediately);
2519 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2520 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2522 LPHANDLER_FUNCTION func = context;
2525 return ERROR_SUCCESS;
2528 /******************************************************************************
2529 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2531 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2533 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2536 /******************************************************************************
2537 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2539 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2541 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2544 /******************************************************************************
2545 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2547 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2550 SERVICE_STATUS_HANDLE ret;
2552 nameW = SERV_dup(name);
2553 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2554 HeapFree( GetProcessHeap(), 0, nameW );
2558 /******************************************************************************
2559 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2561 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2562 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2564 SERVICE_STATUS_HANDLE handle = 0;
2567 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2569 EnterCriticalSection( &service_cs );
2570 for (i = 0; i < nb_services; i++)
2572 if(!strcmpW(lpServiceName, services[i]->name))
2574 services[i]->handler = lpHandlerProc;
2575 services[i]->context = lpContext;
2576 handle = ULongToHandle( i + 1 );
2580 LeaveCriticalSection( &service_cs );
2585 /******************************************************************************
2586 * EnumDependentServicesA [ADVAPI32.@]
2588 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2589 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2590 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2592 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2593 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2595 *lpServicesReturned = 0;
2599 /******************************************************************************
2600 * EnumDependentServicesW [ADVAPI32.@]
2602 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2603 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2604 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2606 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2607 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2609 *lpServicesReturned = 0;