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
72 #define WINESERV_SETPID 4
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
203 static inline LPWSTR SERV_dup( LPCSTR str )
210 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
211 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
212 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
216 static inline LPWSTR SERV_dupmulti(LPCSTR str)
224 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
225 n += (strlen( &str[n] ) + 1);
230 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
231 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
235 static inline VOID SERV_free( LPWSTR wstr )
237 HeapFree( GetProcessHeap(), 0, wstr );
240 /******************************************************************************
241 * registry access functions and data
243 static const WCHAR szDisplayName[] = {
244 'D','i','s','p','l','a','y','N','a','m','e', 0 };
245 static const WCHAR szType[] = {'T','y','p','e',0};
246 static const WCHAR szStart[] = {'S','t','a','r','t',0};
247 static const WCHAR szError[] = {
248 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
249 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
250 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
251 static const WCHAR szDependencies[] = {
252 'D','e','p','e','n','d','e','n','c','i','e','s',0};
253 static const WCHAR szDependOnService[] = {
254 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
255 static const WCHAR szObjectName[] = {
256 'O','b','j','e','c','t','N','a','m','e',0};
257 static const WCHAR szTag[] = {
267 static inline void service_set_value( struct reg_value *val,
268 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
276 static inline void service_set_dword( struct reg_value *val,
277 LPCWSTR name, const DWORD *data )
279 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
282 static inline void service_set_string( struct reg_value *val,
283 LPCWSTR name, LPCWSTR string )
285 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
286 service_set_value( val, REG_SZ, name, string, len );
289 static inline void service_set_multi_string( struct reg_value *val,
290 LPCWSTR name, LPCWSTR string )
294 /* determine the length of a double null terminated multi string */
296 len += (lstrlenW( &string[ len ] )+1);
297 } while ( string[ len++ ] );
299 len *= sizeof (WCHAR);
300 service_set_value( val, REG_MULTI_SZ, name, string, len );
303 static inline LONG service_write_values( HKEY hKey,
304 const struct reg_value *val, int n )
306 LONG r = ERROR_SUCCESS;
311 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
312 (const BYTE*)val[i].data, val[i].size );
313 if( r != ERROR_SUCCESS )
319 /******************************************************************************
320 * Service IPC functions
322 static LPWSTR service_get_pipe_name(LPCWSTR service)
324 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
325 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
329 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
330 name = HeapAlloc(GetProcessHeap(), 0, len);
331 strcpyW(name, prefix);
332 strcatW(name, service);
336 static HANDLE service_open_pipe(LPCWSTR service)
338 LPWSTR szPipe = service_get_pipe_name( service );
339 HANDLE handle = INVALID_HANDLE_VALUE;
342 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
343 0, NULL, OPEN_ALWAYS, 0, NULL);
344 if (handle != INVALID_HANDLE_VALUE)
346 if (GetLastError() != ERROR_PIPE_BUSY)
348 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
354 /******************************************************************************
355 * service_get_event_handle
357 static HANDLE service_get_event_handle(LPCWSTR service)
359 static const WCHAR prefix[] = {
360 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
365 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
366 name = HeapAlloc(GetProcessHeap(), 0, len);
367 strcpyW(name, prefix);
368 strcatW(name, service);
369 handle = CreateEventW(NULL, TRUE, FALSE, name);
374 /******************************************************************************
377 * Call into the main service routine provided by StartServiceCtrlDispatcher.
379 static DWORD WINAPI service_thread(LPVOID arg)
381 service_data *info = arg;
382 LPWSTR str = info->args;
383 DWORD argc = 0, len = 0;
389 len += strlenW(&str[len]) + 1;
396 info->proc.w(0, NULL);
398 info->proc.a(0, NULL);
406 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
407 for (argc=0, p=str; *p; p += strlenW(p) + 1)
411 info->proc.w(argc, argv);
412 HeapFree(GetProcessHeap(), 0, argv);
416 LPSTR strA, *argv, p;
419 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
420 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
421 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
423 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
424 for (argc=0, p=strA; *p; p += strlen(p) + 1)
428 info->proc.a(argc, argv);
429 HeapFree(GetProcessHeap(), 0, argv);
430 HeapFree(GetProcessHeap(), 0, strA);
435 /******************************************************************************
436 * service_handle_start
438 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
440 DWORD read = 0, result = 0;
444 TRACE("%p %p %d\n", pipe, service, count);
446 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
447 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
448 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
450 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
451 r, count, read, debugstr_wn(args, count));
457 ERR("service is not stopped\n");
461 SERV_free(service->args);
462 service->args = args;
464 service->thread = CreateThread( NULL, 0, service_thread,
468 HeapFree(GetProcessHeap(), 0, args);
469 WriteFile( pipe, &result, sizeof result, &read, NULL );
474 /******************************************************************************
475 * service_send_start_message
477 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
479 DWORD i, len, count, result;
480 service_start_info *ssi;
484 TRACE("%p %p %d\n", pipe, argv, argc);
486 /* calculate how much space do we need to send the startup info */
488 for (i=0; i<argc; i++)
489 len += strlenW(argv[i])+1;
491 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
492 ssi->cmd = WINESERV_STARTINFO;
495 /* copy service args into a single buffer*/
497 for (i=0; i<argc; i++)
504 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
506 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
508 HeapFree(GetProcessHeap(),0,ssi);
513 /******************************************************************************
514 * service_handle_get_status
516 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
520 return WriteFile(pipe, &service->status,
521 sizeof service->status, &count, NULL);
524 /******************************************************************************
527 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
529 DWORD cmd[2], count = 0;
532 cmd[0] = WINESERV_GETSTATUS;
534 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
535 if (!r || count != sizeof cmd)
537 ERR("service protocol error - failed to write pipe!\n");
540 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
541 if (!r || count != sizeof *status)
542 ERR("service protocol error - failed to read pipe "
543 "r = %d count = %d!\n", r, count);
547 /******************************************************************************
548 * service_handle_set_processID
550 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
552 DWORD count, ret = ERROR_SUCCESS;
554 TRACE("received control %d\n", dwProcessId);
555 service->status.dwProcessId = dwProcessId;
556 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
559 /******************************************************************************
560 * service_set_processID
562 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
564 DWORD cmd[2], count = 0;
567 cmd[0] = WINESERV_SETPID;
568 cmd[1] = dwprocessId;
569 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
570 if (!r || count != sizeof cmd)
572 ERR("service protocol error - failed to write pipe!\n");
575 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
576 if (!r || count != sizeof *dwResult)
577 ERR("service protocol error - failed to read pipe "
578 "r = %d count = %d!\n", r, count);
582 /******************************************************************************
583 * service_send_control
585 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
587 DWORD cmd[2], count = 0;
590 cmd[0] = WINESERV_SENDCONTROL;
592 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
593 if (!r || count != sizeof cmd)
595 ERR("service protocol error - failed to write pipe!\n");
598 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
599 if (!r || count != sizeof *result)
600 ERR("service protocol error - failed to read pipe "
601 "r = %d count = %d!\n", r, count);
605 /******************************************************************************
606 * service_accepts_control
608 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
610 DWORD a = service->status.dwControlsAccepted;
614 case SERVICE_CONTROL_INTERROGATE:
616 case SERVICE_CONTROL_STOP:
617 if (a&SERVICE_ACCEPT_STOP)
620 case SERVICE_CONTROL_SHUTDOWN:
621 if (a&SERVICE_ACCEPT_SHUTDOWN)
624 case SERVICE_CONTROL_PAUSE:
625 case SERVICE_CONTROL_CONTINUE:
626 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
629 case SERVICE_CONTROL_PARAMCHANGE:
630 if (a&SERVICE_ACCEPT_PARAMCHANGE)
633 case SERVICE_CONTROL_NETBINDADD:
634 case SERVICE_CONTROL_NETBINDREMOVE:
635 case SERVICE_CONTROL_NETBINDENABLE:
636 case SERVICE_CONTROL_NETBINDDISABLE:
637 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
640 if (!service->extended)
644 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
645 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
648 case SERVICE_CONTROL_POWEREVENT:
649 if (a&SERVICE_ACCEPT_POWEREVENT)
652 case SERVICE_CONTROL_SESSIONCHANGE:
653 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
660 /******************************************************************************
661 * service_handle_control
663 static BOOL service_handle_control(HANDLE pipe, service_data *service,
666 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
668 TRACE("received control %d\n", dwControl);
670 if (service_accepts_control(service, dwControl))
672 if (service->extended && service->handler.handler_ex)
674 service->handler.handler_ex(dwControl, 0, NULL, service->context);
677 else if (service->handler.handler)
679 service->handler.handler(dwControl);
683 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
686 /******************************************************************************
687 * service_reap_thread
689 static DWORD service_reap_thread(service_data *service)
693 if (!service->thread)
695 GetExitCodeThread(service->thread, &exitcode);
696 if (exitcode!=STILL_ACTIVE)
698 CloseHandle(service->thread);
704 /******************************************************************************
705 * service_control_dispatcher
707 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
709 service_data *service = arg;
713 TRACE("%p %s\n", service, debugstr_w(service->name));
715 /* create a pipe to talk to the rest of the world with */
716 name = service_get_pipe_name(service->name);
717 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
718 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
721 /* let the process who started us know we've tried to create a pipe */
722 event = service_get_event_handle(service->name);
726 if (pipe==INVALID_HANDLE_VALUE)
728 ERR("failed to create pipe for %s, error = %d\n",
729 debugstr_w(service->name), GetLastError());
733 /* dispatcher loop */
737 DWORD count, req[2] = {0,0};
739 r = ConnectNamedPipe(pipe, NULL);
740 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
742 ERR("pipe connect failed\n");
746 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
747 if (!r || count!=sizeof req)
749 ERR("pipe read failed\n");
753 service_reap_thread(service);
755 /* handle the request */
758 case WINESERV_STARTINFO:
759 service_handle_start(pipe, service, req[1]);
761 case WINESERV_GETSTATUS:
762 service_handle_get_status(pipe, service);
764 case WINESERV_SENDCONTROL:
765 service_handle_control(pipe, service, req[1]);
767 case WINESERV_SETPID:
768 service_handle_set_processID(pipe, service, req[1]);
771 ERR("received invalid command %d length %d\n", req[0], req[1]);
774 FlushFileBuffers(pipe);
775 DisconnectNamedPipe(pipe);
782 /******************************************************************************
783 * service_run_threads
785 static BOOL service_run_threads(void)
787 service_data *service;
791 EnterCriticalSection( &service_cs );
793 count = list_count( &service_list );
795 TRACE("starting %d pipe listener threads\n", count);
797 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
799 handles[n++] = __wine_make_process_system();
801 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
802 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
804 assert(n == count + 1);
806 LeaveCriticalSection( &service_cs );
808 /* wait for all the threads to pack up and exit */
811 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
812 if (!ret) /* system process event */
814 TRACE( "last user process exited, shutting down\n" );
815 /* FIXME: we should maybe send a shutdown control to running services */
818 if (ret < MAXIMUM_WAIT_OBJECTS)
820 CloseHandle( handles[ret] );
821 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
827 while (n) CloseHandle( handles[--n] );
828 HeapFree(GetProcessHeap(), 0, handles);
833 /******************************************************************************
834 * StartServiceCtrlDispatcherA [ADVAPI32.@]
836 * See StartServiceCtrlDispatcherW.
838 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
844 TRACE("%p\n", servent);
846 EnterCriticalSection( &service_cs );
847 while (servent->lpServiceName)
849 LPSTR name = servent->lpServiceName;
851 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
852 sz = len*sizeof(WCHAR) + sizeof *info;
853 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
854 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
855 info->proc.a = servent->lpServiceProc;
856 info->unicode = FALSE;
857 list_add_head( &service_list, &info->entry );
860 LeaveCriticalSection( &service_cs );
862 service_run_threads();
867 /******************************************************************************
868 * StartServiceCtrlDispatcherW [ADVAPI32.@]
870 * Connects a process containing one or more services to the service control
874 * servent [I] A list of the service names and service procedures
880 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
886 TRACE("%p\n", servent);
888 EnterCriticalSection( &service_cs );
889 while (servent->lpServiceName)
891 LPWSTR name = servent->lpServiceName;
894 sz = len*sizeof(WCHAR) + sizeof *info;
895 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
896 strcpyW(info->name, name);
897 info->proc.w = servent->lpServiceProc;
898 info->unicode = TRUE;
899 list_add_head( &service_list, &info->entry );
902 LeaveCriticalSection( &service_cs );
904 service_run_threads();
909 /******************************************************************************
910 * LockServiceDatabase [ADVAPI32.@]
912 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
916 TRACE("%p\n",hSCManager);
918 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
919 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
923 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
926 TRACE("returning %p\n", ret);
931 /******************************************************************************
932 * UnlockServiceDatabase [ADVAPI32.@]
934 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
936 TRACE("%p\n",ScLock);
938 return CloseHandle( ScLock );
941 /******************************************************************************
942 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
944 SERVICE_STATUS_HANDLE WINAPI
945 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
947 LPWSTR lpServiceNameW;
948 SERVICE_STATUS_HANDLE ret;
950 lpServiceNameW = SERV_dup(lpServiceName);
951 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
952 SERV_free(lpServiceNameW);
956 /******************************************************************************
957 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
963 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
964 LPHANDLER_FUNCTION lpfHandler )
966 service_data *service;
967 SERVICE_STATUS_HANDLE handle = 0;
969 EnterCriticalSection( &service_cs );
970 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
972 if(!strcmpW(lpServiceName, service->name))
974 service->handler.handler = lpfHandler;
975 handle = (SERVICE_STATUS_HANDLE)service;
979 LeaveCriticalSection( &service_cs );
983 /******************************************************************************
984 * SetServiceStatus [ADVAPI32.@]
991 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
993 service_data *service;
996 TRACE("%p %x %x %x %x %x %x %x\n", hService,
997 lpStatus->dwServiceType, lpStatus->dwCurrentState,
998 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
999 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
1000 lpStatus->dwWaitHint);
1002 EnterCriticalSection( &service_cs );
1003 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
1005 if(service == (service_data*)hService)
1007 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
1008 TRACE("Set service status to %d\n",service->status.dwCurrentState);
1013 LeaveCriticalSection( &service_cs );
1019 /******************************************************************************
1020 * OpenSCManagerA [ADVAPI32.@]
1022 * Establish a connection to the service control manager and open its database.
1025 * lpMachineName [I] Pointer to machine name string
1026 * lpDatabaseName [I] Pointer to database name string
1027 * dwDesiredAccess [I] Type of access
1030 * Success: A Handle to the service control manager database
1033 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1034 DWORD dwDesiredAccess )
1036 LPWSTR lpMachineNameW, lpDatabaseNameW;
1039 lpMachineNameW = SERV_dup(lpMachineName);
1040 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1041 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1042 SERV_free(lpDatabaseNameW);
1043 SERV_free(lpMachineNameW);
1047 /******************************************************************************
1048 * OpenSCManagerW [ADVAPI32.@]
1050 * See OpenSCManagerA.
1052 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1053 DWORD dwDesiredAccess )
1055 struct sc_manager *manager;
1058 DWORD new_mask = dwDesiredAccess;
1060 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1061 debugstr_w(lpDatabaseName), dwDesiredAccess);
1063 if( lpDatabaseName && lpDatabaseName[0] )
1065 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1067 /* noop, all right */
1069 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1071 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1076 SetLastError( ERROR_INVALID_NAME );
1081 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1082 sc_handle_destroy_manager );
1086 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1087 if (r!=ERROR_SUCCESS)
1090 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1091 RegCloseKey( hReg );
1092 if (r!=ERROR_SUCCESS)
1095 RtlMapGenericMask(&new_mask, &scm_generic);
1096 manager->dwAccess = new_mask;
1097 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1099 return (SC_HANDLE) &manager->hdr;
1102 sc_handle_free( &manager->hdr );
1107 /******************************************************************************
1108 * ControlService [ADVAPI32.@]
1110 * Send a control code to a service.
1113 * hService [I] Handle of the service control manager database
1114 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1115 * lpServiceStatus [O] Destination for the status of the service, if available
1122 * Unlike M$' implementation, control requests are not serialized and may be
1123 * processed asynchronously.
1125 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1126 LPSERVICE_STATUS lpServiceStatus )
1128 struct sc_service *hsvc;
1132 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1134 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1137 SetLastError( ERROR_INVALID_HANDLE );
1141 ret = QueryServiceStatus(hService, lpServiceStatus);
1144 ERR("failed to query service status\n");
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1149 switch (lpServiceStatus->dwCurrentState)
1151 case SERVICE_STOPPED:
1152 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1154 case SERVICE_START_PENDING:
1155 if (dwControl==SERVICE_CONTROL_STOP)
1158 case SERVICE_STOP_PENDING:
1159 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1163 handle = service_open_pipe(hsvc->name);
1164 if (handle!=INVALID_HANDLE_VALUE)
1166 DWORD result = ERROR_SUCCESS;
1167 ret = service_send_control(handle, dwControl, &result);
1168 CloseHandle(handle);
1169 if (result!=ERROR_SUCCESS)
1171 SetLastError(result);
1179 /******************************************************************************
1180 * CloseServiceHandle [ADVAPI32.@]
1182 * Close a handle to a service or the service control manager database.
1185 * hSCObject [I] Handle to service or service control manager database
1192 CloseServiceHandle( SC_HANDLE hSCObject )
1194 TRACE("%p\n", hSCObject);
1196 sc_handle_free( (struct sc_handle*) hSCObject );
1202 /******************************************************************************
1203 * OpenServiceA [ADVAPI32.@]
1205 * Open a handle to a service.
1208 * hSCManager [I] Handle of the service control manager database
1209 * lpServiceName [I] Name of the service to open
1210 * dwDesiredAccess [I] Access required to the service
1213 * Success: Handle to the service
1216 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1217 DWORD dwDesiredAccess )
1219 LPWSTR lpServiceNameW;
1222 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1224 lpServiceNameW = SERV_dup(lpServiceName);
1225 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1226 SERV_free(lpServiceNameW);
1231 /******************************************************************************
1232 * OpenServiceW [ADVAPI32.@]
1236 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1237 DWORD dwDesiredAccess)
1239 struct sc_manager *hscm;
1240 struct sc_service *hsvc;
1244 DWORD new_mask = dwDesiredAccess;
1246 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1248 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1251 SetLastError( ERROR_INVALID_HANDLE );
1257 SetLastError(ERROR_INVALID_ADDRESS);
1261 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1262 if (r!=ERROR_SUCCESS)
1264 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1268 len = strlenW(lpServiceName)+1;
1269 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1270 sizeof (struct sc_service) + len*sizeof(WCHAR),
1271 sc_handle_destroy_service );
1277 strcpyW( hsvc->name, lpServiceName );
1280 RtlMapGenericMask(&new_mask, &svc_generic);
1281 hsvc->dwAccess = new_mask;
1283 /* add reference to SCM handle */
1284 hscm->hdr.ref_count++;
1287 TRACE("returning %p\n",hsvc);
1289 return (SC_HANDLE) &hsvc->hdr;
1292 /******************************************************************************
1293 * CreateServiceW [ADVAPI32.@]
1296 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1297 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1298 DWORD dwServiceType, DWORD dwStartType,
1299 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1300 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1301 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1302 LPCWSTR lpPassword )
1304 struct sc_manager *hscm;
1305 struct sc_service *hsvc = NULL;
1309 struct reg_value val[10];
1311 DWORD new_mask = dwDesiredAccess;
1313 WCHAR buffer[MAX_PATH];
1314 BOOL displayname_exists = FALSE;
1316 TRACE("%p %s %s\n", hSCManager,
1317 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1319 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1322 SetLastError( ERROR_INVALID_HANDLE );
1326 if (!lpServiceName || !lpBinaryPathName)
1328 SetLastError(ERROR_INVALID_ADDRESS);
1332 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1334 SetLastError(ERROR_ACCESS_DENIED);
1338 if (!lpServiceName[0])
1340 SetLastError(ERROR_INVALID_NAME);
1344 if (!lpBinaryPathName[0])
1346 SetLastError(ERROR_INVALID_PARAMETER);
1350 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1351 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1352 * runs under the LocalSystem account)
1354 switch (dwServiceType)
1356 case SERVICE_KERNEL_DRIVER:
1357 case SERVICE_FILE_SYSTEM_DRIVER:
1358 case SERVICE_WIN32_OWN_PROCESS:
1359 case SERVICE_WIN32_SHARE_PROCESS:
1362 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1363 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1364 /* FIXME : Do we need a more thorough check? */
1365 if (lpServiceStartName)
1367 SetLastError(ERROR_INVALID_PARAMETER);
1372 SetLastError(ERROR_INVALID_PARAMETER);
1376 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1377 if (dwStartType > SERVICE_DISABLED)
1379 SetLastError(ERROR_INVALID_PARAMETER);
1383 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1384 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1385 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1387 SetLastError(ERROR_INVALID_PARAMETER);
1391 /* Loop through the registry to check if the service already exists and to
1392 * check if we can use the given displayname.
1393 * FIXME: Should we use EnumServicesStatusEx?
1395 len = sizeof(buffer);
1396 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1400 /* The service already exists, so bail out */
1401 if(!lstrcmpiW(lpServiceName, buffer))
1403 SetLastError(ERROR_SERVICE_EXISTS);
1407 /* The given displayname matches the found servicename. We don't bail out
1408 * as servicename is checked before a duplicate displayname
1410 if(!lstrcmpiW(lpDisplayName, buffer))
1411 displayname_exists = TRUE;
1413 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1415 WCHAR name[MAX_PATH];
1416 DWORD size = sizeof(name);
1418 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1420 /* The given displayname matches the found displayname */
1421 if (!lstrcmpiW(lpDisplayName, name))
1422 displayname_exists = TRUE;
1424 RegCloseKey(service_key);
1427 len = sizeof(buffer);
1430 if (lpDisplayName && displayname_exists)
1432 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1436 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1437 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1438 if (r!=ERROR_SUCCESS)
1440 /* FIXME: Should we set an error? */
1445 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1447 service_set_dword( &val[n++], szType, &dwServiceType );
1448 service_set_dword( &val[n++], szStart, &dwStartType );
1449 service_set_dword( &val[n++], szError, &dwErrorControl );
1451 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1453 if( lpLoadOrderGroup )
1454 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1456 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1457 * There is no such key as what szDependencies refers to */
1458 if( lpDependencies )
1459 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1462 FIXME("Don't know how to add a Password for a service.\n");
1464 if( lpServiceStartName )
1465 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1467 r = service_write_values( hKey, val, n );
1468 if( r != ERROR_SUCCESS )
1471 len = strlenW(lpServiceName)+1;
1472 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1473 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1476 lstrcpyW( hsvc->name, lpServiceName );
1479 RtlMapGenericMask(&new_mask, &svc_generic);
1480 hsvc->dwAccess = new_mask;
1483 hscm->hdr.ref_count++;
1485 return (SC_HANDLE) &hsvc->hdr;
1488 RegCloseKey( hKey );
1493 /******************************************************************************
1494 * CreateServiceA [ADVAPI32.@]
1497 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1498 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1499 DWORD dwServiceType, DWORD dwStartType,
1500 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1501 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1502 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1505 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1506 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1509 TRACE("%p %s %s\n", hSCManager,
1510 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1512 lpServiceNameW = SERV_dup( lpServiceName );
1513 lpDisplayNameW = SERV_dup( lpDisplayName );
1514 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1515 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1516 lpDependenciesW = SERV_dupmulti( lpDependencies );
1517 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1518 lpPasswordW = SERV_dup( lpPassword );
1520 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1521 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1522 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1523 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1525 SERV_free( lpServiceNameW );
1526 SERV_free( lpDisplayNameW );
1527 SERV_free( lpBinaryPathNameW );
1528 SERV_free( lpLoadOrderGroupW );
1529 SERV_free( lpDependenciesW );
1530 SERV_free( lpServiceStartNameW );
1531 SERV_free( lpPasswordW );
1537 /******************************************************************************
1538 * DeleteService [ADVAPI32.@]
1540 * Delete a service from the service control manager database.
1543 * hService [I] Handle of the service to delete
1549 BOOL WINAPI DeleteService( SC_HANDLE hService )
1551 struct sc_service *hsvc;
1553 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1556 SetLastError( ERROR_INVALID_HANDLE );
1560 if (!(hsvc->dwAccess & DELETE))
1562 SetLastError(ERROR_ACCESS_DENIED);
1566 /* Close the key to the service */
1567 RegCloseKey(hsvc->hkey);
1569 /* Delete the service under the Service Control Manager key */
1570 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1578 /******************************************************************************
1579 * StartServiceA [ADVAPI32.@]
1584 * hService [I] Handle of service
1585 * dwNumServiceArgs [I] Number of arguments
1586 * lpServiceArgVectors [I] Address of array of argument strings
1589 * - NT implements this function using an obscure RPC call.
1590 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1591 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1592 * - This will only work for shared address space. How should the service
1593 * args be transferred when address spaces are separated?
1594 * - Can only start one service at a time.
1595 * - Has no concept of privilege.
1601 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1602 LPCSTR *lpServiceArgVectors )
1604 LPWSTR *lpwstr=NULL;
1608 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1610 if (dwNumServiceArgs)
1611 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1612 dwNumServiceArgs*sizeof(LPWSTR) );
1614 for(i=0; i<dwNumServiceArgs; i++)
1615 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1617 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1619 if (dwNumServiceArgs)
1621 for(i=0; i<dwNumServiceArgs; i++)
1622 SERV_free(lpwstr[i]);
1623 HeapFree(GetProcessHeap(), 0, lpwstr);
1629 /******************************************************************************
1630 * service_start_process [INTERNAL]
1632 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1634 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1635 PROCESS_INFORMATION pi;
1637 LPWSTR path = NULL, str;
1638 DWORD type, size, ret, svc_type;
1642 size = sizeof(svc_type);
1643 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1646 if (svc_type == SERVICE_KERNEL_DRIVER)
1648 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1649 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1651 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1652 GetSystemDirectoryW( path, len );
1653 lstrcatW( path, winedeviceW );
1654 lstrcatW( path, hsvc->name );
1658 /* read the executable path from the registry */
1660 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1661 if (ret!=ERROR_SUCCESS)
1663 str = HeapAlloc(GetProcessHeap(),0,size);
1664 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1665 if (ret==ERROR_SUCCESS)
1667 size = ExpandEnvironmentStringsW(str,NULL,0);
1668 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1669 ExpandEnvironmentStringsW(str,path,size);
1671 HeapFree(GetProcessHeap(),0,str);
1676 /* wait for the process to start and set an event or terminate */
1677 handles[0] = service_get_event_handle( hsvc->name );
1678 ZeroMemory(&si, sizeof(STARTUPINFOW));
1679 si.cb = sizeof(STARTUPINFOW);
1680 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1683 if (ppid) *ppid = pi.dwProcessId;
1685 handles[1] = pi.hProcess;
1686 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1687 if(ret != WAIT_OBJECT_0)
1689 SetLastError(ERROR_IO_PENDING);
1693 CloseHandle( pi.hThread );
1694 CloseHandle( pi.hProcess );
1696 CloseHandle( handles[0] );
1697 HeapFree(GetProcessHeap(),0,path);
1701 static BOOL service_wait_for_startup(SC_HANDLE hService)
1704 SERVICE_STATUS status;
1707 TRACE("%p\n", hService);
1709 for (i=0; i<30; i++)
1711 status.dwCurrentState = 0;
1712 r = QueryServiceStatus(hService, &status);
1715 if (status.dwCurrentState == SERVICE_RUNNING)
1717 TRACE("Service started successfully\n");
1726 /******************************************************************************
1727 * StartServiceW [ADVAPI32.@]
1729 * See StartServiceA.
1731 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1732 LPCWSTR *lpServiceArgVectors)
1734 struct sc_service *hsvc;
1736 DWORD dwResult, dwProcessId = 0;
1738 HANDLE handle = INVALID_HANDLE_VALUE;
1740 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1742 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1745 SetLastError(ERROR_INVALID_HANDLE);
1749 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1753 handle = service_open_pipe(hsvc->name);
1754 if (handle==INVALID_HANDLE_VALUE)
1756 /* start the service process */
1757 if (service_start_process(hsvc, &dwProcessId))
1758 handle = service_open_pipe(hsvc->name);
1761 if (handle != INVALID_HANDLE_VALUE)
1763 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1764 CloseHandle(handle);
1767 handle = service_open_pipe(hsvc->name);
1768 if (handle != INVALID_HANDLE_VALUE)
1770 service_set_processID(handle, dwProcessId, &dwResult);
1771 CloseHandle(handle);
1774 UnlockServiceDatabase( hLock );
1776 TRACE("returning %d\n", r);
1779 service_wait_for_startup(hService);
1784 /******************************************************************************
1785 * QueryServiceStatus [ADVAPI32.@]
1788 * hService [I] Handle to service to get information about
1789 * lpservicestatus [O] buffer to receive the status information for the service
1792 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1793 LPSERVICE_STATUS lpservicestatus)
1795 SERVICE_STATUS_PROCESS SvcStatusData;
1798 TRACE("%p %p\n", hService, lpservicestatus);
1800 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1801 sizeof(SERVICE_STATUS_PROCESS), NULL);
1802 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1807 /******************************************************************************
1808 * QueryServiceStatusEx [ADVAPI32.@]
1810 * Get information about a service.
1813 * hService [I] Handle to service to get information about
1814 * InfoLevel [I] Level of information to get
1815 * lpBuffer [O] Destination for requested information
1816 * cbBufSize [I] Size of lpBuffer in bytes
1817 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1823 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1824 LPBYTE lpBuffer, DWORD cbBufSize,
1825 LPDWORD pcbBytesNeeded)
1827 struct sc_service *hsvc;
1828 DWORD size, type, val;
1831 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1833 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1835 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1837 SetLastError( ERROR_INVALID_LEVEL);
1841 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1842 if (pSvcStatusData == NULL)
1844 SetLastError( ERROR_INVALID_PARAMETER);
1848 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1850 if( pcbBytesNeeded != NULL)
1851 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1853 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1857 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1860 SetLastError( ERROR_INVALID_HANDLE );
1864 pipe = service_open_pipe(hsvc->name);
1865 if (pipe != INVALID_HANDLE_VALUE)
1867 r = service_get_status(pipe, pSvcStatusData);
1873 TRACE("Failed to read service status\n");
1875 /* read the service type from the registry */
1877 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1878 if (r != ERROR_SUCCESS || type != REG_DWORD)
1881 pSvcStatusData->dwServiceType = val;
1882 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1883 pSvcStatusData->dwControlsAccepted = 0;
1884 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1885 pSvcStatusData->dwServiceSpecificExitCode = 0;
1886 pSvcStatusData->dwCheckPoint = 0;
1887 pSvcStatusData->dwWaitHint = 0;
1892 /******************************************************************************
1893 * QueryServiceConfigA [ADVAPI32.@]
1895 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1896 DWORD size, LPDWORD needed )
1901 QUERY_SERVICE_CONFIGW *configW;
1903 TRACE("%p %p %d %p\n", hService, config, size, needed);
1905 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1907 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1910 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1911 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1912 if (!ret) goto done;
1914 config->dwServiceType = configW->dwServiceType;
1915 config->dwStartType = configW->dwStartType;
1916 config->dwErrorControl = configW->dwErrorControl;
1917 config->lpBinaryPathName = NULL;
1918 config->lpLoadOrderGroup = NULL;
1919 config->dwTagId = configW->dwTagId;
1920 config->lpDependencies = NULL;
1921 config->lpServiceStartName = NULL;
1922 config->lpDisplayName = NULL;
1924 p = (LPSTR)(config + 1);
1925 n = size - sizeof(*config);
1928 #define MAP_STR(str) \
1932 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1933 if (!sz) goto done; \
1940 MAP_STR( lpBinaryPathName );
1941 MAP_STR( lpLoadOrderGroup );
1942 MAP_STR( lpDependencies );
1943 MAP_STR( lpServiceStartName );
1944 MAP_STR( lpDisplayName );
1947 *needed = p - (LPSTR)config;
1951 HeapFree( GetProcessHeap(), 0, buffer );
1955 /******************************************************************************
1956 * QueryServiceConfigW [ADVAPI32.@]
1959 QueryServiceConfigW( SC_HANDLE hService,
1960 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1961 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1963 WCHAR str_buffer[ MAX_PATH ];
1965 DWORD type, val, sz, total, n;
1968 struct sc_service *hsvc;
1970 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1971 cbBufSize, pcbBytesNeeded);
1973 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1976 SetLastError( ERROR_INVALID_HANDLE );
1981 /* TODO: Check which members are mandatory and what the registry types
1982 * should be. This should of course also be tested when a service is
1986 /* calculate the size required first */
1987 total = sizeof (QUERY_SERVICE_CONFIGW);
1989 sz = sizeof(str_buffer);
1990 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1991 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1993 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1994 if( 0 == sz ) return FALSE;
1996 total += sizeof(WCHAR) * sz;
2000 /* FIXME: set last error */
2005 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
2006 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2009 total += sizeof(WCHAR);
2012 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
2013 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
2016 total += sizeof(WCHAR);
2019 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
2020 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2023 total += sizeof(WCHAR);
2026 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
2027 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2030 total += sizeof(WCHAR);
2032 *pcbBytesNeeded = total;
2034 /* if there's not enough memory, return an error */
2035 if( total > cbBufSize )
2037 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2041 ZeroMemory( lpServiceConfig, total );
2044 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2045 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2046 lpServiceConfig->dwServiceType = val;
2049 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2050 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2051 lpServiceConfig->dwStartType = val;
2054 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2055 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2056 lpServiceConfig->dwErrorControl = val;
2059 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2060 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2061 lpServiceConfig->dwTagId = val;
2063 /* now do the strings */
2064 p = (LPBYTE) &lpServiceConfig[1];
2065 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2067 sz = sizeof(str_buffer);
2068 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2069 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2071 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2072 sz *= sizeof(WCHAR);
2073 if( 0 == sz || sz > n ) return FALSE;
2075 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2081 /* FIXME: set last error */
2086 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2087 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2088 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2101 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2102 lpServiceConfig->lpDependencies = (LPWSTR) p;
2103 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2116 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2117 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2118 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2131 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2132 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2133 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2146 ERR("Buffer overflow!\n");
2148 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2149 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2150 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2151 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2152 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2157 /******************************************************************************
2158 * EnumServicesStatusA [ADVAPI32.@]
2161 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2162 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2163 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2164 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2166 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2167 dwServiceType, dwServiceState, lpServices, cbBufSize,
2168 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2169 SetLastError (ERROR_ACCESS_DENIED);
2173 /******************************************************************************
2174 * EnumServicesStatusW [ADVAPI32.@]
2177 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2178 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2179 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2180 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2182 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2183 dwServiceType, dwServiceState, lpServices, cbBufSize,
2184 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2185 SetLastError (ERROR_ACCESS_DENIED);
2189 /******************************************************************************
2190 * EnumServicesStatusExA [ADVAPI32.@]
2193 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2194 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2195 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2197 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2198 dwServiceType, dwServiceState, lpServices, cbBufSize,
2199 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2200 SetLastError (ERROR_ACCESS_DENIED);
2204 /******************************************************************************
2205 * EnumServicesStatusExW [ADVAPI32.@]
2208 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2209 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2210 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2212 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2213 dwServiceType, dwServiceState, lpServices, cbBufSize,
2214 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2215 SetLastError (ERROR_ACCESS_DENIED);
2219 /******************************************************************************
2220 * GetServiceKeyNameA [ADVAPI32.@]
2222 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2223 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2225 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2229 /******************************************************************************
2230 * GetServiceKeyNameW [ADVAPI32.@]
2232 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2233 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2235 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2239 /******************************************************************************
2240 * QueryServiceLockStatusA [ADVAPI32.@]
2242 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2243 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2244 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2246 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2251 /******************************************************************************
2252 * QueryServiceLockStatusW [ADVAPI32.@]
2254 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2255 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2256 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2258 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2263 /******************************************************************************
2264 * GetServiceDisplayNameA [ADVAPI32.@]
2266 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2267 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2269 LPWSTR lpServiceNameW, lpDisplayNameW = NULL;
2270 DWORD size, sizeW, GLE;
2273 TRACE("%p %s %p %p\n", hSCManager,
2274 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2276 lpServiceNameW = SERV_dup(lpServiceName);
2277 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2279 size = sizeW = *lpcchBuffer;
2280 ret = GetServiceDisplayNameW(hSCManager, lpServiceNameW,
2281 lpDisplayName ? lpDisplayNameW : NULL,
2283 /* Last error will be set by GetServiceDisplayNameW and must be preserved */
2284 GLE = GetLastError();
2286 if (!lpDisplayName && lpcchBuffer && !ret && (GLE == ERROR_INSUFFICIENT_BUFFER))
2288 /* Request for buffersize.
2290 * Only set the size for ERROR_INSUFFICIENT_BUFFER
2294 else if (lpDisplayName && lpcchBuffer && !ret)
2296 /* Request for displayname.
2298 * size only has to be set if this fails
2303 WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2304 *lpcchBuffer, NULL, NULL );
2306 *lpcchBuffer = size;
2308 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2309 SERV_free(lpServiceNameW);
2315 /******************************************************************************
2316 * GetServiceDisplayNameW [ADVAPI32.@]
2318 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2319 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2321 struct sc_manager *hscm;
2325 TRACE("%p %s %p %p\n", hSCManager,
2326 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2328 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2331 SetLastError(ERROR_INVALID_HANDLE);
2337 SetLastError(ERROR_INVALID_ADDRESS);
2341 size = *lpcchBuffer * sizeof(WCHAR);
2342 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2343 if (!ret && !lpDisplayName && size)
2344 ret = ERROR_MORE_DATA;
2348 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2350 if (ret == ERROR_MORE_DATA)
2352 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2353 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2360 /* Always return the correct needed size on success */
2361 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2366 /******************************************************************************
2367 * ChangeServiceConfigW [ADVAPI32.@]
2369 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2370 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2371 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2372 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2374 struct reg_value val[10];
2375 struct sc_service *hsvc;
2376 DWORD r = ERROR_SUCCESS;
2380 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2381 hService, dwServiceType, dwStartType, dwErrorControl,
2382 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2383 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2384 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2386 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2389 SetLastError( ERROR_INVALID_HANDLE );
2394 if( dwServiceType != SERVICE_NO_CHANGE )
2395 service_set_dword( &val[n++], szType, &dwServiceType );
2397 if( dwStartType != SERVICE_NO_CHANGE )
2398 service_set_dword( &val[n++], szStart, &dwStartType );
2400 if( dwErrorControl != SERVICE_NO_CHANGE )
2401 service_set_dword( &val[n++], szError, &dwErrorControl );
2403 if( lpBinaryPathName )
2404 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2406 if( lpLoadOrderGroup )
2407 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2409 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2410 * There is no such key as what szDependencies refers to */
2411 if( lpDependencies )
2412 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2415 FIXME("ignoring password\n");
2417 if( lpServiceStartName )
2418 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2420 r = service_write_values( hsvc->hkey, val, n );
2422 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2425 /******************************************************************************
2426 * ChangeServiceConfigA [ADVAPI32.@]
2428 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2429 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2430 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2431 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2433 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2434 LPWSTR wServiceStartName, wPassword, wDisplayName;
2437 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2438 hService, dwServiceType, dwStartType, dwErrorControl,
2439 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2440 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2441 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2443 wBinaryPathName = SERV_dup( lpBinaryPathName );
2444 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2445 wDependencies = SERV_dupmulti( lpDependencies );
2446 wServiceStartName = SERV_dup( lpServiceStartName );
2447 wPassword = SERV_dup( lpPassword );
2448 wDisplayName = SERV_dup( lpDisplayName );
2450 r = ChangeServiceConfigW( hService, dwServiceType,
2451 dwStartType, dwErrorControl, wBinaryPathName,
2452 wLoadOrderGroup, lpdwTagId, wDependencies,
2453 wServiceStartName, wPassword, wDisplayName);
2455 SERV_free( wBinaryPathName );
2456 SERV_free( wLoadOrderGroup );
2457 SERV_free( wDependencies );
2458 SERV_free( wServiceStartName );
2459 SERV_free( wPassword );
2460 SERV_free( wDisplayName );
2465 /******************************************************************************
2466 * ChangeServiceConfig2A [ADVAPI32.@]
2468 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2473 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2475 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2477 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2478 SERVICE_DESCRIPTIONW sdw;
2480 sdw.lpDescription = SERV_dup( sd->lpDescription );
2482 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2484 SERV_free( sdw.lpDescription );
2486 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2488 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2489 SERVICE_FAILURE_ACTIONSW faw;
2491 faw.dwResetPeriod = fa->dwResetPeriod;
2492 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2493 faw.lpCommand = SERV_dup( fa->lpCommand );
2494 faw.cActions = fa->cActions;
2495 faw.lpsaActions = fa->lpsaActions;
2497 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2499 SERV_free( faw.lpRebootMsg );
2500 SERV_free( faw.lpCommand );
2503 SetLastError( ERROR_INVALID_PARAMETER );
2508 /******************************************************************************
2509 * ChangeServiceConfig2W [ADVAPI32.@]
2511 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2515 struct sc_service *hsvc;
2517 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2520 SetLastError( ERROR_INVALID_HANDLE );
2525 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2527 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2528 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2529 if (sd->lpDescription)
2531 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2532 if (sd->lpDescription[0] == 0)
2533 RegDeleteValueW(hKey,szDescription);
2535 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2536 (LPVOID)sd->lpDescription,
2537 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2541 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2545 /******************************************************************************
2546 * QueryServiceObjectSecurity [ADVAPI32.@]
2548 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2549 SECURITY_INFORMATION dwSecurityInformation,
2550 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2551 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2555 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2556 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2558 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2560 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2561 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2562 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2566 /******************************************************************************
2567 * SetServiceObjectSecurity [ADVAPI32.@]
2569 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2570 SECURITY_INFORMATION dwSecurityInformation,
2571 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2573 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2577 /******************************************************************************
2578 * SetServiceBits [ADVAPI32.@]
2580 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2581 DWORD dwServiceBits,
2583 BOOL bUpdateImmediately)
2585 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2586 bSetBitsOn, bUpdateImmediately);
2590 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2591 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2593 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2597 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2598 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2600 service_data *service;
2601 SERVICE_STATUS_HANDLE handle = 0;
2603 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2605 EnterCriticalSection( &service_cs );
2606 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2608 if(!strcmpW(lpServiceName, service->name))
2610 service->handler.handler_ex = lpHandlerProc;
2611 service->context = lpContext;
2612 service->extended = TRUE;
2613 handle = (SERVICE_STATUS_HANDLE)service;
2617 LeaveCriticalSection( &service_cs );