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"
38 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
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
77 LPHANDLER_FUNCTION handler;
78 LPHANDLER_FUNCTION_EX handler_ex;
81 SERVICE_STATUS_PROCESS status;
84 BOOL extended : 1; /* uses handler_ex instead of handler? */
86 LPSERVICE_MAIN_FUNCTIONA a;
87 LPSERVICE_MAIN_FUNCTIONW w;
93 static CRITICAL_SECTION service_cs;
94 static CRITICAL_SECTION_DEBUG service_cs_debug =
97 { &service_cs_debug.ProcessLocksList,
98 &service_cs_debug.ProcessLocksList },
99 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
101 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
103 static struct list service_list = LIST_INIT(service_list);
105 extern HANDLE __wine_make_process_system(void);
107 /******************************************************************************
111 #define MAX_SERVICE_NAME 256
113 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
116 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
120 SC_HANDLE_TYPE htype;
122 sc_handle_destructor destroy;
125 struct sc_manager /* service control manager handle */
127 struct sc_handle hdr;
128 HKEY hkey; /* handle to services database in the registry */
132 struct sc_service /* service handle */
134 struct sc_handle hdr;
135 HKEY hkey; /* handle to service entry in the registry (under hkey) */
137 struct sc_manager *scm; /* pointer to SCM handle */
141 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
142 sc_handle_destructor destroy)
144 struct sc_handle *hdr;
146 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
151 hdr->destroy = destroy;
153 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
157 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
159 struct sc_handle *hdr = (struct sc_handle *) handle;
163 if (hdr->htype != htype)
168 static void sc_handle_free(struct sc_handle* hdr)
172 if (--hdr->ref_count)
175 HeapFree(GetProcessHeap(), 0, hdr);
178 static void sc_handle_destroy_manager(struct sc_handle *handle)
180 struct sc_manager *mgr = (struct sc_manager*) handle;
182 TRACE("destroying SC Manager %p\n", mgr);
184 RegCloseKey(mgr->hkey);
187 static void sc_handle_destroy_service(struct sc_handle *handle)
189 struct sc_service *svc = (struct sc_service*) handle;
191 TRACE("destroying service %p\n", svc);
193 RegCloseKey(svc->hkey);
195 sc_handle_free(&svc->scm->hdr);
199 /******************************************************************************
200 * String management functions
202 static inline LPWSTR SERV_dup( LPCSTR str )
209 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
210 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
211 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
215 static inline LPWSTR SERV_dupmulti(LPCSTR str)
223 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
224 n += (strlen( &str[n] ) + 1);
229 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
230 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
234 static inline VOID SERV_free( LPWSTR wstr )
236 HeapFree( GetProcessHeap(), 0, wstr );
239 /******************************************************************************
240 * registry access functions and data
242 static const WCHAR szDisplayName[] = {
243 'D','i','s','p','l','a','y','N','a','m','e', 0 };
244 static const WCHAR szType[] = {'T','y','p','e',0};
245 static const WCHAR szStart[] = {'S','t','a','r','t',0};
246 static const WCHAR szError[] = {
247 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
248 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
249 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
250 static const WCHAR szDependencies[] = {
251 'D','e','p','e','n','d','e','n','c','i','e','s',0};
252 static const WCHAR szDependOnService[] = {
253 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
254 static const WCHAR szObjectName[] = {
255 'O','b','j','e','c','t','N','a','m','e',0};
256 static const WCHAR szTag[] = {
266 static inline void service_set_value( struct reg_value *val,
267 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
275 static inline void service_set_dword( struct reg_value *val,
276 LPCWSTR name, const DWORD *data )
278 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
281 static inline void service_set_string( struct reg_value *val,
282 LPCWSTR name, LPCWSTR string )
284 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
285 service_set_value( val, REG_SZ, name, string, len );
288 static inline void service_set_multi_string( struct reg_value *val,
289 LPCWSTR name, LPCWSTR string )
293 /* determine the length of a double null terminated multi string */
295 len += (lstrlenW( &string[ len ] )+1);
296 } while ( string[ len++ ] );
298 len *= sizeof (WCHAR);
299 service_set_value( val, REG_MULTI_SZ, name, string, len );
302 static inline LONG service_write_values( HKEY hKey,
303 const struct reg_value *val, int n )
305 LONG r = ERROR_SUCCESS;
310 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
311 (const BYTE*)val[i].data, val[i].size );
312 if( r != ERROR_SUCCESS )
318 /******************************************************************************
319 * Service IPC functions
321 static LPWSTR service_get_pipe_name(LPCWSTR service)
323 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
324 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
328 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
329 name = HeapAlloc(GetProcessHeap(), 0, len);
330 strcpyW(name, prefix);
331 strcatW(name, service);
335 static HANDLE service_open_pipe(LPCWSTR service)
337 LPWSTR szPipe = service_get_pipe_name( service );
338 HANDLE handle = INVALID_HANDLE_VALUE;
341 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
342 0, NULL, OPEN_ALWAYS, 0, NULL);
343 if (handle != INVALID_HANDLE_VALUE)
345 if (GetLastError() != ERROR_PIPE_BUSY)
347 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
353 /******************************************************************************
354 * service_get_event_handle
356 static HANDLE service_get_event_handle(LPCWSTR service)
358 static const WCHAR prefix[] = {
359 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
364 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
365 name = HeapAlloc(GetProcessHeap(), 0, len);
366 strcpyW(name, prefix);
367 strcatW(name, service);
368 handle = CreateEventW(NULL, TRUE, FALSE, name);
373 /******************************************************************************
376 * Call into the main service routine provided by StartServiceCtrlDispatcher.
378 static DWORD WINAPI service_thread(LPVOID arg)
380 service_data *info = arg;
381 LPWSTR str = info->args;
382 DWORD argc = 0, len = 0;
388 len += strlenW(&str[len]) + 1;
395 info->proc.w(0, NULL);
397 info->proc.a(0, NULL);
405 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
406 for (argc=0, p=str; *p; p += strlenW(p) + 1)
410 info->proc.w(argc, argv);
411 HeapFree(GetProcessHeap(), 0, argv);
415 LPSTR strA, *argv, p;
418 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
419 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
420 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
422 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
423 for (argc=0, p=strA; *p; p += strlen(p) + 1)
427 info->proc.a(argc, argv);
428 HeapFree(GetProcessHeap(), 0, argv);
429 HeapFree(GetProcessHeap(), 0, strA);
434 /******************************************************************************
435 * service_handle_start
437 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
439 DWORD read = 0, result = 0;
443 TRACE("%p %p %d\n", pipe, service, count);
445 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
446 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
447 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
449 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
450 r, count, read, debugstr_wn(args, count));
456 WARN("service is not stopped\n");
457 result = ERROR_SERVICE_ALREADY_RUNNING;
461 SERV_free(service->args);
462 service->args = args;
464 service->thread = CreateThread( NULL, 0, service_thread,
468 HeapFree(GetProcessHeap(), 0, args);
469 WriteFile( pipe, &result, sizeof result, &read, NULL );
474 /******************************************************************************
475 * service_send_start_message
477 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
479 DWORD i, len, count, result;
480 service_start_info *ssi;
484 TRACE("%p %p %d\n", pipe, argv, argc);
486 /* calculate how much space do we need to send the startup info */
488 for (i=0; i<argc; i++)
489 len += strlenW(argv[i])+1;
491 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
492 ssi->cmd = WINESERV_STARTINFO;
495 /* copy service args into a single buffer*/
497 for (i=0; i<argc; i++)
504 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
507 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
510 SetLastError(result);
515 HeapFree(GetProcessHeap(),0,ssi);
520 /******************************************************************************
521 * service_handle_get_status
523 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
527 return WriteFile(pipe, &service->status,
528 sizeof service->status, &count, NULL);
531 /******************************************************************************
534 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
536 DWORD cmd[2], count = 0;
539 cmd[0] = WINESERV_GETSTATUS;
541 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
542 if (!r || count != sizeof cmd)
544 ERR("service protocol error - failed to write pipe!\n");
547 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
548 if (!r || count != sizeof *status)
549 ERR("service protocol error - failed to read pipe "
550 "r = %d count = %d!\n", r, count);
554 /******************************************************************************
555 * service_send_control
557 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
559 DWORD cmd[2], count = 0;
562 cmd[0] = WINESERV_SENDCONTROL;
564 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
565 if (!r || count != sizeof cmd)
567 ERR("service protocol error - failed to write pipe!\n");
570 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
571 if (!r || count != sizeof *result)
572 ERR("service protocol error - failed to read pipe "
573 "r = %d count = %d!\n", r, count);
577 /******************************************************************************
578 * service_accepts_control
580 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
582 DWORD a = service->status.dwControlsAccepted;
586 case SERVICE_CONTROL_INTERROGATE:
588 case SERVICE_CONTROL_STOP:
589 if (a&SERVICE_ACCEPT_STOP)
592 case SERVICE_CONTROL_SHUTDOWN:
593 if (a&SERVICE_ACCEPT_SHUTDOWN)
596 case SERVICE_CONTROL_PAUSE:
597 case SERVICE_CONTROL_CONTINUE:
598 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
601 case SERVICE_CONTROL_PARAMCHANGE:
602 if (a&SERVICE_ACCEPT_PARAMCHANGE)
605 case SERVICE_CONTROL_NETBINDADD:
606 case SERVICE_CONTROL_NETBINDREMOVE:
607 case SERVICE_CONTROL_NETBINDENABLE:
608 case SERVICE_CONTROL_NETBINDDISABLE:
609 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
612 if (!service->extended)
616 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
617 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
620 case SERVICE_CONTROL_POWEREVENT:
621 if (a&SERVICE_ACCEPT_POWEREVENT)
624 case SERVICE_CONTROL_SESSIONCHANGE:
625 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
632 /******************************************************************************
633 * service_handle_control
635 static BOOL service_handle_control(HANDLE pipe, service_data *service,
638 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
640 TRACE("received control %d\n", dwControl);
642 if (service_accepts_control(service, dwControl))
644 if (service->extended && service->handler.handler_ex)
646 service->handler.handler_ex(dwControl, 0, NULL, service->context);
649 else if (service->handler.handler)
651 service->handler.handler(dwControl);
655 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
658 /******************************************************************************
659 * service_reap_thread
661 static DWORD service_reap_thread(service_data *service)
665 if (!service->thread)
667 GetExitCodeThread(service->thread, &exitcode);
668 if (exitcode!=STILL_ACTIVE)
670 CloseHandle(service->thread);
676 /******************************************************************************
677 * service_control_dispatcher
679 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
681 service_data *service = arg;
685 TRACE("%p %s\n", service, debugstr_w(service->name));
687 /* create a pipe to talk to the rest of the world with */
688 name = service_get_pipe_name(service->name);
689 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
690 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
693 /* let the process who started us know we've tried to create a pipe */
694 event = service_get_event_handle(service->name);
698 if (pipe==INVALID_HANDLE_VALUE)
700 ERR("failed to create pipe for %s, error = %d\n",
701 debugstr_w(service->name), GetLastError());
705 /* dispatcher loop */
709 DWORD count, req[2] = {0,0};
711 r = ConnectNamedPipe(pipe, NULL);
712 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
714 ERR("pipe connect failed\n");
718 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
719 if (!r || count!=sizeof req)
721 ERR("pipe read failed\n");
725 service_reap_thread(service);
727 /* handle the request */
730 case WINESERV_STARTINFO:
731 service_handle_start(pipe, service, req[1]);
733 case WINESERV_GETSTATUS:
734 service_handle_get_status(pipe, service);
736 case WINESERV_SENDCONTROL:
737 service_handle_control(pipe, service, req[1]);
740 ERR("received invalid command %d length %d\n", req[0], req[1]);
743 FlushFileBuffers(pipe);
744 DisconnectNamedPipe(pipe);
751 /******************************************************************************
752 * service_run_threads
754 static BOOL service_run_threads(void)
756 service_data *service;
760 EnterCriticalSection( &service_cs );
762 count = list_count( &service_list );
764 TRACE("Starting %d pipe listener threads. Services running as process %d\n", count, GetCurrentProcessId());
766 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
768 handles[n++] = __wine_make_process_system();
770 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
772 service->status.dwProcessId = GetCurrentProcessId();
773 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
776 assert(n == count + 1);
778 LeaveCriticalSection( &service_cs );
780 /* wait for all the threads to pack up and exit */
783 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
784 if (!ret) /* system process event */
786 TRACE( "last user process exited, shutting down\n" );
787 /* FIXME: we should maybe send a shutdown control to running services */
790 if (ret < MAXIMUM_WAIT_OBJECTS)
792 CloseHandle( handles[ret] );
793 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
799 while (n) CloseHandle( handles[--n] );
800 HeapFree(GetProcessHeap(), 0, handles);
805 /******************************************************************************
806 * StartServiceCtrlDispatcherA [ADVAPI32.@]
808 * See StartServiceCtrlDispatcherW.
810 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
816 TRACE("%p\n", servent);
818 EnterCriticalSection( &service_cs );
819 while (servent->lpServiceName)
821 LPSTR name = servent->lpServiceName;
823 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
824 sz = len*sizeof(WCHAR) + sizeof *info;
825 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
826 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
827 info->proc.a = servent->lpServiceProc;
828 info->unicode = FALSE;
829 list_add_head( &service_list, &info->entry );
832 LeaveCriticalSection( &service_cs );
834 service_run_threads();
839 /******************************************************************************
840 * StartServiceCtrlDispatcherW [ADVAPI32.@]
842 * Connects a process containing one or more services to the service control
846 * servent [I] A list of the service names and service procedures
852 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
858 TRACE("%p\n", servent);
860 EnterCriticalSection( &service_cs );
861 while (servent->lpServiceName)
863 LPWSTR name = servent->lpServiceName;
866 sz = len*sizeof(WCHAR) + sizeof *info;
867 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
868 strcpyW(info->name, name);
869 info->proc.w = servent->lpServiceProc;
870 info->unicode = TRUE;
871 list_add_head( &service_list, &info->entry );
874 LeaveCriticalSection( &service_cs );
876 service_run_threads();
881 /******************************************************************************
882 * LockServiceDatabase [ADVAPI32.@]
884 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
888 TRACE("%p\n",hSCManager);
890 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
891 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
895 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
898 TRACE("returning %p\n", ret);
903 /******************************************************************************
904 * UnlockServiceDatabase [ADVAPI32.@]
906 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
908 TRACE("%p\n",ScLock);
910 return CloseHandle( ScLock );
913 /******************************************************************************
914 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
916 SERVICE_STATUS_HANDLE WINAPI
917 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
919 LPWSTR lpServiceNameW;
920 SERVICE_STATUS_HANDLE ret;
922 lpServiceNameW = SERV_dup(lpServiceName);
923 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
924 SERV_free(lpServiceNameW);
928 /******************************************************************************
929 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
935 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
936 LPHANDLER_FUNCTION lpfHandler )
938 service_data *service;
939 SERVICE_STATUS_HANDLE handle = 0;
941 EnterCriticalSection( &service_cs );
942 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
944 if(!strcmpW(lpServiceName, service->name))
946 service->handler.handler = lpfHandler;
947 handle = (SERVICE_STATUS_HANDLE)service;
951 LeaveCriticalSection( &service_cs );
955 /******************************************************************************
956 * SetServiceStatus [ADVAPI32.@]
963 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
965 service_data *service;
968 TRACE("%p %x %x %x %x %x %x %x\n", hService,
969 lpStatus->dwServiceType, lpStatus->dwCurrentState,
970 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
971 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
972 lpStatus->dwWaitHint);
974 EnterCriticalSection( &service_cs );
975 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
977 if(service == (service_data*)hService)
979 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
980 TRACE("Set service status to %d\n",service->status.dwCurrentState);
985 LeaveCriticalSection( &service_cs );
991 /******************************************************************************
992 * OpenSCManagerA [ADVAPI32.@]
994 * Establish a connection to the service control manager and open its database.
997 * lpMachineName [I] Pointer to machine name string
998 * lpDatabaseName [I] Pointer to database name string
999 * dwDesiredAccess [I] Type of access
1002 * Success: A Handle to the service control manager database
1005 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1006 DWORD dwDesiredAccess )
1008 LPWSTR lpMachineNameW, lpDatabaseNameW;
1011 lpMachineNameW = SERV_dup(lpMachineName);
1012 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1013 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1014 SERV_free(lpDatabaseNameW);
1015 SERV_free(lpMachineNameW);
1019 /******************************************************************************
1020 * OpenSCManagerW [ADVAPI32.@]
1022 * See OpenSCManagerA.
1024 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1025 DWORD dwDesiredAccess )
1027 struct sc_manager *manager;
1030 DWORD new_mask = dwDesiredAccess;
1032 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1033 debugstr_w(lpDatabaseName), dwDesiredAccess);
1035 if( lpDatabaseName && lpDatabaseName[0] )
1037 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1039 /* noop, all right */
1041 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1043 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1048 SetLastError( ERROR_INVALID_NAME );
1053 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1054 sc_handle_destroy_manager );
1058 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1059 if (r!=ERROR_SUCCESS)
1062 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1063 RegCloseKey( hReg );
1064 if (r!=ERROR_SUCCESS)
1067 RtlMapGenericMask(&new_mask, &scm_generic);
1068 manager->dwAccess = new_mask;
1069 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1071 return (SC_HANDLE) &manager->hdr;
1074 sc_handle_free( &manager->hdr );
1079 /******************************************************************************
1080 * ControlService [ADVAPI32.@]
1082 * Send a control code to a service.
1085 * hService [I] Handle of the service control manager database
1086 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1087 * lpServiceStatus [O] Destination for the status of the service, if available
1094 * Unlike M$' implementation, control requests are not serialized and may be
1095 * processed asynchronously.
1097 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1098 LPSERVICE_STATUS lpServiceStatus )
1100 struct sc_service *hsvc;
1104 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1106 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1109 SetLastError( ERROR_INVALID_HANDLE );
1113 ret = QueryServiceStatus(hService, lpServiceStatus);
1116 ERR("failed to query service status\n");
1117 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1121 switch (lpServiceStatus->dwCurrentState)
1123 case SERVICE_STOPPED:
1124 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1126 case SERVICE_START_PENDING:
1127 if (dwControl==SERVICE_CONTROL_STOP)
1130 case SERVICE_STOP_PENDING:
1131 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1135 handle = service_open_pipe(hsvc->name);
1136 if (handle!=INVALID_HANDLE_VALUE)
1138 DWORD result = ERROR_SUCCESS;
1139 ret = service_send_control(handle, dwControl, &result);
1140 CloseHandle(handle);
1141 if (result!=ERROR_SUCCESS)
1143 SetLastError(result);
1151 /******************************************************************************
1152 * CloseServiceHandle [ADVAPI32.@]
1154 * Close a handle to a service or the service control manager database.
1157 * hSCObject [I] Handle to service or service control manager database
1164 CloseServiceHandle( SC_HANDLE hSCObject )
1166 TRACE("%p\n", hSCObject);
1168 sc_handle_free( (struct sc_handle*) hSCObject );
1174 /******************************************************************************
1175 * OpenServiceA [ADVAPI32.@]
1177 * Open a handle to a service.
1180 * hSCManager [I] Handle of the service control manager database
1181 * lpServiceName [I] Name of the service to open
1182 * dwDesiredAccess [I] Access required to the service
1185 * Success: Handle to the service
1188 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1189 DWORD dwDesiredAccess )
1191 LPWSTR lpServiceNameW;
1194 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1196 lpServiceNameW = SERV_dup(lpServiceName);
1197 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1198 SERV_free(lpServiceNameW);
1203 /******************************************************************************
1204 * OpenServiceW [ADVAPI32.@]
1208 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1209 DWORD dwDesiredAccess)
1211 struct sc_manager *hscm;
1212 struct sc_service *hsvc;
1216 DWORD new_mask = dwDesiredAccess;
1218 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1220 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1223 SetLastError( ERROR_INVALID_HANDLE );
1229 SetLastError(ERROR_INVALID_ADDRESS);
1233 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1234 if (r!=ERROR_SUCCESS)
1236 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1240 len = strlenW(lpServiceName)+1;
1241 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1242 sizeof (struct sc_service) + len*sizeof(WCHAR),
1243 sc_handle_destroy_service );
1249 strcpyW( hsvc->name, lpServiceName );
1252 RtlMapGenericMask(&new_mask, &svc_generic);
1253 hsvc->dwAccess = new_mask;
1255 /* add reference to SCM handle */
1256 hscm->hdr.ref_count++;
1259 TRACE("returning %p\n",hsvc);
1261 return (SC_HANDLE) &hsvc->hdr;
1264 /******************************************************************************
1265 * CreateServiceW [ADVAPI32.@]
1268 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1269 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1270 DWORD dwServiceType, DWORD dwStartType,
1271 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1272 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1273 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1274 LPCWSTR lpPassword )
1276 struct sc_manager *hscm;
1277 struct sc_service *hsvc = NULL;
1281 struct reg_value val[10];
1283 DWORD new_mask = dwDesiredAccess;
1285 WCHAR buffer[MAX_PATH];
1286 BOOL displayname_exists = FALSE;
1288 TRACE("%p %s %s\n", hSCManager,
1289 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1291 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1294 SetLastError( ERROR_INVALID_HANDLE );
1298 if (!lpServiceName || !lpBinaryPathName)
1300 SetLastError(ERROR_INVALID_ADDRESS);
1304 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1306 SetLastError(ERROR_ACCESS_DENIED);
1310 if (!lpServiceName[0])
1312 SetLastError(ERROR_INVALID_NAME);
1316 if (!lpBinaryPathName[0])
1318 SetLastError(ERROR_INVALID_PARAMETER);
1322 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1323 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1324 * runs under the LocalSystem account)
1326 switch (dwServiceType)
1328 case SERVICE_KERNEL_DRIVER:
1329 case SERVICE_FILE_SYSTEM_DRIVER:
1330 case SERVICE_WIN32_OWN_PROCESS:
1331 case SERVICE_WIN32_SHARE_PROCESS:
1334 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1335 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1336 /* FIXME : Do we need a more thorough check? */
1337 if (lpServiceStartName)
1339 SetLastError(ERROR_INVALID_PARAMETER);
1344 SetLastError(ERROR_INVALID_PARAMETER);
1348 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1349 if (dwStartType > SERVICE_DISABLED)
1351 SetLastError(ERROR_INVALID_PARAMETER);
1355 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1356 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1357 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1359 SetLastError(ERROR_INVALID_PARAMETER);
1363 /* Loop through the registry to check if the service already exists and to
1364 * check if we can use the given displayname.
1365 * FIXME: Should we use EnumServicesStatusEx?
1367 len = sizeof(buffer);
1368 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1372 /* The service already exists, so bail out */
1373 if(!lstrcmpiW(lpServiceName, buffer))
1375 SetLastError(ERROR_SERVICE_EXISTS);
1379 /* The given displayname matches the found servicename. We don't bail out
1380 * as servicename is checked before a duplicate displayname
1382 if(!lstrcmpiW(lpDisplayName, buffer))
1383 displayname_exists = TRUE;
1385 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1387 WCHAR name[MAX_PATH];
1388 DWORD size = sizeof(name);
1390 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1392 /* The given displayname matches the found displayname */
1393 if (!lstrcmpiW(lpDisplayName, name))
1394 displayname_exists = TRUE;
1396 RegCloseKey(service_key);
1399 len = sizeof(buffer);
1402 if (lpDisplayName && displayname_exists)
1404 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1408 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1409 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1410 if (r!=ERROR_SUCCESS)
1412 /* FIXME: Should we set an error? */
1417 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1419 service_set_dword( &val[n++], szType, &dwServiceType );
1420 service_set_dword( &val[n++], szStart, &dwStartType );
1421 service_set_dword( &val[n++], szError, &dwErrorControl );
1423 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1425 if( lpLoadOrderGroup )
1426 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1428 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1429 * There is no such key as what szDependencies refers to */
1430 if( lpDependencies )
1431 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1434 FIXME("Don't know how to add a Password for a service.\n");
1436 if( lpServiceStartName )
1437 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1439 r = service_write_values( hKey, val, n );
1440 if( r != ERROR_SUCCESS )
1443 len = strlenW(lpServiceName)+1;
1444 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1445 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1448 lstrcpyW( hsvc->name, lpServiceName );
1451 RtlMapGenericMask(&new_mask, &svc_generic);
1452 hsvc->dwAccess = new_mask;
1455 hscm->hdr.ref_count++;
1457 return (SC_HANDLE) &hsvc->hdr;
1460 RegCloseKey( hKey );
1465 /******************************************************************************
1466 * CreateServiceA [ADVAPI32.@]
1469 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1470 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1471 DWORD dwServiceType, DWORD dwStartType,
1472 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1473 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1474 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1477 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1478 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1481 TRACE("%p %s %s\n", hSCManager,
1482 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1484 lpServiceNameW = SERV_dup( lpServiceName );
1485 lpDisplayNameW = SERV_dup( lpDisplayName );
1486 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1487 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1488 lpDependenciesW = SERV_dupmulti( lpDependencies );
1489 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1490 lpPasswordW = SERV_dup( lpPassword );
1492 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1493 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1494 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1495 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1497 SERV_free( lpServiceNameW );
1498 SERV_free( lpDisplayNameW );
1499 SERV_free( lpBinaryPathNameW );
1500 SERV_free( lpLoadOrderGroupW );
1501 SERV_free( lpDependenciesW );
1502 SERV_free( lpServiceStartNameW );
1503 SERV_free( lpPasswordW );
1509 /******************************************************************************
1510 * DeleteService [ADVAPI32.@]
1512 * Delete a service from the service control manager database.
1515 * hService [I] Handle of the service to delete
1521 BOOL WINAPI DeleteService( SC_HANDLE hService )
1523 struct sc_service *hsvc;
1525 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1528 SetLastError( ERROR_INVALID_HANDLE );
1532 if (!(hsvc->dwAccess & DELETE))
1534 SetLastError(ERROR_ACCESS_DENIED);
1538 /* Close the key to the service */
1539 RegCloseKey(hsvc->hkey);
1541 /* Delete the service under the Service Control Manager key */
1542 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1550 /******************************************************************************
1551 * StartServiceA [ADVAPI32.@]
1556 * hService [I] Handle of service
1557 * dwNumServiceArgs [I] Number of arguments
1558 * lpServiceArgVectors [I] Address of array of argument strings
1561 * - NT implements this function using an obscure RPC call.
1562 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1563 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1564 * - This will only work for shared address space. How should the service
1565 * args be transferred when address spaces are separated?
1566 * - Can only start one service at a time.
1567 * - Has no concept of privilege.
1573 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1574 LPCSTR *lpServiceArgVectors )
1576 LPWSTR *lpwstr=NULL;
1580 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1582 if (dwNumServiceArgs)
1583 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1584 dwNumServiceArgs*sizeof(LPWSTR) );
1586 for(i=0; i<dwNumServiceArgs; i++)
1587 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1589 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1591 if (dwNumServiceArgs)
1593 for(i=0; i<dwNumServiceArgs; i++)
1594 SERV_free(lpwstr[i]);
1595 HeapFree(GetProcessHeap(), 0, lpwstr);
1601 /******************************************************************************
1602 * service_start_process [INTERNAL]
1604 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1606 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1607 PROCESS_INFORMATION pi;
1609 LPWSTR path = NULL, str;
1610 DWORD type, size, ret, svc_type;
1614 size = sizeof(svc_type);
1615 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1618 if (svc_type == SERVICE_KERNEL_DRIVER)
1620 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1621 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1623 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1624 GetSystemDirectoryW( path, len );
1625 lstrcatW( path, winedeviceW );
1626 lstrcatW( path, hsvc->name );
1630 /* read the executable path from the registry */
1632 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1633 if (ret!=ERROR_SUCCESS)
1635 str = HeapAlloc(GetProcessHeap(),0,size);
1636 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1637 if (ret==ERROR_SUCCESS)
1639 size = ExpandEnvironmentStringsW(str,NULL,0);
1640 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1641 ExpandEnvironmentStringsW(str,path,size);
1643 HeapFree(GetProcessHeap(),0,str);
1648 /* wait for the process to start and set an event or terminate */
1649 handles[0] = service_get_event_handle( hsvc->name );
1650 ZeroMemory(&si, sizeof(STARTUPINFOW));
1651 si.cb = sizeof(STARTUPINFOW);
1652 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1655 if (ppid) *ppid = pi.dwProcessId;
1657 handles[1] = pi.hProcess;
1658 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1659 if(ret != WAIT_OBJECT_0)
1661 SetLastError(ERROR_IO_PENDING);
1665 CloseHandle( pi.hThread );
1666 CloseHandle( pi.hProcess );
1668 CloseHandle( handles[0] );
1669 HeapFree(GetProcessHeap(),0,path);
1673 static BOOL service_wait_for_startup(SC_HANDLE hService)
1676 SERVICE_STATUS status;
1679 TRACE("%p\n", hService);
1681 for (i=0; i<30; i++)
1683 status.dwCurrentState = 0;
1684 r = QueryServiceStatus(hService, &status);
1687 if (status.dwCurrentState == SERVICE_RUNNING)
1689 TRACE("Service started successfully\n");
1698 /******************************************************************************
1699 * StartServiceW [ADVAPI32.@]
1701 * See StartServiceA.
1703 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1704 LPCWSTR *lpServiceArgVectors)
1706 struct sc_service *hsvc;
1709 HANDLE handle = INVALID_HANDLE_VALUE;
1711 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1713 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1716 SetLastError(ERROR_INVALID_HANDLE);
1720 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1724 handle = service_open_pipe(hsvc->name);
1725 if (handle==INVALID_HANDLE_VALUE)
1727 /* start the service process */
1728 if (service_start_process(hsvc, NULL))
1729 handle = service_open_pipe(hsvc->name);
1732 if (handle != INVALID_HANDLE_VALUE)
1734 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1735 CloseHandle(handle);
1738 UnlockServiceDatabase( hLock );
1740 TRACE("returning %d\n", r);
1743 service_wait_for_startup(hService);
1748 /******************************************************************************
1749 * QueryServiceStatus [ADVAPI32.@]
1752 * hService [I] Handle to service to get information about
1753 * lpservicestatus [O] buffer to receive the status information for the service
1756 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1757 LPSERVICE_STATUS lpservicestatus)
1759 SERVICE_STATUS_PROCESS SvcStatusData;
1762 TRACE("%p %p\n", hService, lpservicestatus);
1764 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1765 sizeof(SERVICE_STATUS_PROCESS), NULL);
1766 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1771 /******************************************************************************
1772 * QueryServiceStatusEx [ADVAPI32.@]
1774 * Get information about a service.
1777 * hService [I] Handle to service to get information about
1778 * InfoLevel [I] Level of information to get
1779 * lpBuffer [O] Destination for requested information
1780 * cbBufSize [I] Size of lpBuffer in bytes
1781 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1787 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1788 LPBYTE lpBuffer, DWORD cbBufSize,
1789 LPDWORD pcbBytesNeeded)
1791 struct sc_service *hsvc;
1792 DWORD size, type, val;
1795 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1797 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1799 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1801 SetLastError( ERROR_INVALID_LEVEL);
1805 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1806 if (pSvcStatusData == NULL)
1808 SetLastError( ERROR_INVALID_PARAMETER);
1812 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1814 if( pcbBytesNeeded != NULL)
1815 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1817 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1821 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1824 SetLastError( ERROR_INVALID_HANDLE );
1828 pipe = service_open_pipe(hsvc->name);
1829 if (pipe != INVALID_HANDLE_VALUE)
1831 r = service_get_status(pipe, pSvcStatusData);
1837 TRACE("Failed to read service status\n");
1839 /* read the service type from the registry */
1841 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1842 if (r != ERROR_SUCCESS || type != REG_DWORD)
1845 pSvcStatusData->dwServiceType = val;
1846 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1847 pSvcStatusData->dwControlsAccepted = 0;
1848 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1849 pSvcStatusData->dwServiceSpecificExitCode = 0;
1850 pSvcStatusData->dwCheckPoint = 0;
1851 pSvcStatusData->dwWaitHint = 0;
1856 /******************************************************************************
1857 * QueryServiceConfigA [ADVAPI32.@]
1859 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1860 DWORD size, LPDWORD needed )
1865 QUERY_SERVICE_CONFIGW *configW;
1867 TRACE("%p %p %d %p\n", hService, config, size, needed);
1869 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1871 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1874 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1875 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1876 if (!ret) goto done;
1878 config->dwServiceType = configW->dwServiceType;
1879 config->dwStartType = configW->dwStartType;
1880 config->dwErrorControl = configW->dwErrorControl;
1881 config->lpBinaryPathName = NULL;
1882 config->lpLoadOrderGroup = NULL;
1883 config->dwTagId = configW->dwTagId;
1884 config->lpDependencies = NULL;
1885 config->lpServiceStartName = NULL;
1886 config->lpDisplayName = NULL;
1888 p = (LPSTR)(config + 1);
1889 n = size - sizeof(*config);
1892 #define MAP_STR(str) \
1896 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1897 if (!sz) goto done; \
1904 MAP_STR( lpBinaryPathName );
1905 MAP_STR( lpLoadOrderGroup );
1906 MAP_STR( lpDependencies );
1907 MAP_STR( lpServiceStartName );
1908 MAP_STR( lpDisplayName );
1911 *needed = p - (LPSTR)config;
1915 HeapFree( GetProcessHeap(), 0, buffer );
1919 /******************************************************************************
1920 * QueryServiceConfigW [ADVAPI32.@]
1923 QueryServiceConfigW( SC_HANDLE hService,
1924 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1925 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1927 WCHAR str_buffer[ MAX_PATH ];
1929 DWORD type, val, sz, total, n;
1932 struct sc_service *hsvc;
1934 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1935 cbBufSize, pcbBytesNeeded);
1937 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1940 SetLastError( ERROR_INVALID_HANDLE );
1945 /* TODO: Check which members are mandatory and what the registry types
1946 * should be. This should of course also be tested when a service is
1950 /* calculate the size required first */
1951 total = sizeof (QUERY_SERVICE_CONFIGW);
1953 sz = sizeof(str_buffer);
1954 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1955 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1957 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1958 if( 0 == sz ) return FALSE;
1960 total += sizeof(WCHAR) * sz;
1964 /* FIXME: set last error */
1969 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1970 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1973 total += sizeof(WCHAR);
1976 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1977 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1980 total += sizeof(WCHAR);
1983 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1984 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1987 total += sizeof(WCHAR);
1990 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1991 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1994 total += sizeof(WCHAR);
1996 *pcbBytesNeeded = total;
1998 /* if there's not enough memory, return an error */
1999 if( total > cbBufSize )
2001 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2005 ZeroMemory( lpServiceConfig, total );
2008 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2009 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2010 lpServiceConfig->dwServiceType = val;
2013 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2014 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2015 lpServiceConfig->dwStartType = val;
2018 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2019 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2020 lpServiceConfig->dwErrorControl = val;
2023 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2024 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2025 lpServiceConfig->dwTagId = val;
2027 /* now do the strings */
2028 p = (LPBYTE) &lpServiceConfig[1];
2029 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2031 sz = sizeof(str_buffer);
2032 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2033 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2035 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2036 sz *= sizeof(WCHAR);
2037 if( 0 == sz || sz > n ) return FALSE;
2039 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2045 /* FIXME: set last error */
2050 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2051 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2052 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2065 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2066 lpServiceConfig->lpDependencies = (LPWSTR) p;
2067 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2080 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2081 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2082 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2095 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2096 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2097 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2110 ERR("Buffer overflow!\n");
2112 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2113 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2114 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2115 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2116 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2121 /******************************************************************************
2122 * EnumServicesStatusA [ADVAPI32.@]
2125 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2126 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2127 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2128 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2130 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2131 dwServiceType, dwServiceState, lpServices, cbBufSize,
2132 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2133 SetLastError (ERROR_ACCESS_DENIED);
2137 /******************************************************************************
2138 * EnumServicesStatusW [ADVAPI32.@]
2141 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2142 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2143 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2144 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2146 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2147 dwServiceType, dwServiceState, lpServices, cbBufSize,
2148 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2149 SetLastError (ERROR_ACCESS_DENIED);
2153 /******************************************************************************
2154 * EnumServicesStatusExA [ADVAPI32.@]
2157 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2158 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2159 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2161 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2162 dwServiceType, dwServiceState, lpServices, cbBufSize,
2163 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2164 SetLastError (ERROR_ACCESS_DENIED);
2168 /******************************************************************************
2169 * EnumServicesStatusExW [ADVAPI32.@]
2172 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2173 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2174 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2176 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2177 dwServiceType, dwServiceState, lpServices, cbBufSize,
2178 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2179 SetLastError (ERROR_ACCESS_DENIED);
2183 /******************************************************************************
2184 * GetServiceKeyNameA [ADVAPI32.@]
2186 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2187 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2189 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2193 /******************************************************************************
2194 * GetServiceKeyNameW [ADVAPI32.@]
2196 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2197 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2199 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2203 /******************************************************************************
2204 * QueryServiceLockStatusA [ADVAPI32.@]
2206 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2207 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2208 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2210 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2215 /******************************************************************************
2216 * QueryServiceLockStatusW [ADVAPI32.@]
2218 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2219 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2220 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2222 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2227 /******************************************************************************
2228 * GetServiceDisplayNameA [ADVAPI32.@]
2230 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2231 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2233 LPWSTR lpServiceNameW, lpDisplayNameW = NULL;
2234 DWORD size, sizeW, GLE;
2237 TRACE("%p %s %p %p\n", hSCManager,
2238 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2240 lpServiceNameW = SERV_dup(lpServiceName);
2241 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2243 size = sizeW = *lpcchBuffer;
2244 ret = GetServiceDisplayNameW(hSCManager, lpServiceNameW,
2245 lpDisplayName ? lpDisplayNameW : NULL,
2247 /* Last error will be set by GetServiceDisplayNameW and must be preserved */
2248 GLE = GetLastError();
2250 if (!lpDisplayName && *lpcchBuffer && !ret && (GLE == ERROR_INSUFFICIENT_BUFFER))
2252 /* Request for buffersize.
2254 * Only set the size for ERROR_INSUFFICIENT_BUFFER
2258 else if (lpDisplayName && *lpcchBuffer && !ret)
2260 /* Request for displayname.
2262 * size only has to be set if this fails
2267 WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2268 *lpcchBuffer, NULL, NULL );
2270 *lpcchBuffer = size;
2272 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2273 SERV_free(lpServiceNameW);
2279 /******************************************************************************
2280 * GetServiceDisplayNameW [ADVAPI32.@]
2282 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2283 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2285 struct sc_manager *hscm;
2289 TRACE("%p %s %p %p\n", hSCManager,
2290 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2292 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2295 SetLastError(ERROR_INVALID_HANDLE);
2301 SetLastError(ERROR_INVALID_ADDRESS);
2305 size = *lpcchBuffer * sizeof(WCHAR);
2306 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2307 if (!ret && !lpDisplayName && size)
2308 ret = ERROR_MORE_DATA;
2312 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2314 if (ret == ERROR_MORE_DATA)
2316 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2317 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2319 else if (ret == ERROR_FILE_NOT_FOUND)
2323 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2325 INT len = lstrlenW(lpServiceName);
2328 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2329 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2330 else if (lpDisplayName && *lpcchBuffer)
2332 /* No displayname, but the service exists and the buffer
2333 * is big enough. We should return the servicename.
2335 lstrcpyW(lpDisplayName, lpServiceName);
2344 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2351 /* Always return the correct needed size on success */
2352 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2357 /******************************************************************************
2358 * ChangeServiceConfigW [ADVAPI32.@]
2360 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2361 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2362 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2363 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2365 struct reg_value val[10];
2366 struct sc_service *hsvc;
2367 DWORD r = ERROR_SUCCESS;
2371 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2372 hService, dwServiceType, dwStartType, dwErrorControl,
2373 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2374 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2375 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2377 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2380 SetLastError( ERROR_INVALID_HANDLE );
2385 if( dwServiceType != SERVICE_NO_CHANGE )
2386 service_set_dword( &val[n++], szType, &dwServiceType );
2388 if( dwStartType != SERVICE_NO_CHANGE )
2389 service_set_dword( &val[n++], szStart, &dwStartType );
2391 if( dwErrorControl != SERVICE_NO_CHANGE )
2392 service_set_dword( &val[n++], szError, &dwErrorControl );
2394 if( lpBinaryPathName )
2395 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2397 if( lpLoadOrderGroup )
2398 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2400 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2401 * There is no such key as what szDependencies refers to */
2402 if( lpDependencies )
2403 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2406 FIXME("ignoring password\n");
2408 if( lpServiceStartName )
2409 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2411 r = service_write_values( hsvc->hkey, val, n );
2413 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2416 /******************************************************************************
2417 * ChangeServiceConfigA [ADVAPI32.@]
2419 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2420 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2421 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2422 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2424 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2425 LPWSTR wServiceStartName, wPassword, wDisplayName;
2428 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2429 hService, dwServiceType, dwStartType, dwErrorControl,
2430 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2431 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2432 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2434 wBinaryPathName = SERV_dup( lpBinaryPathName );
2435 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2436 wDependencies = SERV_dupmulti( lpDependencies );
2437 wServiceStartName = SERV_dup( lpServiceStartName );
2438 wPassword = SERV_dup( lpPassword );
2439 wDisplayName = SERV_dup( lpDisplayName );
2441 r = ChangeServiceConfigW( hService, dwServiceType,
2442 dwStartType, dwErrorControl, wBinaryPathName,
2443 wLoadOrderGroup, lpdwTagId, wDependencies,
2444 wServiceStartName, wPassword, wDisplayName);
2446 SERV_free( wBinaryPathName );
2447 SERV_free( wLoadOrderGroup );
2448 SERV_free( wDependencies );
2449 SERV_free( wServiceStartName );
2450 SERV_free( wPassword );
2451 SERV_free( wDisplayName );
2456 /******************************************************************************
2457 * ChangeServiceConfig2A [ADVAPI32.@]
2459 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2464 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2466 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2468 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2469 SERVICE_DESCRIPTIONW sdw;
2471 sdw.lpDescription = SERV_dup( sd->lpDescription );
2473 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2475 SERV_free( sdw.lpDescription );
2477 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2479 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2480 SERVICE_FAILURE_ACTIONSW faw;
2482 faw.dwResetPeriod = fa->dwResetPeriod;
2483 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2484 faw.lpCommand = SERV_dup( fa->lpCommand );
2485 faw.cActions = fa->cActions;
2486 faw.lpsaActions = fa->lpsaActions;
2488 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2490 SERV_free( faw.lpRebootMsg );
2491 SERV_free( faw.lpCommand );
2494 SetLastError( ERROR_INVALID_PARAMETER );
2499 /******************************************************************************
2500 * ChangeServiceConfig2W [ADVAPI32.@]
2502 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2506 struct sc_service *hsvc;
2508 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2511 SetLastError( ERROR_INVALID_HANDLE );
2516 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2518 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2519 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2520 if (sd->lpDescription)
2522 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2523 if (sd->lpDescription[0] == 0)
2524 RegDeleteValueW(hKey,szDescription);
2526 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2527 (LPVOID)sd->lpDescription,
2528 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2532 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2536 /******************************************************************************
2537 * QueryServiceObjectSecurity [ADVAPI32.@]
2539 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2540 SECURITY_INFORMATION dwSecurityInformation,
2541 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2542 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2546 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2547 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2549 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2551 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2552 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2553 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2557 /******************************************************************************
2558 * SetServiceObjectSecurity [ADVAPI32.@]
2560 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2561 SECURITY_INFORMATION dwSecurityInformation,
2562 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2564 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2568 /******************************************************************************
2569 * SetServiceBits [ADVAPI32.@]
2571 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2572 DWORD dwServiceBits,
2574 BOOL bUpdateImmediately)
2576 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2577 bSetBitsOn, bUpdateImmediately);
2581 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2582 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2584 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2588 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2589 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2591 service_data *service;
2592 SERVICE_STATUS_HANDLE handle = 0;
2594 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2596 EnterCriticalSection( &service_cs );
2597 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2599 if(!strcmpW(lpServiceName, service->name))
2601 service->handler.handler_ex = lpHandlerProc;
2602 service->context = lpContext;
2603 service->extended = TRUE;
2604 handle = (SERVICE_STATUS_HANDLE)service;
2608 LeaveCriticalSection( &service_cs );