services: Move SetServiceStatus and QueryServiceStatusEx to services.exe.
[wine/testsucceed.git] / dlls / advapi32 / service.c
blob20f7af5923793fed068ade36abf0ecb0b9c67aec
1 /*
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
23 #include <stdarg.h>
24 #include <string.h>
25 #include <time.h>
26 #include <assert.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winsvc.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
35 #include "winternl.h"
36 #include "lmcons.h"
37 #include "lmserver.h"
39 #include "svcctl.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',
48 'L','O','C','K',0};
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),
64 SC_MANAGER_ALL_ACCESS
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),
71 SERVICE_ALL_ACCESS
74 typedef struct service_start_info_t
76 DWORD cmd;
77 DWORD size;
78 WCHAR str[1];
79 } service_start_info;
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;
88 LPVOID context;
89 SERVICE_STATUS_PROCESS status;
90 HANDLE thread;
91 BOOL unicode : 1;
92 union {
93 LPSERVICE_MAIN_FUNCTIONA a;
94 LPSERVICE_MAIN_FUNCTIONW w;
95 } proc;
96 LPWSTR args;
97 WCHAR name[1];
98 } service_data;
100 static CRITICAL_SECTION service_cs;
101 static CRITICAL_SECTION_DEBUG service_cs_debug =
103 0, 0, &service_cs,
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 /******************************************************************************
117 * SC_HANDLEs
120 #define MAX_SERVICE_NAME 256
122 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
124 struct sc_handle;
125 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
127 struct sc_handle
129 SC_HANDLE_TYPE htype;
130 DWORD ref_count;
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 */
139 DWORD dwAccess;
142 struct sc_service /* service handle */
144 struct sc_handle hdr;
145 HKEY hkey; /* handle to service entry in the registry (under hkey) */
146 DWORD dwAccess;
147 struct sc_manager *scm; /* pointer to SCM handle */
148 WCHAR name[1];
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 );
157 if (hdr)
159 hdr->htype = htype;
160 hdr->ref_count = 1;
161 hdr->destroy = destroy;
163 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
164 return hdr;
167 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
169 struct sc_handle *hdr = (struct sc_handle *) handle;
171 if (!hdr)
172 return NULL;
173 if (hdr->htype != htype)
174 return NULL;
175 return hdr;
178 static void sc_handle_free(struct sc_handle* hdr)
180 if (!hdr)
181 return;
182 if (--hdr->ref_count)
183 return;
184 hdr->destroy(hdr);
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);
193 if (mgr->hkey)
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);
202 if (svc->hkey)
203 RegCloseKey(svc->hkey);
204 svc->hkey = NULL;
205 sc_handle_free(&svc->scm->hdr);
206 svc->scm = NULL;
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 )
216 UINT len;
217 LPWSTR wstr;
219 if( !str )
220 return NULL;
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 );
224 return wstr;
227 static inline LPWSTR SERV_dupmulti(LPCSTR str)
229 UINT len = 0, n = 0;
230 LPWSTR wstr;
232 if( !str )
233 return NULL;
234 do {
235 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
236 n += (strlen( &str[n] ) + 1);
237 } while (str[n]);
238 len++;
239 n++;
241 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
242 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
243 return wstr;
246 static inline DWORD multisz_cb(LPCWSTR wmultisz)
248 const WCHAR *wptr = wmultisz;
250 if (wmultisz == NULL)
251 return 0;
253 while (*wptr)
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;
270 STARTUPINFOW si;
271 HANDLE wait_handles[2];
272 WCHAR path[MAX_PATH];
274 if (!GetSystemDirectoryW(path, MAX_PATH - strlenW(services)))
275 return FALSE;
276 strcatW(path, services);
277 ZeroMemory(&si, sizeof(si));
278 si.cb = 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());
282 return FALSE;
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)
293 DWORD exit_code;
294 GetExitCodeProcess(out.hProcess, &exit_code);
295 ERR("Unexpected termination of services.exe - exit code %d\n", exit_code);
296 CloseHandle(out.hProcess);
297 CloseHandle(hEvent);
298 return FALSE;
301 TRACE("services.exe started successfully\n");
302 CloseHandle(out.hProcess);
303 CloseHandle(hEvent);
304 return TRUE;
307 TRACE("Waiting for services.exe to be available\n");
308 WaitForSingleObject(hEvent, INFINITE);
309 TRACE("Services.exe are available\n");
310 CloseHandle(hEvent);
312 return TRUE;
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;
321 RPC_STATUS status;
322 handle_t rpc_handle;
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())
327 return NULL;
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);
334 return NULL;
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);
343 return NULL;
346 return rpc_handle;
349 void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
351 RpcBindingFree(&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[] = {
372 'T','a','g',0};
374 struct reg_value {
375 DWORD type;
376 DWORD size;
377 LPCWSTR name;
378 LPCVOID data;
381 static inline void service_set_value( struct reg_value *val,
382 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
384 val->name = name;
385 val->type = type;
386 val->data = data;
387 val->size = 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 )
406 DWORD len = 0;
408 /* determine the length of a double null terminated multi string */
409 do {
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;
421 int i;
423 for( i=0; i<n; i++ )
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 )
428 break;
430 return r;
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};
440 LPWSTR name;
441 DWORD len;
443 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
444 name = HeapAlloc(GetProcessHeap(), 0, len);
445 strcpyW(name, prefix);
446 strcatW(name, service);
447 return name;
450 static HANDLE service_open_pipe(LPCWSTR service)
452 LPWSTR szPipe = service_get_pipe_name( service );
453 HANDLE handle = INVALID_HANDLE_VALUE;
455 do {
456 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
457 0, NULL, OPEN_ALWAYS, 0, NULL);
458 if (handle != INVALID_HANDLE_VALUE)
459 break;
460 if (GetLastError() != ERROR_PIPE_BUSY)
461 break;
462 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
463 HeapFree(GetProcessHeap(), 0, szPipe);
465 return handle;
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};
475 LPWSTR name;
476 DWORD len;
477 HANDLE handle;
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);
485 return handle;
488 /******************************************************************************
489 * service_thread
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;
499 TRACE("%p\n", arg);
501 while (str[len])
503 len += strlenW(&str[len]) + 1;
504 argc++;
507 if (!argc)
509 if (info->unicode)
510 info->proc.w(0, NULL);
511 else
512 info->proc.a(0, NULL);
513 return 0;
516 if (info->unicode)
518 LPWSTR *argv, p;
520 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
521 for (argc=0, p=str; *p; p += strlenW(p) + 1)
522 argv[argc++] = p;
523 argv[argc] = NULL;
525 info->proc.w(argc, argv);
526 HeapFree(GetProcessHeap(), 0, argv);
528 else
530 LPSTR strA, *argv, p;
531 DWORD lenA;
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)
539 argv[argc++] = p;
540 argv[argc] = NULL;
542 info->proc.a(argc, argv);
543 HeapFree(GetProcessHeap(), 0, argv);
544 HeapFree(GetProcessHeap(), 0, strA);
546 return 0;
549 /******************************************************************************
550 * service_handle_start
552 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
554 DWORD read = 0, result = 0;
555 LPWSTR args;
556 BOOL r;
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));
566 goto end;
569 if (service->thread)
571 WARN("service is not stopped\n");
572 result = ERROR_SERVICE_ALREADY_RUNNING;
573 goto end;
576 HeapFree(GetProcessHeap(), 0, service->args);
577 service->args = args;
578 args = NULL;
579 service->status.dwCurrentState = SERVICE_START_PENDING;
580 service->thread = CreateThread( NULL, 0, service_thread,
581 service, 0, NULL );
582 SetEvent( service_event ); /* notify the main loop */
584 end:
585 HeapFree(GetProcessHeap(), 0, args);
586 WriteFile( pipe, &result, sizeof result, &read, NULL );
588 return TRUE;
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;
598 LPWSTR p;
599 BOOL r;
601 TRACE("%p %p %d\n", pipe, argv, argc);
603 /* calculate how much space do we need to send the startup info */
604 len = 1;
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;
610 ssi->size = len;
612 /* copy service args into a single buffer*/
613 p = &ssi->str[0];
614 for (i=0; i<argc; i++)
616 strcpyW(p, argv[i]);
617 p += strlenW(p) + 1;
619 *p=0;
621 r = WriteFile(pipe, ssi, FIELD_OFFSET(service_start_info, str[len]), &count, NULL);
622 if (r)
624 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
625 if (r && result)
627 SetLastError(result);
628 r = FALSE;
632 HeapFree(GetProcessHeap(),0,ssi);
634 return r;
637 /******************************************************************************
638 * service_handle_get_status
640 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
642 DWORD count = 0;
643 TRACE("\n");
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;
654 BOOL r;
656 cmd[0] = WINESERV_SENDCONTROL;
657 cmd[1] = dwControl;
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");
662 return r;
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);
668 return r;
671 /******************************************************************************
672 * service_accepts_control
674 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
676 DWORD a = service->status.dwControlsAccepted;
678 switch (dwControl)
680 case SERVICE_CONTROL_INTERROGATE:
681 return TRUE;
682 case SERVICE_CONTROL_STOP:
683 if (a&SERVICE_ACCEPT_STOP)
684 return TRUE;
685 break;
686 case SERVICE_CONTROL_SHUTDOWN:
687 if (a&SERVICE_ACCEPT_SHUTDOWN)
688 return TRUE;
689 break;
690 case SERVICE_CONTROL_PAUSE:
691 case SERVICE_CONTROL_CONTINUE:
692 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
693 return TRUE;
694 break;
695 case SERVICE_CONTROL_PARAMCHANGE:
696 if (a&SERVICE_ACCEPT_PARAMCHANGE)
697 return TRUE;
698 break;
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)
704 return TRUE;
705 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
706 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
707 return TRUE;
708 break;
709 case SERVICE_CONTROL_POWEREVENT:
710 if (a&SERVICE_ACCEPT_POWEREVENT)
711 return TRUE;
712 break;
713 case SERVICE_CONTROL_SESSIONCHANGE:
714 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
715 return TRUE;
716 break;
718 return FALSE;
721 /******************************************************************************
722 * service_handle_control
724 static BOOL service_handle_control(HANDLE pipe, service_data *service,
725 DWORD dwControl)
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;
745 LPWSTR name;
746 HANDLE pipe, event;
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);
763 SetEvent(event);
764 CloseHandle(event);
766 if (pipe==INVALID_HANDLE_VALUE) return 0;
768 /* dispatcher loop */
769 while (1)
771 BOOL r;
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");
778 break;
781 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
782 if (!r || count!=sizeof req)
784 ERR("pipe read failed\n");
785 break;
788 /* handle the request */
789 switch (req[0])
791 case WINESERV_STARTINFO:
792 service_handle_start(pipe, service, req[1]);
793 break;
794 case WINESERV_GETSTATUS:
795 service_handle_get_status(pipe, service);
796 break;
797 case WINESERV_SENDCONTROL:
798 service_handle_control(pipe, service, req[1]);
799 break;
800 default:
801 ERR("received invalid command %d length %d\n", req[0], req[1]);
804 FlushFileBuffers(pipe);
805 DisconnectNamedPipe(pipe);
808 CloseHandle(pipe);
809 return 1;
812 /******************************************************************************
813 * service_run_threads
815 static BOOL service_run_threads(void)
817 DWORD i, n, ret;
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 */
838 for (;;)
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 */
854 ExitProcess(0);
856 else if (ret == 1)
858 continue; /* rebuild the list */
860 else if (ret < n)
862 services[wait_services[ret]]->thread = 0;
863 CloseHandle( wait_handles[ret] );
864 if (n == 3) return TRUE; /* it was the last running thread */
866 else return FALSE;
870 /******************************************************************************
871 * StartServiceCtrlDispatcherA [ADVAPI32.@]
873 * See StartServiceCtrlDispatcherW.
875 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
877 service_data *info;
878 unsigned int i;
879 BOOL ret = TRUE;
881 TRACE("%p\n", servent);
883 if (nb_services)
885 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
886 return FALSE;
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;
899 services[i] = info;
902 service_run_threads();
904 return ret;
907 /******************************************************************************
908 * StartServiceCtrlDispatcherW [ADVAPI32.@]
910 * Connects a process containing one or more services to the service control
911 * manager.
913 * PARAMS
914 * servent [I] A list of the service names and service procedures
916 * RETURNS
917 * Success: TRUE.
918 * Failure: FALSE.
920 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
922 service_data *info;
923 unsigned int i;
924 BOOL ret = TRUE;
926 TRACE("%p\n", servent);
928 if (nb_services)
930 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
931 return FALSE;
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;
944 services[i] = info;
947 service_run_threads();
949 return ret;
952 /******************************************************************************
953 * LockServiceDatabase [ADVAPI32.@]
955 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
957 HANDLE ret;
959 TRACE("%p\n",hSCManager);
961 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
962 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
964 CloseHandle( ret );
965 ret = NULL;
966 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
969 TRACE("returning %p\n", ret);
971 return 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.@]
987 * PARAMS
988 * hService []
989 * lpStatus []
991 BOOL WINAPI
992 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
994 struct sc_service *hsvc;
995 DWORD err;
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);
1004 if (!hsvc)
1006 SetLastError( ERROR_INVALID_HANDLE );
1007 return FALSE;
1010 err = svcctl_SetServiceStatus( hsvc->hdr.server_handle, lpStatus );
1011 if (err != ERROR_SUCCESS)
1013 SetLastError(err);
1014 return FALSE;
1017 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
1018 CloseServiceHandle((SC_HANDLE)hService);
1020 return TRUE;
1024 /******************************************************************************
1025 * OpenSCManagerA [ADVAPI32.@]
1027 * Establish a connection to the service control manager and open its database.
1029 * PARAMS
1030 * lpMachineName [I] Pointer to machine name string
1031 * lpDatabaseName [I] Pointer to database name string
1032 * dwDesiredAccess [I] Type of access
1034 * RETURNS
1035 * Success: A Handle to the service control manager database
1036 * Failure: NULL
1038 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1039 DWORD dwDesiredAccess )
1041 LPWSTR lpMachineNameW, lpDatabaseNameW;
1042 SC_HANDLE ret;
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);
1049 return ret;
1052 /******************************************************************************
1053 * OpenSCManagerW [ADVAPI32.@]
1055 * See OpenSCManagerA.
1057 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1058 DWORD dwDesiredAccess )
1060 struct sc_manager *manager;
1061 HKEY hReg;
1062 LONG r;
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 );
1070 if (!manager)
1071 return NULL;
1073 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, &manager->hdr.server_handle);
1074 if (r!=ERROR_SUCCESS)
1075 goto error;
1077 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1078 if (r!=ERROR_SUCCESS)
1079 goto error;
1081 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1082 RegCloseKey( hReg );
1083 if (r!=ERROR_SUCCESS)
1084 goto error;
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;
1092 error:
1093 sc_handle_free( &manager->hdr );
1094 SetLastError( r);
1095 return NULL;
1098 /******************************************************************************
1099 * ControlService [ADVAPI32.@]
1101 * Send a control code to a service.
1103 * PARAMS
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
1108 * RETURNS
1109 * Success: TRUE.
1110 * Failure: FALSE.
1112 * BUGS
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;
1120 BOOL ret = FALSE;
1121 HANDLE handle;
1123 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1125 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1126 if (!hsvc)
1128 SetLastError( ERROR_INVALID_HANDLE );
1129 return FALSE;
1132 if (lpServiceStatus)
1134 ret = QueryServiceStatus(hService, lpServiceStatus);
1135 if (!ret)
1137 ERR("failed to query service status\n");
1138 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1139 return FALSE;
1142 switch (lpServiceStatus->dwCurrentState)
1144 case SERVICE_STOPPED:
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1146 return FALSE;
1147 case SERVICE_START_PENDING:
1148 if (dwControl==SERVICE_CONTROL_STOP)
1149 break;
1150 /* fall thru */
1151 case SERVICE_STOP_PENDING:
1152 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1153 return FALSE;
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);
1166 ret = FALSE;
1170 return ret;
1173 /******************************************************************************
1174 * CloseServiceHandle [ADVAPI32.@]
1176 * Close a handle to a service or the service control manager database.
1178 * PARAMS
1179 * hSCObject [I] Handle to service or service control manager database
1181 * RETURNS
1182 * Success: TRUE
1183 * Failure: FALSE
1185 BOOL WINAPI
1186 CloseServiceHandle( SC_HANDLE hSCObject )
1188 struct sc_handle *obj;
1189 DWORD err;
1191 TRACE("%p\n", hSCObject);
1192 if (hSCObject == NULL)
1194 SetLastError(ERROR_INVALID_HANDLE);
1195 return FALSE;
1198 obj = (struct sc_handle *)hSCObject;
1199 err = svcctl_CloseServiceHandle(&obj->server_handle);
1200 sc_handle_free( obj );
1202 if (err != ERROR_SUCCESS)
1204 SetLastError(err);
1205 return FALSE;
1207 return TRUE;
1211 /******************************************************************************
1212 * OpenServiceA [ADVAPI32.@]
1214 * Open a handle to a service.
1216 * PARAMS
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
1221 * RETURNS
1222 * Success: Handle to the service
1223 * Failure: NULL
1225 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1226 DWORD dwDesiredAccess )
1228 LPWSTR lpServiceNameW;
1229 SC_HANDLE ret;
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);
1236 return ret;
1240 /******************************************************************************
1241 * OpenServiceW [ADVAPI32.@]
1243 * See OpenServiceA.
1245 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1246 DWORD dwDesiredAccess)
1248 struct sc_manager *hscm;
1249 struct sc_service *hsvc;
1250 DWORD err;
1251 DWORD len;
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 );
1257 if (!hscm)
1259 SetLastError( ERROR_INVALID_HANDLE );
1260 return FALSE;
1263 if (!lpServiceName)
1265 SetLastError(ERROR_INVALID_ADDRESS);
1266 return NULL;
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 );
1273 if (!hsvc)
1275 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1276 return NULL;
1278 strcpyW( hsvc->name, lpServiceName );
1280 /* add reference to SCM handle */
1281 hscm->hdr.ref_count++;
1282 hsvc->scm = hscm;
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);
1289 SetLastError(err);
1290 return NULL;
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.@]
1309 SC_HANDLE WINAPI
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;
1321 DWORD len, err;
1322 SIZE_T passwdlen;
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 );
1328 if (!hscm)
1330 SetLastError( ERROR_INVALID_HANDLE );
1331 return NULL;
1334 if (!lpServiceName || !lpBinaryPathName)
1336 SetLastError(ERROR_INVALID_ADDRESS);
1337 return NULL;
1340 if (lpPassword)
1341 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
1342 else
1343 passwdlen = 0;
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 );
1348 if( !hsvc )
1350 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
1351 return NULL;
1353 lstrcpyW( hsvc->name, lpServiceName );
1355 hsvc->scm = hscm;
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)
1366 SetLastError(err);
1367 sc_handle_free(&hsvc->hdr);
1368 return NULL;
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.@]
1386 SC_HANDLE WINAPI
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,
1393 LPCSTR lpPassword )
1395 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1396 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1397 SC_HANDLE r;
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 );
1423 return r;
1427 /******************************************************************************
1428 * DeleteService [ADVAPI32.@]
1430 * Delete a service from the service control manager database.
1432 * PARAMS
1433 * hService [I] Handle of the service to delete
1435 * RETURNS
1436 * Success: TRUE
1437 * Failure: FALSE
1439 BOOL WINAPI DeleteService( SC_HANDLE hService )
1441 struct sc_service *hsvc;
1442 DWORD err;
1444 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1445 if (!hsvc)
1447 SetLastError( ERROR_INVALID_HANDLE );
1448 return FALSE;
1451 err = svcctl_DeleteService(hsvc->hdr.server_handle);
1452 if (err != 0)
1454 SetLastError(err);
1455 return FALSE;
1458 /* Close the key to the service */
1459 RegCloseKey(hsvc->hkey);
1460 hsvc->hkey = NULL;
1461 return TRUE;
1465 /******************************************************************************
1466 * StartServiceA [ADVAPI32.@]
1468 * Start a service
1470 * PARAMS
1471 * hService [I] Handle of service
1472 * dwNumServiceArgs [I] Number of arguments
1473 * lpServiceArgVectors [I] Address of array of argument strings
1475 * NOTES
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.
1484 * RETURNS
1485 * Success: TRUE.
1486 * Failure: FALSE
1488 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1489 LPCSTR *lpServiceArgVectors )
1491 LPWSTR *lpwstr=NULL;
1492 unsigned int i;
1493 BOOL r;
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);
1513 return r;
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;
1523 STARTUPINFOW si;
1524 LPWSTR path = NULL, str;
1525 DWORD type, size, ret, svc_type;
1526 HANDLE handles[2];
1527 BOOL r;
1529 size = sizeof(svc_type);
1530 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1531 svc_type = 0;
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 );
1543 else
1545 /* read the executable path from the registry */
1546 size = 0;
1547 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1548 if (ret!=ERROR_SUCCESS)
1549 return FALSE;
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);
1559 if (!path)
1560 return FALSE;
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);
1574 if (r)
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);
1583 r = FALSE;
1586 CloseHandle( pi.hThread );
1587 CloseHandle( pi.hProcess );
1589 CloseHandle( handles[0] );
1590 HeapFree(GetProcessHeap(),0,path);
1591 return r;
1594 static BOOL service_wait_for_startup(SC_HANDLE hService)
1596 DWORD i;
1597 SERVICE_STATUS status;
1598 BOOL r = FALSE;
1600 TRACE("%p\n", hService);
1602 for (i=0; i<20; i++)
1604 status.dwCurrentState = 0;
1605 r = QueryServiceStatus(hService, &status);
1606 if (!r)
1607 break;
1608 if (status.dwCurrentState == SERVICE_RUNNING)
1610 TRACE("Service started successfully\n");
1611 break;
1613 r = FALSE;
1614 if (status.dwCurrentState != SERVICE_START_PENDING) break;
1615 Sleep(100 * i);
1617 return r;
1620 /******************************************************************************
1621 * StartServiceW [ADVAPI32.@]
1623 * See StartServiceA.
1625 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1626 LPCWSTR *lpServiceArgVectors)
1628 struct sc_service *hsvc;
1629 BOOL r = FALSE;
1630 SC_LOCK hLock;
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);
1636 if (!hsvc)
1638 SetLastError(ERROR_INVALID_HANDLE);
1639 return r;
1642 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1643 if (!hLock)
1644 return r;
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);
1664 if (r)
1665 service_wait_for_startup(hService);
1667 return r;
1670 /******************************************************************************
1671 * QueryServiceStatus [ADVAPI32.@]
1673 * PARAMS
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;
1682 BOOL ret;
1683 DWORD dummy;
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)) ;
1690 return ret;
1694 /******************************************************************************
1695 * QueryServiceStatusEx [ADVAPI32.@]
1697 * Get information about a service.
1699 * PARAMS
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
1706 * RETURNS
1707 * Success: TRUE
1708 * FAILURE: FALSE
1710 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1711 LPBYTE lpBuffer, DWORD cbBufSize,
1712 LPDWORD pcbBytesNeeded)
1714 struct sc_service *hsvc;
1715 DWORD err;
1717 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1719 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1720 if (!hsvc)
1722 SetLastError( ERROR_INVALID_HANDLE );
1723 return FALSE;
1726 err = svcctl_QueryServiceStatusEx(hsvc->hdr.server_handle, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1727 if (err != ERROR_SUCCESS)
1729 SetLastError(err);
1730 return FALSE;
1733 return TRUE;
1736 /******************************************************************************
1737 * QueryServiceConfigA [ADVAPI32.@]
1739 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1740 DWORD size, LPDWORD needed )
1742 DWORD n;
1743 LPSTR p, buffer;
1744 BOOL ret;
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 );
1752 return FALSE;
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);
1770 ret = FALSE;
1772 #define MAP_STR(str) \
1773 do { \
1774 if (configW->str) \
1776 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1777 if (!sz) goto done; \
1778 config->str = p; \
1779 p += sz; \
1780 n -= sz; \
1782 } while (0)
1784 MAP_STR( lpBinaryPathName );
1785 MAP_STR( lpLoadOrderGroup );
1786 MAP_STR( lpDependencies );
1787 MAP_STR( lpServiceStartName );
1788 MAP_STR( lpDisplayName );
1789 #undef MAP_STR
1791 *needed = p - (LPSTR)config;
1792 ret = TRUE;
1794 done:
1795 HeapFree( GetProcessHeap(), 0, buffer );
1796 return ret;
1799 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1801 DWORD cb;
1802 WCHAR empty_str[] = {0};
1804 if (!*string_ptr)
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;
1812 *buf += cb;
1814 return cb;
1817 static DWORD size_string(LPWSTR string)
1819 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1822 /******************************************************************************
1823 * QueryServiceConfigW [ADVAPI32.@]
1825 BOOL WINAPI
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;
1832 DWORD total;
1833 DWORD err;
1834 BYTE *bufpos;
1836 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1837 cbBufSize, pcbBytesNeeded);
1839 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1840 if (!hsvc)
1842 SetLastError( ERROR_INVALID_HANDLE );
1843 return FALSE;
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);
1851 SetLastError(err);
1852 return FALSE;
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);
1874 return FALSE;
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) );
1894 return TRUE;
1897 /******************************************************************************
1898 * QueryServiceConfig2A [ADVAPI32.@]
1900 * Note
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)
1908 BOOL ret;
1909 LPBYTE bufferW = NULL;
1911 if(buffer && size)
1912 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1914 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1915 if(!ret) goto cleanup;
1917 switch(dwLevel) {
1918 case SERVICE_CONFIG_DESCRIPTION:
1919 { LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1920 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1921 if (configW->lpDescription) {
1922 DWORD sz;
1923 configA->lpDescription = (LPSTR)(configA + 1);
1924 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1925 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1926 if (!sz) {
1927 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1928 ret = FALSE;
1929 configA->lpDescription = NULL;
1932 else configA->lpDescription = NULL;
1934 break;
1935 default:
1936 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1937 ret = FALSE;
1940 cleanup:
1941 HeapFree( GetProcessHeap(), 0, bufferW);
1942 return ret;
1945 /******************************************************************************
1946 * QueryServiceConfig2W [ADVAPI32.@]
1948 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1949 DWORD size, LPDWORD needed)
1951 DWORD sz, type;
1952 HKEY hKey;
1953 LONG r;
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);
1965 return FALSE;
1967 if(!needed || (!buffer && size)) {
1968 SetLastError(ERROR_INVALID_ADDRESS);
1969 return FALSE;
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);
1975 if (!hsvc)
1977 SetLastError(ERROR_INVALID_HANDLE);
1978 return FALSE;
1980 hKey = hsvc->hkey;
1982 switch(dwLevel) {
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);
1994 return FALSE;
1996 *needed += sz;
1997 if(config) {
1998 if(r == ERROR_SUCCESS)
1999 config->lpDescription = (LPWSTR) (config + 1);
2000 else
2001 config->lpDescription = NULL;
2004 break;
2006 if(*needed > size)
2007 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2009 return (*needed <= size);
2012 /******************************************************************************
2013 * EnumServicesStatusA [ADVAPI32.@]
2015 BOOL WINAPI
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);
2025 return FALSE;
2028 /******************************************************************************
2029 * EnumServicesStatusW [ADVAPI32.@]
2031 BOOL WINAPI
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);
2041 return FALSE;
2044 /******************************************************************************
2045 * EnumServicesStatusExA [ADVAPI32.@]
2047 BOOL WINAPI
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);
2057 return FALSE;
2060 /******************************************************************************
2061 * EnumServicesStatusExW [ADVAPI32.@]
2063 BOOL WINAPI
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);
2072 return FALSE;
2075 /******************************************************************************
2076 * GetServiceKeyNameA [ADVAPI32.@]
2078 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2079 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2081 LPWSTR lpDisplayNameW, lpServiceNameW;
2082 DWORD sizeW;
2083 BOOL ret = FALSE;
2085 TRACE("%p %s %p %p\n", hSCManager,
2086 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2088 lpDisplayNameW = SERV_dup(lpDisplayName);
2089 if (lpServiceName)
2090 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2091 else
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 */
2100 goto cleanup;
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);
2109 goto cleanup;
2112 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
2113 ret = TRUE;
2115 cleanup:
2116 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2117 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2118 return ret;
2121 /******************************************************************************
2122 * GetServiceKeyNameW [ADVAPI32.@]
2124 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2125 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2127 struct sc_manager *hscm;
2128 DWORD err;
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);
2134 if (!hscm)
2136 SetLastError(ERROR_INVALID_HANDLE);
2137 return FALSE;
2140 if (!lpDisplayName)
2142 SetLastError(ERROR_INVALID_ADDRESS);
2143 return FALSE;
2146 err = svcctl_GetServiceKeyNameW(hscm->hdr.server_handle,
2147 lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
2149 if (err)
2150 SetLastError(err);
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);
2163 return FALSE;
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);
2175 return FALSE;
2178 /******************************************************************************
2179 * GetServiceDisplayNameA [ADVAPI32.@]
2181 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2182 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2184 LPWSTR lpServiceNameW, lpDisplayNameW;
2185 DWORD sizeW;
2186 BOOL ret = FALSE;
2188 TRACE("%p %s %p %p\n", hSCManager,
2189 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2191 lpServiceNameW = SERV_dup(lpServiceName);
2192 if (lpDisplayName)
2193 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2194 else
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 */
2203 goto cleanup;
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);
2212 goto cleanup;
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) */
2217 ret = TRUE;
2219 cleanup:
2220 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2221 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2222 return ret;
2225 /******************************************************************************
2226 * GetServiceDisplayNameW [ADVAPI32.@]
2228 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2229 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2231 struct sc_manager *hscm;
2232 DWORD err;
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);
2238 if (!hscm)
2240 SetLastError(ERROR_INVALID_HANDLE);
2241 return FALSE;
2244 if (!lpServiceName)
2246 SetLastError(ERROR_INVALID_ADDRESS);
2247 return FALSE;
2250 err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
2251 lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
2253 if (err)
2254 SetLastError(err);
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;
2267 DWORD cb_pwd;
2268 DWORD err;
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);
2277 if (!hsvc)
2279 SetLastError( ERROR_INVALID_HANDLE );
2280 return FALSE;
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)
2291 SetLastError(err);
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;
2306 BOOL r;
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 );
2333 return r;
2336 /******************************************************************************
2337 * ChangeServiceConfig2A [ADVAPI32.@]
2339 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2340 LPVOID lpInfo)
2342 BOOL r = FALSE;
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 );
2373 else
2374 SetLastError( ERROR_INVALID_PARAMETER );
2376 return r;
2379 /******************************************************************************
2380 * ChangeServiceConfig2W [ADVAPI32.@]
2382 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2383 LPVOID lpInfo)
2385 HKEY hKey;
2386 struct sc_service *hsvc;
2388 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2389 if (!hsvc)
2391 SetLastError( ERROR_INVALID_HANDLE );
2392 return FALSE;
2394 hKey = hsvc->hkey;
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);
2405 else
2406 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2407 (LPVOID)sd->lpDescription,
2408 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2411 else
2412 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2413 return TRUE;
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;
2425 DWORD size;
2426 BOOL succ;
2427 ACL acl;
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);
2440 size = cbBufSize;
2441 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2442 *pcbBytesNeeded = size;
2443 return succ;
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);
2454 return TRUE;
2457 /******************************************************************************
2458 * SetServiceBits [ADVAPI32.@]
2460 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2461 DWORD dwServiceBits,
2462 BOOL bSetBitsOn,
2463 BOOL bUpdateImmediately)
2465 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2466 bSetBitsOn, bUpdateImmediately);
2467 return TRUE;
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;
2475 func( control );
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 )
2500 LPWSTR nameW;
2501 SERVICE_STATUS_HANDLE ret;
2503 nameW = SERV_dup(name);
2504 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2505 HeapFree( GetProcessHeap(), 0, nameW );
2506 return ret;
2509 /******************************************************************************
2510 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2512 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2513 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2515 SC_HANDLE hService;
2516 SC_HANDLE hSCM;
2517 unsigned int i;
2518 BOOL found = FALSE;
2520 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2522 hSCM = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
2523 if (!hSCM)
2524 return NULL;
2525 hService = OpenServiceW( hSCM, lpServiceName, SERVICE_SET_STATUS );
2526 CloseServiceHandle(hSCM);
2527 if (!hService)
2528 return NULL;
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;
2537 found = TRUE;
2538 break;
2541 LeaveCriticalSection( &service_cs );
2543 if (!found)
2545 CloseServiceHandle(hService);
2546 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2547 return NULL;
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;
2564 return TRUE;
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;
2578 return TRUE;