wined3d: Add reporting of D3DRTYPE_VOLUME capabilties.
[wine/wine-kai.git] / dlls / advapi32 / service.c
blobae565ab20957d9c2fa78e8d1bbddde55a42e71ce
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(service);
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->status.dwCurrentState = SERVICE_START_PENDING;
459 service->thread = CreateThread( NULL, 0, service_thread,
460 service, 0, NULL );
461 SetEvent( service_event ); /* notify the main loop */
463 end:
464 HeapFree(GetProcessHeap(), 0, args);
465 WriteFile( pipe, &result, sizeof result, &read, NULL );
467 return TRUE;
470 /******************************************************************************
471 * service_send_start_message
473 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
475 DWORD i, len, count, result;
476 service_start_info *ssi;
477 LPWSTR p;
478 BOOL r;
480 TRACE("%p %p %d\n", pipe, argv, argc);
482 /* calculate how much space do we need to send the startup info */
483 len = 1;
484 for (i=0; i<argc; i++)
485 len += strlenW(argv[i])+1;
487 ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, str[len]));
488 ssi->cmd = WINESERV_STARTINFO;
489 ssi->size = len;
491 /* copy service args into a single buffer*/
492 p = &ssi->str[0];
493 for (i=0; i<argc; i++)
495 strcpyW(p, argv[i]);
496 p += strlenW(p) + 1;
498 *p=0;
500 r = WriteFile(pipe, ssi, FIELD_OFFSET(service_start_info, str[len]), &count, NULL);
501 if (r)
503 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
504 if (r && result)
506 SetLastError(result);
507 r = FALSE;
511 HeapFree(GetProcessHeap(),0,ssi);
513 return r;
516 /******************************************************************************
517 * service_handle_get_status
519 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
521 DWORD count = 0;
522 TRACE("\n");
523 return WriteFile(pipe, &service->status,
524 sizeof service->status, &count, NULL);
527 /******************************************************************************
528 * service_get_status
530 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
532 DWORD cmd[2], count = 0;
533 BOOL r;
535 cmd[0] = WINESERV_GETSTATUS;
536 cmd[1] = 0;
537 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
538 if (!r || count != sizeof cmd)
540 ERR("service protocol error - failed to write pipe!\n");
541 return r;
543 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
544 if (!r || count != sizeof *status)
545 ERR("service protocol error - failed to read pipe "
546 "r = %d count = %d!\n", r, count);
547 return r;
550 /******************************************************************************
551 * service_send_control
553 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
555 DWORD cmd[2], count = 0;
556 BOOL r;
558 cmd[0] = WINESERV_SENDCONTROL;
559 cmd[1] = dwControl;
560 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
561 if (!r || count != sizeof cmd)
563 ERR("service protocol error - failed to write pipe!\n");
564 return r;
566 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
567 if (!r || count != sizeof *result)
568 ERR("service protocol error - failed to read pipe "
569 "r = %d count = %d!\n", r, count);
570 return r;
573 /******************************************************************************
574 * service_accepts_control
576 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
578 DWORD a = service->status.dwControlsAccepted;
580 switch (dwControl)
582 case SERVICE_CONTROL_INTERROGATE:
583 return TRUE;
584 case SERVICE_CONTROL_STOP:
585 if (a&SERVICE_ACCEPT_STOP)
586 return TRUE;
587 break;
588 case SERVICE_CONTROL_SHUTDOWN:
589 if (a&SERVICE_ACCEPT_SHUTDOWN)
590 return TRUE;
591 break;
592 case SERVICE_CONTROL_PAUSE:
593 case SERVICE_CONTROL_CONTINUE:
594 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
595 return TRUE;
596 break;
597 case SERVICE_CONTROL_PARAMCHANGE:
598 if (a&SERVICE_ACCEPT_PARAMCHANGE)
599 return TRUE;
600 break;
601 case SERVICE_CONTROL_NETBINDADD:
602 case SERVICE_CONTROL_NETBINDREMOVE:
603 case SERVICE_CONTROL_NETBINDENABLE:
604 case SERVICE_CONTROL_NETBINDDISABLE:
605 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
606 return TRUE;
607 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
608 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
609 return TRUE;
610 break;
611 case SERVICE_CONTROL_POWEREVENT:
612 if (a&SERVICE_ACCEPT_POWEREVENT)
613 return TRUE;
614 break;
615 case SERVICE_CONTROL_SESSIONCHANGE:
616 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
617 return TRUE;
618 break;
620 return FALSE;
623 /******************************************************************************
624 * service_handle_control
626 static BOOL service_handle_control(HANDLE pipe, service_data *service,
627 DWORD dwControl)
629 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
631 TRACE("received control %d\n", dwControl);
633 if (service_accepts_control(service, dwControl))
635 if (service->handler)
636 ret = service->handler(dwControl, 0, NULL, service->context);
638 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
641 /******************************************************************************
642 * service_control_dispatcher
644 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
646 service_data *service = arg;
647 LPWSTR name;
648 HANDLE pipe, event;
650 TRACE("%p %s\n", service, debugstr_w(service->name));
652 /* create a pipe to talk to the rest of the world with */
653 name = service_get_pipe_name(service->name);
654 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
655 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
657 if (pipe==INVALID_HANDLE_VALUE)
658 ERR("failed to create pipe for %s, error = %d\n",
659 debugstr_w(service->name), GetLastError());
661 HeapFree(GetProcessHeap(), 0, name);
663 /* let the process who started us know we've tried to create a pipe */
664 event = service_get_event_handle(service->name);
665 SetEvent(event);
666 CloseHandle(event);
668 if (pipe==INVALID_HANDLE_VALUE) return 0;
670 /* dispatcher loop */
671 while (1)
673 BOOL r;
674 DWORD count, req[2] = {0,0};
676 r = ConnectNamedPipe(pipe, NULL);
677 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
679 ERR("pipe connect failed\n");
680 break;
683 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
684 if (!r || count!=sizeof req)
686 ERR("pipe read failed\n");
687 break;
690 /* handle the request */
691 switch (req[0])
693 case WINESERV_STARTINFO:
694 service_handle_start(pipe, service, req[1]);
695 break;
696 case WINESERV_GETSTATUS:
697 service_handle_get_status(pipe, service);
698 break;
699 case WINESERV_SENDCONTROL:
700 service_handle_control(pipe, service, req[1]);
701 break;
702 default:
703 ERR("received invalid command %d length %d\n", req[0], req[1]);
706 FlushFileBuffers(pipe);
707 DisconnectNamedPipe(pipe);
710 CloseHandle(pipe);
711 return 1;
714 /******************************************************************************
715 * service_run_threads
717 static BOOL service_run_threads(void)
719 DWORD i, n, ret;
720 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
721 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
723 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
725 wait_handles[0] = __wine_make_process_system();
726 wait_handles[1] = service_event;
728 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
729 nb_services, GetCurrentProcessId());
731 EnterCriticalSection( &service_cs );
732 for (i = 0; i < nb_services; i++)
734 services[i]->status.dwProcessId = GetCurrentProcessId();
735 CloseHandle( CreateThread( NULL, 0, service_control_dispatcher, services[i], 0, NULL ));
737 LeaveCriticalSection( &service_cs );
739 /* wait for all the threads to pack up and exit */
740 for (;;)
742 EnterCriticalSection( &service_cs );
743 for (i = 0, n = 2; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
745 if (!services[i]->thread) continue;
746 wait_services[n] = i;
747 wait_handles[n++] = services[i]->thread;
749 LeaveCriticalSection( &service_cs );
751 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
752 if (!ret) /* system process event */
754 TRACE( "last user process exited, shutting down\n" );
755 /* FIXME: we should maybe send a shutdown control to running services */
756 ExitProcess(0);
758 else if (ret == 1)
760 continue; /* rebuild the list */
762 else if (ret < n)
764 services[wait_services[ret]]->thread = 0;
765 CloseHandle( wait_handles[ret] );
766 if (n == 3) return TRUE; /* it was the last running thread */
768 else return FALSE;
772 /******************************************************************************
773 * StartServiceCtrlDispatcherA [ADVAPI32.@]
775 * See StartServiceCtrlDispatcherW.
777 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
779 service_data *info;
780 unsigned int i;
781 BOOL ret = TRUE;
783 TRACE("%p\n", servent);
785 if (nb_services)
787 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
788 return FALSE;
790 while (servent[nb_services].lpServiceName) nb_services++;
791 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
793 for (i = 0; i < nb_services; i++)
795 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
796 DWORD sz = FIELD_OFFSET( service_data, name[len] );
797 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
798 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
799 info->proc.a = servent[i].lpServiceProc;
800 info->unicode = FALSE;
801 services[i] = info;
804 service_run_threads();
806 return ret;
809 /******************************************************************************
810 * StartServiceCtrlDispatcherW [ADVAPI32.@]
812 * Connects a process containing one or more services to the service control
813 * manager.
815 * PARAMS
816 * servent [I] A list of the service names and service procedures
818 * RETURNS
819 * Success: TRUE.
820 * Failure: FALSE.
822 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
824 service_data *info;
825 unsigned int i;
826 BOOL ret = TRUE;
828 TRACE("%p\n", servent);
830 if (nb_services)
832 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
833 return FALSE;
835 while (servent[nb_services].lpServiceName) nb_services++;
836 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
838 for (i = 0; i < nb_services; i++)
840 DWORD len = strlenW(servent[i].lpServiceName) + 1;
841 DWORD sz = FIELD_OFFSET( service_data, name[len] );
842 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
843 strcpyW(info->name, servent[i].lpServiceName);
844 info->proc.w = servent[i].lpServiceProc;
845 info->unicode = TRUE;
846 services[i] = info;
849 service_run_threads();
851 return ret;
854 /******************************************************************************
855 * LockServiceDatabase [ADVAPI32.@]
857 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
859 HANDLE ret;
861 TRACE("%p\n",hSCManager);
863 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
864 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
866 CloseHandle( ret );
867 ret = NULL;
868 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
871 TRACE("returning %p\n", ret);
873 return ret;
876 /******************************************************************************
877 * UnlockServiceDatabase [ADVAPI32.@]
879 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
881 TRACE("%p\n",ScLock);
883 return CloseHandle( ScLock );
886 /******************************************************************************
887 * SetServiceStatus [ADVAPI32.@]
889 * PARAMS
890 * hService []
891 * lpStatus []
893 BOOL WINAPI
894 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
896 ULONG_PTR index = HandleToULong(hService) - 1;
897 BOOL r = FALSE;
899 TRACE("%p %x %x %x %x %x %x %x\n", hService,
900 lpStatus->dwServiceType, lpStatus->dwCurrentState,
901 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
902 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
903 lpStatus->dwWaitHint);
905 EnterCriticalSection( &service_cs );
906 if (index < nb_services)
908 memcpy( &services[index]->status, lpStatus, sizeof(SERVICE_STATUS) );
909 TRACE("Set service status to %d\n",services[index]->status.dwCurrentState);
910 r = TRUE;
912 LeaveCriticalSection( &service_cs );
914 return r;
918 /******************************************************************************
919 * OpenSCManagerA [ADVAPI32.@]
921 * Establish a connection to the service control manager and open its database.
923 * PARAMS
924 * lpMachineName [I] Pointer to machine name string
925 * lpDatabaseName [I] Pointer to database name string
926 * dwDesiredAccess [I] Type of access
928 * RETURNS
929 * Success: A Handle to the service control manager database
930 * Failure: NULL
932 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
933 DWORD dwDesiredAccess )
935 LPWSTR lpMachineNameW, lpDatabaseNameW;
936 SC_HANDLE ret;
938 lpMachineNameW = SERV_dup(lpMachineName);
939 lpDatabaseNameW = SERV_dup(lpDatabaseName);
940 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
941 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
942 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
943 return ret;
946 /******************************************************************************
947 * OpenSCManagerW [ADVAPI32.@]
949 * See OpenSCManagerA.
951 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
952 DWORD dwDesiredAccess )
954 struct sc_manager *manager;
955 HKEY hReg;
956 LONG r;
957 DWORD new_mask = dwDesiredAccess;
959 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
960 debugstr_w(lpDatabaseName), dwDesiredAccess);
962 if( lpDatabaseName && lpDatabaseName[0] )
964 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
966 /* noop, all right */
968 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
970 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
971 return NULL;
973 else
975 SetLastError( ERROR_INVALID_NAME );
976 return NULL;
980 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
981 sc_handle_destroy_manager );
982 if (!manager)
983 return NULL;
985 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
986 if (r!=ERROR_SUCCESS)
987 goto error;
989 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
990 RegCloseKey( hReg );
991 if (r!=ERROR_SUCCESS)
992 goto error;
994 RtlMapGenericMask(&new_mask, &scm_generic);
995 manager->dwAccess = new_mask;
996 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
998 return (SC_HANDLE) &manager->hdr;
1000 error:
1001 sc_handle_free( &manager->hdr );
1002 SetLastError( r);
1003 return NULL;
1006 /******************************************************************************
1007 * ControlService [ADVAPI32.@]
1009 * Send a control code to a service.
1011 * PARAMS
1012 * hService [I] Handle of the service control manager database
1013 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1014 * lpServiceStatus [O] Destination for the status of the service, if available
1016 * RETURNS
1017 * Success: TRUE.
1018 * Failure: FALSE.
1020 * BUGS
1021 * Unlike M$' implementation, control requests are not serialized and may be
1022 * processed asynchronously.
1024 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1025 LPSERVICE_STATUS lpServiceStatus )
1027 struct sc_service *hsvc;
1028 BOOL ret = FALSE;
1029 HANDLE handle;
1031 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1033 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1034 if (!hsvc)
1036 SetLastError( ERROR_INVALID_HANDLE );
1037 return FALSE;
1040 if (lpServiceStatus)
1042 ret = QueryServiceStatus(hService, lpServiceStatus);
1043 if (!ret)
1045 ERR("failed to query service status\n");
1046 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1047 return FALSE;
1050 switch (lpServiceStatus->dwCurrentState)
1052 case SERVICE_STOPPED:
1053 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1054 return FALSE;
1055 case SERVICE_START_PENDING:
1056 if (dwControl==SERVICE_CONTROL_STOP)
1057 break;
1058 /* fall thru */
1059 case SERVICE_STOP_PENDING:
1060 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1061 return FALSE;
1065 handle = service_open_pipe(hsvc->name);
1066 if (handle!=INVALID_HANDLE_VALUE)
1068 DWORD result = ERROR_SUCCESS;
1069 ret = service_send_control(handle, dwControl, &result);
1070 CloseHandle(handle);
1071 if (result!=ERROR_SUCCESS)
1073 SetLastError(result);
1074 ret = FALSE;
1078 return ret;
1081 /******************************************************************************
1082 * CloseServiceHandle [ADVAPI32.@]
1084 * Close a handle to a service or the service control manager database.
1086 * PARAMS
1087 * hSCObject [I] Handle to service or service control manager database
1089 * RETURNS
1090 * Success: TRUE
1091 * Failure: FALSE
1093 BOOL WINAPI
1094 CloseServiceHandle( SC_HANDLE hSCObject )
1096 TRACE("%p\n", hSCObject);
1098 sc_handle_free( (struct sc_handle*) hSCObject );
1100 return TRUE;
1104 /******************************************************************************
1105 * OpenServiceA [ADVAPI32.@]
1107 * Open a handle to a service.
1109 * PARAMS
1110 * hSCManager [I] Handle of the service control manager database
1111 * lpServiceName [I] Name of the service to open
1112 * dwDesiredAccess [I] Access required to the service
1114 * RETURNS
1115 * Success: Handle to the service
1116 * Failure: NULL
1118 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1119 DWORD dwDesiredAccess )
1121 LPWSTR lpServiceNameW;
1122 SC_HANDLE ret;
1124 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1126 lpServiceNameW = SERV_dup(lpServiceName);
1127 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1128 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1129 return ret;
1133 /******************************************************************************
1134 * OpenServiceW [ADVAPI32.@]
1136 * See OpenServiceA.
1138 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1139 DWORD dwDesiredAccess)
1141 struct sc_manager *hscm;
1142 struct sc_service *hsvc;
1143 HKEY hKey;
1144 long r;
1145 DWORD len;
1146 DWORD new_mask = dwDesiredAccess;
1148 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1150 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1151 if (!hscm)
1153 SetLastError( ERROR_INVALID_HANDLE );
1154 return FALSE;
1157 if (!lpServiceName)
1159 SetLastError(ERROR_INVALID_ADDRESS);
1160 return NULL;
1163 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1164 if (r!=ERROR_SUCCESS)
1166 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1167 return NULL;
1170 len = strlenW(lpServiceName)+1;
1171 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1172 sizeof (struct sc_service) + len*sizeof(WCHAR),
1173 sc_handle_destroy_service );
1174 if (!hsvc)
1176 RegCloseKey(hKey);
1177 return NULL;
1179 strcpyW( hsvc->name, lpServiceName );
1180 hsvc->hkey = hKey;
1182 RtlMapGenericMask(&new_mask, &svc_generic);
1183 hsvc->dwAccess = new_mask;
1185 /* add reference to SCM handle */
1186 hscm->hdr.ref_count++;
1187 hsvc->scm = hscm;
1189 TRACE("returning %p\n",hsvc);
1191 return (SC_HANDLE) &hsvc->hdr;
1194 /******************************************************************************
1195 * CreateServiceW [ADVAPI32.@]
1197 SC_HANDLE WINAPI
1198 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1199 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1200 DWORD dwServiceType, DWORD dwStartType,
1201 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1202 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1203 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1204 LPCWSTR lpPassword )
1206 struct sc_manager *hscm;
1207 struct sc_service *hsvc = NULL;
1208 HKEY hKey;
1209 LONG r;
1210 DWORD dp, len;
1211 struct reg_value val[10];
1212 int n = 0;
1213 DWORD new_mask = dwDesiredAccess;
1214 DWORD index = 0;
1215 WCHAR buffer[MAX_PATH];
1216 BOOL displayname_exists = FALSE;
1218 TRACE("%p %s %s\n", hSCManager,
1219 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1221 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1222 if (!hscm)
1224 SetLastError( ERROR_INVALID_HANDLE );
1225 return NULL;
1228 if (!lpServiceName || !lpBinaryPathName)
1230 SetLastError(ERROR_INVALID_ADDRESS);
1231 return NULL;
1234 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1236 SetLastError(ERROR_ACCESS_DENIED);
1237 return NULL;
1240 if (!lpServiceName[0])
1242 SetLastError(ERROR_INVALID_NAME);
1243 return NULL;
1246 if (!lpBinaryPathName[0])
1248 SetLastError(ERROR_INVALID_PARAMETER);
1249 return NULL;
1252 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1253 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1254 * runs under the LocalSystem account)
1256 switch (dwServiceType)
1258 case SERVICE_KERNEL_DRIVER:
1259 case SERVICE_FILE_SYSTEM_DRIVER:
1260 case SERVICE_WIN32_OWN_PROCESS:
1261 case SERVICE_WIN32_SHARE_PROCESS:
1262 /* No problem */
1263 break;
1264 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1265 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1266 /* FIXME : Do we need a more thorough check? */
1267 if (lpServiceStartName)
1269 SetLastError(ERROR_INVALID_PARAMETER);
1270 return NULL;
1272 break;
1273 default:
1274 SetLastError(ERROR_INVALID_PARAMETER);
1275 return NULL;
1278 if (!lpServiceStartName && (dwServiceType & SERVICE_WIN32))
1279 lpServiceStartName = szLocalSystem;
1281 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1282 if (dwStartType > SERVICE_DISABLED)
1284 SetLastError(ERROR_INVALID_PARAMETER);
1285 return NULL;
1288 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1289 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1290 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1292 SetLastError(ERROR_INVALID_PARAMETER);
1293 return NULL;
1296 /* Loop through the registry to check if the service already exists and to
1297 * check if we can use the given displayname.
1298 * FIXME: Should we use EnumServicesStatusEx?
1300 len = sizeof(buffer);
1301 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1303 HKEY service_key;
1305 /* Open service first before deciding whether it already exists or not
1306 * It could be that it's not a valid service, but only the registry key itself exists
1308 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1310 WCHAR name[MAX_PATH];
1311 DWORD size = sizeof(name);
1313 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1315 if (lpDisplayName && (!lstrcmpiW(lpDisplayName, name)
1316 || !lstrcmpiW(lpDisplayName, buffer)))
1317 displayname_exists = TRUE;
1319 if (!lstrcmpiW(lpServiceName, buffer))
1321 RegCloseKey(service_key);
1322 SetLastError(ERROR_SERVICE_EXISTS);
1323 return NULL;
1326 RegCloseKey(service_key);
1328 index++;
1329 len = sizeof(buffer);
1332 if (displayname_exists)
1334 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1335 return NULL;
1338 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1339 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1340 if (r!=ERROR_SUCCESS)
1342 /* FIXME: Should we set an error? */
1343 return NULL;
1346 if( lpDisplayName )
1347 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1349 service_set_dword( &val[n++], szType, &dwServiceType );
1350 service_set_dword( &val[n++], szStart, &dwStartType );
1351 service_set_dword( &val[n++], szError, &dwErrorControl );
1353 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1355 if( lpLoadOrderGroup )
1356 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1358 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1359 * There is no such key as what szDependencies refers to */
1360 if( lpDependencies )
1361 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1363 if( lpPassword )
1364 FIXME("Don't know how to add a Password for a service.\n");
1366 if( lpServiceStartName )
1367 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1369 r = service_write_values( hKey, val, n );
1370 if( r != ERROR_SUCCESS )
1371 goto error;
1373 len = strlenW(lpServiceName)+1;
1374 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1375 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1376 if( !hsvc )
1377 goto error;
1378 lstrcpyW( hsvc->name, lpServiceName );
1379 hsvc->hkey = hKey;
1381 RtlMapGenericMask(&new_mask, &svc_generic);
1382 hsvc->dwAccess = new_mask;
1384 hsvc->scm = hscm;
1385 hscm->hdr.ref_count++;
1387 return (SC_HANDLE) &hsvc->hdr;
1389 error:
1390 RegCloseKey( hKey );
1391 return NULL;
1395 /******************************************************************************
1396 * CreateServiceA [ADVAPI32.@]
1398 SC_HANDLE WINAPI
1399 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1400 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1401 DWORD dwServiceType, DWORD dwStartType,
1402 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1403 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1404 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1405 LPCSTR lpPassword )
1407 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1408 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1409 SC_HANDLE r;
1411 TRACE("%p %s %s\n", hSCManager,
1412 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1414 lpServiceNameW = SERV_dup( lpServiceName );
1415 lpDisplayNameW = SERV_dup( lpDisplayName );
1416 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1417 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1418 lpDependenciesW = SERV_dupmulti( lpDependencies );
1419 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1420 lpPasswordW = SERV_dup( lpPassword );
1422 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1423 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1424 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1425 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1427 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1428 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1429 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1430 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1431 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1432 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1433 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1435 return r;
1439 /******************************************************************************
1440 * DeleteService [ADVAPI32.@]
1442 * Delete a service from the service control manager database.
1444 * PARAMS
1445 * hService [I] Handle of the service to delete
1447 * RETURNS
1448 * Success: TRUE
1449 * Failure: FALSE
1451 BOOL WINAPI DeleteService( SC_HANDLE hService )
1453 struct sc_service *hsvc;
1455 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1456 if (!hsvc)
1458 SetLastError( ERROR_INVALID_HANDLE );
1459 return FALSE;
1462 if (!(hsvc->dwAccess & DELETE))
1464 SetLastError(ERROR_ACCESS_DENIED);
1465 return FALSE;
1468 /* Close the key to the service */
1469 RegCloseKey(hsvc->hkey);
1471 /* Delete the service under the Service Control Manager key */
1472 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1474 hsvc->hkey = NULL;
1476 return TRUE;
1480 /******************************************************************************
1481 * StartServiceA [ADVAPI32.@]
1483 * Start a service
1485 * PARAMS
1486 * hService [I] Handle of service
1487 * dwNumServiceArgs [I] Number of arguments
1488 * lpServiceArgVectors [I] Address of array of argument strings
1490 * NOTES
1491 * - NT implements this function using an obscure RPC call.
1492 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1493 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1494 * - This will only work for shared address space. How should the service
1495 * args be transferred when address spaces are separated?
1496 * - Can only start one service at a time.
1497 * - Has no concept of privilege.
1499 * RETURNS
1500 * Success: TRUE.
1501 * Failure: FALSE
1503 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1504 LPCSTR *lpServiceArgVectors )
1506 LPWSTR *lpwstr=NULL;
1507 unsigned int i;
1508 BOOL r;
1510 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1512 if (dwNumServiceArgs)
1513 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1514 dwNumServiceArgs*sizeof(LPWSTR) );
1516 for(i=0; i<dwNumServiceArgs; i++)
1517 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1519 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1521 if (dwNumServiceArgs)
1523 for(i=0; i<dwNumServiceArgs; i++)
1524 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1525 HeapFree(GetProcessHeap(), 0, lpwstr);
1528 return r;
1531 /******************************************************************************
1532 * service_start_process [INTERNAL]
1534 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1536 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1537 PROCESS_INFORMATION pi;
1538 STARTUPINFOW si;
1539 LPWSTR path = NULL, str;
1540 DWORD type, size, ret, svc_type;
1541 HANDLE handles[2];
1542 BOOL r;
1544 size = sizeof(svc_type);
1545 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1546 svc_type = 0;
1548 if (svc_type == SERVICE_KERNEL_DRIVER)
1550 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1551 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1553 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1554 GetSystemDirectoryW( path, len );
1555 lstrcatW( path, winedeviceW );
1556 lstrcatW( path, hsvc->name );
1558 else
1560 /* read the executable path from the registry */
1561 size = 0;
1562 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1563 if (ret!=ERROR_SUCCESS)
1564 return FALSE;
1565 str = HeapAlloc(GetProcessHeap(),0,size);
1566 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1567 if (ret==ERROR_SUCCESS)
1569 size = ExpandEnvironmentStringsW(str,NULL,0);
1570 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1571 ExpandEnvironmentStringsW(str,path,size);
1573 HeapFree(GetProcessHeap(),0,str);
1574 if (!path)
1575 return FALSE;
1578 /* wait for the process to start and set an event or terminate */
1579 handles[0] = service_get_event_handle( hsvc->name );
1580 ZeroMemory(&si, sizeof(STARTUPINFOW));
1581 si.cb = sizeof(STARTUPINFOW);
1582 if (!(svc_type & SERVICE_INTERACTIVE_PROCESS))
1584 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};
1585 si.lpDesktop = desktopW;
1588 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1589 if (r)
1591 if (ppid) *ppid = pi.dwProcessId;
1593 handles[1] = pi.hProcess;
1594 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1595 if(ret != WAIT_OBJECT_0)
1597 SetLastError(ERROR_IO_PENDING);
1598 r = FALSE;
1601 CloseHandle( pi.hThread );
1602 CloseHandle( pi.hProcess );
1604 CloseHandle( handles[0] );
1605 HeapFree(GetProcessHeap(),0,path);
1606 return r;
1609 static BOOL service_wait_for_startup(SC_HANDLE hService)
1611 DWORD i;
1612 SERVICE_STATUS status;
1613 BOOL r = FALSE;
1615 TRACE("%p\n", hService);
1617 for (i=0; i<20; i++)
1619 status.dwCurrentState = 0;
1620 r = QueryServiceStatus(hService, &status);
1621 if (!r)
1622 break;
1623 if (status.dwCurrentState == SERVICE_RUNNING)
1625 TRACE("Service started successfully\n");
1626 break;
1628 r = FALSE;
1629 if (status.dwCurrentState != SERVICE_START_PENDING) break;
1630 Sleep(100 * i);
1632 return r;
1635 /******************************************************************************
1636 * StartServiceW [ADVAPI32.@]
1638 * See StartServiceA.
1640 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1641 LPCWSTR *lpServiceArgVectors)
1643 struct sc_service *hsvc;
1644 BOOL r = FALSE;
1645 SC_LOCK hLock;
1646 HANDLE handle = INVALID_HANDLE_VALUE;
1648 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1650 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1651 if (!hsvc)
1653 SetLastError(ERROR_INVALID_HANDLE);
1654 return r;
1657 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1658 if (!hLock)
1659 return r;
1661 handle = service_open_pipe(hsvc->name);
1662 if (handle==INVALID_HANDLE_VALUE)
1664 /* start the service process */
1665 if (service_start_process(hsvc, NULL))
1666 handle = service_open_pipe(hsvc->name);
1669 if (handle != INVALID_HANDLE_VALUE)
1671 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1672 CloseHandle(handle);
1675 UnlockServiceDatabase( hLock );
1677 TRACE("returning %d\n", r);
1679 if (r)
1680 service_wait_for_startup(hService);
1682 return r;
1685 /******************************************************************************
1686 * QueryServiceStatus [ADVAPI32.@]
1688 * PARAMS
1689 * hService [I] Handle to service to get information about
1690 * lpservicestatus [O] buffer to receive the status information for the service
1693 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1694 LPSERVICE_STATUS lpservicestatus)
1696 SERVICE_STATUS_PROCESS SvcStatusData;
1697 BOOL ret;
1699 TRACE("%p %p\n", hService, lpservicestatus);
1701 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1702 sizeof(SERVICE_STATUS_PROCESS), NULL);
1703 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1704 return ret;
1708 /******************************************************************************
1709 * QueryServiceStatusEx [ADVAPI32.@]
1711 * Get information about a service.
1713 * PARAMS
1714 * hService [I] Handle to service to get information about
1715 * InfoLevel [I] Level of information to get
1716 * lpBuffer [O] Destination for requested information
1717 * cbBufSize [I] Size of lpBuffer in bytes
1718 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1720 * RETURNS
1721 * Success: TRUE
1722 * FAILURE: FALSE
1724 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1725 LPBYTE lpBuffer, DWORD cbBufSize,
1726 LPDWORD pcbBytesNeeded)
1728 struct sc_service *hsvc;
1729 DWORD size, type, val;
1730 HANDLE pipe;
1731 LONG r;
1732 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1734 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1736 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1738 SetLastError( ERROR_INVALID_LEVEL);
1739 return FALSE;
1742 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1743 if (pSvcStatusData == NULL)
1745 SetLastError( ERROR_INVALID_PARAMETER);
1746 return FALSE;
1749 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1751 if( pcbBytesNeeded != NULL)
1752 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1754 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1755 return FALSE;
1758 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1759 if (!hsvc)
1761 SetLastError( ERROR_INVALID_HANDLE );
1762 return FALSE;
1765 pipe = service_open_pipe(hsvc->name);
1766 if (pipe != INVALID_HANDLE_VALUE)
1768 r = service_get_status(pipe, pSvcStatusData);
1769 CloseHandle(pipe);
1770 if (r)
1771 return TRUE;
1774 TRACE("Failed to read service status\n");
1776 /* read the service type from the registry */
1777 size = sizeof(val);
1778 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1779 if (r != ERROR_SUCCESS || type != REG_DWORD)
1780 val = 0;
1782 pSvcStatusData->dwServiceType = val;
1783 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1784 pSvcStatusData->dwControlsAccepted = 0;
1785 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1786 pSvcStatusData->dwServiceSpecificExitCode = 0;
1787 pSvcStatusData->dwCheckPoint = 0;
1788 pSvcStatusData->dwWaitHint = 0;
1790 return TRUE;
1793 /******************************************************************************
1794 * QueryServiceConfigA [ADVAPI32.@]
1796 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1797 DWORD size, LPDWORD needed )
1799 DWORD n;
1800 LPSTR p, buffer;
1801 BOOL ret;
1802 QUERY_SERVICE_CONFIGW *configW;
1804 TRACE("%p %p %d %p\n", hService, config, size, needed);
1806 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1808 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1809 return FALSE;
1811 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1812 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1813 if (!ret) goto done;
1815 config->dwServiceType = configW->dwServiceType;
1816 config->dwStartType = configW->dwStartType;
1817 config->dwErrorControl = configW->dwErrorControl;
1818 config->lpBinaryPathName = NULL;
1819 config->lpLoadOrderGroup = NULL;
1820 config->dwTagId = configW->dwTagId;
1821 config->lpDependencies = NULL;
1822 config->lpServiceStartName = NULL;
1823 config->lpDisplayName = NULL;
1825 p = (LPSTR)(config + 1);
1826 n = size - sizeof(*config);
1827 ret = FALSE;
1829 #define MAP_STR(str) \
1830 do { \
1831 if (configW->str) \
1833 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1834 if (!sz) goto done; \
1835 config->str = p; \
1836 p += sz; \
1837 n -= sz; \
1839 } while (0)
1841 MAP_STR( lpBinaryPathName );
1842 MAP_STR( lpLoadOrderGroup );
1843 MAP_STR( lpDependencies );
1844 MAP_STR( lpServiceStartName );
1845 MAP_STR( lpDisplayName );
1846 #undef MAP_STR
1848 *needed = p - (LPSTR)config;
1849 ret = TRUE;
1851 done:
1852 HeapFree( GetProcessHeap(), 0, buffer );
1853 return ret;
1856 /******************************************************************************
1857 * QueryServiceConfigW [ADVAPI32.@]
1859 BOOL WINAPI
1860 QueryServiceConfigW( SC_HANDLE hService,
1861 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1862 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1864 WCHAR str_buffer[ MAX_PATH ];
1865 LONG r;
1866 DWORD type, val, sz, total, n;
1867 LPBYTE p;
1868 HKEY hKey;
1869 struct sc_service *hsvc;
1871 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1872 cbBufSize, pcbBytesNeeded);
1874 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1875 if (!hsvc)
1877 SetLastError( ERROR_INVALID_HANDLE );
1878 return FALSE;
1880 hKey = hsvc->hkey;
1882 /* TODO: Check which members are mandatory and what the registry types
1883 * should be. This should of course also be tested when a service is
1884 * created.
1887 /* calculate the size required first */
1888 total = sizeof (QUERY_SERVICE_CONFIGW);
1890 sz = sizeof(str_buffer);
1891 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1892 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1894 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1895 if( 0 == sz ) return FALSE;
1897 total += sizeof(WCHAR) * sz;
1899 else
1901 /* FIXME: set last error */
1902 return FALSE;
1905 sz = 0;
1906 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1907 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1908 total += sz;
1909 else
1910 total += sizeof(WCHAR);
1912 sz = 0;
1913 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1914 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1915 total += sz;
1916 else
1917 total += sizeof(WCHAR);
1919 sz = 0;
1920 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1921 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1922 total += sz;
1923 else
1924 total += sizeof(WCHAR);
1926 sz = 0;
1927 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1928 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1929 total += sz;
1930 else
1931 total += sizeof(WCHAR);
1933 *pcbBytesNeeded = total;
1935 /* if there's not enough memory, return an error */
1936 if( total > cbBufSize )
1938 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1939 return FALSE;
1942 ZeroMemory( lpServiceConfig, total );
1944 sz = sizeof val;
1945 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1946 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1947 lpServiceConfig->dwServiceType = val;
1949 sz = sizeof val;
1950 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1951 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1952 lpServiceConfig->dwStartType = val;
1954 sz = sizeof val;
1955 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1956 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1957 lpServiceConfig->dwErrorControl = val;
1959 sz = sizeof val;
1960 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
1961 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1962 lpServiceConfig->dwTagId = val;
1964 /* now do the strings */
1965 p = (LPBYTE) &lpServiceConfig[1];
1966 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1968 sz = sizeof(str_buffer);
1969 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1970 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1972 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1973 sz *= sizeof(WCHAR);
1974 if( 0 == sz || sz > n ) return FALSE;
1976 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1977 p += sz;
1978 n -= sz;
1980 else
1982 /* FIXME: set last error */
1983 return FALSE;
1986 sz = n;
1987 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1988 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1989 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1991 p += sz;
1992 n -= sz;
1994 else
1996 *(WCHAR *) p = 0;
1997 p += sizeof(WCHAR);
1998 n -= sizeof(WCHAR);
2001 sz = n;
2002 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2003 lpServiceConfig->lpDependencies = (LPWSTR) p;
2004 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2006 p += sz;
2007 n -= sz;
2009 else
2011 *(WCHAR *) p = 0;
2012 p += sizeof(WCHAR);
2013 n -= sizeof(WCHAR);
2016 sz = n;
2017 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2018 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2019 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2021 p += sz;
2022 n -= sz;
2024 else
2026 *(WCHAR *) p = 0;
2027 p += sizeof(WCHAR);
2028 n -= sizeof(WCHAR);
2031 sz = n;
2032 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2033 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2034 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2036 p += sz;
2037 n -= sz;
2039 else
2041 *(WCHAR *) p = 0;
2042 p += sizeof(WCHAR);
2043 n -= sizeof(WCHAR);
2046 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2047 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2048 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2049 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2050 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2052 return TRUE;
2055 /******************************************************************************
2056 * EnumServicesStatusA [ADVAPI32.@]
2058 BOOL WINAPI
2059 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2060 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2061 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2062 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2064 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2065 dwServiceType, dwServiceState, lpServices, cbBufSize,
2066 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2067 SetLastError (ERROR_ACCESS_DENIED);
2068 return FALSE;
2071 /******************************************************************************
2072 * EnumServicesStatusW [ADVAPI32.@]
2074 BOOL WINAPI
2075 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2076 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2077 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2078 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2080 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2081 dwServiceType, dwServiceState, lpServices, cbBufSize,
2082 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2083 SetLastError (ERROR_ACCESS_DENIED);
2084 return FALSE;
2087 /******************************************************************************
2088 * EnumServicesStatusExA [ADVAPI32.@]
2090 BOOL WINAPI
2091 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2092 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2093 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2095 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2096 dwServiceType, dwServiceState, lpServices, cbBufSize,
2097 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2098 *lpServicesReturned = 0;
2099 SetLastError (ERROR_ACCESS_DENIED);
2100 return FALSE;
2103 /******************************************************************************
2104 * EnumServicesStatusExW [ADVAPI32.@]
2106 BOOL WINAPI
2107 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2108 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2109 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2111 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2112 dwServiceType, dwServiceState, lpServices, cbBufSize,
2113 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2114 SetLastError (ERROR_ACCESS_DENIED);
2115 return FALSE;
2118 /******************************************************************************
2119 * GetServiceKeyNameA [ADVAPI32.@]
2121 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2122 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2124 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2125 return FALSE;
2128 /******************************************************************************
2129 * GetServiceKeyNameW [ADVAPI32.@]
2131 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2132 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2134 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2135 return FALSE;
2138 /******************************************************************************
2139 * QueryServiceLockStatusA [ADVAPI32.@]
2141 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2142 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2143 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2145 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2147 return FALSE;
2150 /******************************************************************************
2151 * QueryServiceLockStatusW [ADVAPI32.@]
2153 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2154 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2155 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2157 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2159 return FALSE;
2162 /******************************************************************************
2163 * GetServiceDisplayNameA [ADVAPI32.@]
2165 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2166 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2168 LPWSTR lpServiceNameW, lpDisplayNameW;
2169 DWORD sizeW;
2170 BOOL ret = FALSE;
2172 TRACE("%p %s %p %p\n", hSCManager,
2173 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2175 lpServiceNameW = SERV_dup(lpServiceName);
2176 if (lpDisplayName)
2177 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2178 else
2179 lpDisplayNameW = NULL;
2181 sizeW = *lpcchBuffer;
2182 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2184 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2185 goto cleanup;
2188 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2189 *lpcchBuffer, NULL, NULL ))
2191 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2192 goto cleanup;
2195 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2196 * (but if the function succeeded it means that is a good upper estimation of the size) */
2197 ret = TRUE;
2199 cleanup:
2200 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2201 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2202 return ret;
2205 /******************************************************************************
2206 * GetServiceDisplayNameW [ADVAPI32.@]
2208 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2209 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2211 struct sc_manager *hscm;
2212 DWORD type, size;
2213 LONG ret;
2215 TRACE("%p %s %p %p\n", hSCManager,
2216 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2218 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2219 if (!hscm)
2221 SetLastError(ERROR_INVALID_HANDLE);
2222 return FALSE;
2225 if (!lpServiceName)
2227 SetLastError(ERROR_INVALID_ADDRESS);
2228 return FALSE;
2231 size = *lpcchBuffer * sizeof(WCHAR);
2232 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2233 if (!ret && !lpDisplayName && size)
2234 ret = ERROR_MORE_DATA;
2236 if (ret)
2238 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2240 if (ret == ERROR_MORE_DATA)
2242 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2243 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2245 else if (ret == ERROR_FILE_NOT_FOUND)
2247 HKEY hkey;
2249 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2251 UINT len = lstrlenW(lpServiceName);
2252 BOOL r = FALSE;
2254 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2255 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2256 else if (lpDisplayName && *lpcchBuffer)
2258 /* No displayname, but the service exists and the buffer
2259 * is big enough. We should return the servicename.
2261 lstrcpyW(lpDisplayName, lpServiceName);
2262 r = TRUE;
2265 *lpcchBuffer = len;
2266 RegCloseKey(hkey);
2267 return r;
2269 else
2270 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2272 else
2273 SetLastError(ret);
2274 return FALSE;
2277 /* Always return the correct needed size on success */
2278 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2280 return TRUE;
2283 /******************************************************************************
2284 * ChangeServiceConfigW [ADVAPI32.@]
2286 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2287 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2288 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2289 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2291 struct reg_value val[10];
2292 struct sc_service *hsvc;
2293 DWORD r = ERROR_SUCCESS;
2294 HKEY hKey;
2295 int n = 0;
2297 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2298 hService, dwServiceType, dwStartType, dwErrorControl,
2299 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2300 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2301 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2303 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2304 if (!hsvc)
2306 SetLastError( ERROR_INVALID_HANDLE );
2307 return FALSE;
2309 hKey = hsvc->hkey;
2311 if( dwServiceType != SERVICE_NO_CHANGE )
2312 service_set_dword( &val[n++], szType, &dwServiceType );
2314 if( dwStartType != SERVICE_NO_CHANGE )
2315 service_set_dword( &val[n++], szStart, &dwStartType );
2317 if( dwErrorControl != SERVICE_NO_CHANGE )
2318 service_set_dword( &val[n++], szError, &dwErrorControl );
2320 if( lpBinaryPathName )
2321 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2323 if( lpLoadOrderGroup )
2324 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2326 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2327 * There is no such key as what szDependencies refers to */
2328 if( lpDependencies )
2329 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2331 if( lpPassword )
2332 FIXME("ignoring password\n");
2334 if( lpServiceStartName )
2335 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2337 r = service_write_values( hsvc->hkey, val, n );
2339 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2342 /******************************************************************************
2343 * ChangeServiceConfigA [ADVAPI32.@]
2345 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2346 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2347 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2348 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2350 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2351 LPWSTR wServiceStartName, wPassword, wDisplayName;
2352 BOOL r;
2354 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2355 hService, dwServiceType, dwStartType, dwErrorControl,
2356 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2357 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2358 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2360 wBinaryPathName = SERV_dup( lpBinaryPathName );
2361 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2362 wDependencies = SERV_dupmulti( lpDependencies );
2363 wServiceStartName = SERV_dup( lpServiceStartName );
2364 wPassword = SERV_dup( lpPassword );
2365 wDisplayName = SERV_dup( lpDisplayName );
2367 r = ChangeServiceConfigW( hService, dwServiceType,
2368 dwStartType, dwErrorControl, wBinaryPathName,
2369 wLoadOrderGroup, lpdwTagId, wDependencies,
2370 wServiceStartName, wPassword, wDisplayName);
2372 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2373 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2374 HeapFree( GetProcessHeap(), 0, wDependencies );
2375 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2376 HeapFree( GetProcessHeap(), 0, wPassword );
2377 HeapFree( GetProcessHeap(), 0, wDisplayName );
2379 return r;
2382 /******************************************************************************
2383 * ChangeServiceConfig2A [ADVAPI32.@]
2385 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2386 LPVOID lpInfo)
2388 BOOL r = FALSE;
2390 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2392 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2394 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2395 SERVICE_DESCRIPTIONW sdw;
2397 sdw.lpDescription = SERV_dup( sd->lpDescription );
2399 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2401 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2403 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2405 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2406 SERVICE_FAILURE_ACTIONSW faw;
2408 faw.dwResetPeriod = fa->dwResetPeriod;
2409 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2410 faw.lpCommand = SERV_dup( fa->lpCommand );
2411 faw.cActions = fa->cActions;
2412 faw.lpsaActions = fa->lpsaActions;
2414 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2416 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2417 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2419 else
2420 SetLastError( ERROR_INVALID_PARAMETER );
2422 return r;
2425 /******************************************************************************
2426 * ChangeServiceConfig2W [ADVAPI32.@]
2428 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2429 LPVOID lpInfo)
2431 HKEY hKey;
2432 struct sc_service *hsvc;
2434 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2435 if (!hsvc)
2437 SetLastError( ERROR_INVALID_HANDLE );
2438 return FALSE;
2440 hKey = hsvc->hkey;
2442 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2444 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2445 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2446 if (sd->lpDescription)
2448 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2449 if (sd->lpDescription[0] == 0)
2450 RegDeleteValueW(hKey,szDescription);
2451 else
2452 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2453 (LPVOID)sd->lpDescription,
2454 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2457 else
2458 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2459 return TRUE;
2462 /******************************************************************************
2463 * QueryServiceObjectSecurity [ADVAPI32.@]
2465 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2466 SECURITY_INFORMATION dwSecurityInformation,
2467 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2468 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2470 SECURITY_DESCRIPTOR descriptor;
2471 DWORD size;
2472 BOOL succ;
2473 ACL acl;
2475 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2476 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2478 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2479 FIXME("information %d not supported\n", dwSecurityInformation);
2481 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2483 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2484 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2486 size = cbBufSize;
2487 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2488 *pcbBytesNeeded = size;
2489 return succ;
2492 /******************************************************************************
2493 * SetServiceObjectSecurity [ADVAPI32.@]
2495 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2496 SECURITY_INFORMATION dwSecurityInformation,
2497 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2499 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2500 return TRUE;
2503 /******************************************************************************
2504 * SetServiceBits [ADVAPI32.@]
2506 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2507 DWORD dwServiceBits,
2508 BOOL bSetBitsOn,
2509 BOOL bUpdateImmediately)
2511 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2512 bSetBitsOn, bUpdateImmediately);
2513 return TRUE;
2516 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2517 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2519 LPHANDLER_FUNCTION func = context;
2521 func( control );
2522 return ERROR_SUCCESS;
2525 /******************************************************************************
2526 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2528 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2530 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2533 /******************************************************************************
2534 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2536 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2538 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2541 /******************************************************************************
2542 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2544 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2546 LPWSTR nameW;
2547 SERVICE_STATUS_HANDLE ret;
2549 nameW = SERV_dup(name);
2550 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2551 HeapFree( GetProcessHeap(), 0, nameW );
2552 return ret;
2555 /******************************************************************************
2556 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2558 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2559 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2561 SERVICE_STATUS_HANDLE handle = 0;
2562 unsigned int i;
2564 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2566 EnterCriticalSection( &service_cs );
2567 for (i = 0; i < nb_services; i++)
2569 if(!strcmpW(lpServiceName, services[i]->name))
2571 services[i]->handler = lpHandlerProc;
2572 services[i]->context = lpContext;
2573 handle = ULongToHandle( i + 1 );
2574 break;
2577 LeaveCriticalSection( &service_cs );
2579 return handle;
2582 /******************************************************************************
2583 * EnumDependentServicesA [ADVAPI32.@]
2585 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2586 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2587 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2589 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2590 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2592 *lpServicesReturned = 0;
2593 return TRUE;
2596 /******************************************************************************
2597 * EnumDependentServicesW [ADVAPI32.@]
2599 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2600 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2601 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2603 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2604 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2606 *lpServicesReturned = 0;
2607 return TRUE;