kernel32: Silence a fixme in GetNativeSystemInfo.
[wine/multimedia.git] / dlls / advapi32 / service.c
blob8a775adcb4c14cb4d478c125b0f63694ba393c27
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 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
41 static const WCHAR szLocalSystem[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
42 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
43 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
44 'S','e','r','v','i','c','e','s',0 };
45 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
46 'L','O','C','K',0};
48 static const GENERIC_MAPPING scm_generic = {
49 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
50 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
51 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
52 SC_MANAGER_ALL_ACCESS
55 static const GENERIC_MAPPING svc_generic = {
56 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
57 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
58 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
59 SERVICE_ALL_ACCESS
62 typedef struct service_start_info_t
64 DWORD cmd;
65 DWORD size;
66 WCHAR str[1];
67 } service_start_info;
69 #define WINESERV_STARTINFO 1
70 #define WINESERV_GETSTATUS 2
71 #define WINESERV_SENDCONTROL 3
73 typedef struct service_data_t
75 LPHANDLER_FUNCTION_EX handler;
76 LPVOID context;
77 SERVICE_STATUS_PROCESS status;
78 HANDLE thread;
79 BOOL unicode : 1;
80 union {
81 LPSERVICE_MAIN_FUNCTIONA a;
82 LPSERVICE_MAIN_FUNCTIONW w;
83 } proc;
84 LPWSTR args;
85 WCHAR name[1];
86 } service_data;
88 static CRITICAL_SECTION service_cs;
89 static CRITICAL_SECTION_DEBUG service_cs_debug =
91 0, 0, &service_cs,
92 { &service_cs_debug.ProcessLocksList,
93 &service_cs_debug.ProcessLocksList },
94 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
96 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
98 static service_data **services;
99 static unsigned int nb_services;
100 static HANDLE service_event;
102 extern HANDLE __wine_make_process_system(void);
104 /******************************************************************************
105 * SC_HANDLEs
108 #define MAX_SERVICE_NAME 256
110 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
112 struct sc_handle;
113 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
115 struct sc_handle
117 SC_HANDLE_TYPE htype;
118 DWORD ref_count;
119 sc_handle_destructor destroy;
122 struct sc_manager /* service control manager handle */
124 struct sc_handle hdr;
125 HKEY hkey; /* handle to services database in the registry */
126 DWORD dwAccess;
129 struct sc_service /* service handle */
131 struct sc_handle hdr;
132 HKEY hkey; /* handle to service entry in the registry (under hkey) */
133 DWORD dwAccess;
134 struct sc_manager *scm; /* pointer to SCM handle */
135 WCHAR name[1];
138 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
139 sc_handle_destructor destroy)
141 struct sc_handle *hdr;
143 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
144 if (hdr)
146 hdr->htype = htype;
147 hdr->ref_count = 1;
148 hdr->destroy = destroy;
150 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
151 return hdr;
154 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
156 struct sc_handle *hdr = (struct sc_handle *) handle;
158 if (!hdr)
159 return NULL;
160 if (hdr->htype != htype)
161 return NULL;
162 return hdr;
165 static void sc_handle_free(struct sc_handle* hdr)
167 if (!hdr)
168 return;
169 if (--hdr->ref_count)
170 return;
171 hdr->destroy(hdr);
172 HeapFree(GetProcessHeap(), 0, hdr);
175 static void sc_handle_destroy_manager(struct sc_handle *handle)
177 struct sc_manager *mgr = (struct sc_manager*) handle;
179 TRACE("destroying SC Manager %p\n", mgr);
180 if (mgr->hkey)
181 RegCloseKey(mgr->hkey);
184 static void sc_handle_destroy_service(struct sc_handle *handle)
186 struct sc_service *svc = (struct sc_service*) handle;
188 TRACE("destroying service %p\n", svc);
189 if (svc->hkey)
190 RegCloseKey(svc->hkey);
191 svc->hkey = NULL;
192 sc_handle_free(&svc->scm->hdr);
193 svc->scm = NULL;
196 /******************************************************************************
197 * String management functions (same behaviour as strdup)
198 * NOTE: the caller of those functions is responsible for calling HeapFree
199 * in order to release the memory allocated by those functions.
201 static inline LPWSTR SERV_dup( LPCSTR str )
203 UINT len;
204 LPWSTR wstr;
206 if( !str )
207 return NULL;
208 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
209 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
210 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
211 return wstr;
214 static inline LPWSTR SERV_dupmulti(LPCSTR str)
216 UINT len = 0, n = 0;
217 LPWSTR wstr;
219 if( !str )
220 return NULL;
221 do {
222 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
223 n += (strlen( &str[n] ) + 1);
224 } while (str[n]);
225 len++;
226 n++;
228 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
229 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
230 return wstr;
233 /******************************************************************************
234 * registry access functions and data
236 static const WCHAR szDisplayName[] = {
237 'D','i','s','p','l','a','y','N','a','m','e', 0 };
238 static const WCHAR szType[] = {'T','y','p','e',0};
239 static const WCHAR szStart[] = {'S','t','a','r','t',0};
240 static const WCHAR szError[] = {
241 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
242 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
243 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
244 static const WCHAR szDependencies[] = {
245 'D','e','p','e','n','d','e','n','c','i','e','s',0};
246 static const WCHAR szDependOnService[] = {
247 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
248 static const WCHAR szObjectName[] = {
249 'O','b','j','e','c','t','N','a','m','e',0};
250 static const WCHAR szTag[] = {
251 'T','a','g',0};
253 struct reg_value {
254 DWORD type;
255 DWORD size;
256 LPCWSTR name;
257 LPCVOID data;
260 static inline void service_set_value( struct reg_value *val,
261 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
263 val->name = name;
264 val->type = type;
265 val->data = data;
266 val->size = size;
269 static inline void service_set_dword( struct reg_value *val,
270 LPCWSTR name, const DWORD *data )
272 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
275 static inline void service_set_string( struct reg_value *val,
276 LPCWSTR name, LPCWSTR string )
278 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
279 service_set_value( val, REG_SZ, name, string, len );
282 static inline void service_set_multi_string( struct reg_value *val,
283 LPCWSTR name, LPCWSTR string )
285 DWORD len = 0;
287 /* determine the length of a double null terminated multi string */
288 do {
289 len += (lstrlenW( &string[ len ] )+1);
290 } while ( string[ len++ ] );
292 len *= sizeof (WCHAR);
293 service_set_value( val, REG_MULTI_SZ, name, string, len );
296 static inline LONG service_write_values( HKEY hKey,
297 const struct reg_value *val, int n )
299 LONG r = ERROR_SUCCESS;
300 int i;
302 for( i=0; i<n; i++ )
304 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
305 (const BYTE*)val[i].data, val[i].size );
306 if( r != ERROR_SUCCESS )
307 break;
309 return r;
312 /******************************************************************************
313 * Service IPC functions
315 static LPWSTR service_get_pipe_name(LPCWSTR service)
317 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
318 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
319 LPWSTR name;
320 DWORD len;
322 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
323 name = HeapAlloc(GetProcessHeap(), 0, len);
324 strcpyW(name, prefix);
325 strcatW(name, service);
326 return name;
329 static HANDLE service_open_pipe(LPCWSTR service)
331 LPWSTR szPipe = service_get_pipe_name( service );
332 HANDLE handle = INVALID_HANDLE_VALUE;
334 do {
335 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
336 0, NULL, OPEN_ALWAYS, 0, NULL);
337 if (handle != INVALID_HANDLE_VALUE)
338 break;
339 if (GetLastError() != ERROR_PIPE_BUSY)
340 break;
341 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
342 HeapFree(GetProcessHeap(), 0, szPipe);
344 return handle;
347 /******************************************************************************
348 * service_get_event_handle
350 static HANDLE service_get_event_handle(LPCWSTR service)
352 static const WCHAR prefix[] = {
353 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
354 LPWSTR name;
355 DWORD len;
356 HANDLE handle;
358 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
359 name = HeapAlloc(GetProcessHeap(), 0, len);
360 strcpyW(name, prefix);
361 strcatW(name, service);
362 handle = CreateEventW(NULL, TRUE, FALSE, name);
363 HeapFree(GetProcessHeap(), 0, name);
364 return handle;
367 /******************************************************************************
368 * service_thread
370 * Call into the main service routine provided by StartServiceCtrlDispatcher.
372 static DWORD WINAPI service_thread(LPVOID arg)
374 service_data *info = arg;
375 LPWSTR str = info->args;
376 DWORD argc = 0, len = 0;
378 TRACE("%p\n", arg);
380 while (str[len])
382 len += strlenW(&str[len]) + 1;
383 argc++;
386 if (!argc)
388 if (info->unicode)
389 info->proc.w(0, NULL);
390 else
391 info->proc.a(0, NULL);
392 return 0;
395 if (info->unicode)
397 LPWSTR *argv, p;
399 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
400 for (argc=0, p=str; *p; p += strlenW(p) + 1)
401 argv[argc++] = p;
402 argv[argc] = NULL;
404 info->proc.w(argc, argv);
405 HeapFree(GetProcessHeap(), 0, argv);
407 else
409 LPSTR strA, *argv, p;
410 DWORD lenA;
412 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
413 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
414 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
416 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
417 for (argc=0, p=strA; *p; p += strlen(p) + 1)
418 argv[argc++] = p;
419 argv[argc] = NULL;
421 info->proc.a(argc, argv);
422 HeapFree(GetProcessHeap(), 0, argv);
423 HeapFree(GetProcessHeap(), 0, strA);
425 return 0;
428 /******************************************************************************
429 * service_handle_start
431 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
433 DWORD read = 0, result = 0;
434 LPWSTR args;
435 BOOL r;
437 TRACE("%p %p %d\n", pipe, service, count);
439 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
440 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
441 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
443 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
444 r, count, read, debugstr_wn(args, count));
445 goto end;
448 if (service->thread)
450 WARN("service is not stopped\n");
451 result = ERROR_SERVICE_ALREADY_RUNNING;
452 goto end;
455 HeapFree(GetProcessHeap(), 0, service->args);
456 service->args = args;
457 args = NULL;
458 service->thread = CreateThread( NULL, 0, service_thread,
459 service, 0, NULL );
460 SetEvent( service_event ); /* notify the main loop */
462 end:
463 HeapFree(GetProcessHeap(), 0, args);
464 WriteFile( pipe, &result, sizeof result, &read, NULL );
466 return TRUE;
469 /******************************************************************************
470 * service_send_start_message
472 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
474 DWORD i, len, count, result;
475 service_start_info *ssi;
476 LPWSTR p;
477 BOOL r;
479 TRACE("%p %p %d\n", pipe, argv, argc);
481 /* calculate how much space do we need to send the startup info */
482 len = 1;
483 for (i=0; i<argc; i++)
484 len += strlenW(argv[i])+1;
486 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
487 ssi->cmd = WINESERV_STARTINFO;
488 ssi->size = len;
490 /* copy service args into a single buffer*/
491 p = &ssi->str[0];
492 for (i=0; i<argc; i++)
494 strcpyW(p, argv[i]);
495 p += strlenW(p) + 1;
497 *p=0;
499 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
500 if (r)
502 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
503 if (r && result)
505 SetLastError(result);
506 r = FALSE;
510 HeapFree(GetProcessHeap(),0,ssi);
512 return r;
515 /******************************************************************************
516 * service_handle_get_status
518 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
520 DWORD count = 0;
521 TRACE("\n");
522 return WriteFile(pipe, &service->status,
523 sizeof service->status, &count, NULL);
526 /******************************************************************************
527 * service_get_status
529 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
531 DWORD cmd[2], count = 0;
532 BOOL r;
534 cmd[0] = WINESERV_GETSTATUS;
535 cmd[1] = 0;
536 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
537 if (!r || count != sizeof cmd)
539 ERR("service protocol error - failed to write pipe!\n");
540 return r;
542 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
543 if (!r || count != sizeof *status)
544 ERR("service protocol error - failed to read pipe "
545 "r = %d count = %d!\n", r, count);
546 return r;
549 /******************************************************************************
550 * service_send_control
552 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
554 DWORD cmd[2], count = 0;
555 BOOL r;
557 cmd[0] = WINESERV_SENDCONTROL;
558 cmd[1] = dwControl;
559 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
560 if (!r || count != sizeof cmd)
562 ERR("service protocol error - failed to write pipe!\n");
563 return r;
565 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
566 if (!r || count != sizeof *result)
567 ERR("service protocol error - failed to read pipe "
568 "r = %d count = %d!\n", r, count);
569 return r;
572 /******************************************************************************
573 * service_accepts_control
575 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
577 DWORD a = service->status.dwControlsAccepted;
579 switch (dwControl)
581 case SERVICE_CONTROL_INTERROGATE:
582 return TRUE;
583 case SERVICE_CONTROL_STOP:
584 if (a&SERVICE_ACCEPT_STOP)
585 return TRUE;
586 break;
587 case SERVICE_CONTROL_SHUTDOWN:
588 if (a&SERVICE_ACCEPT_SHUTDOWN)
589 return TRUE;
590 break;
591 case SERVICE_CONTROL_PAUSE:
592 case SERVICE_CONTROL_CONTINUE:
593 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
594 return TRUE;
595 break;
596 case SERVICE_CONTROL_PARAMCHANGE:
597 if (a&SERVICE_ACCEPT_PARAMCHANGE)
598 return TRUE;
599 break;
600 case SERVICE_CONTROL_NETBINDADD:
601 case SERVICE_CONTROL_NETBINDREMOVE:
602 case SERVICE_CONTROL_NETBINDENABLE:
603 case SERVICE_CONTROL_NETBINDDISABLE:
604 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
605 return TRUE;
606 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
607 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
608 return TRUE;
609 break;
610 case SERVICE_CONTROL_POWEREVENT:
611 if (a&SERVICE_ACCEPT_POWEREVENT)
612 return TRUE;
613 break;
614 case SERVICE_CONTROL_SESSIONCHANGE:
615 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
616 return TRUE;
617 break;
619 return FALSE;
622 /******************************************************************************
623 * service_handle_control
625 static BOOL service_handle_control(HANDLE pipe, service_data *service,
626 DWORD dwControl)
628 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
630 TRACE("received control %d\n", dwControl);
632 if (service_accepts_control(service, dwControl))
634 if (service->handler)
635 ret = service->handler(dwControl, 0, NULL, service->context);
637 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
640 /******************************************************************************
641 * service_control_dispatcher
643 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
645 service_data *service = arg;
646 LPWSTR name;
647 HANDLE pipe, event;
649 TRACE("%p %s\n", service, debugstr_w(service->name));
651 /* create a pipe to talk to the rest of the world with */
652 name = service_get_pipe_name(service->name);
653 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
654 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
656 if (pipe==INVALID_HANDLE_VALUE)
657 ERR("failed to create pipe for %s, error = %d\n",
658 debugstr_w(service->name), GetLastError());
660 HeapFree(GetProcessHeap(), 0, name);
662 /* let the process who started us know we've tried to create a pipe */
663 event = service_get_event_handle(service->name);
664 SetEvent(event);
665 CloseHandle(event);
667 if (pipe==INVALID_HANDLE_VALUE) return 0;
669 /* dispatcher loop */
670 while (1)
672 BOOL r;
673 DWORD count, req[2] = {0,0};
675 r = ConnectNamedPipe(pipe, NULL);
676 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
678 ERR("pipe connect failed\n");
679 break;
682 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
683 if (!r || count!=sizeof req)
685 ERR("pipe read failed\n");
686 break;
689 /* handle the request */
690 switch (req[0])
692 case WINESERV_STARTINFO:
693 service_handle_start(pipe, service, req[1]);
694 break;
695 case WINESERV_GETSTATUS:
696 service_handle_get_status(pipe, service);
697 break;
698 case WINESERV_SENDCONTROL:
699 service_handle_control(pipe, service, req[1]);
700 break;
701 default:
702 ERR("received invalid command %d length %d\n", req[0], req[1]);
705 FlushFileBuffers(pipe);
706 DisconnectNamedPipe(pipe);
709 CloseHandle(pipe);
710 return 1;
713 /******************************************************************************
714 * service_run_threads
716 static BOOL service_run_threads(void)
718 DWORD i, n, ret;
719 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
720 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
722 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
724 wait_handles[0] = __wine_make_process_system();
725 wait_handles[1] = service_event;
727 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
728 nb_services, GetCurrentProcessId());
730 EnterCriticalSection( &service_cs );
731 for (i = 0; i < nb_services; i++)
733 services[i]->status.dwProcessId = GetCurrentProcessId();
734 CloseHandle( CreateThread( NULL, 0, service_control_dispatcher, services[i], 0, NULL ));
736 LeaveCriticalSection( &service_cs );
738 /* wait for all the threads to pack up and exit */
739 for (;;)
741 EnterCriticalSection( &service_cs );
742 for (i = 0, n = 2; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
744 if (!services[i]->thread) continue;
745 wait_services[n] = i;
746 wait_handles[n++] = services[i]->thread;
748 LeaveCriticalSection( &service_cs );
750 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
751 if (!ret) /* system process event */
753 TRACE( "last user process exited, shutting down\n" );
754 /* FIXME: we should maybe send a shutdown control to running services */
755 ExitProcess(0);
757 else if (ret == 1)
759 continue; /* rebuild the list */
761 else if (ret < n)
763 services[wait_services[ret]]->thread = 0;
764 CloseHandle( wait_handles[ret] );
765 if (n == 3) return TRUE; /* it was the last running thread */
767 else return FALSE;
771 /******************************************************************************
772 * StartServiceCtrlDispatcherA [ADVAPI32.@]
774 * See StartServiceCtrlDispatcherW.
776 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
778 service_data *info;
779 unsigned int i;
780 BOOL ret = TRUE;
782 TRACE("%p\n", servent);
784 if (nb_services)
786 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
787 return FALSE;
789 while (servent[nb_services].lpServiceName) nb_services++;
790 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
792 for (i = 0; i < nb_services; i++)
794 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
795 DWORD sz = FIELD_OFFSET( service_data, name[len] );
796 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
797 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
798 info->proc.a = servent[i].lpServiceProc;
799 info->unicode = FALSE;
800 services[i] = info;
803 service_run_threads();
805 return ret;
808 /******************************************************************************
809 * StartServiceCtrlDispatcherW [ADVAPI32.@]
811 * Connects a process containing one or more services to the service control
812 * manager.
814 * PARAMS
815 * servent [I] A list of the service names and service procedures
817 * RETURNS
818 * Success: TRUE.
819 * Failure: FALSE.
821 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
823 service_data *info;
824 unsigned int i;
825 BOOL ret = TRUE;
827 TRACE("%p\n", servent);
829 if (nb_services)
831 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
832 return FALSE;
834 while (servent[nb_services].lpServiceName) nb_services++;
835 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
837 for (i = 0; i < nb_services; i++)
839 DWORD len = strlenW(servent[i].lpServiceName) + 1;
840 DWORD sz = FIELD_OFFSET( service_data, name[len] );
841 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
842 strcpyW(info->name, servent[i].lpServiceName);
843 info->proc.w = servent[i].lpServiceProc;
844 info->unicode = TRUE;
845 services[i] = info;
848 service_run_threads();
850 return ret;
853 /******************************************************************************
854 * LockServiceDatabase [ADVAPI32.@]
856 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
858 HANDLE ret;
860 TRACE("%p\n",hSCManager);
862 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
863 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
865 CloseHandle( ret );
866 ret = NULL;
867 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
870 TRACE("returning %p\n", ret);
872 return ret;
875 /******************************************************************************
876 * UnlockServiceDatabase [ADVAPI32.@]
878 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
880 TRACE("%p\n",ScLock);
882 return CloseHandle( ScLock );
885 /******************************************************************************
886 * SetServiceStatus [ADVAPI32.@]
888 * PARAMS
889 * hService []
890 * lpStatus []
892 BOOL WINAPI
893 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
895 ULONG_PTR index = HandleToULong(hService) - 1;
896 BOOL r = FALSE;
898 TRACE("%p %x %x %x %x %x %x %x\n", hService,
899 lpStatus->dwServiceType, lpStatus->dwCurrentState,
900 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
901 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
902 lpStatus->dwWaitHint);
904 EnterCriticalSection( &service_cs );
905 if (index < nb_services)
907 memcpy( &services[index]->status, lpStatus, sizeof(SERVICE_STATUS) );
908 TRACE("Set service status to %d\n",services[index]->status.dwCurrentState);
909 r = TRUE;
911 LeaveCriticalSection( &service_cs );
913 return r;
917 /******************************************************************************
918 * OpenSCManagerA [ADVAPI32.@]
920 * Establish a connection to the service control manager and open its database.
922 * PARAMS
923 * lpMachineName [I] Pointer to machine name string
924 * lpDatabaseName [I] Pointer to database name string
925 * dwDesiredAccess [I] Type of access
927 * RETURNS
928 * Success: A Handle to the service control manager database
929 * Failure: NULL
931 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
932 DWORD dwDesiredAccess )
934 LPWSTR lpMachineNameW, lpDatabaseNameW;
935 SC_HANDLE ret;
937 lpMachineNameW = SERV_dup(lpMachineName);
938 lpDatabaseNameW = SERV_dup(lpDatabaseName);
939 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
940 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
941 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
942 return ret;
945 /******************************************************************************
946 * OpenSCManagerW [ADVAPI32.@]
948 * See OpenSCManagerA.
950 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
951 DWORD dwDesiredAccess )
953 struct sc_manager *manager;
954 HKEY hReg;
955 LONG r;
956 DWORD new_mask = dwDesiredAccess;
958 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
959 debugstr_w(lpDatabaseName), dwDesiredAccess);
961 if( lpDatabaseName && lpDatabaseName[0] )
963 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
965 /* noop, all right */
967 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
969 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
970 return NULL;
972 else
974 SetLastError( ERROR_INVALID_NAME );
975 return NULL;
979 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
980 sc_handle_destroy_manager );
981 if (!manager)
982 return NULL;
984 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
985 if (r!=ERROR_SUCCESS)
986 goto error;
988 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
989 RegCloseKey( hReg );
990 if (r!=ERROR_SUCCESS)
991 goto error;
993 RtlMapGenericMask(&new_mask, &scm_generic);
994 manager->dwAccess = new_mask;
995 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
997 return (SC_HANDLE) &manager->hdr;
999 error:
1000 sc_handle_free( &manager->hdr );
1001 SetLastError( r);
1002 return NULL;
1005 /******************************************************************************
1006 * ControlService [ADVAPI32.@]
1008 * Send a control code to a service.
1010 * PARAMS
1011 * hService [I] Handle of the service control manager database
1012 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1013 * lpServiceStatus [O] Destination for the status of the service, if available
1015 * RETURNS
1016 * Success: TRUE.
1017 * Failure: FALSE.
1019 * BUGS
1020 * Unlike M$' implementation, control requests are not serialized and may be
1021 * processed asynchronously.
1023 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1024 LPSERVICE_STATUS lpServiceStatus )
1026 struct sc_service *hsvc;
1027 BOOL ret = FALSE;
1028 HANDLE handle;
1030 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1032 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1033 if (!hsvc)
1035 SetLastError( ERROR_INVALID_HANDLE );
1036 return FALSE;
1039 ret = QueryServiceStatus(hService, lpServiceStatus);
1040 if (!ret)
1042 ERR("failed to query service status\n");
1043 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1044 return FALSE;
1047 switch (lpServiceStatus->dwCurrentState)
1049 case SERVICE_STOPPED:
1050 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1051 return FALSE;
1052 case SERVICE_START_PENDING:
1053 if (dwControl==SERVICE_CONTROL_STOP)
1054 break;
1055 /* fall thru */
1056 case SERVICE_STOP_PENDING:
1057 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1058 return FALSE;
1061 handle = service_open_pipe(hsvc->name);
1062 if (handle!=INVALID_HANDLE_VALUE)
1064 DWORD result = ERROR_SUCCESS;
1065 ret = service_send_control(handle, dwControl, &result);
1066 CloseHandle(handle);
1067 if (result!=ERROR_SUCCESS)
1069 SetLastError(result);
1070 ret = FALSE;
1074 return ret;
1077 /******************************************************************************
1078 * CloseServiceHandle [ADVAPI32.@]
1080 * Close a handle to a service or the service control manager database.
1082 * PARAMS
1083 * hSCObject [I] Handle to service or service control manager database
1085 * RETURNS
1086 * Success: TRUE
1087 * Failure: FALSE
1089 BOOL WINAPI
1090 CloseServiceHandle( SC_HANDLE hSCObject )
1092 TRACE("%p\n", hSCObject);
1094 sc_handle_free( (struct sc_handle*) hSCObject );
1096 return TRUE;
1100 /******************************************************************************
1101 * OpenServiceA [ADVAPI32.@]
1103 * Open a handle to a service.
1105 * PARAMS
1106 * hSCManager [I] Handle of the service control manager database
1107 * lpServiceName [I] Name of the service to open
1108 * dwDesiredAccess [I] Access required to the service
1110 * RETURNS
1111 * Success: Handle to the service
1112 * Failure: NULL
1114 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1115 DWORD dwDesiredAccess )
1117 LPWSTR lpServiceNameW;
1118 SC_HANDLE ret;
1120 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1122 lpServiceNameW = SERV_dup(lpServiceName);
1123 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1124 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1125 return ret;
1129 /******************************************************************************
1130 * OpenServiceW [ADVAPI32.@]
1132 * See OpenServiceA.
1134 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1135 DWORD dwDesiredAccess)
1137 struct sc_manager *hscm;
1138 struct sc_service *hsvc;
1139 HKEY hKey;
1140 long r;
1141 DWORD len;
1142 DWORD new_mask = dwDesiredAccess;
1144 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1146 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1147 if (!hscm)
1149 SetLastError( ERROR_INVALID_HANDLE );
1150 return FALSE;
1153 if (!lpServiceName)
1155 SetLastError(ERROR_INVALID_ADDRESS);
1156 return NULL;
1159 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1160 if (r!=ERROR_SUCCESS)
1162 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1163 return NULL;
1166 len = strlenW(lpServiceName)+1;
1167 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1168 sizeof (struct sc_service) + len*sizeof(WCHAR),
1169 sc_handle_destroy_service );
1170 if (!hsvc)
1172 RegCloseKey(hKey);
1173 return NULL;
1175 strcpyW( hsvc->name, lpServiceName );
1176 hsvc->hkey = hKey;
1178 RtlMapGenericMask(&new_mask, &svc_generic);
1179 hsvc->dwAccess = new_mask;
1181 /* add reference to SCM handle */
1182 hscm->hdr.ref_count++;
1183 hsvc->scm = hscm;
1185 TRACE("returning %p\n",hsvc);
1187 return (SC_HANDLE) &hsvc->hdr;
1190 /******************************************************************************
1191 * CreateServiceW [ADVAPI32.@]
1193 SC_HANDLE WINAPI
1194 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1195 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1196 DWORD dwServiceType, DWORD dwStartType,
1197 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1198 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1199 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1200 LPCWSTR lpPassword )
1202 struct sc_manager *hscm;
1203 struct sc_service *hsvc = NULL;
1204 HKEY hKey;
1205 LONG r;
1206 DWORD dp, len;
1207 struct reg_value val[10];
1208 int n = 0;
1209 DWORD new_mask = dwDesiredAccess;
1210 DWORD index = 0;
1211 WCHAR buffer[MAX_PATH];
1212 BOOL displayname_exists = FALSE;
1214 TRACE("%p %s %s\n", hSCManager,
1215 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1217 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1218 if (!hscm)
1220 SetLastError( ERROR_INVALID_HANDLE );
1221 return NULL;
1224 if (!lpServiceName || !lpBinaryPathName)
1226 SetLastError(ERROR_INVALID_ADDRESS);
1227 return NULL;
1230 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1232 SetLastError(ERROR_ACCESS_DENIED);
1233 return NULL;
1236 if (!lpServiceName[0])
1238 SetLastError(ERROR_INVALID_NAME);
1239 return NULL;
1242 if (!lpBinaryPathName[0])
1244 SetLastError(ERROR_INVALID_PARAMETER);
1245 return NULL;
1248 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1249 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1250 * runs under the LocalSystem account)
1252 switch (dwServiceType)
1254 case SERVICE_KERNEL_DRIVER:
1255 case SERVICE_FILE_SYSTEM_DRIVER:
1256 case SERVICE_WIN32_OWN_PROCESS:
1257 case SERVICE_WIN32_SHARE_PROCESS:
1258 /* No problem */
1259 break;
1260 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1261 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1262 /* FIXME : Do we need a more thorough check? */
1263 if (lpServiceStartName)
1265 SetLastError(ERROR_INVALID_PARAMETER);
1266 return NULL;
1268 break;
1269 default:
1270 SetLastError(ERROR_INVALID_PARAMETER);
1271 return NULL;
1274 if (!lpServiceStartName && (dwServiceType & SERVICE_WIN32))
1275 lpServiceStartName = szLocalSystem;
1277 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1278 if (dwStartType > SERVICE_DISABLED)
1280 SetLastError(ERROR_INVALID_PARAMETER);
1281 return NULL;
1284 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1285 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1286 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1288 SetLastError(ERROR_INVALID_PARAMETER);
1289 return NULL;
1292 /* Loop through the registry to check if the service already exists and to
1293 * check if we can use the given displayname.
1294 * FIXME: Should we use EnumServicesStatusEx?
1296 len = sizeof(buffer);
1297 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1299 HKEY service_key;
1301 /* The service already exists, so bail out */
1302 if(!lstrcmpiW(lpServiceName, buffer))
1304 SetLastError(ERROR_SERVICE_EXISTS);
1305 return NULL;
1308 /* The given displayname matches the found servicename. We don't bail out
1309 * as servicename is checked before a duplicate displayname
1311 if(!lstrcmpiW(lpDisplayName, buffer))
1312 displayname_exists = TRUE;
1314 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1316 WCHAR name[MAX_PATH];
1317 DWORD size = sizeof(name);
1319 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1321 /* The given displayname matches the found displayname */
1322 if (!lstrcmpiW(lpDisplayName, name))
1323 displayname_exists = TRUE;
1325 RegCloseKey(service_key);
1327 index++;
1328 len = sizeof(buffer);
1331 if (lpDisplayName && displayname_exists)
1333 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1334 return NULL;
1337 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1338 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1339 if (r!=ERROR_SUCCESS)
1341 /* FIXME: Should we set an error? */
1342 return NULL;
1345 if( lpDisplayName )
1346 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1348 service_set_dword( &val[n++], szType, &dwServiceType );
1349 service_set_dword( &val[n++], szStart, &dwStartType );
1350 service_set_dword( &val[n++], szError, &dwErrorControl );
1352 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1354 if( lpLoadOrderGroup )
1355 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1357 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1358 * There is no such key as what szDependencies refers to */
1359 if( lpDependencies )
1360 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1362 if( lpPassword )
1363 FIXME("Don't know how to add a Password for a service.\n");
1365 if( lpServiceStartName )
1366 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1368 r = service_write_values( hKey, val, n );
1369 if( r != ERROR_SUCCESS )
1370 goto error;
1372 len = strlenW(lpServiceName)+1;
1373 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1374 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1375 if( !hsvc )
1376 goto error;
1377 lstrcpyW( hsvc->name, lpServiceName );
1378 hsvc->hkey = hKey;
1380 RtlMapGenericMask(&new_mask, &svc_generic);
1381 hsvc->dwAccess = new_mask;
1383 hsvc->scm = hscm;
1384 hscm->hdr.ref_count++;
1386 return (SC_HANDLE) &hsvc->hdr;
1388 error:
1389 RegCloseKey( hKey );
1390 return NULL;
1394 /******************************************************************************
1395 * CreateServiceA [ADVAPI32.@]
1397 SC_HANDLE WINAPI
1398 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1399 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1400 DWORD dwServiceType, DWORD dwStartType,
1401 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1402 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1403 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1404 LPCSTR lpPassword )
1406 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1407 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1408 SC_HANDLE r;
1410 TRACE("%p %s %s\n", hSCManager,
1411 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1413 lpServiceNameW = SERV_dup( lpServiceName );
1414 lpDisplayNameW = SERV_dup( lpDisplayName );
1415 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1416 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1417 lpDependenciesW = SERV_dupmulti( lpDependencies );
1418 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1419 lpPasswordW = SERV_dup( lpPassword );
1421 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1422 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1423 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1424 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1426 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1427 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1428 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1429 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1430 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1431 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1432 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1434 return r;
1438 /******************************************************************************
1439 * DeleteService [ADVAPI32.@]
1441 * Delete a service from the service control manager database.
1443 * PARAMS
1444 * hService [I] Handle of the service to delete
1446 * RETURNS
1447 * Success: TRUE
1448 * Failure: FALSE
1450 BOOL WINAPI DeleteService( SC_HANDLE hService )
1452 struct sc_service *hsvc;
1454 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1455 if (!hsvc)
1457 SetLastError( ERROR_INVALID_HANDLE );
1458 return FALSE;
1461 if (!(hsvc->dwAccess & DELETE))
1463 SetLastError(ERROR_ACCESS_DENIED);
1464 return FALSE;
1467 /* Close the key to the service */
1468 RegCloseKey(hsvc->hkey);
1470 /* Delete the service under the Service Control Manager key */
1471 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1473 hsvc->hkey = NULL;
1475 return TRUE;
1479 /******************************************************************************
1480 * StartServiceA [ADVAPI32.@]
1482 * Start a service
1484 * PARAMS
1485 * hService [I] Handle of service
1486 * dwNumServiceArgs [I] Number of arguments
1487 * lpServiceArgVectors [I] Address of array of argument strings
1489 * NOTES
1490 * - NT implements this function using an obscure RPC call.
1491 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1492 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1493 * - This will only work for shared address space. How should the service
1494 * args be transferred when address spaces are separated?
1495 * - Can only start one service at a time.
1496 * - Has no concept of privilege.
1498 * RETURNS
1499 * Success: TRUE.
1500 * Failure: FALSE
1502 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1503 LPCSTR *lpServiceArgVectors )
1505 LPWSTR *lpwstr=NULL;
1506 unsigned int i;
1507 BOOL r;
1509 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1511 if (dwNumServiceArgs)
1512 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1513 dwNumServiceArgs*sizeof(LPWSTR) );
1515 for(i=0; i<dwNumServiceArgs; i++)
1516 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1518 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1520 if (dwNumServiceArgs)
1522 for(i=0; i<dwNumServiceArgs; i++)
1523 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1524 HeapFree(GetProcessHeap(), 0, lpwstr);
1527 return r;
1530 /******************************************************************************
1531 * service_start_process [INTERNAL]
1533 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1535 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1536 PROCESS_INFORMATION pi;
1537 STARTUPINFOW si;
1538 LPWSTR path = NULL, str;
1539 DWORD type, size, ret, svc_type;
1540 HANDLE handles[2];
1541 BOOL r;
1543 size = sizeof(svc_type);
1544 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1545 svc_type = 0;
1547 if (svc_type == SERVICE_KERNEL_DRIVER)
1549 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1550 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1552 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1553 GetSystemDirectoryW( path, len );
1554 lstrcatW( path, winedeviceW );
1555 lstrcatW( path, hsvc->name );
1557 else
1559 /* read the executable path from the registry */
1560 size = 0;
1561 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1562 if (ret!=ERROR_SUCCESS)
1563 return FALSE;
1564 str = HeapAlloc(GetProcessHeap(),0,size);
1565 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1566 if (ret==ERROR_SUCCESS)
1568 size = ExpandEnvironmentStringsW(str,NULL,0);
1569 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1570 ExpandEnvironmentStringsW(str,path,size);
1572 HeapFree(GetProcessHeap(),0,str);
1573 if (!path)
1574 return FALSE;
1577 /* wait for the process to start and set an event or terminate */
1578 handles[0] = service_get_event_handle( hsvc->name );
1579 ZeroMemory(&si, sizeof(STARTUPINFOW));
1580 si.cb = sizeof(STARTUPINFOW);
1581 if (!(svc_type & SERVICE_INTERACTIVE_PROCESS))
1583 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};
1584 si.lpDesktop = desktopW;
1587 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1588 if (r)
1590 if (ppid) *ppid = pi.dwProcessId;
1592 handles[1] = pi.hProcess;
1593 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1594 if(ret != WAIT_OBJECT_0)
1596 SetLastError(ERROR_IO_PENDING);
1597 r = FALSE;
1600 CloseHandle( pi.hThread );
1601 CloseHandle( pi.hProcess );
1603 CloseHandle( handles[0] );
1604 HeapFree(GetProcessHeap(),0,path);
1605 return r;
1608 static BOOL service_wait_for_startup(SC_HANDLE hService)
1610 DWORD i;
1611 SERVICE_STATUS status;
1612 BOOL r = FALSE;
1614 TRACE("%p\n", hService);
1616 for (i=0; i<20; i++)
1618 status.dwCurrentState = 0;
1619 r = QueryServiceStatus(hService, &status);
1620 if (!r)
1621 break;
1622 if (status.dwCurrentState == SERVICE_RUNNING)
1624 TRACE("Service started successfully\n");
1625 break;
1627 r = FALSE;
1628 Sleep(100 * i);
1630 return r;
1633 /******************************************************************************
1634 * StartServiceW [ADVAPI32.@]
1636 * See StartServiceA.
1638 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1639 LPCWSTR *lpServiceArgVectors)
1641 struct sc_service *hsvc;
1642 BOOL r = FALSE;
1643 SC_LOCK hLock;
1644 HANDLE handle = INVALID_HANDLE_VALUE;
1646 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1648 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1649 if (!hsvc)
1651 SetLastError(ERROR_INVALID_HANDLE);
1652 return r;
1655 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1656 if (!hLock)
1657 return r;
1659 handle = service_open_pipe(hsvc->name);
1660 if (handle==INVALID_HANDLE_VALUE)
1662 /* start the service process */
1663 if (service_start_process(hsvc, NULL))
1664 handle = service_open_pipe(hsvc->name);
1667 if (handle != INVALID_HANDLE_VALUE)
1669 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1670 CloseHandle(handle);
1673 UnlockServiceDatabase( hLock );
1675 TRACE("returning %d\n", r);
1677 if (r)
1678 service_wait_for_startup(hService);
1680 return r;
1683 /******************************************************************************
1684 * QueryServiceStatus [ADVAPI32.@]
1686 * PARAMS
1687 * hService [I] Handle to service to get information about
1688 * lpservicestatus [O] buffer to receive the status information for the service
1691 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1692 LPSERVICE_STATUS lpservicestatus)
1694 SERVICE_STATUS_PROCESS SvcStatusData;
1695 BOOL ret;
1697 TRACE("%p %p\n", hService, lpservicestatus);
1699 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1700 sizeof(SERVICE_STATUS_PROCESS), NULL);
1701 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1702 return ret;
1706 /******************************************************************************
1707 * QueryServiceStatusEx [ADVAPI32.@]
1709 * Get information about a service.
1711 * PARAMS
1712 * hService [I] Handle to service to get information about
1713 * InfoLevel [I] Level of information to get
1714 * lpBuffer [O] Destination for requested information
1715 * cbBufSize [I] Size of lpBuffer in bytes
1716 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1718 * RETURNS
1719 * Success: TRUE
1720 * FAILURE: FALSE
1722 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1723 LPBYTE lpBuffer, DWORD cbBufSize,
1724 LPDWORD pcbBytesNeeded)
1726 struct sc_service *hsvc;
1727 DWORD size, type, val;
1728 HANDLE pipe;
1729 LONG r;
1730 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1732 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1734 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1736 SetLastError( ERROR_INVALID_LEVEL);
1737 return FALSE;
1740 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1741 if (pSvcStatusData == NULL)
1743 SetLastError( ERROR_INVALID_PARAMETER);
1744 return FALSE;
1747 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1749 if( pcbBytesNeeded != NULL)
1750 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1752 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1753 return FALSE;
1756 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1757 if (!hsvc)
1759 SetLastError( ERROR_INVALID_HANDLE );
1760 return FALSE;
1763 pipe = service_open_pipe(hsvc->name);
1764 if (pipe != INVALID_HANDLE_VALUE)
1766 r = service_get_status(pipe, pSvcStatusData);
1767 CloseHandle(pipe);
1768 if (r)
1769 return TRUE;
1772 TRACE("Failed to read service status\n");
1774 /* read the service type from the registry */
1775 size = sizeof(val);
1776 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1777 if (r != ERROR_SUCCESS || type != REG_DWORD)
1778 val = 0;
1780 pSvcStatusData->dwServiceType = val;
1781 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1782 pSvcStatusData->dwControlsAccepted = 0;
1783 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1784 pSvcStatusData->dwServiceSpecificExitCode = 0;
1785 pSvcStatusData->dwCheckPoint = 0;
1786 pSvcStatusData->dwWaitHint = 0;
1788 return TRUE;
1791 /******************************************************************************
1792 * QueryServiceConfigA [ADVAPI32.@]
1794 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1795 DWORD size, LPDWORD needed )
1797 DWORD n;
1798 LPSTR p, buffer;
1799 BOOL ret;
1800 QUERY_SERVICE_CONFIGW *configW;
1802 TRACE("%p %p %d %p\n", hService, config, size, needed);
1804 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1806 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1807 return FALSE;
1809 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1810 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1811 if (!ret) goto done;
1813 config->dwServiceType = configW->dwServiceType;
1814 config->dwStartType = configW->dwStartType;
1815 config->dwErrorControl = configW->dwErrorControl;
1816 config->lpBinaryPathName = NULL;
1817 config->lpLoadOrderGroup = NULL;
1818 config->dwTagId = configW->dwTagId;
1819 config->lpDependencies = NULL;
1820 config->lpServiceStartName = NULL;
1821 config->lpDisplayName = NULL;
1823 p = (LPSTR)(config + 1);
1824 n = size - sizeof(*config);
1825 ret = FALSE;
1827 #define MAP_STR(str) \
1828 do { \
1829 if (configW->str) \
1831 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1832 if (!sz) goto done; \
1833 config->str = p; \
1834 p += sz; \
1835 n -= sz; \
1837 } while (0)
1839 MAP_STR( lpBinaryPathName );
1840 MAP_STR( lpLoadOrderGroup );
1841 MAP_STR( lpDependencies );
1842 MAP_STR( lpServiceStartName );
1843 MAP_STR( lpDisplayName );
1844 #undef MAP_STR
1846 *needed = p - (LPSTR)config;
1847 ret = TRUE;
1849 done:
1850 HeapFree( GetProcessHeap(), 0, buffer );
1851 return ret;
1854 /******************************************************************************
1855 * QueryServiceConfigW [ADVAPI32.@]
1857 BOOL WINAPI
1858 QueryServiceConfigW( SC_HANDLE hService,
1859 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1860 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1862 WCHAR str_buffer[ MAX_PATH ];
1863 LONG r;
1864 DWORD type, val, sz, total, n;
1865 LPBYTE p;
1866 HKEY hKey;
1867 struct sc_service *hsvc;
1869 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1870 cbBufSize, pcbBytesNeeded);
1872 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1873 if (!hsvc)
1875 SetLastError( ERROR_INVALID_HANDLE );
1876 return FALSE;
1878 hKey = hsvc->hkey;
1880 /* TODO: Check which members are mandatory and what the registry types
1881 * should be. This should of course also be tested when a service is
1882 * created.
1885 /* calculate the size required first */
1886 total = sizeof (QUERY_SERVICE_CONFIGW);
1888 sz = sizeof(str_buffer);
1889 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1890 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1892 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1893 if( 0 == sz ) return FALSE;
1895 total += sizeof(WCHAR) * sz;
1897 else
1899 /* FIXME: set last error */
1900 return FALSE;
1903 sz = 0;
1904 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1905 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1906 total += sz;
1907 else
1908 total += sizeof(WCHAR);
1910 sz = 0;
1911 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1912 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1913 total += sz;
1914 else
1915 total += sizeof(WCHAR);
1917 sz = 0;
1918 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1919 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1920 total += sz;
1921 else
1922 total += sizeof(WCHAR);
1924 sz = 0;
1925 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1926 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1927 total += sz;
1928 else
1929 total += sizeof(WCHAR);
1931 *pcbBytesNeeded = total;
1933 /* if there's not enough memory, return an error */
1934 if( total > cbBufSize )
1936 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1937 return FALSE;
1940 ZeroMemory( lpServiceConfig, total );
1942 sz = sizeof val;
1943 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1944 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1945 lpServiceConfig->dwServiceType = val;
1947 sz = sizeof val;
1948 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1949 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1950 lpServiceConfig->dwStartType = val;
1952 sz = sizeof val;
1953 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1954 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1955 lpServiceConfig->dwErrorControl = val;
1957 sz = sizeof val;
1958 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
1959 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1960 lpServiceConfig->dwTagId = val;
1962 /* now do the strings */
1963 p = (LPBYTE) &lpServiceConfig[1];
1964 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1966 sz = sizeof(str_buffer);
1967 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1968 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1970 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1971 sz *= sizeof(WCHAR);
1972 if( 0 == sz || sz > n ) return FALSE;
1974 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1975 p += sz;
1976 n -= sz;
1978 else
1980 /* FIXME: set last error */
1981 return FALSE;
1984 sz = n;
1985 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1986 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1987 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1989 p += sz;
1990 n -= sz;
1992 else
1994 *(WCHAR *) p = 0;
1995 p += sizeof(WCHAR);
1996 n -= sizeof(WCHAR);
1999 sz = n;
2000 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2001 lpServiceConfig->lpDependencies = (LPWSTR) p;
2002 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2004 p += sz;
2005 n -= sz;
2007 else
2009 *(WCHAR *) p = 0;
2010 p += sizeof(WCHAR);
2011 n -= sizeof(WCHAR);
2014 sz = n;
2015 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2016 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2017 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2019 p += sz;
2020 n -= sz;
2022 else
2024 *(WCHAR *) p = 0;
2025 p += sizeof(WCHAR);
2026 n -= sizeof(WCHAR);
2029 sz = n;
2030 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2031 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2032 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2034 p += sz;
2035 n -= sz;
2037 else
2039 *(WCHAR *) p = 0;
2040 p += sizeof(WCHAR);
2041 n -= sizeof(WCHAR);
2044 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2045 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2046 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2047 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2048 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2050 return TRUE;
2053 /******************************************************************************
2054 * EnumServicesStatusA [ADVAPI32.@]
2056 BOOL WINAPI
2057 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2058 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2059 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2060 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2062 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2063 dwServiceType, dwServiceState, lpServices, cbBufSize,
2064 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2065 SetLastError (ERROR_ACCESS_DENIED);
2066 return FALSE;
2069 /******************************************************************************
2070 * EnumServicesStatusW [ADVAPI32.@]
2072 BOOL WINAPI
2073 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2074 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2075 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2076 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2078 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2079 dwServiceType, dwServiceState, lpServices, cbBufSize,
2080 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2081 SetLastError (ERROR_ACCESS_DENIED);
2082 return FALSE;
2085 /******************************************************************************
2086 * EnumServicesStatusExA [ADVAPI32.@]
2088 BOOL WINAPI
2089 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2090 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2091 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2093 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2094 dwServiceType, dwServiceState, lpServices, cbBufSize,
2095 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2096 *lpServicesReturned = 0;
2097 SetLastError (ERROR_ACCESS_DENIED);
2098 return FALSE;
2101 /******************************************************************************
2102 * EnumServicesStatusExW [ADVAPI32.@]
2104 BOOL WINAPI
2105 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2106 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2107 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2109 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2110 dwServiceType, dwServiceState, lpServices, cbBufSize,
2111 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2112 SetLastError (ERROR_ACCESS_DENIED);
2113 return FALSE;
2116 /******************************************************************************
2117 * GetServiceKeyNameA [ADVAPI32.@]
2119 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2120 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2122 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2123 return FALSE;
2126 /******************************************************************************
2127 * GetServiceKeyNameW [ADVAPI32.@]
2129 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2130 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2132 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2133 return FALSE;
2136 /******************************************************************************
2137 * QueryServiceLockStatusA [ADVAPI32.@]
2139 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2140 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2141 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2143 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2145 return FALSE;
2148 /******************************************************************************
2149 * QueryServiceLockStatusW [ADVAPI32.@]
2151 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2152 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2153 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2155 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2157 return FALSE;
2160 /******************************************************************************
2161 * GetServiceDisplayNameA [ADVAPI32.@]
2163 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2164 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2166 LPWSTR lpServiceNameW, lpDisplayNameW;
2167 DWORD sizeW;
2168 BOOL ret = FALSE;
2170 TRACE("%p %s %p %p\n", hSCManager,
2171 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2173 lpServiceNameW = SERV_dup(lpServiceName);
2174 if (lpDisplayName)
2175 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2176 else
2177 lpDisplayNameW = NULL;
2179 sizeW = *lpcchBuffer;
2180 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2182 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2183 goto cleanup;
2186 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2187 *lpcchBuffer, NULL, NULL ))
2189 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2190 goto cleanup;
2193 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2194 * (but if the function succeeded it means that is a good upper estimation of the size) */
2195 ret = TRUE;
2197 cleanup:
2198 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2199 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2200 return ret;
2203 /******************************************************************************
2204 * GetServiceDisplayNameW [ADVAPI32.@]
2206 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2207 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2209 struct sc_manager *hscm;
2210 DWORD type, size;
2211 LONG ret;
2213 TRACE("%p %s %p %p\n", hSCManager,
2214 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2216 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2217 if (!hscm)
2219 SetLastError(ERROR_INVALID_HANDLE);
2220 return FALSE;
2223 if (!lpServiceName)
2225 SetLastError(ERROR_INVALID_ADDRESS);
2226 return FALSE;
2229 size = *lpcchBuffer * sizeof(WCHAR);
2230 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2231 if (!ret && !lpDisplayName && size)
2232 ret = ERROR_MORE_DATA;
2234 if (ret)
2236 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2238 if (ret == ERROR_MORE_DATA)
2240 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2241 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2243 else if (ret == ERROR_FILE_NOT_FOUND)
2245 HKEY hkey;
2247 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2249 UINT len = lstrlenW(lpServiceName);
2250 BOOL r = FALSE;
2252 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2253 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2254 else if (lpDisplayName && *lpcchBuffer)
2256 /* No displayname, but the service exists and the buffer
2257 * is big enough. We should return the servicename.
2259 lstrcpyW(lpDisplayName, lpServiceName);
2260 r = TRUE;
2263 *lpcchBuffer = len;
2264 RegCloseKey(hkey);
2265 return r;
2267 else
2268 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2270 else
2271 SetLastError(ret);
2272 return FALSE;
2275 /* Always return the correct needed size on success */
2276 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2278 return TRUE;
2281 /******************************************************************************
2282 * ChangeServiceConfigW [ADVAPI32.@]
2284 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2285 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2286 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2287 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2289 struct reg_value val[10];
2290 struct sc_service *hsvc;
2291 DWORD r = ERROR_SUCCESS;
2292 HKEY hKey;
2293 int n = 0;
2295 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2296 hService, dwServiceType, dwStartType, dwErrorControl,
2297 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2298 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2299 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2301 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2302 if (!hsvc)
2304 SetLastError( ERROR_INVALID_HANDLE );
2305 return FALSE;
2307 hKey = hsvc->hkey;
2309 if( dwServiceType != SERVICE_NO_CHANGE )
2310 service_set_dword( &val[n++], szType, &dwServiceType );
2312 if( dwStartType != SERVICE_NO_CHANGE )
2313 service_set_dword( &val[n++], szStart, &dwStartType );
2315 if( dwErrorControl != SERVICE_NO_CHANGE )
2316 service_set_dword( &val[n++], szError, &dwErrorControl );
2318 if( lpBinaryPathName )
2319 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2321 if( lpLoadOrderGroup )
2322 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2324 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2325 * There is no such key as what szDependencies refers to */
2326 if( lpDependencies )
2327 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2329 if( lpPassword )
2330 FIXME("ignoring password\n");
2332 if( lpServiceStartName )
2333 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2335 r = service_write_values( hsvc->hkey, val, n );
2337 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2340 /******************************************************************************
2341 * ChangeServiceConfigA [ADVAPI32.@]
2343 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2344 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2345 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2346 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2348 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2349 LPWSTR wServiceStartName, wPassword, wDisplayName;
2350 BOOL r;
2352 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2353 hService, dwServiceType, dwStartType, dwErrorControl,
2354 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2355 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2356 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2358 wBinaryPathName = SERV_dup( lpBinaryPathName );
2359 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2360 wDependencies = SERV_dupmulti( lpDependencies );
2361 wServiceStartName = SERV_dup( lpServiceStartName );
2362 wPassword = SERV_dup( lpPassword );
2363 wDisplayName = SERV_dup( lpDisplayName );
2365 r = ChangeServiceConfigW( hService, dwServiceType,
2366 dwStartType, dwErrorControl, wBinaryPathName,
2367 wLoadOrderGroup, lpdwTagId, wDependencies,
2368 wServiceStartName, wPassword, wDisplayName);
2370 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2371 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2372 HeapFree( GetProcessHeap(), 0, wDependencies );
2373 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2374 HeapFree( GetProcessHeap(), 0, wPassword );
2375 HeapFree( GetProcessHeap(), 0, wDisplayName );
2377 return r;
2380 /******************************************************************************
2381 * ChangeServiceConfig2A [ADVAPI32.@]
2383 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2384 LPVOID lpInfo)
2386 BOOL r = FALSE;
2388 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2390 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2392 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2393 SERVICE_DESCRIPTIONW sdw;
2395 sdw.lpDescription = SERV_dup( sd->lpDescription );
2397 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2399 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2401 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2403 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2404 SERVICE_FAILURE_ACTIONSW faw;
2406 faw.dwResetPeriod = fa->dwResetPeriod;
2407 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2408 faw.lpCommand = SERV_dup( fa->lpCommand );
2409 faw.cActions = fa->cActions;
2410 faw.lpsaActions = fa->lpsaActions;
2412 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2414 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2415 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2417 else
2418 SetLastError( ERROR_INVALID_PARAMETER );
2420 return r;
2423 /******************************************************************************
2424 * ChangeServiceConfig2W [ADVAPI32.@]
2426 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2427 LPVOID lpInfo)
2429 HKEY hKey;
2430 struct sc_service *hsvc;
2432 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2433 if (!hsvc)
2435 SetLastError( ERROR_INVALID_HANDLE );
2436 return FALSE;
2438 hKey = hsvc->hkey;
2440 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2442 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2443 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2444 if (sd->lpDescription)
2446 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2447 if (sd->lpDescription[0] == 0)
2448 RegDeleteValueW(hKey,szDescription);
2449 else
2450 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2451 (LPVOID)sd->lpDescription,
2452 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2455 else
2456 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2457 return TRUE;
2460 /******************************************************************************
2461 * QueryServiceObjectSecurity [ADVAPI32.@]
2463 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2464 SECURITY_INFORMATION dwSecurityInformation,
2465 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2466 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2468 SECURITY_DESCRIPTOR descriptor;
2469 DWORD size;
2470 BOOL succ;
2471 ACL acl;
2473 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2474 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2476 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2477 FIXME("information %d not supported\n", dwSecurityInformation);
2479 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2481 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2482 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2484 size = cbBufSize;
2485 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2486 *pcbBytesNeeded = size;
2487 return succ;
2490 /******************************************************************************
2491 * SetServiceObjectSecurity [ADVAPI32.@]
2493 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2494 SECURITY_INFORMATION dwSecurityInformation,
2495 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2497 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2498 return TRUE;
2501 /******************************************************************************
2502 * SetServiceBits [ADVAPI32.@]
2504 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2505 DWORD dwServiceBits,
2506 BOOL bSetBitsOn,
2507 BOOL bUpdateImmediately)
2509 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2510 bSetBitsOn, bUpdateImmediately);
2511 return TRUE;
2514 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2515 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2517 LPHANDLER_FUNCTION func = context;
2519 func( control );
2520 return ERROR_SUCCESS;
2523 /******************************************************************************
2524 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2526 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2528 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2531 /******************************************************************************
2532 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2534 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2536 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2539 /******************************************************************************
2540 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2542 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2544 LPWSTR nameW;
2545 SERVICE_STATUS_HANDLE ret;
2547 nameW = SERV_dup(name);
2548 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2549 HeapFree( GetProcessHeap(), 0, nameW );
2550 return ret;
2553 /******************************************************************************
2554 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2556 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2557 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2559 SERVICE_STATUS_HANDLE handle = 0;
2560 unsigned int i;
2562 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2564 EnterCriticalSection( &service_cs );
2565 for (i = 0; i < nb_services; i++)
2567 if(!strcmpW(lpServiceName, services[i]->name))
2569 services[i]->handler = lpHandlerProc;
2570 services[i]->context = lpContext;
2571 handle = ULongToHandle( i + 1 );
2572 break;
2575 LeaveCriticalSection( &service_cs );
2577 return handle;
2580 /******************************************************************************
2581 * EnumDependentServicesA [ADVAPI32.@]
2583 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2584 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2585 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2587 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2588 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2590 *lpServicesReturned = 0;
2591 return TRUE;
2594 /******************************************************************************
2595 * EnumDependentServicesW [ADVAPI32.@]
2597 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2598 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2599 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2601 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2602 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2604 *lpServicesReturned = 0;
2605 return TRUE;