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 (same behaviour as strdup)
201 * NOTE: the caller of those functions is responsible for calling HeapFree
202 * in order to release the memory allocated by those functions.
204 static inline LPWSTR SERV_dup( LPCSTR str )
211 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
212 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
213 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
217 static inline LPWSTR SERV_dupmulti(LPCSTR str)
225 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
226 n += (strlen( &str[n] ) + 1);
231 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
232 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
236 /******************************************************************************
237 * registry access functions and data
239 static const WCHAR szDisplayName[] = {
240 'D','i','s','p','l','a','y','N','a','m','e', 0 };
241 static const WCHAR szType[] = {'T','y','p','e',0};
242 static const WCHAR szStart[] = {'S','t','a','r','t',0};
243 static const WCHAR szError[] = {
244 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
245 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
246 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
247 static const WCHAR szDependencies[] = {
248 'D','e','p','e','n','d','e','n','c','i','e','s',0};
249 static const WCHAR szDependOnService[] = {
250 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
251 static const WCHAR szObjectName[] = {
252 'O','b','j','e','c','t','N','a','m','e',0};
253 static const WCHAR szTag[] = {
263 static inline void service_set_value( struct reg_value *val,
264 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
272 static inline void service_set_dword( struct reg_value *val,
273 LPCWSTR name, const DWORD *data )
275 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
278 static inline void service_set_string( struct reg_value *val,
279 LPCWSTR name, LPCWSTR string )
281 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
282 service_set_value( val, REG_SZ, name, string, len );
285 static inline void service_set_multi_string( struct reg_value *val,
286 LPCWSTR name, LPCWSTR string )
290 /* determine the length of a double null terminated multi string */
292 len += (lstrlenW( &string[ len ] )+1);
293 } while ( string[ len++ ] );
295 len *= sizeof (WCHAR);
296 service_set_value( val, REG_MULTI_SZ, name, string, len );
299 static inline LONG service_write_values( HKEY hKey,
300 const struct reg_value *val, int n )
302 LONG r = ERROR_SUCCESS;
307 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
308 (const BYTE*)val[i].data, val[i].size );
309 if( r != ERROR_SUCCESS )
315 /******************************************************************************
316 * Service IPC functions
318 static LPWSTR service_get_pipe_name(LPCWSTR service)
320 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
321 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
325 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
326 name = HeapAlloc(GetProcessHeap(), 0, len);
327 strcpyW(name, prefix);
328 strcatW(name, service);
332 static HANDLE service_open_pipe(LPCWSTR service)
334 LPWSTR szPipe = service_get_pipe_name( service );
335 HANDLE handle = INVALID_HANDLE_VALUE;
338 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
339 0, NULL, OPEN_ALWAYS, 0, NULL);
340 if (handle != INVALID_HANDLE_VALUE)
342 if (GetLastError() != ERROR_PIPE_BUSY)
344 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
345 HeapFree(GetProcessHeap(), 0, szPipe);
350 /******************************************************************************
351 * service_get_event_handle
353 static HANDLE service_get_event_handle(LPCWSTR service)
355 static const WCHAR prefix[] = {
356 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
361 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
362 name = HeapAlloc(GetProcessHeap(), 0, len);
363 strcpyW(name, prefix);
364 strcatW(name, service);
365 handle = CreateEventW(NULL, TRUE, FALSE, name);
366 HeapFree(GetProcessHeap(), 0, name);
370 /******************************************************************************
373 * Call into the main service routine provided by StartServiceCtrlDispatcher.
375 static DWORD WINAPI service_thread(LPVOID arg)
377 service_data *info = arg;
378 LPWSTR str = info->args;
379 DWORD argc = 0, len = 0;
385 len += strlenW(&str[len]) + 1;
392 info->proc.w(0, NULL);
394 info->proc.a(0, NULL);
402 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
403 for (argc=0, p=str; *p; p += strlenW(p) + 1)
407 info->proc.w(argc, argv);
408 HeapFree(GetProcessHeap(), 0, argv);
412 LPSTR strA, *argv, p;
415 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
416 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
417 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
419 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
420 for (argc=0, p=strA; *p; p += strlen(p) + 1)
424 info->proc.a(argc, argv);
425 HeapFree(GetProcessHeap(), 0, argv);
426 HeapFree(GetProcessHeap(), 0, strA);
431 /******************************************************************************
432 * service_handle_start
434 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
436 DWORD read = 0, result = 0;
440 TRACE("%p %p %d\n", pipe, service, count);
442 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
443 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
444 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
446 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
447 r, count, read, debugstr_wn(args, count));
453 WARN("service is not stopped\n");
454 result = ERROR_SERVICE_ALREADY_RUNNING;
458 HeapFree(GetProcessHeap(), 0, service->args);
459 service->args = args;
461 service->thread = CreateThread( NULL, 0, service_thread,
465 HeapFree(GetProcessHeap(), 0, args);
466 WriteFile( pipe, &result, sizeof result, &read, NULL );
471 /******************************************************************************
472 * service_send_start_message
474 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
476 DWORD i, len, count, result;
477 service_start_info *ssi;
481 TRACE("%p %p %d\n", pipe, argv, argc);
483 /* calculate how much space do we need to send the startup info */
485 for (i=0; i<argc; i++)
486 len += strlenW(argv[i])+1;
488 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
489 ssi->cmd = WINESERV_STARTINFO;
492 /* copy service args into a single buffer*/
494 for (i=0; i<argc; i++)
501 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
504 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
507 SetLastError(result);
512 HeapFree(GetProcessHeap(),0,ssi);
517 /******************************************************************************
518 * service_handle_get_status
520 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
524 return WriteFile(pipe, &service->status,
525 sizeof service->status, &count, NULL);
528 /******************************************************************************
531 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
533 DWORD cmd[2], count = 0;
536 cmd[0] = WINESERV_GETSTATUS;
538 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
539 if (!r || count != sizeof cmd)
541 ERR("service protocol error - failed to write pipe!\n");
544 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
545 if (!r || count != sizeof *status)
546 ERR("service protocol error - failed to read pipe "
547 "r = %d count = %d!\n", r, count);
551 /******************************************************************************
552 * service_send_control
554 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
556 DWORD cmd[2], count = 0;
559 cmd[0] = WINESERV_SENDCONTROL;
561 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
562 if (!r || count != sizeof cmd)
564 ERR("service protocol error - failed to write pipe!\n");
567 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
568 if (!r || count != sizeof *result)
569 ERR("service protocol error - failed to read pipe "
570 "r = %d count = %d!\n", r, count);
574 /******************************************************************************
575 * service_accepts_control
577 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
579 DWORD a = service->status.dwControlsAccepted;
583 case SERVICE_CONTROL_INTERROGATE:
585 case SERVICE_CONTROL_STOP:
586 if (a&SERVICE_ACCEPT_STOP)
589 case SERVICE_CONTROL_SHUTDOWN:
590 if (a&SERVICE_ACCEPT_SHUTDOWN)
593 case SERVICE_CONTROL_PAUSE:
594 case SERVICE_CONTROL_CONTINUE:
595 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
598 case SERVICE_CONTROL_PARAMCHANGE:
599 if (a&SERVICE_ACCEPT_PARAMCHANGE)
602 case SERVICE_CONTROL_NETBINDADD:
603 case SERVICE_CONTROL_NETBINDREMOVE:
604 case SERVICE_CONTROL_NETBINDENABLE:
605 case SERVICE_CONTROL_NETBINDDISABLE:
606 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
609 if (!service->extended)
613 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
614 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
617 case SERVICE_CONTROL_POWEREVENT:
618 if (a&SERVICE_ACCEPT_POWEREVENT)
621 case SERVICE_CONTROL_SESSIONCHANGE:
622 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
629 /******************************************************************************
630 * service_handle_control
632 static BOOL service_handle_control(HANDLE pipe, service_data *service,
635 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
637 TRACE("received control %d\n", dwControl);
639 if (service_accepts_control(service, dwControl))
641 if (service->extended && service->handler.handler_ex)
643 service->handler.handler_ex(dwControl, 0, NULL, service->context);
646 else if (service->handler.handler)
648 service->handler.handler(dwControl);
652 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
655 /******************************************************************************
656 * service_reap_thread
658 static DWORD service_reap_thread(service_data *service)
662 if (!service->thread)
664 GetExitCodeThread(service->thread, &exitcode);
665 if (exitcode!=STILL_ACTIVE)
667 CloseHandle(service->thread);
673 /******************************************************************************
674 * service_control_dispatcher
676 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
678 service_data *service = arg;
682 TRACE("%p %s\n", service, debugstr_w(service->name));
684 /* create a pipe to talk to the rest of the world with */
685 name = service_get_pipe_name(service->name);
686 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
687 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
688 HeapFree(GetProcessHeap(), 0, name);
690 /* let the process who started us know we've tried to create a pipe */
691 event = service_get_event_handle(service->name);
695 if (pipe==INVALID_HANDLE_VALUE)
697 ERR("failed to create pipe for %s, error = %d\n",
698 debugstr_w(service->name), GetLastError());
702 /* dispatcher loop */
706 DWORD count, req[2] = {0,0};
708 r = ConnectNamedPipe(pipe, NULL);
709 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
711 ERR("pipe connect failed\n");
715 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
716 if (!r || count!=sizeof req)
718 ERR("pipe read failed\n");
722 service_reap_thread(service);
724 /* handle the request */
727 case WINESERV_STARTINFO:
728 service_handle_start(pipe, service, req[1]);
730 case WINESERV_GETSTATUS:
731 service_handle_get_status(pipe, service);
733 case WINESERV_SENDCONTROL:
734 service_handle_control(pipe, service, req[1]);
737 ERR("received invalid command %d length %d\n", req[0], req[1]);
740 FlushFileBuffers(pipe);
741 DisconnectNamedPipe(pipe);
748 /******************************************************************************
749 * service_run_threads
751 static BOOL service_run_threads(void)
753 service_data *service;
757 EnterCriticalSection( &service_cs );
759 count = list_count( &service_list );
761 TRACE("Starting %d pipe listener threads. Services running as process %d\n", count, GetCurrentProcessId());
763 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
765 handles[n++] = __wine_make_process_system();
767 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
769 service->status.dwProcessId = GetCurrentProcessId();
770 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
773 assert(n == count + 1);
775 LeaveCriticalSection( &service_cs );
777 /* wait for all the threads to pack up and exit */
780 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
781 if (!ret) /* system process event */
783 TRACE( "last user process exited, shutting down\n" );
784 /* FIXME: we should maybe send a shutdown control to running services */
787 if (ret < MAXIMUM_WAIT_OBJECTS)
789 CloseHandle( handles[ret] );
790 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
796 while (n) CloseHandle( handles[--n] );
797 HeapFree(GetProcessHeap(), 0, handles);
802 /******************************************************************************
803 * StartServiceCtrlDispatcherA [ADVAPI32.@]
805 * See StartServiceCtrlDispatcherW.
807 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
813 TRACE("%p\n", servent);
815 EnterCriticalSection( &service_cs );
816 while (servent->lpServiceName)
818 LPSTR name = servent->lpServiceName;
820 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
821 sz = len*sizeof(WCHAR) + sizeof *info;
822 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
823 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
824 info->proc.a = servent->lpServiceProc;
825 info->unicode = FALSE;
826 list_add_head( &service_list, &info->entry );
829 LeaveCriticalSection( &service_cs );
831 service_run_threads();
836 /******************************************************************************
837 * StartServiceCtrlDispatcherW [ADVAPI32.@]
839 * Connects a process containing one or more services to the service control
843 * servent [I] A list of the service names and service procedures
849 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
855 TRACE("%p\n", servent);
857 EnterCriticalSection( &service_cs );
858 while (servent->lpServiceName)
860 LPWSTR name = servent->lpServiceName;
863 sz = len*sizeof(WCHAR) + sizeof *info;
864 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
865 strcpyW(info->name, name);
866 info->proc.w = servent->lpServiceProc;
867 info->unicode = TRUE;
868 list_add_head( &service_list, &info->entry );
871 LeaveCriticalSection( &service_cs );
873 service_run_threads();
878 /******************************************************************************
879 * LockServiceDatabase [ADVAPI32.@]
881 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
885 TRACE("%p\n",hSCManager);
887 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
888 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
892 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
895 TRACE("returning %p\n", ret);
900 /******************************************************************************
901 * UnlockServiceDatabase [ADVAPI32.@]
903 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
905 TRACE("%p\n",ScLock);
907 return CloseHandle( ScLock );
910 /******************************************************************************
911 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
913 SERVICE_STATUS_HANDLE WINAPI
914 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
916 LPWSTR lpServiceNameW;
917 SERVICE_STATUS_HANDLE ret;
919 lpServiceNameW = SERV_dup(lpServiceName);
920 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
921 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
925 /******************************************************************************
926 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
932 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
933 LPHANDLER_FUNCTION lpfHandler )
935 service_data *service;
936 SERVICE_STATUS_HANDLE handle = 0;
938 EnterCriticalSection( &service_cs );
939 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
941 if(!strcmpW(lpServiceName, service->name))
943 service->handler.handler = lpfHandler;
944 handle = (SERVICE_STATUS_HANDLE)service;
948 LeaveCriticalSection( &service_cs );
952 /******************************************************************************
953 * SetServiceStatus [ADVAPI32.@]
960 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
962 service_data *service;
965 TRACE("%p %x %x %x %x %x %x %x\n", hService,
966 lpStatus->dwServiceType, lpStatus->dwCurrentState,
967 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
968 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
969 lpStatus->dwWaitHint);
971 EnterCriticalSection( &service_cs );
972 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
974 if(service == (service_data*)hService)
976 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
977 TRACE("Set service status to %d\n",service->status.dwCurrentState);
982 LeaveCriticalSection( &service_cs );
988 /******************************************************************************
989 * OpenSCManagerA [ADVAPI32.@]
991 * Establish a connection to the service control manager and open its database.
994 * lpMachineName [I] Pointer to machine name string
995 * lpDatabaseName [I] Pointer to database name string
996 * dwDesiredAccess [I] Type of access
999 * Success: A Handle to the service control manager database
1002 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1003 DWORD dwDesiredAccess )
1005 LPWSTR lpMachineNameW, lpDatabaseNameW;
1008 lpMachineNameW = SERV_dup(lpMachineName);
1009 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1010 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1011 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
1012 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
1016 /******************************************************************************
1017 * OpenSCManagerW [ADVAPI32.@]
1019 * See OpenSCManagerA.
1021 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1022 DWORD dwDesiredAccess )
1024 struct sc_manager *manager;
1027 DWORD new_mask = dwDesiredAccess;
1029 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1030 debugstr_w(lpDatabaseName), dwDesiredAccess);
1032 if( lpDatabaseName && lpDatabaseName[0] )
1034 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1036 /* noop, all right */
1038 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1040 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1045 SetLastError( ERROR_INVALID_NAME );
1050 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1051 sc_handle_destroy_manager );
1055 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1056 if (r!=ERROR_SUCCESS)
1059 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1060 RegCloseKey( hReg );
1061 if (r!=ERROR_SUCCESS)
1064 RtlMapGenericMask(&new_mask, &scm_generic);
1065 manager->dwAccess = new_mask;
1066 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1068 return (SC_HANDLE) &manager->hdr;
1071 sc_handle_free( &manager->hdr );
1076 /******************************************************************************
1077 * ControlService [ADVAPI32.@]
1079 * Send a control code to a service.
1082 * hService [I] Handle of the service control manager database
1083 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1084 * lpServiceStatus [O] Destination for the status of the service, if available
1091 * Unlike M$' implementation, control requests are not serialized and may be
1092 * processed asynchronously.
1094 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1095 LPSERVICE_STATUS lpServiceStatus )
1097 struct sc_service *hsvc;
1101 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1103 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1106 SetLastError( ERROR_INVALID_HANDLE );
1110 ret = QueryServiceStatus(hService, lpServiceStatus);
1113 ERR("failed to query service status\n");
1114 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1118 switch (lpServiceStatus->dwCurrentState)
1120 case SERVICE_STOPPED:
1121 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1123 case SERVICE_START_PENDING:
1124 if (dwControl==SERVICE_CONTROL_STOP)
1127 case SERVICE_STOP_PENDING:
1128 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1132 handle = service_open_pipe(hsvc->name);
1133 if (handle!=INVALID_HANDLE_VALUE)
1135 DWORD result = ERROR_SUCCESS;
1136 ret = service_send_control(handle, dwControl, &result);
1137 CloseHandle(handle);
1138 if (result!=ERROR_SUCCESS)
1140 SetLastError(result);
1148 /******************************************************************************
1149 * CloseServiceHandle [ADVAPI32.@]
1151 * Close a handle to a service or the service control manager database.
1154 * hSCObject [I] Handle to service or service control manager database
1161 CloseServiceHandle( SC_HANDLE hSCObject )
1163 TRACE("%p\n", hSCObject);
1165 sc_handle_free( (struct sc_handle*) hSCObject );
1171 /******************************************************************************
1172 * OpenServiceA [ADVAPI32.@]
1174 * Open a handle to a service.
1177 * hSCManager [I] Handle of the service control manager database
1178 * lpServiceName [I] Name of the service to open
1179 * dwDesiredAccess [I] Access required to the service
1182 * Success: Handle to the service
1185 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1186 DWORD dwDesiredAccess )
1188 LPWSTR lpServiceNameW;
1191 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1193 lpServiceNameW = SERV_dup(lpServiceName);
1194 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1195 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1200 /******************************************************************************
1201 * OpenServiceW [ADVAPI32.@]
1205 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1206 DWORD dwDesiredAccess)
1208 struct sc_manager *hscm;
1209 struct sc_service *hsvc;
1213 DWORD new_mask = dwDesiredAccess;
1215 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1217 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1220 SetLastError( ERROR_INVALID_HANDLE );
1226 SetLastError(ERROR_INVALID_ADDRESS);
1230 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1231 if (r!=ERROR_SUCCESS)
1233 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1237 len = strlenW(lpServiceName)+1;
1238 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1239 sizeof (struct sc_service) + len*sizeof(WCHAR),
1240 sc_handle_destroy_service );
1246 strcpyW( hsvc->name, lpServiceName );
1249 RtlMapGenericMask(&new_mask, &svc_generic);
1250 hsvc->dwAccess = new_mask;
1252 /* add reference to SCM handle */
1253 hscm->hdr.ref_count++;
1256 TRACE("returning %p\n",hsvc);
1258 return (SC_HANDLE) &hsvc->hdr;
1261 /******************************************************************************
1262 * CreateServiceW [ADVAPI32.@]
1265 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1266 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1267 DWORD dwServiceType, DWORD dwStartType,
1268 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1269 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1270 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1271 LPCWSTR lpPassword )
1273 struct sc_manager *hscm;
1274 struct sc_service *hsvc = NULL;
1278 struct reg_value val[10];
1280 DWORD new_mask = dwDesiredAccess;
1282 WCHAR buffer[MAX_PATH];
1283 BOOL displayname_exists = FALSE;
1285 TRACE("%p %s %s\n", hSCManager,
1286 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1288 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1291 SetLastError( ERROR_INVALID_HANDLE );
1295 if (!lpServiceName || !lpBinaryPathName)
1297 SetLastError(ERROR_INVALID_ADDRESS);
1301 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1303 SetLastError(ERROR_ACCESS_DENIED);
1307 if (!lpServiceName[0])
1309 SetLastError(ERROR_INVALID_NAME);
1313 if (!lpBinaryPathName[0])
1315 SetLastError(ERROR_INVALID_PARAMETER);
1319 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1320 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1321 * runs under the LocalSystem account)
1323 switch (dwServiceType)
1325 case SERVICE_KERNEL_DRIVER:
1326 case SERVICE_FILE_SYSTEM_DRIVER:
1327 case SERVICE_WIN32_OWN_PROCESS:
1328 case SERVICE_WIN32_SHARE_PROCESS:
1331 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1332 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1333 /* FIXME : Do we need a more thorough check? */
1334 if (lpServiceStartName)
1336 SetLastError(ERROR_INVALID_PARAMETER);
1341 SetLastError(ERROR_INVALID_PARAMETER);
1345 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1346 if (dwStartType > SERVICE_DISABLED)
1348 SetLastError(ERROR_INVALID_PARAMETER);
1352 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1353 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1354 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1356 SetLastError(ERROR_INVALID_PARAMETER);
1360 /* Loop through the registry to check if the service already exists and to
1361 * check if we can use the given displayname.
1362 * FIXME: Should we use EnumServicesStatusEx?
1364 len = sizeof(buffer);
1365 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1369 /* The service already exists, so bail out */
1370 if(!lstrcmpiW(lpServiceName, buffer))
1372 SetLastError(ERROR_SERVICE_EXISTS);
1376 /* The given displayname matches the found servicename. We don't bail out
1377 * as servicename is checked before a duplicate displayname
1379 if(!lstrcmpiW(lpDisplayName, buffer))
1380 displayname_exists = TRUE;
1382 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1384 WCHAR name[MAX_PATH];
1385 DWORD size = sizeof(name);
1387 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1389 /* The given displayname matches the found displayname */
1390 if (!lstrcmpiW(lpDisplayName, name))
1391 displayname_exists = TRUE;
1393 RegCloseKey(service_key);
1396 len = sizeof(buffer);
1399 if (lpDisplayName && displayname_exists)
1401 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1405 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1406 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1407 if (r!=ERROR_SUCCESS)
1409 /* FIXME: Should we set an error? */
1414 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1416 service_set_dword( &val[n++], szType, &dwServiceType );
1417 service_set_dword( &val[n++], szStart, &dwStartType );
1418 service_set_dword( &val[n++], szError, &dwErrorControl );
1420 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1422 if( lpLoadOrderGroup )
1423 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1425 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1426 * There is no such key as what szDependencies refers to */
1427 if( lpDependencies )
1428 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1431 FIXME("Don't know how to add a Password for a service.\n");
1433 if( lpServiceStartName )
1434 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1436 r = service_write_values( hKey, val, n );
1437 if( r != ERROR_SUCCESS )
1440 len = strlenW(lpServiceName)+1;
1441 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1442 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1445 lstrcpyW( hsvc->name, lpServiceName );
1448 RtlMapGenericMask(&new_mask, &svc_generic);
1449 hsvc->dwAccess = new_mask;
1452 hscm->hdr.ref_count++;
1454 return (SC_HANDLE) &hsvc->hdr;
1457 RegCloseKey( hKey );
1462 /******************************************************************************
1463 * CreateServiceA [ADVAPI32.@]
1466 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1467 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1468 DWORD dwServiceType, DWORD dwStartType,
1469 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1470 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1471 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1474 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1475 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1478 TRACE("%p %s %s\n", hSCManager,
1479 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1481 lpServiceNameW = SERV_dup( lpServiceName );
1482 lpDisplayNameW = SERV_dup( lpDisplayName );
1483 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1484 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1485 lpDependenciesW = SERV_dupmulti( lpDependencies );
1486 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1487 lpPasswordW = SERV_dup( lpPassword );
1489 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1490 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1491 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1492 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1494 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1495 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1496 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1497 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1498 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1499 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1500 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1506 /******************************************************************************
1507 * DeleteService [ADVAPI32.@]
1509 * Delete a service from the service control manager database.
1512 * hService [I] Handle of the service to delete
1518 BOOL WINAPI DeleteService( SC_HANDLE hService )
1520 struct sc_service *hsvc;
1522 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1525 SetLastError( ERROR_INVALID_HANDLE );
1529 if (!(hsvc->dwAccess & DELETE))
1531 SetLastError(ERROR_ACCESS_DENIED);
1535 /* Close the key to the service */
1536 RegCloseKey(hsvc->hkey);
1538 /* Delete the service under the Service Control Manager key */
1539 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1547 /******************************************************************************
1548 * StartServiceA [ADVAPI32.@]
1553 * hService [I] Handle of service
1554 * dwNumServiceArgs [I] Number of arguments
1555 * lpServiceArgVectors [I] Address of array of argument strings
1558 * - NT implements this function using an obscure RPC call.
1559 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1560 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1561 * - This will only work for shared address space. How should the service
1562 * args be transferred when address spaces are separated?
1563 * - Can only start one service at a time.
1564 * - Has no concept of privilege.
1570 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1571 LPCSTR *lpServiceArgVectors )
1573 LPWSTR *lpwstr=NULL;
1577 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1579 if (dwNumServiceArgs)
1580 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1581 dwNumServiceArgs*sizeof(LPWSTR) );
1583 for(i=0; i<dwNumServiceArgs; i++)
1584 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1586 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1588 if (dwNumServiceArgs)
1590 for(i=0; i<dwNumServiceArgs; i++)
1591 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1592 HeapFree(GetProcessHeap(), 0, lpwstr);
1598 /******************************************************************************
1599 * service_start_process [INTERNAL]
1601 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1603 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1604 PROCESS_INFORMATION pi;
1606 LPWSTR path = NULL, str;
1607 DWORD type, size, ret, svc_type;
1611 size = sizeof(svc_type);
1612 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1615 if (svc_type == SERVICE_KERNEL_DRIVER)
1617 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1618 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1620 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1621 GetSystemDirectoryW( path, len );
1622 lstrcatW( path, winedeviceW );
1623 lstrcatW( path, hsvc->name );
1627 /* read the executable path from the registry */
1629 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1630 if (ret!=ERROR_SUCCESS)
1632 str = HeapAlloc(GetProcessHeap(),0,size);
1633 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1634 if (ret==ERROR_SUCCESS)
1636 size = ExpandEnvironmentStringsW(str,NULL,0);
1637 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1638 ExpandEnvironmentStringsW(str,path,size);
1640 HeapFree(GetProcessHeap(),0,str);
1645 /* wait for the process to start and set an event or terminate */
1646 handles[0] = service_get_event_handle( hsvc->name );
1647 ZeroMemory(&si, sizeof(STARTUPINFOW));
1648 si.cb = sizeof(STARTUPINFOW);
1649 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1652 if (ppid) *ppid = pi.dwProcessId;
1654 handles[1] = pi.hProcess;
1655 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1656 if(ret != WAIT_OBJECT_0)
1658 SetLastError(ERROR_IO_PENDING);
1662 CloseHandle( pi.hThread );
1663 CloseHandle( pi.hProcess );
1665 CloseHandle( handles[0] );
1666 HeapFree(GetProcessHeap(),0,path);
1670 static BOOL service_wait_for_startup(SC_HANDLE hService)
1673 SERVICE_STATUS status;
1676 TRACE("%p\n", hService);
1678 for (i=0; i<30; i++)
1680 status.dwCurrentState = 0;
1681 r = QueryServiceStatus(hService, &status);
1684 if (status.dwCurrentState == SERVICE_RUNNING)
1686 TRACE("Service started successfully\n");
1695 /******************************************************************************
1696 * StartServiceW [ADVAPI32.@]
1698 * See StartServiceA.
1700 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1701 LPCWSTR *lpServiceArgVectors)
1703 struct sc_service *hsvc;
1706 HANDLE handle = INVALID_HANDLE_VALUE;
1708 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1710 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1713 SetLastError(ERROR_INVALID_HANDLE);
1717 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1721 handle = service_open_pipe(hsvc->name);
1722 if (handle==INVALID_HANDLE_VALUE)
1724 /* start the service process */
1725 if (service_start_process(hsvc, NULL))
1726 handle = service_open_pipe(hsvc->name);
1729 if (handle != INVALID_HANDLE_VALUE)
1731 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1732 CloseHandle(handle);
1735 UnlockServiceDatabase( hLock );
1737 TRACE("returning %d\n", r);
1740 service_wait_for_startup(hService);
1745 /******************************************************************************
1746 * QueryServiceStatus [ADVAPI32.@]
1749 * hService [I] Handle to service to get information about
1750 * lpservicestatus [O] buffer to receive the status information for the service
1753 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1754 LPSERVICE_STATUS lpservicestatus)
1756 SERVICE_STATUS_PROCESS SvcStatusData;
1759 TRACE("%p %p\n", hService, lpservicestatus);
1761 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1762 sizeof(SERVICE_STATUS_PROCESS), NULL);
1763 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1768 /******************************************************************************
1769 * QueryServiceStatusEx [ADVAPI32.@]
1771 * Get information about a service.
1774 * hService [I] Handle to service to get information about
1775 * InfoLevel [I] Level of information to get
1776 * lpBuffer [O] Destination for requested information
1777 * cbBufSize [I] Size of lpBuffer in bytes
1778 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1784 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1785 LPBYTE lpBuffer, DWORD cbBufSize,
1786 LPDWORD pcbBytesNeeded)
1788 struct sc_service *hsvc;
1789 DWORD size, type, val;
1792 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1794 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1796 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1798 SetLastError( ERROR_INVALID_LEVEL);
1802 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1803 if (pSvcStatusData == NULL)
1805 SetLastError( ERROR_INVALID_PARAMETER);
1809 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1811 if( pcbBytesNeeded != NULL)
1812 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1814 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1818 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1821 SetLastError( ERROR_INVALID_HANDLE );
1825 pipe = service_open_pipe(hsvc->name);
1826 if (pipe != INVALID_HANDLE_VALUE)
1828 r = service_get_status(pipe, pSvcStatusData);
1834 TRACE("Failed to read service status\n");
1836 /* read the service type from the registry */
1838 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1839 if (r != ERROR_SUCCESS || type != REG_DWORD)
1842 pSvcStatusData->dwServiceType = val;
1843 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1844 pSvcStatusData->dwControlsAccepted = 0;
1845 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1846 pSvcStatusData->dwServiceSpecificExitCode = 0;
1847 pSvcStatusData->dwCheckPoint = 0;
1848 pSvcStatusData->dwWaitHint = 0;
1853 /******************************************************************************
1854 * QueryServiceConfigA [ADVAPI32.@]
1856 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1857 DWORD size, LPDWORD needed )
1862 QUERY_SERVICE_CONFIGW *configW;
1864 TRACE("%p %p %d %p\n", hService, config, size, needed);
1866 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1868 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1871 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1872 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1873 if (!ret) goto done;
1875 config->dwServiceType = configW->dwServiceType;
1876 config->dwStartType = configW->dwStartType;
1877 config->dwErrorControl = configW->dwErrorControl;
1878 config->lpBinaryPathName = NULL;
1879 config->lpLoadOrderGroup = NULL;
1880 config->dwTagId = configW->dwTagId;
1881 config->lpDependencies = NULL;
1882 config->lpServiceStartName = NULL;
1883 config->lpDisplayName = NULL;
1885 p = (LPSTR)(config + 1);
1886 n = size - sizeof(*config);
1889 #define MAP_STR(str) \
1893 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1894 if (!sz) goto done; \
1901 MAP_STR( lpBinaryPathName );
1902 MAP_STR( lpLoadOrderGroup );
1903 MAP_STR( lpDependencies );
1904 MAP_STR( lpServiceStartName );
1905 MAP_STR( lpDisplayName );
1908 *needed = p - (LPSTR)config;
1912 HeapFree( GetProcessHeap(), 0, buffer );
1916 /******************************************************************************
1917 * QueryServiceConfigW [ADVAPI32.@]
1920 QueryServiceConfigW( SC_HANDLE hService,
1921 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1922 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1924 WCHAR str_buffer[ MAX_PATH ];
1926 DWORD type, val, sz, total, n;
1929 struct sc_service *hsvc;
1931 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1932 cbBufSize, pcbBytesNeeded);
1934 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1937 SetLastError( ERROR_INVALID_HANDLE );
1942 /* TODO: Check which members are mandatory and what the registry types
1943 * should be. This should of course also be tested when a service is
1947 /* calculate the size required first */
1948 total = sizeof (QUERY_SERVICE_CONFIGW);
1950 sz = sizeof(str_buffer);
1951 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1952 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1954 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1955 if( 0 == sz ) return FALSE;
1957 total += sizeof(WCHAR) * sz;
1961 /* FIXME: set last error */
1966 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1967 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1970 total += sizeof(WCHAR);
1973 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1974 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1977 total += sizeof(WCHAR);
1980 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1981 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1984 total += sizeof(WCHAR);
1987 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1988 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1991 total += sizeof(WCHAR);
1993 *pcbBytesNeeded = total;
1995 /* if there's not enough memory, return an error */
1996 if( total > cbBufSize )
1998 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2002 ZeroMemory( lpServiceConfig, total );
2005 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2006 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2007 lpServiceConfig->dwServiceType = val;
2010 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2011 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2012 lpServiceConfig->dwStartType = val;
2015 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2016 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2017 lpServiceConfig->dwErrorControl = val;
2020 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2021 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2022 lpServiceConfig->dwTagId = val;
2024 /* now do the strings */
2025 p = (LPBYTE) &lpServiceConfig[1];
2026 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2028 sz = sizeof(str_buffer);
2029 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2030 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2032 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2033 sz *= sizeof(WCHAR);
2034 if( 0 == sz || sz > n ) return FALSE;
2036 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2042 /* FIXME: set last error */
2047 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2048 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2049 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2062 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2063 lpServiceConfig->lpDependencies = (LPWSTR) p;
2064 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2077 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2078 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2079 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2092 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2093 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2094 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2107 ERR("Buffer overflow!\n");
2109 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2110 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2111 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2112 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2113 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2118 /******************************************************************************
2119 * EnumServicesStatusA [ADVAPI32.@]
2122 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2123 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2124 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2125 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2127 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2128 dwServiceType, dwServiceState, lpServices, cbBufSize,
2129 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2130 SetLastError (ERROR_ACCESS_DENIED);
2134 /******************************************************************************
2135 * EnumServicesStatusW [ADVAPI32.@]
2138 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2139 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2140 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2141 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2143 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2144 dwServiceType, dwServiceState, lpServices, cbBufSize,
2145 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2146 SetLastError (ERROR_ACCESS_DENIED);
2150 /******************************************************************************
2151 * EnumServicesStatusExA [ADVAPI32.@]
2154 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2155 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2156 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2158 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2159 dwServiceType, dwServiceState, lpServices, cbBufSize,
2160 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2161 SetLastError (ERROR_ACCESS_DENIED);
2165 /******************************************************************************
2166 * EnumServicesStatusExW [ADVAPI32.@]
2169 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2170 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2171 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2173 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2174 dwServiceType, dwServiceState, lpServices, cbBufSize,
2175 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2176 SetLastError (ERROR_ACCESS_DENIED);
2180 /******************************************************************************
2181 * GetServiceKeyNameA [ADVAPI32.@]
2183 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2184 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2186 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2190 /******************************************************************************
2191 * GetServiceKeyNameW [ADVAPI32.@]
2193 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2194 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2196 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2200 /******************************************************************************
2201 * QueryServiceLockStatusA [ADVAPI32.@]
2203 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2204 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2205 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2207 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2212 /******************************************************************************
2213 * QueryServiceLockStatusW [ADVAPI32.@]
2215 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2216 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2217 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2219 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2224 /******************************************************************************
2225 * GetServiceDisplayNameA [ADVAPI32.@]
2227 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2228 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2230 LPWSTR lpServiceNameW, lpDisplayNameW = NULL;
2231 DWORD size, sizeW, GLE;
2234 TRACE("%p %s %p %p\n", hSCManager,
2235 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2237 lpServiceNameW = SERV_dup(lpServiceName);
2238 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2240 size = sizeW = *lpcchBuffer;
2241 ret = GetServiceDisplayNameW(hSCManager, lpServiceNameW,
2242 lpDisplayName ? lpDisplayNameW : NULL,
2244 /* Last error will be set by GetServiceDisplayNameW and must be preserved */
2245 GLE = GetLastError();
2247 if (!lpDisplayName && *lpcchBuffer && !ret && (GLE == ERROR_INSUFFICIENT_BUFFER))
2249 /* Request for buffersize.
2251 * Only set the size for ERROR_INSUFFICIENT_BUFFER
2255 else if (lpDisplayName && *lpcchBuffer && !ret)
2257 /* Request for displayname.
2259 * size only has to be set if this fails
2264 WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2265 *lpcchBuffer, NULL, NULL );
2267 *lpcchBuffer = size;
2269 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2270 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2276 /******************************************************************************
2277 * GetServiceDisplayNameW [ADVAPI32.@]
2279 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2280 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2282 struct sc_manager *hscm;
2286 TRACE("%p %s %p %p\n", hSCManager,
2287 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2289 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2292 SetLastError(ERROR_INVALID_HANDLE);
2298 SetLastError(ERROR_INVALID_ADDRESS);
2302 size = *lpcchBuffer * sizeof(WCHAR);
2303 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2304 if (!ret && !lpDisplayName && size)
2305 ret = ERROR_MORE_DATA;
2309 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2311 if (ret == ERROR_MORE_DATA)
2313 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2314 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2316 else if (ret == ERROR_FILE_NOT_FOUND)
2320 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2322 INT len = lstrlenW(lpServiceName);
2325 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2326 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2327 else if (lpDisplayName && *lpcchBuffer)
2329 /* No displayname, but the service exists and the buffer
2330 * is big enough. We should return the servicename.
2332 lstrcpyW(lpDisplayName, lpServiceName);
2341 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2348 /* Always return the correct needed size on success */
2349 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2354 /******************************************************************************
2355 * ChangeServiceConfigW [ADVAPI32.@]
2357 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2358 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2359 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2360 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2362 struct reg_value val[10];
2363 struct sc_service *hsvc;
2364 DWORD r = ERROR_SUCCESS;
2368 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2369 hService, dwServiceType, dwStartType, dwErrorControl,
2370 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2371 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2372 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2374 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2377 SetLastError( ERROR_INVALID_HANDLE );
2382 if( dwServiceType != SERVICE_NO_CHANGE )
2383 service_set_dword( &val[n++], szType, &dwServiceType );
2385 if( dwStartType != SERVICE_NO_CHANGE )
2386 service_set_dword( &val[n++], szStart, &dwStartType );
2388 if( dwErrorControl != SERVICE_NO_CHANGE )
2389 service_set_dword( &val[n++], szError, &dwErrorControl );
2391 if( lpBinaryPathName )
2392 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2394 if( lpLoadOrderGroup )
2395 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2397 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2398 * There is no such key as what szDependencies refers to */
2399 if( lpDependencies )
2400 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2403 FIXME("ignoring password\n");
2405 if( lpServiceStartName )
2406 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2408 r = service_write_values( hsvc->hkey, val, n );
2410 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2413 /******************************************************************************
2414 * ChangeServiceConfigA [ADVAPI32.@]
2416 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2417 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2418 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2419 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2421 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2422 LPWSTR wServiceStartName, wPassword, wDisplayName;
2425 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2426 hService, dwServiceType, dwStartType, dwErrorControl,
2427 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2428 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2429 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2431 wBinaryPathName = SERV_dup( lpBinaryPathName );
2432 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2433 wDependencies = SERV_dupmulti( lpDependencies );
2434 wServiceStartName = SERV_dup( lpServiceStartName );
2435 wPassword = SERV_dup( lpPassword );
2436 wDisplayName = SERV_dup( lpDisplayName );
2438 r = ChangeServiceConfigW( hService, dwServiceType,
2439 dwStartType, dwErrorControl, wBinaryPathName,
2440 wLoadOrderGroup, lpdwTagId, wDependencies,
2441 wServiceStartName, wPassword, wDisplayName);
2443 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2444 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2445 HeapFree( GetProcessHeap(), 0, wDependencies );
2446 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2447 HeapFree( GetProcessHeap(), 0, wPassword );
2448 HeapFree( GetProcessHeap(), 0, wDisplayName );
2453 /******************************************************************************
2454 * ChangeServiceConfig2A [ADVAPI32.@]
2456 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2461 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2463 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2465 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2466 SERVICE_DESCRIPTIONW sdw;
2468 sdw.lpDescription = SERV_dup( sd->lpDescription );
2470 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2472 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2474 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2476 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2477 SERVICE_FAILURE_ACTIONSW faw;
2479 faw.dwResetPeriod = fa->dwResetPeriod;
2480 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2481 faw.lpCommand = SERV_dup( fa->lpCommand );
2482 faw.cActions = fa->cActions;
2483 faw.lpsaActions = fa->lpsaActions;
2485 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2487 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2488 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2491 SetLastError( ERROR_INVALID_PARAMETER );
2496 /******************************************************************************
2497 * ChangeServiceConfig2W [ADVAPI32.@]
2499 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2503 struct sc_service *hsvc;
2505 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2508 SetLastError( ERROR_INVALID_HANDLE );
2513 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2515 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2516 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2517 if (sd->lpDescription)
2519 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2520 if (sd->lpDescription[0] == 0)
2521 RegDeleteValueW(hKey,szDescription);
2523 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2524 (LPVOID)sd->lpDescription,
2525 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2529 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2533 /******************************************************************************
2534 * QueryServiceObjectSecurity [ADVAPI32.@]
2536 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2537 SECURITY_INFORMATION dwSecurityInformation,
2538 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2539 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2543 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2544 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2546 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2548 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2549 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2550 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2554 /******************************************************************************
2555 * SetServiceObjectSecurity [ADVAPI32.@]
2557 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2558 SECURITY_INFORMATION dwSecurityInformation,
2559 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2561 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2565 /******************************************************************************
2566 * SetServiceBits [ADVAPI32.@]
2568 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2569 DWORD dwServiceBits,
2571 BOOL bUpdateImmediately)
2573 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2574 bSetBitsOn, bUpdateImmediately);
2578 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2579 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2581 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2585 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2586 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2588 service_data *service;
2589 SERVICE_STATUS_HANDLE handle = 0;
2591 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2593 EnterCriticalSection( &service_cs );
2594 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2596 if(!strcmpW(lpServiceName, service->name))
2598 service->handler.handler_ex = lpHandlerProc;
2599 service->context = lpContext;
2600 service->extended = TRUE;
2601 handle = (SERVICE_STATUS_HANDLE)service;
2605 LeaveCriticalSection( &service_cs );