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(service);
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 /* Open service first before deciding whether it already exists or not
1306 * It could be that it's not a valid service, but only the registry key itself exists
1308 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1310 WCHAR name[MAX_PATH];
1311 DWORD size = sizeof(name);
1313 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1315 if (lpDisplayName && (!lstrcmpiW(lpDisplayName, name)
1316 || !lstrcmpiW(lpDisplayName, buffer)))
1317 displayname_exists = TRUE;
1319 if (!lstrcmpiW(lpServiceName, buffer))
1321 RegCloseKey(service_key);
1322 SetLastError(ERROR_SERVICE_EXISTS);
1326 RegCloseKey(service_key);
1329 len = sizeof(buffer);
1332 if (displayname_exists)
1334 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1338 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1339 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1340 if (r!=ERROR_SUCCESS)
1342 /* FIXME: Should we set an error? */
1347 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1349 service_set_dword( &val[n++], szType, &dwServiceType );
1350 service_set_dword( &val[n++], szStart, &dwStartType );
1351 service_set_dword( &val[n++], szError, &dwErrorControl );
1353 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1355 if( lpLoadOrderGroup )
1356 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1358 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1359 * There is no such key as what szDependencies refers to */
1360 if( lpDependencies )
1361 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1364 FIXME("Don't know how to add a Password for a service.\n");
1366 if( lpServiceStartName )
1367 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1369 r = service_write_values( hKey, val, n );
1370 if( r != ERROR_SUCCESS )
1373 len = strlenW(lpServiceName)+1;
1374 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1375 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1378 lstrcpyW( hsvc->name, lpServiceName );
1381 RtlMapGenericMask(&new_mask, &svc_generic);
1382 hsvc->dwAccess = new_mask;
1385 hscm->hdr.ref_count++;
1387 return (SC_HANDLE) &hsvc->hdr;
1390 RegCloseKey( hKey );
1395 /******************************************************************************
1396 * CreateServiceA [ADVAPI32.@]
1399 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1400 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1401 DWORD dwServiceType, DWORD dwStartType,
1402 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1403 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1404 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1407 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1408 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1411 TRACE("%p %s %s\n", hSCManager,
1412 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1414 lpServiceNameW = SERV_dup( lpServiceName );
1415 lpDisplayNameW = SERV_dup( lpDisplayName );
1416 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1417 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1418 lpDependenciesW = SERV_dupmulti( lpDependencies );
1419 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1420 lpPasswordW = SERV_dup( lpPassword );
1422 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1423 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1424 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1425 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1427 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1428 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1429 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1430 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1431 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1432 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1433 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1439 /******************************************************************************
1440 * DeleteService [ADVAPI32.@]
1442 * Delete a service from the service control manager database.
1445 * hService [I] Handle of the service to delete
1451 BOOL WINAPI DeleteService( SC_HANDLE hService )
1453 struct sc_service *hsvc;
1455 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1458 SetLastError( ERROR_INVALID_HANDLE );
1462 if (!(hsvc->dwAccess & DELETE))
1464 SetLastError(ERROR_ACCESS_DENIED);
1468 /* Close the key to the service */
1469 RegCloseKey(hsvc->hkey);
1471 /* Delete the service under the Service Control Manager key */
1472 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1480 /******************************************************************************
1481 * StartServiceA [ADVAPI32.@]
1486 * hService [I] Handle of service
1487 * dwNumServiceArgs [I] Number of arguments
1488 * lpServiceArgVectors [I] Address of array of argument strings
1491 * - NT implements this function using an obscure RPC call.
1492 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1493 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1494 * - This will only work for shared address space. How should the service
1495 * args be transferred when address spaces are separated?
1496 * - Can only start one service at a time.
1497 * - Has no concept of privilege.
1503 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1504 LPCSTR *lpServiceArgVectors )
1506 LPWSTR *lpwstr=NULL;
1510 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1512 if (dwNumServiceArgs)
1513 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1514 dwNumServiceArgs*sizeof(LPWSTR) );
1516 for(i=0; i<dwNumServiceArgs; i++)
1517 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1519 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1521 if (dwNumServiceArgs)
1523 for(i=0; i<dwNumServiceArgs; i++)
1524 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1525 HeapFree(GetProcessHeap(), 0, lpwstr);
1531 /******************************************************************************
1532 * service_start_process [INTERNAL]
1534 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1536 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1537 PROCESS_INFORMATION pi;
1539 LPWSTR path = NULL, str;
1540 DWORD type, size, ret, svc_type;
1544 size = sizeof(svc_type);
1545 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1548 if (svc_type == SERVICE_KERNEL_DRIVER)
1550 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1551 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1553 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1554 GetSystemDirectoryW( path, len );
1555 lstrcatW( path, winedeviceW );
1556 lstrcatW( path, hsvc->name );
1560 /* read the executable path from the registry */
1562 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1563 if (ret!=ERROR_SUCCESS)
1565 str = HeapAlloc(GetProcessHeap(),0,size);
1566 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1567 if (ret==ERROR_SUCCESS)
1569 size = ExpandEnvironmentStringsW(str,NULL,0);
1570 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1571 ExpandEnvironmentStringsW(str,path,size);
1573 HeapFree(GetProcessHeap(),0,str);
1578 /* wait for the process to start and set an event or terminate */
1579 handles[0] = service_get_event_handle( hsvc->name );
1580 ZeroMemory(&si, sizeof(STARTUPINFOW));
1581 si.cb = sizeof(STARTUPINFOW);
1582 if (!(svc_type & SERVICE_INTERACTIVE_PROCESS))
1584 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};
1585 si.lpDesktop = desktopW;
1588 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1591 if (ppid) *ppid = pi.dwProcessId;
1593 handles[1] = pi.hProcess;
1594 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1595 if(ret != WAIT_OBJECT_0)
1597 SetLastError(ERROR_IO_PENDING);
1601 CloseHandle( pi.hThread );
1602 CloseHandle( pi.hProcess );
1604 CloseHandle( handles[0] );
1605 HeapFree(GetProcessHeap(),0,path);
1609 static BOOL service_wait_for_startup(SC_HANDLE hService)
1612 SERVICE_STATUS status;
1615 TRACE("%p\n", hService);
1617 for (i=0; i<20; i++)
1619 status.dwCurrentState = 0;
1620 r = QueryServiceStatus(hService, &status);
1623 if (status.dwCurrentState == SERVICE_RUNNING)
1625 TRACE("Service started successfully\n");
1629 if (status.dwCurrentState != SERVICE_START_PENDING) break;
1635 /******************************************************************************
1636 * StartServiceW [ADVAPI32.@]
1638 * See StartServiceA.
1640 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1641 LPCWSTR *lpServiceArgVectors)
1643 struct sc_service *hsvc;
1646 HANDLE handle = INVALID_HANDLE_VALUE;
1648 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1650 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1653 SetLastError(ERROR_INVALID_HANDLE);
1657 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1661 handle = service_open_pipe(hsvc->name);
1662 if (handle==INVALID_HANDLE_VALUE)
1664 /* start the service process */
1665 if (service_start_process(hsvc, NULL))
1666 handle = service_open_pipe(hsvc->name);
1669 if (handle != INVALID_HANDLE_VALUE)
1671 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1672 CloseHandle(handle);
1675 UnlockServiceDatabase( hLock );
1677 TRACE("returning %d\n", r);
1680 service_wait_for_startup(hService);
1685 /******************************************************************************
1686 * QueryServiceStatus [ADVAPI32.@]
1689 * hService [I] Handle to service to get information about
1690 * lpservicestatus [O] buffer to receive the status information for the service
1693 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1694 LPSERVICE_STATUS lpservicestatus)
1696 SERVICE_STATUS_PROCESS SvcStatusData;
1699 TRACE("%p %p\n", hService, lpservicestatus);
1701 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1702 sizeof(SERVICE_STATUS_PROCESS), NULL);
1703 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1708 /******************************************************************************
1709 * QueryServiceStatusEx [ADVAPI32.@]
1711 * Get information about a service.
1714 * hService [I] Handle to service to get information about
1715 * InfoLevel [I] Level of information to get
1716 * lpBuffer [O] Destination for requested information
1717 * cbBufSize [I] Size of lpBuffer in bytes
1718 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1724 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1725 LPBYTE lpBuffer, DWORD cbBufSize,
1726 LPDWORD pcbBytesNeeded)
1728 struct sc_service *hsvc;
1729 DWORD size, type, val;
1732 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1734 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1736 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1738 SetLastError( ERROR_INVALID_LEVEL);
1742 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1743 if (pSvcStatusData == NULL)
1745 SetLastError( ERROR_INVALID_PARAMETER);
1749 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1751 if( pcbBytesNeeded != NULL)
1752 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1754 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1758 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1761 SetLastError( ERROR_INVALID_HANDLE );
1765 pipe = service_open_pipe(hsvc->name);
1766 if (pipe != INVALID_HANDLE_VALUE)
1768 r = service_get_status(pipe, pSvcStatusData);
1774 TRACE("Failed to read service status\n");
1776 /* read the service type from the registry */
1778 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1779 if (r != ERROR_SUCCESS || type != REG_DWORD)
1782 pSvcStatusData->dwServiceType = val;
1783 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1784 pSvcStatusData->dwControlsAccepted = 0;
1785 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1786 pSvcStatusData->dwServiceSpecificExitCode = 0;
1787 pSvcStatusData->dwCheckPoint = 0;
1788 pSvcStatusData->dwWaitHint = 0;
1793 /******************************************************************************
1794 * QueryServiceConfigA [ADVAPI32.@]
1796 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1797 DWORD size, LPDWORD needed )
1802 QUERY_SERVICE_CONFIGW *configW;
1804 TRACE("%p %p %d %p\n", hService, config, size, needed);
1806 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1808 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1811 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1812 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1813 if (!ret) goto done;
1815 config->dwServiceType = configW->dwServiceType;
1816 config->dwStartType = configW->dwStartType;
1817 config->dwErrorControl = configW->dwErrorControl;
1818 config->lpBinaryPathName = NULL;
1819 config->lpLoadOrderGroup = NULL;
1820 config->dwTagId = configW->dwTagId;
1821 config->lpDependencies = NULL;
1822 config->lpServiceStartName = NULL;
1823 config->lpDisplayName = NULL;
1825 p = (LPSTR)(config + 1);
1826 n = size - sizeof(*config);
1829 #define MAP_STR(str) \
1833 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1834 if (!sz) goto done; \
1841 MAP_STR( lpBinaryPathName );
1842 MAP_STR( lpLoadOrderGroup );
1843 MAP_STR( lpDependencies );
1844 MAP_STR( lpServiceStartName );
1845 MAP_STR( lpDisplayName );
1848 *needed = p - (LPSTR)config;
1852 HeapFree( GetProcessHeap(), 0, buffer );
1856 /******************************************************************************
1857 * QueryServiceConfigW [ADVAPI32.@]
1860 QueryServiceConfigW( SC_HANDLE hService,
1861 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1862 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1864 WCHAR str_buffer[ MAX_PATH ];
1866 DWORD type, val, sz, total, n;
1869 struct sc_service *hsvc;
1871 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1872 cbBufSize, pcbBytesNeeded);
1874 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1877 SetLastError( ERROR_INVALID_HANDLE );
1882 /* TODO: Check which members are mandatory and what the registry types
1883 * should be. This should of course also be tested when a service is
1887 /* calculate the size required first */
1888 total = sizeof (QUERY_SERVICE_CONFIGW);
1890 sz = sizeof(str_buffer);
1891 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1892 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1894 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1895 if( 0 == sz ) return FALSE;
1897 total += sizeof(WCHAR) * sz;
1901 /* FIXME: set last error */
1906 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1907 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1910 total += sizeof(WCHAR);
1913 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1914 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1917 total += sizeof(WCHAR);
1920 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1921 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1924 total += sizeof(WCHAR);
1927 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1928 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1931 total += sizeof(WCHAR);
1933 *pcbBytesNeeded = total;
1935 /* if there's not enough memory, return an error */
1936 if( total > cbBufSize )
1938 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1942 ZeroMemory( lpServiceConfig, total );
1945 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1946 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1947 lpServiceConfig->dwServiceType = val;
1950 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1951 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1952 lpServiceConfig->dwStartType = val;
1955 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1956 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1957 lpServiceConfig->dwErrorControl = val;
1960 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
1961 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1962 lpServiceConfig->dwTagId = val;
1964 /* now do the strings */
1965 p = (LPBYTE) &lpServiceConfig[1];
1966 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1968 sz = sizeof(str_buffer);
1969 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1970 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1972 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1973 sz *= sizeof(WCHAR);
1974 if( 0 == sz || sz > n ) return FALSE;
1976 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1982 /* FIXME: set last error */
1987 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1988 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1989 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2002 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2003 lpServiceConfig->lpDependencies = (LPWSTR) p;
2004 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2017 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2018 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2019 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2032 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2033 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2034 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2046 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2047 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2048 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2049 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2050 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2055 /******************************************************************************
2056 * EnumServicesStatusA [ADVAPI32.@]
2059 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2060 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2061 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2062 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2064 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2065 dwServiceType, dwServiceState, lpServices, cbBufSize,
2066 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2067 SetLastError (ERROR_ACCESS_DENIED);
2071 /******************************************************************************
2072 * EnumServicesStatusW [ADVAPI32.@]
2075 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2076 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2077 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2078 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2080 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2081 dwServiceType, dwServiceState, lpServices, cbBufSize,
2082 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2083 SetLastError (ERROR_ACCESS_DENIED);
2087 /******************************************************************************
2088 * EnumServicesStatusExA [ADVAPI32.@]
2091 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2092 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2093 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2095 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2096 dwServiceType, dwServiceState, lpServices, cbBufSize,
2097 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2098 *lpServicesReturned = 0;
2099 SetLastError (ERROR_ACCESS_DENIED);
2103 /******************************************************************************
2104 * EnumServicesStatusExW [ADVAPI32.@]
2107 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2108 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2109 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2111 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2112 dwServiceType, dwServiceState, lpServices, cbBufSize,
2113 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2114 SetLastError (ERROR_ACCESS_DENIED);
2118 /******************************************************************************
2119 * GetServiceKeyNameA [ADVAPI32.@]
2121 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2122 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2124 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2128 /******************************************************************************
2129 * GetServiceKeyNameW [ADVAPI32.@]
2131 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2132 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2134 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2138 /******************************************************************************
2139 * QueryServiceLockStatusA [ADVAPI32.@]
2141 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2142 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2143 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2145 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2150 /******************************************************************************
2151 * QueryServiceLockStatusW [ADVAPI32.@]
2153 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2154 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2155 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2157 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2162 /******************************************************************************
2163 * GetServiceDisplayNameA [ADVAPI32.@]
2165 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2166 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2168 LPWSTR lpServiceNameW, lpDisplayNameW;
2172 TRACE("%p %s %p %p\n", hSCManager,
2173 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2175 lpServiceNameW = SERV_dup(lpServiceName);
2177 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2179 lpDisplayNameW = NULL;
2181 sizeW = *lpcchBuffer;
2182 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2184 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2188 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2189 *lpcchBuffer, NULL, NULL ))
2191 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2195 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2196 * (but if the function succeeded it means that is a good upper estimation of the size) */
2200 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2201 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2205 /******************************************************************************
2206 * GetServiceDisplayNameW [ADVAPI32.@]
2208 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2209 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2211 struct sc_manager *hscm;
2215 TRACE("%p %s %p %p\n", hSCManager,
2216 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2218 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2221 SetLastError(ERROR_INVALID_HANDLE);
2227 SetLastError(ERROR_INVALID_ADDRESS);
2231 size = *lpcchBuffer * sizeof(WCHAR);
2232 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2233 if (!ret && !lpDisplayName && size)
2234 ret = ERROR_MORE_DATA;
2238 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2240 if (ret == ERROR_MORE_DATA)
2242 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2243 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2245 else if (ret == ERROR_FILE_NOT_FOUND)
2249 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2251 UINT len = lstrlenW(lpServiceName);
2254 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2255 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2256 else if (lpDisplayName && *lpcchBuffer)
2258 /* No displayname, but the service exists and the buffer
2259 * is big enough. We should return the servicename.
2261 lstrcpyW(lpDisplayName, lpServiceName);
2270 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2277 /* Always return the correct needed size on success */
2278 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2283 /******************************************************************************
2284 * ChangeServiceConfigW [ADVAPI32.@]
2286 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2287 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2288 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2289 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2291 struct reg_value val[10];
2292 struct sc_service *hsvc;
2293 DWORD r = ERROR_SUCCESS;
2297 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2298 hService, dwServiceType, dwStartType, dwErrorControl,
2299 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2300 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2301 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2303 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2306 SetLastError( ERROR_INVALID_HANDLE );
2311 if( dwServiceType != SERVICE_NO_CHANGE )
2312 service_set_dword( &val[n++], szType, &dwServiceType );
2314 if( dwStartType != SERVICE_NO_CHANGE )
2315 service_set_dword( &val[n++], szStart, &dwStartType );
2317 if( dwErrorControl != SERVICE_NO_CHANGE )
2318 service_set_dword( &val[n++], szError, &dwErrorControl );
2320 if( lpBinaryPathName )
2321 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2323 if( lpLoadOrderGroup )
2324 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2326 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2327 * There is no such key as what szDependencies refers to */
2328 if( lpDependencies )
2329 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2332 FIXME("ignoring password\n");
2334 if( lpServiceStartName )
2335 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2337 r = service_write_values( hsvc->hkey, val, n );
2339 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2342 /******************************************************************************
2343 * ChangeServiceConfigA [ADVAPI32.@]
2345 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2346 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2347 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2348 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2350 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2351 LPWSTR wServiceStartName, wPassword, wDisplayName;
2354 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2355 hService, dwServiceType, dwStartType, dwErrorControl,
2356 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2357 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2358 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2360 wBinaryPathName = SERV_dup( lpBinaryPathName );
2361 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2362 wDependencies = SERV_dupmulti( lpDependencies );
2363 wServiceStartName = SERV_dup( lpServiceStartName );
2364 wPassword = SERV_dup( lpPassword );
2365 wDisplayName = SERV_dup( lpDisplayName );
2367 r = ChangeServiceConfigW( hService, dwServiceType,
2368 dwStartType, dwErrorControl, wBinaryPathName,
2369 wLoadOrderGroup, lpdwTagId, wDependencies,
2370 wServiceStartName, wPassword, wDisplayName);
2372 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2373 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2374 HeapFree( GetProcessHeap(), 0, wDependencies );
2375 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2376 HeapFree( GetProcessHeap(), 0, wPassword );
2377 HeapFree( GetProcessHeap(), 0, wDisplayName );
2382 /******************************************************************************
2383 * ChangeServiceConfig2A [ADVAPI32.@]
2385 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2390 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2392 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2394 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2395 SERVICE_DESCRIPTIONW sdw;
2397 sdw.lpDescription = SERV_dup( sd->lpDescription );
2399 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2401 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2403 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2405 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2406 SERVICE_FAILURE_ACTIONSW faw;
2408 faw.dwResetPeriod = fa->dwResetPeriod;
2409 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2410 faw.lpCommand = SERV_dup( fa->lpCommand );
2411 faw.cActions = fa->cActions;
2412 faw.lpsaActions = fa->lpsaActions;
2414 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2416 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2417 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2420 SetLastError( ERROR_INVALID_PARAMETER );
2425 /******************************************************************************
2426 * ChangeServiceConfig2W [ADVAPI32.@]
2428 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2432 struct sc_service *hsvc;
2434 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2437 SetLastError( ERROR_INVALID_HANDLE );
2442 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2444 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2445 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2446 if (sd->lpDescription)
2448 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2449 if (sd->lpDescription[0] == 0)
2450 RegDeleteValueW(hKey,szDescription);
2452 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2453 (LPVOID)sd->lpDescription,
2454 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2458 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2462 /******************************************************************************
2463 * QueryServiceObjectSecurity [ADVAPI32.@]
2465 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2466 SECURITY_INFORMATION dwSecurityInformation,
2467 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2468 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2470 SECURITY_DESCRIPTOR descriptor;
2475 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2476 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2478 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2479 FIXME("information %d not supported\n", dwSecurityInformation);
2481 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2483 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2484 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2487 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2488 *pcbBytesNeeded = size;
2492 /******************************************************************************
2493 * SetServiceObjectSecurity [ADVAPI32.@]
2495 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2496 SECURITY_INFORMATION dwSecurityInformation,
2497 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2499 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2503 /******************************************************************************
2504 * SetServiceBits [ADVAPI32.@]
2506 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2507 DWORD dwServiceBits,
2509 BOOL bUpdateImmediately)
2511 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2512 bSetBitsOn, bUpdateImmediately);
2516 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2517 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2519 LPHANDLER_FUNCTION func = context;
2522 return ERROR_SUCCESS;
2525 /******************************************************************************
2526 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2528 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2530 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2533 /******************************************************************************
2534 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2536 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2538 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2541 /******************************************************************************
2542 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2544 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2547 SERVICE_STATUS_HANDLE ret;
2549 nameW = SERV_dup(name);
2550 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2551 HeapFree( GetProcessHeap(), 0, nameW );
2555 /******************************************************************************
2556 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2558 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2559 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2561 SERVICE_STATUS_HANDLE handle = 0;
2564 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2566 EnterCriticalSection( &service_cs );
2567 for (i = 0; i < nb_services; i++)
2569 if(!strcmpW(lpServiceName, services[i]->name))
2571 services[i]->handler = lpHandlerProc;
2572 services[i]->context = lpContext;
2573 handle = ULongToHandle( i + 1 );
2577 LeaveCriticalSection( &service_cs );
2582 /******************************************************************************
2583 * EnumDependentServicesA [ADVAPI32.@]
2585 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2586 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2587 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2589 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2590 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2592 *lpServicesReturned = 0;
2596 /******************************************************************************
2597 * EnumDependentServicesW [ADVAPI32.@]
2599 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2600 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2601 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2603 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2604 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2606 *lpServicesReturned = 0;