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 szLocalSystem[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
43 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
44 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
45 'S','e','r','v','i','c','e','s',0 };
46 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
49 static const GENERIC_MAPPING scm_generic = {
50 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
51 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
52 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
56 static const GENERIC_MAPPING svc_generic = {
57 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
58 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
59 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
63 typedef struct service_start_info_t
70 #define WINESERV_STARTINFO 1
71 #define WINESERV_GETSTATUS 2
72 #define WINESERV_SENDCONTROL 3
74 typedef struct service_data_t
78 LPHANDLER_FUNCTION handler;
79 LPHANDLER_FUNCTION_EX handler_ex;
82 SERVICE_STATUS_PROCESS status;
85 BOOL extended : 1; /* uses handler_ex instead of handler? */
87 LPSERVICE_MAIN_FUNCTIONA a;
88 LPSERVICE_MAIN_FUNCTIONW w;
94 static CRITICAL_SECTION service_cs;
95 static CRITICAL_SECTION_DEBUG service_cs_debug =
98 { &service_cs_debug.ProcessLocksList,
99 &service_cs_debug.ProcessLocksList },
100 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
102 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
104 static struct list service_list = LIST_INIT(service_list);
106 extern HANDLE __wine_make_process_system(void);
108 /******************************************************************************
112 #define MAX_SERVICE_NAME 256
114 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
117 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
121 SC_HANDLE_TYPE htype;
123 sc_handle_destructor destroy;
126 struct sc_manager /* service control manager handle */
128 struct sc_handle hdr;
129 HKEY hkey; /* handle to services database in the registry */
133 struct sc_service /* service handle */
135 struct sc_handle hdr;
136 HKEY hkey; /* handle to service entry in the registry (under hkey) */
138 struct sc_manager *scm; /* pointer to SCM handle */
142 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
143 sc_handle_destructor destroy)
145 struct sc_handle *hdr;
147 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
152 hdr->destroy = destroy;
154 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
158 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
160 struct sc_handle *hdr = (struct sc_handle *) handle;
164 if (hdr->htype != htype)
169 static void sc_handle_free(struct sc_handle* hdr)
173 if (--hdr->ref_count)
176 HeapFree(GetProcessHeap(), 0, hdr);
179 static void sc_handle_destroy_manager(struct sc_handle *handle)
181 struct sc_manager *mgr = (struct sc_manager*) handle;
183 TRACE("destroying SC Manager %p\n", mgr);
185 RegCloseKey(mgr->hkey);
188 static void sc_handle_destroy_service(struct sc_handle *handle)
190 struct sc_service *svc = (struct sc_service*) handle;
192 TRACE("destroying service %p\n", svc);
194 RegCloseKey(svc->hkey);
196 sc_handle_free(&svc->scm->hdr);
200 /******************************************************************************
201 * String management functions (same behaviour as strdup)
202 * NOTE: the caller of those functions is responsible for calling HeapFree
203 * in order to release the memory allocated by those functions.
205 static inline LPWSTR SERV_dup( LPCSTR str )
212 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
213 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
214 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
218 static inline LPWSTR SERV_dupmulti(LPCSTR str)
226 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
227 n += (strlen( &str[n] ) + 1);
232 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
233 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
237 /******************************************************************************
238 * registry access functions and data
240 static const WCHAR szDisplayName[] = {
241 'D','i','s','p','l','a','y','N','a','m','e', 0 };
242 static const WCHAR szType[] = {'T','y','p','e',0};
243 static const WCHAR szStart[] = {'S','t','a','r','t',0};
244 static const WCHAR szError[] = {
245 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
246 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
247 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
248 static const WCHAR szDependencies[] = {
249 'D','e','p','e','n','d','e','n','c','i','e','s',0};
250 static const WCHAR szDependOnService[] = {
251 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
252 static const WCHAR szObjectName[] = {
253 'O','b','j','e','c','t','N','a','m','e',0};
254 static const WCHAR szTag[] = {
264 static inline void service_set_value( struct reg_value *val,
265 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
273 static inline void service_set_dword( struct reg_value *val,
274 LPCWSTR name, const DWORD *data )
276 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
279 static inline void service_set_string( struct reg_value *val,
280 LPCWSTR name, LPCWSTR string )
282 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
283 service_set_value( val, REG_SZ, name, string, len );
286 static inline void service_set_multi_string( struct reg_value *val,
287 LPCWSTR name, LPCWSTR string )
291 /* determine the length of a double null terminated multi string */
293 len += (lstrlenW( &string[ len ] )+1);
294 } while ( string[ len++ ] );
296 len *= sizeof (WCHAR);
297 service_set_value( val, REG_MULTI_SZ, name, string, len );
300 static inline LONG service_write_values( HKEY hKey,
301 const struct reg_value *val, int n )
303 LONG r = ERROR_SUCCESS;
308 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
309 (const BYTE*)val[i].data, val[i].size );
310 if( r != ERROR_SUCCESS )
316 /******************************************************************************
317 * Service IPC functions
319 static LPWSTR service_get_pipe_name(LPCWSTR service)
321 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
322 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
326 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
327 name = HeapAlloc(GetProcessHeap(), 0, len);
328 strcpyW(name, prefix);
329 strcatW(name, service);
333 static HANDLE service_open_pipe(LPCWSTR service)
335 LPWSTR szPipe = service_get_pipe_name( service );
336 HANDLE handle = INVALID_HANDLE_VALUE;
339 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
340 0, NULL, OPEN_ALWAYS, 0, NULL);
341 if (handle != INVALID_HANDLE_VALUE)
343 if (GetLastError() != ERROR_PIPE_BUSY)
345 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
346 HeapFree(GetProcessHeap(), 0, szPipe);
351 /******************************************************************************
352 * service_get_event_handle
354 static HANDLE service_get_event_handle(LPCWSTR service)
356 static const WCHAR prefix[] = {
357 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
362 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
363 name = HeapAlloc(GetProcessHeap(), 0, len);
364 strcpyW(name, prefix);
365 strcatW(name, service);
366 handle = CreateEventW(NULL, TRUE, FALSE, name);
367 HeapFree(GetProcessHeap(), 0, name);
371 /******************************************************************************
374 * Call into the main service routine provided by StartServiceCtrlDispatcher.
376 static DWORD WINAPI service_thread(LPVOID arg)
378 service_data *info = arg;
379 LPWSTR str = info->args;
380 DWORD argc = 0, len = 0;
386 len += strlenW(&str[len]) + 1;
393 info->proc.w(0, NULL);
395 info->proc.a(0, NULL);
403 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
404 for (argc=0, p=str; *p; p += strlenW(p) + 1)
408 info->proc.w(argc, argv);
409 HeapFree(GetProcessHeap(), 0, argv);
413 LPSTR strA, *argv, p;
416 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
417 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
418 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
420 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
421 for (argc=0, p=strA; *p; p += strlen(p) + 1)
425 info->proc.a(argc, argv);
426 HeapFree(GetProcessHeap(), 0, argv);
427 HeapFree(GetProcessHeap(), 0, strA);
432 /******************************************************************************
433 * service_handle_start
435 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
437 DWORD read = 0, result = 0;
441 TRACE("%p %p %d\n", pipe, service, count);
443 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
444 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
445 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
447 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
448 r, count, read, debugstr_wn(args, count));
454 WARN("service is not stopped\n");
455 result = ERROR_SERVICE_ALREADY_RUNNING;
459 HeapFree(GetProcessHeap(), 0, service->args);
460 service->args = args;
462 service->thread = CreateThread( NULL, 0, service_thread,
466 HeapFree(GetProcessHeap(), 0, args);
467 WriteFile( pipe, &result, sizeof result, &read, NULL );
472 /******************************************************************************
473 * service_send_start_message
475 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
477 DWORD i, len, count, result;
478 service_start_info *ssi;
482 TRACE("%p %p %d\n", pipe, argv, argc);
484 /* calculate how much space do we need to send the startup info */
486 for (i=0; i<argc; i++)
487 len += strlenW(argv[i])+1;
489 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
490 ssi->cmd = WINESERV_STARTINFO;
493 /* copy service args into a single buffer*/
495 for (i=0; i<argc; i++)
502 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
505 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
508 SetLastError(result);
513 HeapFree(GetProcessHeap(),0,ssi);
518 /******************************************************************************
519 * service_handle_get_status
521 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
525 return WriteFile(pipe, &service->status,
526 sizeof service->status, &count, NULL);
529 /******************************************************************************
532 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
534 DWORD cmd[2], count = 0;
537 cmd[0] = WINESERV_GETSTATUS;
539 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
540 if (!r || count != sizeof cmd)
542 ERR("service protocol error - failed to write pipe!\n");
545 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
546 if (!r || count != sizeof *status)
547 ERR("service protocol error - failed to read pipe "
548 "r = %d count = %d!\n", r, count);
552 /******************************************************************************
553 * service_send_control
555 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
557 DWORD cmd[2], count = 0;
560 cmd[0] = WINESERV_SENDCONTROL;
562 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
563 if (!r || count != sizeof cmd)
565 ERR("service protocol error - failed to write pipe!\n");
568 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
569 if (!r || count != sizeof *result)
570 ERR("service protocol error - failed to read pipe "
571 "r = %d count = %d!\n", r, count);
575 /******************************************************************************
576 * service_accepts_control
578 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
580 DWORD a = service->status.dwControlsAccepted;
584 case SERVICE_CONTROL_INTERROGATE:
586 case SERVICE_CONTROL_STOP:
587 if (a&SERVICE_ACCEPT_STOP)
590 case SERVICE_CONTROL_SHUTDOWN:
591 if (a&SERVICE_ACCEPT_SHUTDOWN)
594 case SERVICE_CONTROL_PAUSE:
595 case SERVICE_CONTROL_CONTINUE:
596 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
599 case SERVICE_CONTROL_PARAMCHANGE:
600 if (a&SERVICE_ACCEPT_PARAMCHANGE)
603 case SERVICE_CONTROL_NETBINDADD:
604 case SERVICE_CONTROL_NETBINDREMOVE:
605 case SERVICE_CONTROL_NETBINDENABLE:
606 case SERVICE_CONTROL_NETBINDDISABLE:
607 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
610 if (!service->extended)
614 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
615 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
618 case SERVICE_CONTROL_POWEREVENT:
619 if (a&SERVICE_ACCEPT_POWEREVENT)
622 case SERVICE_CONTROL_SESSIONCHANGE:
623 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
630 /******************************************************************************
631 * service_handle_control
633 static BOOL service_handle_control(HANDLE pipe, service_data *service,
636 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
638 TRACE("received control %d\n", dwControl);
640 if (service_accepts_control(service, dwControl))
642 if (service->extended && service->handler.handler_ex)
644 service->handler.handler_ex(dwControl, 0, NULL, service->context);
647 else if (service->handler.handler)
649 service->handler.handler(dwControl);
653 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
656 /******************************************************************************
657 * service_reap_thread
659 static DWORD service_reap_thread(service_data *service)
663 if (!service->thread)
665 GetExitCodeThread(service->thread, &exitcode);
666 if (exitcode!=STILL_ACTIVE)
668 CloseHandle(service->thread);
674 /******************************************************************************
675 * service_control_dispatcher
677 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
679 service_data *service = arg;
683 TRACE("%p %s\n", service, debugstr_w(service->name));
685 /* create a pipe to talk to the rest of the world with */
686 name = service_get_pipe_name(service->name);
687 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
688 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
689 HeapFree(GetProcessHeap(), 0, name);
691 /* let the process who started us know we've tried to create a pipe */
692 event = service_get_event_handle(service->name);
696 if (pipe==INVALID_HANDLE_VALUE)
698 ERR("failed to create pipe for %s, error = %d\n",
699 debugstr_w(service->name), GetLastError());
703 /* dispatcher loop */
707 DWORD count, req[2] = {0,0};
709 r = ConnectNamedPipe(pipe, NULL);
710 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
712 ERR("pipe connect failed\n");
716 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
717 if (!r || count!=sizeof req)
719 ERR("pipe read failed\n");
723 service_reap_thread(service);
725 /* handle the request */
728 case WINESERV_STARTINFO:
729 service_handle_start(pipe, service, req[1]);
731 case WINESERV_GETSTATUS:
732 service_handle_get_status(pipe, service);
734 case WINESERV_SENDCONTROL:
735 service_handle_control(pipe, service, req[1]);
738 ERR("received invalid command %d length %d\n", req[0], req[1]);
741 FlushFileBuffers(pipe);
742 DisconnectNamedPipe(pipe);
749 /******************************************************************************
750 * service_run_threads
752 static BOOL service_run_threads(void)
754 service_data *service;
758 EnterCriticalSection( &service_cs );
760 count = list_count( &service_list );
762 TRACE("Starting %d pipe listener threads. Services running as process %d\n", count, GetCurrentProcessId());
764 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
766 handles[n++] = __wine_make_process_system();
768 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
770 service->status.dwProcessId = GetCurrentProcessId();
771 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
774 assert(n == count + 1);
776 LeaveCriticalSection( &service_cs );
778 /* wait for all the threads to pack up and exit */
781 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
782 if (!ret) /* system process event */
784 TRACE( "last user process exited, shutting down\n" );
785 /* FIXME: we should maybe send a shutdown control to running services */
788 if (ret < MAXIMUM_WAIT_OBJECTS)
790 CloseHandle( handles[ret] );
791 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
797 while (n) CloseHandle( handles[--n] );
798 HeapFree(GetProcessHeap(), 0, handles);
803 /******************************************************************************
804 * StartServiceCtrlDispatcherA [ADVAPI32.@]
806 * See StartServiceCtrlDispatcherW.
808 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
814 TRACE("%p\n", servent);
816 EnterCriticalSection( &service_cs );
817 while (servent->lpServiceName)
819 LPSTR name = servent->lpServiceName;
821 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
822 sz = len*sizeof(WCHAR) + sizeof *info;
823 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
824 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
825 info->proc.a = servent->lpServiceProc;
826 info->unicode = FALSE;
827 list_add_head( &service_list, &info->entry );
830 LeaveCriticalSection( &service_cs );
832 service_run_threads();
837 /******************************************************************************
838 * StartServiceCtrlDispatcherW [ADVAPI32.@]
840 * Connects a process containing one or more services to the service control
844 * servent [I] A list of the service names and service procedures
850 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
856 TRACE("%p\n", servent);
858 EnterCriticalSection( &service_cs );
859 while (servent->lpServiceName)
861 LPWSTR name = servent->lpServiceName;
864 sz = len*sizeof(WCHAR) + sizeof *info;
865 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
866 strcpyW(info->name, name);
867 info->proc.w = servent->lpServiceProc;
868 info->unicode = TRUE;
869 list_add_head( &service_list, &info->entry );
872 LeaveCriticalSection( &service_cs );
874 service_run_threads();
879 /******************************************************************************
880 * LockServiceDatabase [ADVAPI32.@]
882 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
886 TRACE("%p\n",hSCManager);
888 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
889 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
893 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
896 TRACE("returning %p\n", ret);
901 /******************************************************************************
902 * UnlockServiceDatabase [ADVAPI32.@]
904 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
906 TRACE("%p\n",ScLock);
908 return CloseHandle( ScLock );
911 /******************************************************************************
912 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
914 SERVICE_STATUS_HANDLE WINAPI
915 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
917 LPWSTR lpServiceNameW;
918 SERVICE_STATUS_HANDLE ret;
920 lpServiceNameW = SERV_dup(lpServiceName);
921 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
922 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
926 /******************************************************************************
927 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
933 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
934 LPHANDLER_FUNCTION lpfHandler )
936 service_data *service;
937 SERVICE_STATUS_HANDLE handle = 0;
939 EnterCriticalSection( &service_cs );
940 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
942 if(!strcmpW(lpServiceName, service->name))
944 service->handler.handler = lpfHandler;
945 handle = (SERVICE_STATUS_HANDLE)service;
949 LeaveCriticalSection( &service_cs );
953 /******************************************************************************
954 * SetServiceStatus [ADVAPI32.@]
961 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
963 service_data *service;
966 TRACE("%p %x %x %x %x %x %x %x\n", hService,
967 lpStatus->dwServiceType, lpStatus->dwCurrentState,
968 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
969 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
970 lpStatus->dwWaitHint);
972 EnterCriticalSection( &service_cs );
973 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
975 if(service == (service_data*)hService)
977 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
978 TRACE("Set service status to %d\n",service->status.dwCurrentState);
983 LeaveCriticalSection( &service_cs );
989 /******************************************************************************
990 * OpenSCManagerA [ADVAPI32.@]
992 * Establish a connection to the service control manager and open its database.
995 * lpMachineName [I] Pointer to machine name string
996 * lpDatabaseName [I] Pointer to database name string
997 * dwDesiredAccess [I] Type of access
1000 * Success: A Handle to the service control manager database
1003 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1004 DWORD dwDesiredAccess )
1006 LPWSTR lpMachineNameW, lpDatabaseNameW;
1009 lpMachineNameW = SERV_dup(lpMachineName);
1010 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1011 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1012 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
1013 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
1017 /******************************************************************************
1018 * OpenSCManagerW [ADVAPI32.@]
1020 * See OpenSCManagerA.
1022 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1023 DWORD dwDesiredAccess )
1025 struct sc_manager *manager;
1028 DWORD new_mask = dwDesiredAccess;
1030 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1031 debugstr_w(lpDatabaseName), dwDesiredAccess);
1033 if( lpDatabaseName && lpDatabaseName[0] )
1035 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1037 /* noop, all right */
1039 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1041 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1046 SetLastError( ERROR_INVALID_NAME );
1051 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1052 sc_handle_destroy_manager );
1056 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1057 if (r!=ERROR_SUCCESS)
1060 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1061 RegCloseKey( hReg );
1062 if (r!=ERROR_SUCCESS)
1065 RtlMapGenericMask(&new_mask, &scm_generic);
1066 manager->dwAccess = new_mask;
1067 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1069 return (SC_HANDLE) &manager->hdr;
1072 sc_handle_free( &manager->hdr );
1077 /******************************************************************************
1078 * ControlService [ADVAPI32.@]
1080 * Send a control code to a service.
1083 * hService [I] Handle of the service control manager database
1084 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1085 * lpServiceStatus [O] Destination for the status of the service, if available
1092 * Unlike M$' implementation, control requests are not serialized and may be
1093 * processed asynchronously.
1095 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1096 LPSERVICE_STATUS lpServiceStatus )
1098 struct sc_service *hsvc;
1102 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1104 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1107 SetLastError( ERROR_INVALID_HANDLE );
1111 ret = QueryServiceStatus(hService, lpServiceStatus);
1114 ERR("failed to query service status\n");
1115 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1119 switch (lpServiceStatus->dwCurrentState)
1121 case SERVICE_STOPPED:
1122 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1124 case SERVICE_START_PENDING:
1125 if (dwControl==SERVICE_CONTROL_STOP)
1128 case SERVICE_STOP_PENDING:
1129 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1133 handle = service_open_pipe(hsvc->name);
1134 if (handle!=INVALID_HANDLE_VALUE)
1136 DWORD result = ERROR_SUCCESS;
1137 ret = service_send_control(handle, dwControl, &result);
1138 CloseHandle(handle);
1139 if (result!=ERROR_SUCCESS)
1141 SetLastError(result);
1149 /******************************************************************************
1150 * CloseServiceHandle [ADVAPI32.@]
1152 * Close a handle to a service or the service control manager database.
1155 * hSCObject [I] Handle to service or service control manager database
1162 CloseServiceHandle( SC_HANDLE hSCObject )
1164 TRACE("%p\n", hSCObject);
1166 sc_handle_free( (struct sc_handle*) hSCObject );
1172 /******************************************************************************
1173 * OpenServiceA [ADVAPI32.@]
1175 * Open a handle to a service.
1178 * hSCManager [I] Handle of the service control manager database
1179 * lpServiceName [I] Name of the service to open
1180 * dwDesiredAccess [I] Access required to the service
1183 * Success: Handle to the service
1186 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1187 DWORD dwDesiredAccess )
1189 LPWSTR lpServiceNameW;
1192 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1194 lpServiceNameW = SERV_dup(lpServiceName);
1195 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1196 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1201 /******************************************************************************
1202 * OpenServiceW [ADVAPI32.@]
1206 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1207 DWORD dwDesiredAccess)
1209 struct sc_manager *hscm;
1210 struct sc_service *hsvc;
1214 DWORD new_mask = dwDesiredAccess;
1216 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1218 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1221 SetLastError( ERROR_INVALID_HANDLE );
1227 SetLastError(ERROR_INVALID_ADDRESS);
1231 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1232 if (r!=ERROR_SUCCESS)
1234 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1238 len = strlenW(lpServiceName)+1;
1239 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1240 sizeof (struct sc_service) + len*sizeof(WCHAR),
1241 sc_handle_destroy_service );
1247 strcpyW( hsvc->name, lpServiceName );
1250 RtlMapGenericMask(&new_mask, &svc_generic);
1251 hsvc->dwAccess = new_mask;
1253 /* add reference to SCM handle */
1254 hscm->hdr.ref_count++;
1257 TRACE("returning %p\n",hsvc);
1259 return (SC_HANDLE) &hsvc->hdr;
1262 /******************************************************************************
1263 * CreateServiceW [ADVAPI32.@]
1266 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1267 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1268 DWORD dwServiceType, DWORD dwStartType,
1269 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1270 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1271 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1272 LPCWSTR lpPassword )
1274 struct sc_manager *hscm;
1275 struct sc_service *hsvc = NULL;
1279 struct reg_value val[10];
1281 DWORD new_mask = dwDesiredAccess;
1283 WCHAR buffer[MAX_PATH];
1284 BOOL displayname_exists = FALSE;
1286 TRACE("%p %s %s\n", hSCManager,
1287 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1289 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1292 SetLastError( ERROR_INVALID_HANDLE );
1296 if (!lpServiceName || !lpBinaryPathName)
1298 SetLastError(ERROR_INVALID_ADDRESS);
1302 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1304 SetLastError(ERROR_ACCESS_DENIED);
1308 if (!lpServiceName[0])
1310 SetLastError(ERROR_INVALID_NAME);
1314 if (!lpBinaryPathName[0])
1316 SetLastError(ERROR_INVALID_PARAMETER);
1320 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1321 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1322 * runs under the LocalSystem account)
1324 switch (dwServiceType)
1326 case SERVICE_KERNEL_DRIVER:
1327 case SERVICE_FILE_SYSTEM_DRIVER:
1328 case SERVICE_WIN32_OWN_PROCESS:
1329 case SERVICE_WIN32_SHARE_PROCESS:
1332 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1333 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1334 /* FIXME : Do we need a more thorough check? */
1335 if (lpServiceStartName)
1337 SetLastError(ERROR_INVALID_PARAMETER);
1342 SetLastError(ERROR_INVALID_PARAMETER);
1346 if (!lpServiceStartName && (dwServiceType & SERVICE_WIN32))
1347 lpServiceStartName = szLocalSystem;
1349 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1350 if (dwStartType > SERVICE_DISABLED)
1352 SetLastError(ERROR_INVALID_PARAMETER);
1356 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1357 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1358 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1360 SetLastError(ERROR_INVALID_PARAMETER);
1364 /* Loop through the registry to check if the service already exists and to
1365 * check if we can use the given displayname.
1366 * FIXME: Should we use EnumServicesStatusEx?
1368 len = sizeof(buffer);
1369 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1373 /* The service already exists, so bail out */
1374 if(!lstrcmpiW(lpServiceName, buffer))
1376 SetLastError(ERROR_SERVICE_EXISTS);
1380 /* The given displayname matches the found servicename. We don't bail out
1381 * as servicename is checked before a duplicate displayname
1383 if(!lstrcmpiW(lpDisplayName, buffer))
1384 displayname_exists = TRUE;
1386 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1388 WCHAR name[MAX_PATH];
1389 DWORD size = sizeof(name);
1391 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1393 /* The given displayname matches the found displayname */
1394 if (!lstrcmpiW(lpDisplayName, name))
1395 displayname_exists = TRUE;
1397 RegCloseKey(service_key);
1400 len = sizeof(buffer);
1403 if (lpDisplayName && displayname_exists)
1405 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1409 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1410 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1411 if (r!=ERROR_SUCCESS)
1413 /* FIXME: Should we set an error? */
1418 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1420 service_set_dword( &val[n++], szType, &dwServiceType );
1421 service_set_dword( &val[n++], szStart, &dwStartType );
1422 service_set_dword( &val[n++], szError, &dwErrorControl );
1424 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1426 if( lpLoadOrderGroup )
1427 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1429 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1430 * There is no such key as what szDependencies refers to */
1431 if( lpDependencies )
1432 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1435 FIXME("Don't know how to add a Password for a service.\n");
1437 if( lpServiceStartName )
1438 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1440 r = service_write_values( hKey, val, n );
1441 if( r != ERROR_SUCCESS )
1444 len = strlenW(lpServiceName)+1;
1445 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1446 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1449 lstrcpyW( hsvc->name, lpServiceName );
1452 RtlMapGenericMask(&new_mask, &svc_generic);
1453 hsvc->dwAccess = new_mask;
1456 hscm->hdr.ref_count++;
1458 return (SC_HANDLE) &hsvc->hdr;
1461 RegCloseKey( hKey );
1466 /******************************************************************************
1467 * CreateServiceA [ADVAPI32.@]
1470 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1471 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1472 DWORD dwServiceType, DWORD dwStartType,
1473 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1474 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1475 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1478 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1479 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1482 TRACE("%p %s %s\n", hSCManager,
1483 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1485 lpServiceNameW = SERV_dup( lpServiceName );
1486 lpDisplayNameW = SERV_dup( lpDisplayName );
1487 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1488 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1489 lpDependenciesW = SERV_dupmulti( lpDependencies );
1490 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1491 lpPasswordW = SERV_dup( lpPassword );
1493 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1494 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1495 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1496 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1498 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1499 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1500 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1501 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1502 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1503 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1504 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1510 /******************************************************************************
1511 * DeleteService [ADVAPI32.@]
1513 * Delete a service from the service control manager database.
1516 * hService [I] Handle of the service to delete
1522 BOOL WINAPI DeleteService( SC_HANDLE hService )
1524 struct sc_service *hsvc;
1526 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1529 SetLastError( ERROR_INVALID_HANDLE );
1533 if (!(hsvc->dwAccess & DELETE))
1535 SetLastError(ERROR_ACCESS_DENIED);
1539 /* Close the key to the service */
1540 RegCloseKey(hsvc->hkey);
1542 /* Delete the service under the Service Control Manager key */
1543 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1551 /******************************************************************************
1552 * StartServiceA [ADVAPI32.@]
1557 * hService [I] Handle of service
1558 * dwNumServiceArgs [I] Number of arguments
1559 * lpServiceArgVectors [I] Address of array of argument strings
1562 * - NT implements this function using an obscure RPC call.
1563 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1564 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1565 * - This will only work for shared address space. How should the service
1566 * args be transferred when address spaces are separated?
1567 * - Can only start one service at a time.
1568 * - Has no concept of privilege.
1574 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1575 LPCSTR *lpServiceArgVectors )
1577 LPWSTR *lpwstr=NULL;
1581 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1583 if (dwNumServiceArgs)
1584 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1585 dwNumServiceArgs*sizeof(LPWSTR) );
1587 for(i=0; i<dwNumServiceArgs; i++)
1588 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1590 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1592 if (dwNumServiceArgs)
1594 for(i=0; i<dwNumServiceArgs; i++)
1595 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1596 HeapFree(GetProcessHeap(), 0, lpwstr);
1602 /******************************************************************************
1603 * service_start_process [INTERNAL]
1605 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1607 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1608 PROCESS_INFORMATION pi;
1610 LPWSTR path = NULL, str;
1611 DWORD type, size, ret, svc_type;
1615 size = sizeof(svc_type);
1616 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1619 if (svc_type == SERVICE_KERNEL_DRIVER)
1621 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1622 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1624 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1625 GetSystemDirectoryW( path, len );
1626 lstrcatW( path, winedeviceW );
1627 lstrcatW( path, hsvc->name );
1631 /* read the executable path from the registry */
1633 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1634 if (ret!=ERROR_SUCCESS)
1636 str = HeapAlloc(GetProcessHeap(),0,size);
1637 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1638 if (ret==ERROR_SUCCESS)
1640 size = ExpandEnvironmentStringsW(str,NULL,0);
1641 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1642 ExpandEnvironmentStringsW(str,path,size);
1644 HeapFree(GetProcessHeap(),0,str);
1649 /* wait for the process to start and set an event or terminate */
1650 handles[0] = service_get_event_handle( hsvc->name );
1651 ZeroMemory(&si, sizeof(STARTUPINFOW));
1652 si.cb = sizeof(STARTUPINFOW);
1653 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1656 if (ppid) *ppid = pi.dwProcessId;
1658 handles[1] = pi.hProcess;
1659 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1660 if(ret != WAIT_OBJECT_0)
1662 SetLastError(ERROR_IO_PENDING);
1666 CloseHandle( pi.hThread );
1667 CloseHandle( pi.hProcess );
1669 CloseHandle( handles[0] );
1670 HeapFree(GetProcessHeap(),0,path);
1674 static BOOL service_wait_for_startup(SC_HANDLE hService)
1677 SERVICE_STATUS status;
1680 TRACE("%p\n", hService);
1682 for (i=0; i<30; i++)
1684 status.dwCurrentState = 0;
1685 r = QueryServiceStatus(hService, &status);
1688 if (status.dwCurrentState == SERVICE_RUNNING)
1690 TRACE("Service started successfully\n");
1699 /******************************************************************************
1700 * StartServiceW [ADVAPI32.@]
1702 * See StartServiceA.
1704 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1705 LPCWSTR *lpServiceArgVectors)
1707 struct sc_service *hsvc;
1710 HANDLE handle = INVALID_HANDLE_VALUE;
1712 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1714 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1717 SetLastError(ERROR_INVALID_HANDLE);
1721 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1725 handle = service_open_pipe(hsvc->name);
1726 if (handle==INVALID_HANDLE_VALUE)
1728 /* start the service process */
1729 if (service_start_process(hsvc, NULL))
1730 handle = service_open_pipe(hsvc->name);
1733 if (handle != INVALID_HANDLE_VALUE)
1735 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1736 CloseHandle(handle);
1739 UnlockServiceDatabase( hLock );
1741 TRACE("returning %d\n", r);
1744 service_wait_for_startup(hService);
1749 /******************************************************************************
1750 * QueryServiceStatus [ADVAPI32.@]
1753 * hService [I] Handle to service to get information about
1754 * lpservicestatus [O] buffer to receive the status information for the service
1757 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1758 LPSERVICE_STATUS lpservicestatus)
1760 SERVICE_STATUS_PROCESS SvcStatusData;
1763 TRACE("%p %p\n", hService, lpservicestatus);
1765 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1766 sizeof(SERVICE_STATUS_PROCESS), NULL);
1767 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1772 /******************************************************************************
1773 * QueryServiceStatusEx [ADVAPI32.@]
1775 * Get information about a service.
1778 * hService [I] Handle to service to get information about
1779 * InfoLevel [I] Level of information to get
1780 * lpBuffer [O] Destination for requested information
1781 * cbBufSize [I] Size of lpBuffer in bytes
1782 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1788 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1789 LPBYTE lpBuffer, DWORD cbBufSize,
1790 LPDWORD pcbBytesNeeded)
1792 struct sc_service *hsvc;
1793 DWORD size, type, val;
1796 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1798 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1800 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1802 SetLastError( ERROR_INVALID_LEVEL);
1806 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1807 if (pSvcStatusData == NULL)
1809 SetLastError( ERROR_INVALID_PARAMETER);
1813 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1815 if( pcbBytesNeeded != NULL)
1816 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1818 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1822 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1825 SetLastError( ERROR_INVALID_HANDLE );
1829 pipe = service_open_pipe(hsvc->name);
1830 if (pipe != INVALID_HANDLE_VALUE)
1832 r = service_get_status(pipe, pSvcStatusData);
1838 TRACE("Failed to read service status\n");
1840 /* read the service type from the registry */
1842 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1843 if (r != ERROR_SUCCESS || type != REG_DWORD)
1846 pSvcStatusData->dwServiceType = val;
1847 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1848 pSvcStatusData->dwControlsAccepted = 0;
1849 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1850 pSvcStatusData->dwServiceSpecificExitCode = 0;
1851 pSvcStatusData->dwCheckPoint = 0;
1852 pSvcStatusData->dwWaitHint = 0;
1857 /******************************************************************************
1858 * QueryServiceConfigA [ADVAPI32.@]
1860 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1861 DWORD size, LPDWORD needed )
1866 QUERY_SERVICE_CONFIGW *configW;
1868 TRACE("%p %p %d %p\n", hService, config, size, needed);
1870 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1872 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1875 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1876 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1877 if (!ret) goto done;
1879 config->dwServiceType = configW->dwServiceType;
1880 config->dwStartType = configW->dwStartType;
1881 config->dwErrorControl = configW->dwErrorControl;
1882 config->lpBinaryPathName = NULL;
1883 config->lpLoadOrderGroup = NULL;
1884 config->dwTagId = configW->dwTagId;
1885 config->lpDependencies = NULL;
1886 config->lpServiceStartName = NULL;
1887 config->lpDisplayName = NULL;
1889 p = (LPSTR)(config + 1);
1890 n = size - sizeof(*config);
1893 #define MAP_STR(str) \
1897 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1898 if (!sz) goto done; \
1905 MAP_STR( lpBinaryPathName );
1906 MAP_STR( lpLoadOrderGroup );
1907 MAP_STR( lpDependencies );
1908 MAP_STR( lpServiceStartName );
1909 MAP_STR( lpDisplayName );
1912 *needed = p - (LPSTR)config;
1916 HeapFree( GetProcessHeap(), 0, buffer );
1920 /******************************************************************************
1921 * QueryServiceConfigW [ADVAPI32.@]
1924 QueryServiceConfigW( SC_HANDLE hService,
1925 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1926 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1928 WCHAR str_buffer[ MAX_PATH ];
1930 DWORD type, val, sz, total, n;
1933 struct sc_service *hsvc;
1935 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1936 cbBufSize, pcbBytesNeeded);
1938 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1941 SetLastError( ERROR_INVALID_HANDLE );
1946 /* TODO: Check which members are mandatory and what the registry types
1947 * should be. This should of course also be tested when a service is
1951 /* calculate the size required first */
1952 total = sizeof (QUERY_SERVICE_CONFIGW);
1954 sz = sizeof(str_buffer);
1955 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1956 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1958 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1959 if( 0 == sz ) return FALSE;
1961 total += sizeof(WCHAR) * sz;
1965 /* FIXME: set last error */
1970 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1971 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1974 total += sizeof(WCHAR);
1977 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1978 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1981 total += sizeof(WCHAR);
1984 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1985 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1988 total += sizeof(WCHAR);
1991 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1992 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1995 total += sizeof(WCHAR);
1997 *pcbBytesNeeded = total;
1999 /* if there's not enough memory, return an error */
2000 if( total > cbBufSize )
2002 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2006 ZeroMemory( lpServiceConfig, total );
2009 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2010 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2011 lpServiceConfig->dwServiceType = val;
2014 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2015 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2016 lpServiceConfig->dwStartType = val;
2019 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2020 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2021 lpServiceConfig->dwErrorControl = val;
2024 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2025 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2026 lpServiceConfig->dwTagId = val;
2028 /* now do the strings */
2029 p = (LPBYTE) &lpServiceConfig[1];
2030 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2032 sz = sizeof(str_buffer);
2033 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2034 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2036 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2037 sz *= sizeof(WCHAR);
2038 if( 0 == sz || sz > n ) return FALSE;
2040 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2046 /* FIXME: set last error */
2051 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2052 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2053 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2066 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2067 lpServiceConfig->lpDependencies = (LPWSTR) p;
2068 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2081 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2082 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2083 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2096 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2097 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2098 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2111 ERR("Buffer overflow!\n");
2113 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2114 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2115 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2116 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2117 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2122 /******************************************************************************
2123 * EnumServicesStatusA [ADVAPI32.@]
2126 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2127 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2128 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2129 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2131 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2132 dwServiceType, dwServiceState, lpServices, cbBufSize,
2133 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2134 SetLastError (ERROR_ACCESS_DENIED);
2138 /******************************************************************************
2139 * EnumServicesStatusW [ADVAPI32.@]
2142 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2143 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2144 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2145 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2147 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2148 dwServiceType, dwServiceState, lpServices, cbBufSize,
2149 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2150 SetLastError (ERROR_ACCESS_DENIED);
2154 /******************************************************************************
2155 * EnumServicesStatusExA [ADVAPI32.@]
2158 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2159 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2160 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2162 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2163 dwServiceType, dwServiceState, lpServices, cbBufSize,
2164 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2165 *lpServicesReturned = 0;
2166 SetLastError (ERROR_ACCESS_DENIED);
2170 /******************************************************************************
2171 * EnumServicesStatusExW [ADVAPI32.@]
2174 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2175 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2176 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2178 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2179 dwServiceType, dwServiceState, lpServices, cbBufSize,
2180 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2181 SetLastError (ERROR_ACCESS_DENIED);
2185 /******************************************************************************
2186 * GetServiceKeyNameA [ADVAPI32.@]
2188 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2189 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2191 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2195 /******************************************************************************
2196 * GetServiceKeyNameW [ADVAPI32.@]
2198 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2199 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2201 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2205 /******************************************************************************
2206 * QueryServiceLockStatusA [ADVAPI32.@]
2208 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2209 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2210 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2212 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2217 /******************************************************************************
2218 * QueryServiceLockStatusW [ADVAPI32.@]
2220 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2221 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2222 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2224 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2229 /******************************************************************************
2230 * GetServiceDisplayNameA [ADVAPI32.@]
2232 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2233 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2235 LPWSTR lpServiceNameW, lpDisplayNameW;
2239 TRACE("%p %s %p %p\n", hSCManager,
2240 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2242 lpServiceNameW = SERV_dup(lpServiceName);
2244 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2246 lpDisplayNameW = NULL;
2248 sizeW = *lpcchBuffer;
2249 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2251 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2255 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2256 *lpcchBuffer, NULL, NULL ))
2258 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2262 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2263 * (but if the function succeeded it means that is a good upper estimation of the size) */
2267 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2268 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2272 /******************************************************************************
2273 * GetServiceDisplayNameW [ADVAPI32.@]
2275 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2276 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2278 struct sc_manager *hscm;
2282 TRACE("%p %s %p %p\n", hSCManager,
2283 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2285 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2288 SetLastError(ERROR_INVALID_HANDLE);
2294 SetLastError(ERROR_INVALID_ADDRESS);
2298 size = *lpcchBuffer * sizeof(WCHAR);
2299 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2300 if (!ret && !lpDisplayName && size)
2301 ret = ERROR_MORE_DATA;
2305 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2307 if (ret == ERROR_MORE_DATA)
2309 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2310 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2312 else if (ret == ERROR_FILE_NOT_FOUND)
2316 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2318 UINT len = lstrlenW(lpServiceName);
2321 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2322 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2323 else if (lpDisplayName && *lpcchBuffer)
2325 /* No displayname, but the service exists and the buffer
2326 * is big enough. We should return the servicename.
2328 lstrcpyW(lpDisplayName, lpServiceName);
2337 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2344 /* Always return the correct needed size on success */
2345 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2350 /******************************************************************************
2351 * ChangeServiceConfigW [ADVAPI32.@]
2353 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2354 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2355 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2356 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2358 struct reg_value val[10];
2359 struct sc_service *hsvc;
2360 DWORD r = ERROR_SUCCESS;
2364 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2365 hService, dwServiceType, dwStartType, dwErrorControl,
2366 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2367 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2368 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2370 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2373 SetLastError( ERROR_INVALID_HANDLE );
2378 if( dwServiceType != SERVICE_NO_CHANGE )
2379 service_set_dword( &val[n++], szType, &dwServiceType );
2381 if( dwStartType != SERVICE_NO_CHANGE )
2382 service_set_dword( &val[n++], szStart, &dwStartType );
2384 if( dwErrorControl != SERVICE_NO_CHANGE )
2385 service_set_dword( &val[n++], szError, &dwErrorControl );
2387 if( lpBinaryPathName )
2388 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2390 if( lpLoadOrderGroup )
2391 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2393 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2394 * There is no such key as what szDependencies refers to */
2395 if( lpDependencies )
2396 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2399 FIXME("ignoring password\n");
2401 if( lpServiceStartName )
2402 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2404 r = service_write_values( hsvc->hkey, val, n );
2406 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2409 /******************************************************************************
2410 * ChangeServiceConfigA [ADVAPI32.@]
2412 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2413 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2414 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2415 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2417 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2418 LPWSTR wServiceStartName, wPassword, wDisplayName;
2421 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2422 hService, dwServiceType, dwStartType, dwErrorControl,
2423 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2424 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2425 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2427 wBinaryPathName = SERV_dup( lpBinaryPathName );
2428 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2429 wDependencies = SERV_dupmulti( lpDependencies );
2430 wServiceStartName = SERV_dup( lpServiceStartName );
2431 wPassword = SERV_dup( lpPassword );
2432 wDisplayName = SERV_dup( lpDisplayName );
2434 r = ChangeServiceConfigW( hService, dwServiceType,
2435 dwStartType, dwErrorControl, wBinaryPathName,
2436 wLoadOrderGroup, lpdwTagId, wDependencies,
2437 wServiceStartName, wPassword, wDisplayName);
2439 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2440 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2441 HeapFree( GetProcessHeap(), 0, wDependencies );
2442 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2443 HeapFree( GetProcessHeap(), 0, wPassword );
2444 HeapFree( GetProcessHeap(), 0, wDisplayName );
2449 /******************************************************************************
2450 * ChangeServiceConfig2A [ADVAPI32.@]
2452 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2457 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2459 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2461 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2462 SERVICE_DESCRIPTIONW sdw;
2464 sdw.lpDescription = SERV_dup( sd->lpDescription );
2466 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2468 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2470 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2472 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2473 SERVICE_FAILURE_ACTIONSW faw;
2475 faw.dwResetPeriod = fa->dwResetPeriod;
2476 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2477 faw.lpCommand = SERV_dup( fa->lpCommand );
2478 faw.cActions = fa->cActions;
2479 faw.lpsaActions = fa->lpsaActions;
2481 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2483 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2484 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2487 SetLastError( ERROR_INVALID_PARAMETER );
2492 /******************************************************************************
2493 * ChangeServiceConfig2W [ADVAPI32.@]
2495 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2499 struct sc_service *hsvc;
2501 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2504 SetLastError( ERROR_INVALID_HANDLE );
2509 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2511 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2512 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2513 if (sd->lpDescription)
2515 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2516 if (sd->lpDescription[0] == 0)
2517 RegDeleteValueW(hKey,szDescription);
2519 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2520 (LPVOID)sd->lpDescription,
2521 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2525 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2529 /******************************************************************************
2530 * QueryServiceObjectSecurity [ADVAPI32.@]
2532 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2533 SECURITY_INFORMATION dwSecurityInformation,
2534 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2535 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2537 SECURITY_DESCRIPTOR descriptor;
2542 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2543 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2545 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2546 FIXME("information %d not supported\n", dwSecurityInformation);
2548 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2550 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2551 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2554 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2555 *pcbBytesNeeded = size;
2559 /******************************************************************************
2560 * SetServiceObjectSecurity [ADVAPI32.@]
2562 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2563 SECURITY_INFORMATION dwSecurityInformation,
2564 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2566 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2570 /******************************************************************************
2571 * SetServiceBits [ADVAPI32.@]
2573 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2574 DWORD dwServiceBits,
2576 BOOL bUpdateImmediately)
2578 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2579 bSetBitsOn, bUpdateImmediately);
2583 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2584 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2586 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2590 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2591 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2593 service_data *service;
2594 SERVICE_STATUS_HANDLE handle = 0;
2596 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2598 EnterCriticalSection( &service_cs );
2599 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2601 if(!strcmpW(lpServiceName, service->name))
2603 service->handler.handler_ex = lpHandlerProc;
2604 service->context = lpContext;
2605 service->extended = TRUE;
2606 handle = (SERVICE_STATUS_HANDLE)service;
2610 LeaveCriticalSection( &service_cs );