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 TRACE("%p %s %s\n", hSCManager,
1314 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1316 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1319 SetLastError( ERROR_INVALID_HANDLE );
1323 if (!lpServiceName || !lpBinaryPathName)
1325 SetLastError(ERROR_INVALID_ADDRESS);
1329 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1331 SetLastError(ERROR_ACCESS_DENIED);
1335 if (!lpServiceName[0])
1337 SetLastError(ERROR_INVALID_NAME);
1341 if (!lpBinaryPathName[0])
1343 SetLastError(ERROR_INVALID_PARAMETER);
1347 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1348 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1349 * runs under the LocalSystem account)
1351 switch (dwServiceType)
1353 case SERVICE_KERNEL_DRIVER:
1354 case SERVICE_FILE_SYSTEM_DRIVER:
1355 case SERVICE_WIN32_OWN_PROCESS:
1356 case SERVICE_WIN32_SHARE_PROCESS:
1359 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1360 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1361 /* FIXME : Do we need a more thorough check? */
1362 if (lpServiceStartName)
1364 SetLastError(ERROR_INVALID_PARAMETER);
1369 SetLastError(ERROR_INVALID_PARAMETER);
1373 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1374 if (dwStartType > SERVICE_DISABLED)
1376 SetLastError(ERROR_INVALID_PARAMETER);
1380 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1381 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1382 if (r!=ERROR_SUCCESS)
1385 if (dp != REG_CREATED_NEW_KEY)
1387 SetLastError(ERROR_SERVICE_EXISTS);
1392 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1394 service_set_dword( &val[n++], szType, &dwServiceType );
1395 service_set_dword( &val[n++], szStart, &dwStartType );
1396 service_set_dword( &val[n++], szError, &dwErrorControl );
1398 if( lpBinaryPathName )
1399 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1401 if( lpLoadOrderGroup )
1402 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1404 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1405 * There is no such key as what szDependencies refers to */
1406 if( lpDependencies )
1407 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1410 FIXME("Don't know how to add a Password for a service.\n");
1412 if( lpServiceStartName )
1413 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1415 r = service_write_values( hKey, val, n );
1416 if( r != ERROR_SUCCESS )
1419 len = strlenW(lpServiceName)+1;
1420 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1421 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1424 lstrcpyW( hsvc->name, lpServiceName );
1427 RtlMapGenericMask(&new_mask, &svc_generic);
1428 hsvc->dwAccess = new_mask;
1431 hscm->hdr.ref_count++;
1433 return (SC_HANDLE) &hsvc->hdr;
1436 RegCloseKey( hKey );
1441 /******************************************************************************
1442 * CreateServiceA [ADVAPI32.@]
1445 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1446 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1447 DWORD dwServiceType, DWORD dwStartType,
1448 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1449 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1450 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1453 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1454 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1457 TRACE("%p %s %s\n", hSCManager,
1458 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1460 lpServiceNameW = SERV_dup( lpServiceName );
1461 lpDisplayNameW = SERV_dup( lpDisplayName );
1462 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1463 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1464 lpDependenciesW = SERV_dupmulti( lpDependencies );
1465 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1466 lpPasswordW = SERV_dup( lpPassword );
1468 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1469 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1470 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1471 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1473 SERV_free( lpServiceNameW );
1474 SERV_free( lpDisplayNameW );
1475 SERV_free( lpBinaryPathNameW );
1476 SERV_free( lpLoadOrderGroupW );
1477 SERV_free( lpDependenciesW );
1478 SERV_free( lpServiceStartNameW );
1479 SERV_free( lpPasswordW );
1485 /******************************************************************************
1486 * DeleteService [ADVAPI32.@]
1488 * Delete a service from the service control manager database.
1491 * hService [I] Handle of the service to delete
1497 BOOL WINAPI DeleteService( SC_HANDLE hService )
1499 struct sc_service *hsvc;
1501 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1504 SetLastError( ERROR_INVALID_HANDLE );
1508 /* Close the key to the service */
1509 RegCloseKey(hsvc->hkey);
1511 /* Delete the service under the Service Control Manager key */
1512 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1520 /******************************************************************************
1521 * StartServiceA [ADVAPI32.@]
1526 * hService [I] Handle of service
1527 * dwNumServiceArgs [I] Number of arguments
1528 * lpServiceArgVectors [I] Address of array of argument strings
1531 * - NT implements this function using an obscure RPC call.
1532 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1533 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1534 * - This will only work for shared address space. How should the service
1535 * args be transferred when address spaces are separated?
1536 * - Can only start one service at a time.
1537 * - Has no concept of privilege.
1543 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1544 LPCSTR *lpServiceArgVectors )
1546 LPWSTR *lpwstr=NULL;
1550 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1552 if (dwNumServiceArgs)
1553 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1554 dwNumServiceArgs*sizeof(LPWSTR) );
1556 for(i=0; i<dwNumServiceArgs; i++)
1557 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1559 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1561 if (dwNumServiceArgs)
1563 for(i=0; i<dwNumServiceArgs; i++)
1564 SERV_free(lpwstr[i]);
1565 HeapFree(GetProcessHeap(), 0, lpwstr);
1571 /******************************************************************************
1572 * service_start_process [INTERNAL]
1574 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1576 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1577 PROCESS_INFORMATION pi;
1579 LPWSTR path = NULL, str;
1580 DWORD type, size, ret, svc_type;
1584 size = sizeof(svc_type);
1585 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1588 if (svc_type == SERVICE_KERNEL_DRIVER)
1590 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1591 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1593 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1594 GetSystemDirectoryW( path, len );
1595 lstrcatW( path, winedeviceW );
1596 lstrcatW( path, hsvc->name );
1600 /* read the executable path from the registry */
1602 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1603 if (ret!=ERROR_SUCCESS)
1605 str = HeapAlloc(GetProcessHeap(),0,size);
1606 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1607 if (ret==ERROR_SUCCESS)
1609 size = ExpandEnvironmentStringsW(str,NULL,0);
1610 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1611 ExpandEnvironmentStringsW(str,path,size);
1613 HeapFree(GetProcessHeap(),0,str);
1618 /* wait for the process to start and set an event or terminate */
1619 handles[0] = service_get_event_handle( hsvc->name );
1620 ZeroMemory(&si, sizeof(STARTUPINFOW));
1621 si.cb = sizeof(STARTUPINFOW);
1622 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1625 if (ppid) *ppid = pi.dwProcessId;
1627 handles[1] = pi.hProcess;
1628 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1629 if(ret != WAIT_OBJECT_0)
1631 SetLastError(ERROR_IO_PENDING);
1635 CloseHandle( pi.hThread );
1636 CloseHandle( pi.hProcess );
1638 CloseHandle( handles[0] );
1639 HeapFree(GetProcessHeap(),0,path);
1643 static BOOL service_wait_for_startup(SC_HANDLE hService)
1646 SERVICE_STATUS status;
1649 TRACE("%p\n", hService);
1651 for (i=0; i<30; i++)
1653 status.dwCurrentState = 0;
1654 r = QueryServiceStatus(hService, &status);
1657 if (status.dwCurrentState == SERVICE_RUNNING)
1659 TRACE("Service started successfully\n");
1668 /******************************************************************************
1669 * StartServiceW [ADVAPI32.@]
1671 * See StartServiceA.
1673 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1674 LPCWSTR *lpServiceArgVectors)
1676 struct sc_service *hsvc;
1678 DWORD dwResult, dwProcessId = 0;
1680 HANDLE handle = INVALID_HANDLE_VALUE;
1682 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1684 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1687 SetLastError(ERROR_INVALID_HANDLE);
1691 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1695 handle = service_open_pipe(hsvc->name);
1696 if (handle==INVALID_HANDLE_VALUE)
1698 /* start the service process */
1699 if (service_start_process(hsvc, &dwProcessId))
1700 handle = service_open_pipe(hsvc->name);
1703 if (handle != INVALID_HANDLE_VALUE)
1705 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1706 CloseHandle(handle);
1709 handle = service_open_pipe(hsvc->name);
1710 if (handle != INVALID_HANDLE_VALUE)
1712 service_set_processID(handle, dwProcessId, &dwResult);
1713 CloseHandle(handle);
1716 UnlockServiceDatabase( hLock );
1718 TRACE("returning %d\n", r);
1721 service_wait_for_startup(hService);
1726 /******************************************************************************
1727 * QueryServiceStatus [ADVAPI32.@]
1730 * hService [I] Handle to service to get information about
1731 * lpservicestatus [O] buffer to receive the status information for the service
1734 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1735 LPSERVICE_STATUS lpservicestatus)
1737 SERVICE_STATUS_PROCESS SvcStatusData;
1740 TRACE("%p %p\n", hService, lpservicestatus);
1742 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1743 sizeof(SERVICE_STATUS_PROCESS), NULL);
1744 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1749 /******************************************************************************
1750 * QueryServiceStatusEx [ADVAPI32.@]
1752 * Get information about a service.
1755 * hService [I] Handle to service to get information about
1756 * InfoLevel [I] Level of information to get
1757 * lpBuffer [O] Destination for requested information
1758 * cbBufSize [I] Size of lpBuffer in bytes
1759 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1765 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1766 LPBYTE lpBuffer, DWORD cbBufSize,
1767 LPDWORD pcbBytesNeeded)
1769 struct sc_service *hsvc;
1770 DWORD size, type, val;
1773 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1775 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1777 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1779 SetLastError( ERROR_INVALID_LEVEL);
1783 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1784 if (pSvcStatusData == NULL)
1786 SetLastError( ERROR_INVALID_PARAMETER);
1790 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1792 if( pcbBytesNeeded != NULL)
1793 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1795 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1799 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1802 SetLastError( ERROR_INVALID_HANDLE );
1806 pipe = service_open_pipe(hsvc->name);
1807 if (pipe != INVALID_HANDLE_VALUE)
1809 r = service_get_status(pipe, pSvcStatusData);
1815 TRACE("Failed to read service status\n");
1817 /* read the service type from the registry */
1819 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1820 if (r != ERROR_SUCCESS || type != REG_DWORD)
1823 pSvcStatusData->dwServiceType = val;
1824 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1825 pSvcStatusData->dwControlsAccepted = 0;
1826 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1827 pSvcStatusData->dwServiceSpecificExitCode = 0;
1828 pSvcStatusData->dwCheckPoint = 0;
1829 pSvcStatusData->dwWaitHint = 0;
1834 /******************************************************************************
1835 * QueryServiceConfigA [ADVAPI32.@]
1837 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1838 DWORD size, LPDWORD needed )
1843 QUERY_SERVICE_CONFIGW *configW;
1845 TRACE("%p %p %d %p\n", hService, config, size, needed);
1847 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1849 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1852 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1853 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1854 if (!ret) goto done;
1856 config->dwServiceType = configW->dwServiceType;
1857 config->dwStartType = configW->dwStartType;
1858 config->dwErrorControl = configW->dwErrorControl;
1859 config->lpBinaryPathName = NULL;
1860 config->lpLoadOrderGroup = NULL;
1861 config->dwTagId = configW->dwTagId;
1862 config->lpDependencies = NULL;
1863 config->lpServiceStartName = NULL;
1864 config->lpDisplayName = NULL;
1866 p = (LPSTR)(config + 1);
1867 n = size - sizeof(*config);
1870 #define MAP_STR(str) \
1874 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1875 if (!sz) goto done; \
1882 MAP_STR( lpBinaryPathName );
1883 MAP_STR( lpLoadOrderGroup );
1884 MAP_STR( lpDependencies );
1885 MAP_STR( lpServiceStartName );
1886 MAP_STR( lpDisplayName );
1889 *needed = p - (LPSTR)config;
1893 HeapFree( GetProcessHeap(), 0, buffer );
1897 /******************************************************************************
1898 * QueryServiceConfigW [ADVAPI32.@]
1901 QueryServiceConfigW( SC_HANDLE hService,
1902 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1903 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1905 WCHAR str_buffer[ MAX_PATH ];
1907 DWORD type, val, sz, total, n;
1910 struct sc_service *hsvc;
1912 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1913 cbBufSize, pcbBytesNeeded);
1915 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1918 SetLastError( ERROR_INVALID_HANDLE );
1923 /* TODO: Check which members are mandatory and what the registry types
1924 * should be. This should of course also be tested when a service is
1928 /* calculate the size required first */
1929 total = sizeof (QUERY_SERVICE_CONFIGW);
1931 sz = sizeof(str_buffer);
1932 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1933 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1935 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1936 if( 0 == sz ) return FALSE;
1938 total += sizeof(WCHAR) * sz;
1942 /* FIXME: set last error */
1947 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1948 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1951 total += sizeof(WCHAR);
1954 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1955 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1958 total += sizeof(WCHAR);
1961 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1962 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1965 total += sizeof(WCHAR);
1968 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1969 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1972 total += sizeof(WCHAR);
1974 *pcbBytesNeeded = total;
1976 /* if there's not enough memory, return an error */
1977 if( total > cbBufSize )
1979 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1983 ZeroMemory( lpServiceConfig, total );
1986 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1987 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1988 lpServiceConfig->dwServiceType = val;
1991 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1992 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1993 lpServiceConfig->dwStartType = val;
1996 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1997 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1998 lpServiceConfig->dwErrorControl = val;
2001 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2002 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2003 lpServiceConfig->dwTagId = val;
2005 /* now do the strings */
2006 p = (LPBYTE) &lpServiceConfig[1];
2007 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2009 sz = sizeof(str_buffer);
2010 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2011 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2013 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2014 sz *= sizeof(WCHAR);
2015 if( 0 == sz || sz > n ) return FALSE;
2017 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2023 /* FIXME: set last error */
2028 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2029 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2030 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2043 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2044 lpServiceConfig->lpDependencies = (LPWSTR) p;
2045 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2058 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2059 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2060 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2073 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2074 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2075 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2088 ERR("Buffer overflow!\n");
2090 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2091 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2092 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2093 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2094 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2099 /******************************************************************************
2100 * EnumServicesStatusA [ADVAPI32.@]
2103 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2104 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2105 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2106 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2108 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2109 dwServiceType, dwServiceState, lpServices, cbBufSize,
2110 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2111 SetLastError (ERROR_ACCESS_DENIED);
2115 /******************************************************************************
2116 * EnumServicesStatusW [ADVAPI32.@]
2119 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2120 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2121 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2122 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2124 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2125 dwServiceType, dwServiceState, lpServices, cbBufSize,
2126 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2127 SetLastError (ERROR_ACCESS_DENIED);
2131 /******************************************************************************
2132 * EnumServicesStatusExA [ADVAPI32.@]
2135 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2136 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2137 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2139 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2140 dwServiceType, dwServiceState, lpServices, cbBufSize,
2141 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2142 SetLastError (ERROR_ACCESS_DENIED);
2146 /******************************************************************************
2147 * EnumServicesStatusExW [ADVAPI32.@]
2150 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2151 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2152 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2154 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2155 dwServiceType, dwServiceState, lpServices, cbBufSize,
2156 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2157 SetLastError (ERROR_ACCESS_DENIED);
2161 /******************************************************************************
2162 * GetServiceKeyNameA [ADVAPI32.@]
2164 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2165 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2167 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2171 /******************************************************************************
2172 * GetServiceKeyNameW [ADVAPI32.@]
2174 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2175 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2177 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2181 /******************************************************************************
2182 * QueryServiceLockStatusA [ADVAPI32.@]
2184 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2185 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2186 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2188 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2193 /******************************************************************************
2194 * QueryServiceLockStatusW [ADVAPI32.@]
2196 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2197 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2198 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2200 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2205 /******************************************************************************
2206 * GetServiceDisplayNameA [ADVAPI32.@]
2208 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2209 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2211 struct sc_manager *hscm;
2215 TRACE("%p %s %p %p\n", hSCManager,
2216 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2220 SetLastError(ERROR_INVALID_PARAMETER);
2224 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2227 SetLastError(ERROR_INVALID_HANDLE);
2231 size = *lpcchBuffer;
2232 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2233 if (!ret && !lpDisplayName && size)
2234 ret = ERROR_MORE_DATA;
2238 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2240 if (ret == ERROR_MORE_DATA)
2242 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2243 *lpcchBuffer = size - 1;
2252 /******************************************************************************
2253 * GetServiceDisplayNameW [ADVAPI32.@]
2255 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2256 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2258 struct sc_manager *hscm;
2262 TRACE("%p %s %p %p\n", hSCManager,
2263 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2267 SetLastError(ERROR_INVALID_PARAMETER);
2271 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2274 SetLastError(ERROR_INVALID_HANDLE);
2278 size = *lpcchBuffer * sizeof(WCHAR);
2279 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2280 if (!ret && !lpDisplayName && size)
2281 ret = ERROR_MORE_DATA;
2285 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2287 if (ret == ERROR_MORE_DATA)
2289 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2290 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2299 /******************************************************************************
2300 * ChangeServiceConfigW [ADVAPI32.@]
2302 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2303 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2304 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2305 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2307 struct reg_value val[10];
2308 struct sc_service *hsvc;
2309 DWORD r = ERROR_SUCCESS;
2313 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2314 hService, dwServiceType, dwStartType, dwErrorControl,
2315 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2316 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2317 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2319 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2322 SetLastError( ERROR_INVALID_HANDLE );
2327 if( dwServiceType != SERVICE_NO_CHANGE )
2328 service_set_dword( &val[n++], szType, &dwServiceType );
2330 if( dwStartType != SERVICE_NO_CHANGE )
2331 service_set_dword( &val[n++], szStart, &dwStartType );
2333 if( dwErrorControl != SERVICE_NO_CHANGE )
2334 service_set_dword( &val[n++], szError, &dwErrorControl );
2336 if( lpBinaryPathName )
2337 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2339 if( lpLoadOrderGroup )
2340 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2342 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2343 * There is no such key as what szDependencies refers to */
2344 if( lpDependencies )
2345 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2348 FIXME("ignoring password\n");
2350 if( lpServiceStartName )
2351 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2353 r = service_write_values( hsvc->hkey, val, n );
2355 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2358 /******************************************************************************
2359 * ChangeServiceConfigA [ADVAPI32.@]
2361 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2362 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2363 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2364 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2366 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2367 LPWSTR wServiceStartName, wPassword, wDisplayName;
2370 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2371 hService, dwServiceType, dwStartType, dwErrorControl,
2372 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2373 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2374 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2376 wBinaryPathName = SERV_dup( lpBinaryPathName );
2377 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2378 wDependencies = SERV_dupmulti( lpDependencies );
2379 wServiceStartName = SERV_dup( lpServiceStartName );
2380 wPassword = SERV_dup( lpPassword );
2381 wDisplayName = SERV_dup( lpDisplayName );
2383 r = ChangeServiceConfigW( hService, dwServiceType,
2384 dwStartType, dwErrorControl, wBinaryPathName,
2385 wLoadOrderGroup, lpdwTagId, wDependencies,
2386 wServiceStartName, wPassword, wDisplayName);
2388 SERV_free( wBinaryPathName );
2389 SERV_free( wLoadOrderGroup );
2390 SERV_free( wDependencies );
2391 SERV_free( wServiceStartName );
2392 SERV_free( wPassword );
2393 SERV_free( wDisplayName );
2398 /******************************************************************************
2399 * ChangeServiceConfig2A [ADVAPI32.@]
2401 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2406 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2408 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2410 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2411 SERVICE_DESCRIPTIONW sdw;
2413 sdw.lpDescription = SERV_dup( sd->lpDescription );
2415 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2417 SERV_free( sdw.lpDescription );
2419 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2421 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2422 SERVICE_FAILURE_ACTIONSW faw;
2424 faw.dwResetPeriod = fa->dwResetPeriod;
2425 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2426 faw.lpCommand = SERV_dup( fa->lpCommand );
2427 faw.cActions = fa->cActions;
2428 faw.lpsaActions = fa->lpsaActions;
2430 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2432 SERV_free( faw.lpRebootMsg );
2433 SERV_free( faw.lpCommand );
2436 SetLastError( ERROR_INVALID_PARAMETER );
2441 /******************************************************************************
2442 * ChangeServiceConfig2W [ADVAPI32.@]
2444 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2448 struct sc_service *hsvc;
2450 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2453 SetLastError( ERROR_INVALID_HANDLE );
2458 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2460 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2461 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2462 if (sd->lpDescription)
2464 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2465 if (sd->lpDescription[0] == 0)
2466 RegDeleteValueW(hKey,szDescription);
2468 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2469 (LPVOID)sd->lpDescription,
2470 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2474 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2478 /******************************************************************************
2479 * QueryServiceObjectSecurity [ADVAPI32.@]
2481 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2482 SECURITY_INFORMATION dwSecurityInformation,
2483 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2484 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2488 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2489 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2491 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2493 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2494 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2495 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2499 /******************************************************************************
2500 * SetServiceObjectSecurity [ADVAPI32.@]
2502 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2503 SECURITY_INFORMATION dwSecurityInformation,
2504 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2506 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2510 /******************************************************************************
2511 * SetServiceBits [ADVAPI32.@]
2513 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2514 DWORD dwServiceBits,
2516 BOOL bUpdateImmediately)
2518 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2519 bSetBitsOn, bUpdateImmediately);
2523 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2524 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2526 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2530 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2531 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2533 service_data *service;
2534 SERVICE_STATUS_HANDLE handle = 0;
2536 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2538 EnterCriticalSection( &service_cs );
2539 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2541 if(!strcmpW(lpServiceName, service->name))
2543 service->handler.handler_ex = lpHandlerProc;
2544 service->context = lpContext;
2545 service->extended = TRUE;
2546 handle = (SERVICE_STATUS_HANDLE)service;
2550 LeaveCriticalSection( &service_cs );