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"
41 WINE_DEFAULT_DEBUG_CHANNEL(service);
43 static const WCHAR szLocalSystem[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
44 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
45 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
46 'S','e','r','v','i','c','e','s',0 };
47 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
50 void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t len)
52 return HeapAlloc(GetProcessHeap(), 0, len);
55 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
57 HeapFree(GetProcessHeap(), 0, ptr);
60 static const GENERIC_MAPPING scm_generic = {
61 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
62 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
63 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
67 static const GENERIC_MAPPING svc_generic = {
68 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
69 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
70 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
74 typedef struct service_start_info_t
81 #define WINESERV_STARTINFO 1
82 #define WINESERV_GETSTATUS 2
83 #define WINESERV_SENDCONTROL 3
85 typedef struct service_data_t
87 LPHANDLER_FUNCTION_EX handler;
89 SERVICE_STATUS_PROCESS status;
93 LPSERVICE_MAIN_FUNCTIONA a;
94 LPSERVICE_MAIN_FUNCTIONW w;
100 static CRITICAL_SECTION service_cs;
101 static CRITICAL_SECTION_DEBUG service_cs_debug =
104 { &service_cs_debug.ProcessLocksList,
105 &service_cs_debug.ProcessLocksList },
106 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
108 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
110 static service_data **services;
111 static unsigned int nb_services;
112 static HANDLE service_event;
114 extern HANDLE __wine_make_process_system(void);
116 /******************************************************************************
120 #define MAX_SERVICE_NAME 256
122 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
125 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
129 SC_HANDLE_TYPE htype;
131 sc_handle_destructor destroy;
132 SC_RPC_HANDLE server_handle; /* server-side handle */
135 struct sc_manager /* service control manager handle */
137 struct sc_handle hdr;
138 HKEY hkey; /* handle to services database in the registry */
142 struct sc_service /* service handle */
144 struct sc_handle hdr;
145 HKEY hkey; /* handle to service entry in the registry (under hkey) */
147 struct sc_manager *scm; /* pointer to SCM handle */
151 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
152 sc_handle_destructor destroy)
154 struct sc_handle *hdr;
156 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
161 hdr->destroy = destroy;
163 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
167 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
169 struct sc_handle *hdr = (struct sc_handle *) handle;
173 if (hdr->htype != htype)
178 static void sc_handle_free(struct sc_handle* hdr)
182 if (--hdr->ref_count)
185 HeapFree(GetProcessHeap(), 0, hdr);
188 static void sc_handle_destroy_manager(struct sc_handle *handle)
190 struct sc_manager *mgr = (struct sc_manager*) handle;
192 TRACE("destroying SC Manager %p\n", mgr);
194 RegCloseKey(mgr->hkey);
197 static void sc_handle_destroy_service(struct sc_handle *handle)
199 struct sc_service *svc = (struct sc_service*) handle;
201 TRACE("destroying service %p\n", svc);
203 RegCloseKey(svc->hkey);
205 sc_handle_free(&svc->scm->hdr);
209 /******************************************************************************
210 * String management functions (same behaviour as strdup)
211 * NOTE: the caller of those functions is responsible for calling HeapFree
212 * in order to release the memory allocated by those functions.
214 static inline LPWSTR SERV_dup( LPCSTR str )
221 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
222 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
223 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
227 static inline LPWSTR SERV_dupmulti(LPCSTR str)
235 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
236 n += (strlen( &str[n] ) + 1);
241 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
242 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
246 static inline DWORD multisz_cb(LPCWSTR wmultisz)
248 const WCHAR *wptr = wmultisz;
250 if (wmultisz == NULL)
254 wptr += lstrlenW(wptr)+1;
255 return (wptr - wmultisz + 1)*sizeof(WCHAR);
258 /******************************************************************************
259 * RPC connection with servies.exe
262 static BOOL check_services_exe(void)
264 static const WCHAR svcctl_started_event[] = SVCCTL_STARTED_EVENT;
265 HANDLE hEvent = OpenEventW(SYNCHRONIZE, FALSE, svcctl_started_event);
266 if (hEvent == NULL) /* need to start services.exe */
268 static const WCHAR services[] = {'\\','s','e','r','v','i','c','e','s','.','e','x','e',0};
269 PROCESS_INFORMATION out;
271 HANDLE wait_handles[2];
272 WCHAR path[MAX_PATH];
274 if (!GetSystemDirectoryW(path, MAX_PATH - strlenW(services)))
276 strcatW(path, services);
277 ZeroMemory(&si, sizeof(si));
279 if (!CreateProcessW(path, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &out))
281 ERR("Couldn't start services.exe: error %u\n", GetLastError());
284 CloseHandle(out.hThread);
286 hEvent = CreateEventW(NULL, TRUE, FALSE, svcctl_started_event);
287 wait_handles[0] = hEvent;
288 wait_handles[1] = out.hProcess;
290 /* wait for the event to become available or the process to exit */
291 if ((WaitForMultipleObjects(2, wait_handles, FALSE, INFINITE)) == WAIT_OBJECT_0 + 1)
294 GetExitCodeProcess(out.hProcess, &exit_code);
295 ERR("Unexpected termination of services.exe - exit code %d\n", exit_code);
296 CloseHandle(out.hProcess);
301 TRACE("services.exe started successfully\n");
302 CloseHandle(out.hProcess);
307 TRACE("Waiting for services.exe to be available\n");
308 WaitForSingleObject(hEvent, INFINITE);
309 TRACE("Services.exe are available\n");
315 handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
317 WCHAR transport[] = SVCCTL_TRANSPORT;
318 WCHAR endpoint[] = SVCCTL_ENDPOINT;
319 LPWSTR server_copy = NULL;
320 RPC_WSTR binding_str;
324 /* unlike Windows we start services.exe on demand. We start it always as
325 * checking if this is our address can be tricky */
326 if (!check_services_exe())
329 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
330 HeapFree(GetProcessHeap(), 0, server_copy);
331 if (status != RPC_S_OK)
333 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
337 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
338 RpcStringFreeW(&binding_str);
340 if (status != RPC_S_OK)
342 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
349 void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
354 /******************************************************************************
355 * registry access functions and data
357 static const WCHAR szDisplayName[] = {
358 'D','i','s','p','l','a','y','N','a','m','e', 0 };
359 static const WCHAR szType[] = {'T','y','p','e',0};
360 static const WCHAR szStart[] = {'S','t','a','r','t',0};
361 static const WCHAR szError[] = {
362 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
363 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
364 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
365 static const WCHAR szDependencies[] = {
366 'D','e','p','e','n','d','e','n','c','i','e','s',0};
367 static const WCHAR szDependOnService[] = {
368 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
369 static const WCHAR szObjectName[] = {
370 'O','b','j','e','c','t','N','a','m','e',0};
371 static const WCHAR szTag[] = {
381 static inline void service_set_value( struct reg_value *val,
382 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
390 static inline void service_set_dword( struct reg_value *val,
391 LPCWSTR name, const DWORD *data )
393 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
396 static inline void service_set_string( struct reg_value *val,
397 LPCWSTR name, LPCWSTR string )
399 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
400 service_set_value( val, REG_SZ, name, string, len );
403 static inline void service_set_multi_string( struct reg_value *val,
404 LPCWSTR name, LPCWSTR string )
408 /* determine the length of a double null terminated multi string */
410 len += (lstrlenW( &string[ len ] )+1);
411 } while ( string[ len++ ] );
413 len *= sizeof (WCHAR);
414 service_set_value( val, REG_MULTI_SZ, name, string, len );
417 static inline LONG service_write_values( HKEY hKey,
418 const struct reg_value *val, int n )
420 LONG r = ERROR_SUCCESS;
425 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
426 (const BYTE*)val[i].data, val[i].size );
427 if( r != ERROR_SUCCESS )
433 /******************************************************************************
434 * Service IPC functions
436 static LPWSTR service_get_pipe_name(LPCWSTR service)
438 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
439 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
443 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
444 name = HeapAlloc(GetProcessHeap(), 0, len);
445 strcpyW(name, prefix);
446 strcatW(name, service);
450 static HANDLE service_open_pipe(LPCWSTR service)
452 LPWSTR szPipe = service_get_pipe_name( service );
453 HANDLE handle = INVALID_HANDLE_VALUE;
456 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
457 0, NULL, OPEN_ALWAYS, 0, NULL);
458 if (handle != INVALID_HANDLE_VALUE)
460 if (GetLastError() != ERROR_PIPE_BUSY)
462 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
463 HeapFree(GetProcessHeap(), 0, szPipe);
468 /******************************************************************************
469 * service_get_event_handle
471 static HANDLE service_get_event_handle(LPCWSTR service)
473 static const WCHAR prefix[] = {
474 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
479 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
480 name = HeapAlloc(GetProcessHeap(), 0, len);
481 strcpyW(name, prefix);
482 strcatW(name, service);
483 handle = CreateEventW(NULL, TRUE, FALSE, name);
484 HeapFree(GetProcessHeap(), 0, name);
488 /******************************************************************************
491 * Call into the main service routine provided by StartServiceCtrlDispatcher.
493 static DWORD WINAPI service_thread(LPVOID arg)
495 service_data *info = arg;
496 LPWSTR str = info->args;
497 DWORD argc = 0, len = 0;
503 len += strlenW(&str[len]) + 1;
510 info->proc.w(0, NULL);
512 info->proc.a(0, NULL);
520 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
521 for (argc=0, p=str; *p; p += strlenW(p) + 1)
525 info->proc.w(argc, argv);
526 HeapFree(GetProcessHeap(), 0, argv);
530 LPSTR strA, *argv, p;
533 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
534 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
535 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
537 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
538 for (argc=0, p=strA; *p; p += strlen(p) + 1)
542 info->proc.a(argc, argv);
543 HeapFree(GetProcessHeap(), 0, argv);
544 HeapFree(GetProcessHeap(), 0, strA);
549 /******************************************************************************
550 * service_handle_start
552 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
554 DWORD read = 0, result = 0;
558 TRACE("%p %p %d\n", pipe, service, count);
560 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
561 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
562 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
564 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
565 r, count, read, debugstr_wn(args, count));
571 WARN("service is not stopped\n");
572 result = ERROR_SERVICE_ALREADY_RUNNING;
576 HeapFree(GetProcessHeap(), 0, service->args);
577 service->args = args;
579 service->status.dwCurrentState = SERVICE_START_PENDING;
580 service->thread = CreateThread( NULL, 0, service_thread,
582 SetEvent( service_event ); /* notify the main loop */
585 HeapFree(GetProcessHeap(), 0, args);
586 WriteFile( pipe, &result, sizeof result, &read, NULL );
591 /******************************************************************************
592 * service_send_start_message
594 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
596 DWORD i, len, count, result;
597 service_start_info *ssi;
601 TRACE("%p %p %d\n", pipe, argv, argc);
603 /* calculate how much space do we need to send the startup info */
605 for (i=0; i<argc; i++)
606 len += strlenW(argv[i])+1;
608 ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, str[len]));
609 ssi->cmd = WINESERV_STARTINFO;
612 /* copy service args into a single buffer*/
614 for (i=0; i<argc; i++)
621 r = WriteFile(pipe, ssi, FIELD_OFFSET(service_start_info, str[len]), &count, NULL);
624 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
627 SetLastError(result);
632 HeapFree(GetProcessHeap(),0,ssi);
637 /******************************************************************************
638 * service_handle_get_status
640 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
644 return WriteFile(pipe, &service->status,
645 sizeof service->status, &count, NULL);
648 /******************************************************************************
649 * service_send_control
651 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
653 DWORD cmd[2], count = 0;
656 cmd[0] = WINESERV_SENDCONTROL;
658 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
659 if (!r || count != sizeof cmd)
661 ERR("service protocol error - failed to write pipe!\n");
664 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
665 if (!r || count != sizeof *result)
666 ERR("service protocol error - failed to read pipe "
667 "r = %d count = %d!\n", r, count);
671 /******************************************************************************
672 * service_accepts_control
674 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
676 DWORD a = service->status.dwControlsAccepted;
680 case SERVICE_CONTROL_INTERROGATE:
682 case SERVICE_CONTROL_STOP:
683 if (a&SERVICE_ACCEPT_STOP)
686 case SERVICE_CONTROL_SHUTDOWN:
687 if (a&SERVICE_ACCEPT_SHUTDOWN)
690 case SERVICE_CONTROL_PAUSE:
691 case SERVICE_CONTROL_CONTINUE:
692 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
695 case SERVICE_CONTROL_PARAMCHANGE:
696 if (a&SERVICE_ACCEPT_PARAMCHANGE)
699 case SERVICE_CONTROL_NETBINDADD:
700 case SERVICE_CONTROL_NETBINDREMOVE:
701 case SERVICE_CONTROL_NETBINDENABLE:
702 case SERVICE_CONTROL_NETBINDDISABLE:
703 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
705 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
706 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
709 case SERVICE_CONTROL_POWEREVENT:
710 if (a&SERVICE_ACCEPT_POWEREVENT)
713 case SERVICE_CONTROL_SESSIONCHANGE:
714 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
721 /******************************************************************************
722 * service_handle_control
724 static BOOL service_handle_control(HANDLE pipe, service_data *service,
727 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
729 TRACE("received control %d\n", dwControl);
731 if (service_accepts_control(service, dwControl))
733 if (service->handler)
734 ret = service->handler(dwControl, 0, NULL, service->context);
736 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
739 /******************************************************************************
740 * service_control_dispatcher
742 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
744 service_data *service = arg;
748 TRACE("%p %s\n", service, debugstr_w(service->name));
750 /* create a pipe to talk to the rest of the world with */
751 name = service_get_pipe_name(service->name);
752 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
753 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
755 if (pipe==INVALID_HANDLE_VALUE)
756 ERR("failed to create pipe for %s, error = %d\n",
757 debugstr_w(service->name), GetLastError());
759 HeapFree(GetProcessHeap(), 0, name);
761 /* let the process who started us know we've tried to create a pipe */
762 event = service_get_event_handle(service->name);
766 if (pipe==INVALID_HANDLE_VALUE) return 0;
768 /* dispatcher loop */
772 DWORD count, req[2] = {0,0};
774 r = ConnectNamedPipe(pipe, NULL);
775 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
777 ERR("pipe connect failed\n");
781 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
782 if (!r || count!=sizeof req)
784 ERR("pipe read failed\n");
788 /* handle the request */
791 case WINESERV_STARTINFO:
792 service_handle_start(pipe, service, req[1]);
794 case WINESERV_GETSTATUS:
795 service_handle_get_status(pipe, service);
797 case WINESERV_SENDCONTROL:
798 service_handle_control(pipe, service, req[1]);
801 ERR("received invalid command %d length %d\n", req[0], req[1]);
804 FlushFileBuffers(pipe);
805 DisconnectNamedPipe(pipe);
812 /******************************************************************************
813 * service_run_threads
815 static BOOL service_run_threads(void)
818 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
819 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
821 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
823 wait_handles[0] = __wine_make_process_system();
824 wait_handles[1] = service_event;
826 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
827 nb_services, GetCurrentProcessId());
829 EnterCriticalSection( &service_cs );
830 for (i = 0; i < nb_services; i++)
832 services[i]->status.dwProcessId = GetCurrentProcessId();
833 CloseHandle( CreateThread( NULL, 0, service_control_dispatcher, services[i], 0, NULL ));
835 LeaveCriticalSection( &service_cs );
837 /* wait for all the threads to pack up and exit */
840 EnterCriticalSection( &service_cs );
841 for (i = 0, n = 2; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
843 if (!services[i]->thread) continue;
844 wait_services[n] = i;
845 wait_handles[n++] = services[i]->thread;
847 LeaveCriticalSection( &service_cs );
849 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
850 if (!ret) /* system process event */
852 TRACE( "last user process exited, shutting down\n" );
853 /* FIXME: we should maybe send a shutdown control to running services */
858 continue; /* rebuild the list */
862 services[wait_services[ret]]->thread = 0;
863 CloseHandle( wait_handles[ret] );
864 if (n == 3) return TRUE; /* it was the last running thread */
870 /******************************************************************************
871 * StartServiceCtrlDispatcherA [ADVAPI32.@]
873 * See StartServiceCtrlDispatcherW.
875 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
881 TRACE("%p\n", servent);
885 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
888 while (servent[nb_services].lpServiceName) nb_services++;
889 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
891 for (i = 0; i < nb_services; i++)
893 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
894 DWORD sz = FIELD_OFFSET( service_data, name[len] );
895 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
896 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
897 info->proc.a = servent[i].lpServiceProc;
898 info->unicode = FALSE;
902 service_run_threads();
907 /******************************************************************************
908 * StartServiceCtrlDispatcherW [ADVAPI32.@]
910 * Connects a process containing one or more services to the service control
914 * servent [I] A list of the service names and service procedures
920 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
926 TRACE("%p\n", servent);
930 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
933 while (servent[nb_services].lpServiceName) nb_services++;
934 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
936 for (i = 0; i < nb_services; i++)
938 DWORD len = strlenW(servent[i].lpServiceName) + 1;
939 DWORD sz = FIELD_OFFSET( service_data, name[len] );
940 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
941 strcpyW(info->name, servent[i].lpServiceName);
942 info->proc.w = servent[i].lpServiceProc;
943 info->unicode = TRUE;
947 service_run_threads();
952 /******************************************************************************
953 * LockServiceDatabase [ADVAPI32.@]
955 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
959 TRACE("%p\n",hSCManager);
961 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
962 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
966 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
969 TRACE("returning %p\n", ret);
974 /******************************************************************************
975 * UnlockServiceDatabase [ADVAPI32.@]
977 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
979 TRACE("%p\n",ScLock);
981 return CloseHandle( ScLock );
984 /******************************************************************************
985 * SetServiceStatus [ADVAPI32.@]
992 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
994 struct sc_service *hsvc;
997 TRACE("%p %x %x %x %x %x %x %x\n", hService,
998 lpStatus->dwServiceType, lpStatus->dwCurrentState,
999 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
1000 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
1001 lpStatus->dwWaitHint);
1003 hsvc = sc_handle_get_handle_data((SC_HANDLE)hService, SC_HTYPE_SERVICE);
1006 SetLastError( ERROR_INVALID_HANDLE );
1010 err = svcctl_SetServiceStatus( hsvc->hdr.server_handle, lpStatus );
1011 if (err != ERROR_SUCCESS)
1017 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
1018 CloseServiceHandle((SC_HANDLE)hService);
1024 /******************************************************************************
1025 * OpenSCManagerA [ADVAPI32.@]
1027 * Establish a connection to the service control manager and open its database.
1030 * lpMachineName [I] Pointer to machine name string
1031 * lpDatabaseName [I] Pointer to database name string
1032 * dwDesiredAccess [I] Type of access
1035 * Success: A Handle to the service control manager database
1038 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1039 DWORD dwDesiredAccess )
1041 LPWSTR lpMachineNameW, lpDatabaseNameW;
1044 lpMachineNameW = SERV_dup(lpMachineName);
1045 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1046 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1047 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
1048 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
1052 /******************************************************************************
1053 * OpenSCManagerW [ADVAPI32.@]
1055 * See OpenSCManagerA.
1057 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1058 DWORD dwDesiredAccess )
1060 struct sc_manager *manager;
1063 DWORD new_mask = dwDesiredAccess;
1065 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1066 debugstr_w(lpDatabaseName), dwDesiredAccess);
1068 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1069 sc_handle_destroy_manager );
1073 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
1074 if (r!=ERROR_SUCCESS)
1077 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1078 if (r!=ERROR_SUCCESS)
1081 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1082 RegCloseKey( hReg );
1083 if (r!=ERROR_SUCCESS)
1086 RtlMapGenericMask(&new_mask, &scm_generic);
1087 manager->dwAccess = new_mask;
1088 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1090 return (SC_HANDLE) &manager->hdr;
1093 sc_handle_free( &manager->hdr );
1098 /******************************************************************************
1099 * ControlService [ADVAPI32.@]
1101 * Send a control code to a service.
1104 * hService [I] Handle of the service control manager database
1105 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1106 * lpServiceStatus [O] Destination for the status of the service, if available
1113 * Unlike M$' implementation, control requests are not serialized and may be
1114 * processed asynchronously.
1116 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1117 LPSERVICE_STATUS lpServiceStatus )
1119 struct sc_service *hsvc;
1123 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1125 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1128 SetLastError( ERROR_INVALID_HANDLE );
1132 if (lpServiceStatus)
1134 ret = QueryServiceStatus(hService, lpServiceStatus);
1137 ERR("failed to query service status\n");
1138 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1142 switch (lpServiceStatus->dwCurrentState)
1144 case SERVICE_STOPPED:
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1147 case SERVICE_START_PENDING:
1148 if (dwControl==SERVICE_CONTROL_STOP)
1151 case SERVICE_STOP_PENDING:
1152 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1157 handle = service_open_pipe(hsvc->name);
1158 if (handle!=INVALID_HANDLE_VALUE)
1160 DWORD result = ERROR_SUCCESS;
1161 ret = service_send_control(handle, dwControl, &result);
1162 CloseHandle(handle);
1163 if (result!=ERROR_SUCCESS)
1165 SetLastError(result);
1173 /******************************************************************************
1174 * CloseServiceHandle [ADVAPI32.@]
1176 * Close a handle to a service or the service control manager database.
1179 * hSCObject [I] Handle to service or service control manager database
1186 CloseServiceHandle( SC_HANDLE hSCObject )
1188 struct sc_handle *obj;
1191 TRACE("%p\n", hSCObject);
1192 if (hSCObject == NULL)
1194 SetLastError(ERROR_INVALID_HANDLE);
1198 obj = (struct sc_handle *)hSCObject;
1199 err = svcctl_CloseServiceHandle(&obj->server_handle);
1200 sc_handle_free( obj );
1202 if (err != ERROR_SUCCESS)
1211 /******************************************************************************
1212 * OpenServiceA [ADVAPI32.@]
1214 * Open a handle to a service.
1217 * hSCManager [I] Handle of the service control manager database
1218 * lpServiceName [I] Name of the service to open
1219 * dwDesiredAccess [I] Access required to the service
1222 * Success: Handle to the service
1225 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1226 DWORD dwDesiredAccess )
1228 LPWSTR lpServiceNameW;
1231 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1233 lpServiceNameW = SERV_dup(lpServiceName);
1234 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1235 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1240 /******************************************************************************
1241 * OpenServiceW [ADVAPI32.@]
1245 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1246 DWORD dwDesiredAccess)
1248 struct sc_manager *hscm;
1249 struct sc_service *hsvc;
1252 DWORD new_mask = dwDesiredAccess;
1254 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1256 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1259 SetLastError( ERROR_INVALID_HANDLE );
1265 SetLastError(ERROR_INVALID_ADDRESS);
1269 len = strlenW(lpServiceName)+1;
1270 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1271 sizeof (struct sc_service) + len*sizeof(WCHAR),
1272 sc_handle_destroy_service );
1275 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1278 strcpyW( hsvc->name, lpServiceName );
1280 /* add reference to SCM handle */
1281 hscm->hdr.ref_count++;
1284 err = svcctl_OpenServiceW(hscm->hdr.server_handle, lpServiceName, dwDesiredAccess, &hsvc->hdr.server_handle);
1286 if (err != ERROR_SUCCESS)
1288 sc_handle_free(&hsvc->hdr);
1293 /* for parts of advapi32 not using services.exe yet */
1294 RtlMapGenericMask(&new_mask, &svc_generic);
1295 hsvc->dwAccess = new_mask;
1297 err = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hsvc->hkey );
1298 if (err != ERROR_SUCCESS)
1299 ERR("Shouldn't hapen - service key for service validated by services.exe doesn't exist\n");
1301 TRACE("returning %p\n",hsvc);
1303 return (SC_HANDLE) &hsvc->hdr;
1306 /******************************************************************************
1307 * CreateServiceW [ADVAPI32.@]
1310 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1311 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1312 DWORD dwServiceType, DWORD dwStartType,
1313 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1314 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1315 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1316 LPCWSTR lpPassword )
1318 struct sc_manager *hscm;
1319 struct sc_service *hsvc = NULL;
1320 DWORD new_mask = dwDesiredAccess;
1324 TRACE("%p %s %s\n", hSCManager,
1325 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1327 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1330 SetLastError( ERROR_INVALID_HANDLE );
1334 if (!lpServiceName || !lpBinaryPathName)
1336 SetLastError(ERROR_INVALID_ADDRESS);
1341 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1345 len = strlenW(lpServiceName)+1;
1346 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1347 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1350 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1353 lstrcpyW( hsvc->name, lpServiceName );
1356 hscm->hdr.ref_count++;
1358 err = svcctl_CreateServiceW(hscm->hdr.server_handle, lpServiceName,
1359 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1360 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (LPBYTE)lpDependencies,
1361 multisz_cb(lpDependencies), lpServiceStartName, (LPBYTE)lpPassword, passwdlen,
1362 &hsvc->hdr.server_handle);
1364 if (err != ERROR_SUCCESS)
1367 sc_handle_free(&hsvc->hdr);
1371 /* for parts of advapi32 not using services.exe yet */
1372 err = RegOpenKeyW(hscm->hkey, lpServiceName, &hsvc->hkey);
1373 if (err != ERROR_SUCCESS)
1374 WINE_ERR("Couldn't open key that should have been created by services.exe\n");
1376 RtlMapGenericMask(&new_mask, &svc_generic);
1377 hsvc->dwAccess = new_mask;
1379 return (SC_HANDLE) &hsvc->hdr;
1383 /******************************************************************************
1384 * CreateServiceA [ADVAPI32.@]
1387 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1388 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1389 DWORD dwServiceType, DWORD dwStartType,
1390 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1391 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1392 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1395 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1396 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1399 TRACE("%p %s %s\n", hSCManager,
1400 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1402 lpServiceNameW = SERV_dup( lpServiceName );
1403 lpDisplayNameW = SERV_dup( lpDisplayName );
1404 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1405 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1406 lpDependenciesW = SERV_dupmulti( lpDependencies );
1407 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1408 lpPasswordW = SERV_dup( lpPassword );
1410 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1411 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1412 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1413 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1415 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1416 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1417 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1418 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1419 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1420 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1421 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1427 /******************************************************************************
1428 * DeleteService [ADVAPI32.@]
1430 * Delete a service from the service control manager database.
1433 * hService [I] Handle of the service to delete
1439 BOOL WINAPI DeleteService( SC_HANDLE hService )
1441 struct sc_service *hsvc;
1444 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1447 SetLastError( ERROR_INVALID_HANDLE );
1451 err = svcctl_DeleteService(hsvc->hdr.server_handle);
1458 /* Close the key to the service */
1459 RegCloseKey(hsvc->hkey);
1465 /******************************************************************************
1466 * StartServiceA [ADVAPI32.@]
1471 * hService [I] Handle of service
1472 * dwNumServiceArgs [I] Number of arguments
1473 * lpServiceArgVectors [I] Address of array of argument strings
1476 * - NT implements this function using an obscure RPC call.
1477 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1478 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1479 * - This will only work for shared address space. How should the service
1480 * args be transferred when address spaces are separated?
1481 * - Can only start one service at a time.
1482 * - Has no concept of privilege.
1488 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1489 LPCSTR *lpServiceArgVectors )
1491 LPWSTR *lpwstr=NULL;
1495 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1497 if (dwNumServiceArgs)
1498 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1499 dwNumServiceArgs*sizeof(LPWSTR) );
1501 for(i=0; i<dwNumServiceArgs; i++)
1502 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1504 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1506 if (dwNumServiceArgs)
1508 for(i=0; i<dwNumServiceArgs; i++)
1509 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1510 HeapFree(GetProcessHeap(), 0, lpwstr);
1516 /******************************************************************************
1517 * service_start_process [INTERNAL]
1519 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1521 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1522 PROCESS_INFORMATION pi;
1524 LPWSTR path = NULL, str;
1525 DWORD type, size, ret, svc_type;
1529 size = sizeof(svc_type);
1530 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1533 if (svc_type == SERVICE_KERNEL_DRIVER)
1535 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1536 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1538 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1539 GetSystemDirectoryW( path, len );
1540 lstrcatW( path, winedeviceW );
1541 lstrcatW( path, hsvc->name );
1545 /* read the executable path from the registry */
1547 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1548 if (ret!=ERROR_SUCCESS)
1550 str = HeapAlloc(GetProcessHeap(),0,size);
1551 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1552 if (ret==ERROR_SUCCESS)
1554 size = ExpandEnvironmentStringsW(str,NULL,0);
1555 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1556 ExpandEnvironmentStringsW(str,path,size);
1558 HeapFree(GetProcessHeap(),0,str);
1563 /* wait for the process to start and set an event or terminate */
1564 handles[0] = service_get_event_handle( hsvc->name );
1565 ZeroMemory(&si, sizeof(STARTUPINFOW));
1566 si.cb = sizeof(STARTUPINFOW);
1567 if (!(svc_type & SERVICE_INTERACTIVE_PROCESS))
1569 static WCHAR desktopW[] = {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n','\\','D','e','f','a','u','l','t',0};
1570 si.lpDesktop = desktopW;
1573 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1576 if (ppid) *ppid = pi.dwProcessId;
1578 handles[1] = pi.hProcess;
1579 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1580 if(ret != WAIT_OBJECT_0)
1582 SetLastError(ERROR_IO_PENDING);
1586 CloseHandle( pi.hThread );
1587 CloseHandle( pi.hProcess );
1589 CloseHandle( handles[0] );
1590 HeapFree(GetProcessHeap(),0,path);
1594 static BOOL service_wait_for_startup(SC_HANDLE hService)
1597 SERVICE_STATUS status;
1600 TRACE("%p\n", hService);
1602 for (i=0; i<20; i++)
1604 status.dwCurrentState = 0;
1605 r = QueryServiceStatus(hService, &status);
1608 if (status.dwCurrentState == SERVICE_RUNNING)
1610 TRACE("Service started successfully\n");
1614 if (status.dwCurrentState != SERVICE_START_PENDING) break;
1620 /******************************************************************************
1621 * StartServiceW [ADVAPI32.@]
1623 * See StartServiceA.
1625 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1626 LPCWSTR *lpServiceArgVectors)
1628 struct sc_service *hsvc;
1631 HANDLE handle = INVALID_HANDLE_VALUE;
1633 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1635 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1638 SetLastError(ERROR_INVALID_HANDLE);
1642 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1646 handle = service_open_pipe(hsvc->name);
1647 if (handle==INVALID_HANDLE_VALUE)
1649 /* start the service process */
1650 if (service_start_process(hsvc, NULL))
1651 handle = service_open_pipe(hsvc->name);
1654 if (handle != INVALID_HANDLE_VALUE)
1656 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1657 CloseHandle(handle);
1660 UnlockServiceDatabase( hLock );
1662 TRACE("returning %d\n", r);
1665 service_wait_for_startup(hService);
1670 /******************************************************************************
1671 * QueryServiceStatus [ADVAPI32.@]
1674 * hService [I] Handle to service to get information about
1675 * lpservicestatus [O] buffer to receive the status information for the service
1678 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1679 LPSERVICE_STATUS lpservicestatus)
1681 SERVICE_STATUS_PROCESS SvcStatusData;
1685 TRACE("%p %p\n", hService, lpservicestatus);
1687 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1688 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1689 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1694 /******************************************************************************
1695 * QueryServiceStatusEx [ADVAPI32.@]
1697 * Get information about a service.
1700 * hService [I] Handle to service to get information about
1701 * InfoLevel [I] Level of information to get
1702 * lpBuffer [O] Destination for requested information
1703 * cbBufSize [I] Size of lpBuffer in bytes
1704 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1710 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1711 LPBYTE lpBuffer, DWORD cbBufSize,
1712 LPDWORD pcbBytesNeeded)
1714 struct sc_service *hsvc;
1717 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1719 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1722 SetLastError( ERROR_INVALID_HANDLE );
1726 err = svcctl_QueryServiceStatusEx(hsvc->hdr.server_handle, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1727 if (err != ERROR_SUCCESS)
1736 /******************************************************************************
1737 * QueryServiceConfigA [ADVAPI32.@]
1739 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1740 DWORD size, LPDWORD needed )
1745 QUERY_SERVICE_CONFIGW *configW;
1747 TRACE("%p %p %d %p\n", hService, config, size, needed);
1749 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1751 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1754 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1755 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1756 if (!ret) goto done;
1758 config->dwServiceType = configW->dwServiceType;
1759 config->dwStartType = configW->dwStartType;
1760 config->dwErrorControl = configW->dwErrorControl;
1761 config->lpBinaryPathName = NULL;
1762 config->lpLoadOrderGroup = NULL;
1763 config->dwTagId = configW->dwTagId;
1764 config->lpDependencies = NULL;
1765 config->lpServiceStartName = NULL;
1766 config->lpDisplayName = NULL;
1768 p = (LPSTR)(config + 1);
1769 n = size - sizeof(*config);
1772 #define MAP_STR(str) \
1776 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1777 if (!sz) goto done; \
1784 MAP_STR( lpBinaryPathName );
1785 MAP_STR( lpLoadOrderGroup );
1786 MAP_STR( lpDependencies );
1787 MAP_STR( lpServiceStartName );
1788 MAP_STR( lpDisplayName );
1791 *needed = p - (LPSTR)config;
1795 HeapFree( GetProcessHeap(), 0, buffer );
1799 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1802 WCHAR empty_str[] = {0};
1805 *string_ptr = empty_str;
1807 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1809 memcpy(*buf, *string_ptr, cb);
1810 MIDL_user_free(*string_ptr);
1811 *string_ptr = (LPWSTR)*buf;
1817 static DWORD size_string(LPWSTR string)
1819 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1822 /******************************************************************************
1823 * QueryServiceConfigW [ADVAPI32.@]
1826 QueryServiceConfigW( SC_HANDLE hService,
1827 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1828 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1830 QUERY_SERVICE_CONFIGW config;
1831 struct sc_service *hsvc;
1836 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1837 cbBufSize, pcbBytesNeeded);
1839 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1842 SetLastError( ERROR_INVALID_HANDLE );
1846 memset(&config, 0, sizeof(config));
1848 if ((err = svcctl_QueryServiceConfigW(hsvc->hdr.server_handle, &config)) != 0)
1850 TRACE("services.exe: error %u\n", err);
1855 /* calculate the size required first */
1856 total = sizeof (QUERY_SERVICE_CONFIGW);
1857 total += size_string(config.lpBinaryPathName);
1858 total += size_string(config.lpLoadOrderGroup);
1859 total += size_string(config.lpDependencies);
1860 total += size_string(config.lpServiceStartName);
1861 total += size_string(config.lpDisplayName);
1863 *pcbBytesNeeded = total;
1865 /* if there's not enough memory, return an error */
1866 if( total > cbBufSize )
1868 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1869 MIDL_user_free(config.lpBinaryPathName);
1870 MIDL_user_free(config.lpLoadOrderGroup);
1871 MIDL_user_free(config.lpDependencies);
1872 MIDL_user_free(config.lpServiceStartName);
1873 MIDL_user_free(config.lpDisplayName);
1877 *lpServiceConfig = config;
1878 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1879 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1880 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1881 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1882 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1883 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1885 if (bufpos - (LPBYTE)lpServiceConfig > cbBufSize)
1886 ERR("Buffer overflow!\n");
1888 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1889 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1890 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1891 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1892 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1897 /******************************************************************************
1898 * QueryServiceConfig2A [ADVAPI32.@]
1901 * observed under win2k:
1902 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1903 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1905 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1906 DWORD size, LPDWORD needed)
1909 LPBYTE bufferW = NULL;
1912 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1914 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1915 if(!ret) goto cleanup;
1918 case SERVICE_CONFIG_DESCRIPTION:
1919 { LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1920 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1921 if (configW->lpDescription) {
1923 configA->lpDescription = (LPSTR)(configA + 1);
1924 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1925 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1927 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1929 configA->lpDescription = NULL;
1932 else configA->lpDescription = NULL;
1936 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1941 HeapFree( GetProcessHeap(), 0, bufferW);
1945 /******************************************************************************
1946 * QueryServiceConfig2W [ADVAPI32.@]
1948 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1949 DWORD size, LPDWORD needed)
1954 struct sc_service *hsvc;
1956 if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1957 if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
1958 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
1959 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
1960 (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
1961 (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
1962 (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
1963 FIXME("Level %d not implemented\n", dwLevel);
1964 SetLastError(ERROR_INVALID_LEVEL);
1967 if(!needed || (!buffer && size)) {
1968 SetLastError(ERROR_INVALID_ADDRESS);
1972 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1974 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1977 SetLastError(ERROR_INVALID_HANDLE);
1983 case SERVICE_CONFIG_DESCRIPTION: {
1984 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1985 LPSERVICE_DESCRIPTIONW config = (LPSERVICE_DESCRIPTIONW) buffer;
1986 LPBYTE strbuf = NULL;
1987 *needed = sizeof (SERVICE_DESCRIPTIONW);
1988 sz = size - *needed;
1989 if(config && (*needed <= size))
1990 strbuf = (LPBYTE) (config + 1);
1991 r = RegQueryValueExW( hKey, szDescription, 0, &type, strbuf, &sz );
1992 if((r == ERROR_SUCCESS) && ( type != REG_SZ)) {
1993 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type);
1998 if(r == ERROR_SUCCESS)
1999 config->lpDescription = (LPWSTR) (config + 1);
2001 config->lpDescription = NULL;
2007 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2009 return (*needed <= size);
2012 /******************************************************************************
2013 * EnumServicesStatusA [ADVAPI32.@]
2016 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2017 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2018 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2019 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2021 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2022 dwServiceType, dwServiceState, lpServices, cbBufSize,
2023 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2024 SetLastError (ERROR_ACCESS_DENIED);
2028 /******************************************************************************
2029 * EnumServicesStatusW [ADVAPI32.@]
2032 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2033 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2034 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2035 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2037 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2038 dwServiceType, dwServiceState, lpServices, cbBufSize,
2039 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2040 SetLastError (ERROR_ACCESS_DENIED);
2044 /******************************************************************************
2045 * EnumServicesStatusExA [ADVAPI32.@]
2048 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2049 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2050 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2052 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2053 dwServiceType, dwServiceState, lpServices, cbBufSize,
2054 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2055 *lpServicesReturned = 0;
2056 SetLastError (ERROR_ACCESS_DENIED);
2060 /******************************************************************************
2061 * EnumServicesStatusExW [ADVAPI32.@]
2064 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2065 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2066 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2068 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2069 dwServiceType, dwServiceState, lpServices, cbBufSize,
2070 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2071 SetLastError (ERROR_ACCESS_DENIED);
2075 /******************************************************************************
2076 * GetServiceKeyNameA [ADVAPI32.@]
2078 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2079 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2081 LPWSTR lpDisplayNameW, lpServiceNameW;
2085 TRACE("%p %s %p %p\n", hSCManager,
2086 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2088 lpDisplayNameW = SERV_dup(lpDisplayName);
2090 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2092 lpServiceNameW = NULL;
2094 sizeW = *lpcchBuffer;
2095 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
2097 if (*lpcchBuffer && lpServiceName)
2098 lpServiceName[0] = 0;
2099 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2103 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
2104 *lpcchBuffer, NULL, NULL ))
2106 if (*lpcchBuffer && lpServiceName)
2107 lpServiceName[0] = 0;
2108 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
2112 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
2116 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2117 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2121 /******************************************************************************
2122 * GetServiceKeyNameW [ADVAPI32.@]
2124 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2125 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2127 struct sc_manager *hscm;
2130 TRACE("%p %s %p %p\n", hSCManager,
2131 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2133 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2136 SetLastError(ERROR_INVALID_HANDLE);
2142 SetLastError(ERROR_INVALID_ADDRESS);
2146 err = svcctl_GetServiceKeyNameW(hscm->hdr.server_handle,
2147 lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
2151 return err == ERROR_SUCCESS;
2154 /******************************************************************************
2155 * QueryServiceLockStatusA [ADVAPI32.@]
2157 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2158 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2159 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2161 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2166 /******************************************************************************
2167 * QueryServiceLockStatusW [ADVAPI32.@]
2169 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2170 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2171 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2173 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2178 /******************************************************************************
2179 * GetServiceDisplayNameA [ADVAPI32.@]
2181 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2182 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2184 LPWSTR lpServiceNameW, lpDisplayNameW;
2188 TRACE("%p %s %p %p\n", hSCManager,
2189 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2191 lpServiceNameW = SERV_dup(lpServiceName);
2193 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2195 lpDisplayNameW = NULL;
2197 sizeW = *lpcchBuffer;
2198 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2200 if (*lpcchBuffer && lpDisplayName)
2201 lpDisplayName[0] = 0;
2202 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2206 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2207 *lpcchBuffer, NULL, NULL ))
2209 if (*lpcchBuffer && lpDisplayName)
2210 lpDisplayName[0] = 0;
2211 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2215 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2216 * (but if the function succeeded it means that is a good upper estimation of the size) */
2220 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2221 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2225 /******************************************************************************
2226 * GetServiceDisplayNameW [ADVAPI32.@]
2228 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2229 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2231 struct sc_manager *hscm;
2234 TRACE("%p %s %p %p\n", hSCManager,
2235 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2237 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2240 SetLastError(ERROR_INVALID_HANDLE);
2246 SetLastError(ERROR_INVALID_ADDRESS);
2250 err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
2251 lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
2255 return err == ERROR_SUCCESS;
2258 /******************************************************************************
2259 * ChangeServiceConfigW [ADVAPI32.@]
2261 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2262 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2263 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2264 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2266 struct sc_service *hsvc;
2270 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2271 hService, dwServiceType, dwStartType, dwErrorControl,
2272 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2273 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2274 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2276 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2279 SetLastError( ERROR_INVALID_HANDLE );
2283 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2285 err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
2286 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2287 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2288 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2290 if (err != ERROR_SUCCESS)
2293 return err == ERROR_SUCCESS;
2296 /******************************************************************************
2297 * ChangeServiceConfigA [ADVAPI32.@]
2299 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2300 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2301 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2302 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2304 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2305 LPWSTR wServiceStartName, wPassword, wDisplayName;
2308 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2309 hService, dwServiceType, dwStartType, dwErrorControl,
2310 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2311 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2312 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2314 wBinaryPathName = SERV_dup( lpBinaryPathName );
2315 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2316 wDependencies = SERV_dupmulti( lpDependencies );
2317 wServiceStartName = SERV_dup( lpServiceStartName );
2318 wPassword = SERV_dup( lpPassword );
2319 wDisplayName = SERV_dup( lpDisplayName );
2321 r = ChangeServiceConfigW( hService, dwServiceType,
2322 dwStartType, dwErrorControl, wBinaryPathName,
2323 wLoadOrderGroup, lpdwTagId, wDependencies,
2324 wServiceStartName, wPassword, wDisplayName);
2326 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2327 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2328 HeapFree( GetProcessHeap(), 0, wDependencies );
2329 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2330 HeapFree( GetProcessHeap(), 0, wPassword );
2331 HeapFree( GetProcessHeap(), 0, wDisplayName );
2336 /******************************************************************************
2337 * ChangeServiceConfig2A [ADVAPI32.@]
2339 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2344 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2346 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2348 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2349 SERVICE_DESCRIPTIONW sdw;
2351 sdw.lpDescription = SERV_dup( sd->lpDescription );
2353 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2355 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2357 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2359 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2360 SERVICE_FAILURE_ACTIONSW faw;
2362 faw.dwResetPeriod = fa->dwResetPeriod;
2363 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2364 faw.lpCommand = SERV_dup( fa->lpCommand );
2365 faw.cActions = fa->cActions;
2366 faw.lpsaActions = fa->lpsaActions;
2368 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2370 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2371 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2374 SetLastError( ERROR_INVALID_PARAMETER );
2379 /******************************************************************************
2380 * ChangeServiceConfig2W [ADVAPI32.@]
2382 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2386 struct sc_service *hsvc;
2388 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2391 SetLastError( ERROR_INVALID_HANDLE );
2396 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2398 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2399 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2400 if (sd->lpDescription)
2402 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2403 if (sd->lpDescription[0] == 0)
2404 RegDeleteValueW(hKey,szDescription);
2406 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2407 (LPVOID)sd->lpDescription,
2408 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2412 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2416 /******************************************************************************
2417 * QueryServiceObjectSecurity [ADVAPI32.@]
2419 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2420 SECURITY_INFORMATION dwSecurityInformation,
2421 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2422 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2424 SECURITY_DESCRIPTOR descriptor;
2429 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2430 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2432 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2433 FIXME("information %d not supported\n", dwSecurityInformation);
2435 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2437 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2438 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2441 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2442 *pcbBytesNeeded = size;
2446 /******************************************************************************
2447 * SetServiceObjectSecurity [ADVAPI32.@]
2449 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2450 SECURITY_INFORMATION dwSecurityInformation,
2451 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2453 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2457 /******************************************************************************
2458 * SetServiceBits [ADVAPI32.@]
2460 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2461 DWORD dwServiceBits,
2463 BOOL bUpdateImmediately)
2465 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2466 bSetBitsOn, bUpdateImmediately);
2470 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2471 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2473 LPHANDLER_FUNCTION func = context;
2476 return ERROR_SUCCESS;
2479 /******************************************************************************
2480 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2482 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2484 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2487 /******************************************************************************
2488 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2490 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2492 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2495 /******************************************************************************
2496 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2498 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2501 SERVICE_STATUS_HANDLE ret;
2503 nameW = SERV_dup(name);
2504 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2505 HeapFree( GetProcessHeap(), 0, nameW );
2509 /******************************************************************************
2510 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2512 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2513 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2520 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2522 hSCM = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
2525 hService = OpenServiceW( hSCM, lpServiceName, SERVICE_SET_STATUS );
2526 CloseServiceHandle(hSCM);
2530 EnterCriticalSection( &service_cs );
2531 for (i = 0; i < nb_services; i++)
2533 if(!strcmpW(lpServiceName, services[i]->name))
2535 services[i]->handler = lpHandlerProc;
2536 services[i]->context = lpContext;
2541 LeaveCriticalSection( &service_cs );
2545 CloseServiceHandle(hService);
2546 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2550 return (SERVICE_STATUS_HANDLE)hService;
2553 /******************************************************************************
2554 * EnumDependentServicesA [ADVAPI32.@]
2556 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2557 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2558 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2560 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2561 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2563 *lpServicesReturned = 0;
2567 /******************************************************************************
2568 * EnumDependentServicesW [ADVAPI32.@]
2570 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2571 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2572 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2574 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2575 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2577 *lpServicesReturned = 0;