advapi32/service: Some tests for DeleteService.
[wine/wine64.git] / dlls / advapi32 / service.c
blob15fd4b2070ec3626f5e5d8a2c27d0e6d90354991
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"
38 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
42 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
43 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
44 'S','e','r','v','i','c','e','s',0 };
45 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
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
72 #define WINESERV_SETPID 4
74 typedef struct service_data_t
76 struct list entry;
77 union {
78 LPHANDLER_FUNCTION handler;
79 LPHANDLER_FUNCTION_EX handler_ex;
80 } handler;
81 LPVOID context;
82 SERVICE_STATUS_PROCESS status;
83 HANDLE thread;
84 BOOL unicode : 1;
85 BOOL extended : 1; /* uses handler_ex instead of handler? */
86 union {
87 LPSERVICE_MAIN_FUNCTIONA a;
88 LPSERVICE_MAIN_FUNCTIONW w;
89 } proc;
90 LPWSTR args;
91 WCHAR name[1];
92 } service_data;
94 static CRITICAL_SECTION service_cs;
95 static CRITICAL_SECTION_DEBUG service_cs_debug =
97 0, 0, &service_cs,
98 { &service_cs_debug.ProcessLocksList,
99 &service_cs_debug.ProcessLocksList },
100 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
102 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
104 static struct list service_list = LIST_INIT(service_list);
106 extern HANDLE __wine_make_process_system(void);
108 /******************************************************************************
109 * SC_HANDLEs
112 #define MAX_SERVICE_NAME 256
114 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
116 struct sc_handle;
117 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
119 struct sc_handle
121 SC_HANDLE_TYPE htype;
122 DWORD ref_count;
123 sc_handle_destructor destroy;
126 struct sc_manager /* service control manager handle */
128 struct sc_handle hdr;
129 HKEY hkey; /* handle to services database in the registry */
130 DWORD dwAccess;
133 struct sc_service /* service handle */
135 struct sc_handle hdr;
136 HKEY hkey; /* handle to service entry in the registry (under hkey) */
137 DWORD dwAccess;
138 struct sc_manager *scm; /* pointer to SCM handle */
139 WCHAR name[1];
142 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
143 sc_handle_destructor destroy)
145 struct sc_handle *hdr;
147 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
148 if (hdr)
150 hdr->htype = htype;
151 hdr->ref_count = 1;
152 hdr->destroy = destroy;
154 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
155 return hdr;
158 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
160 struct sc_handle *hdr = (struct sc_handle *) handle;
162 if (!hdr)
163 return NULL;
164 if (hdr->htype != htype)
165 return NULL;
166 return hdr;
169 static void sc_handle_free(struct sc_handle* hdr)
171 if (!hdr)
172 return;
173 if (--hdr->ref_count)
174 return;
175 hdr->destroy(hdr);
176 HeapFree(GetProcessHeap(), 0, hdr);
179 static void sc_handle_destroy_manager(struct sc_handle *handle)
181 struct sc_manager *mgr = (struct sc_manager*) handle;
183 TRACE("destroying SC Manager %p\n", mgr);
184 if (mgr->hkey)
185 RegCloseKey(mgr->hkey);
188 static void sc_handle_destroy_service(struct sc_handle *handle)
190 struct sc_service *svc = (struct sc_service*) handle;
192 TRACE("destroying service %p\n", svc);
193 if (svc->hkey)
194 RegCloseKey(svc->hkey);
195 svc->hkey = NULL;
196 sc_handle_free(&svc->scm->hdr);
197 svc->scm = NULL;
200 /******************************************************************************
201 * String management functions
203 static inline LPWSTR SERV_dup( LPCSTR str )
205 UINT len;
206 LPWSTR wstr;
208 if( !str )
209 return NULL;
210 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
211 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
212 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
213 return wstr;
216 static inline LPWSTR SERV_dupmulti(LPCSTR str)
218 UINT len = 0, n = 0;
219 LPWSTR wstr;
221 if( !str )
222 return NULL;
223 do {
224 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
225 n += (strlen( &str[n] ) + 1);
226 } while (str[n]);
227 len++;
228 n++;
230 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
231 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
232 return wstr;
235 static inline VOID SERV_free( LPWSTR wstr )
237 HeapFree( GetProcessHeap(), 0, wstr );
240 /******************************************************************************
241 * registry access functions and data
243 static const WCHAR szDisplayName[] = {
244 'D','i','s','p','l','a','y','N','a','m','e', 0 };
245 static const WCHAR szType[] = {'T','y','p','e',0};
246 static const WCHAR szStart[] = {'S','t','a','r','t',0};
247 static const WCHAR szError[] = {
248 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
249 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
250 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
251 static const WCHAR szDependencies[] = {
252 'D','e','p','e','n','d','e','n','c','i','e','s',0};
253 static const WCHAR szDependOnService[] = {
254 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
255 static const WCHAR szObjectName[] = {
256 'O','b','j','e','c','t','N','a','m','e',0};
257 static const WCHAR szTag[] = {
258 'T','a','g',0};
260 struct reg_value {
261 DWORD type;
262 DWORD size;
263 LPCWSTR name;
264 LPCVOID data;
267 static inline void service_set_value( struct reg_value *val,
268 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
270 val->name = name;
271 val->type = type;
272 val->data = data;
273 val->size = size;
276 static inline void service_set_dword( struct reg_value *val,
277 LPCWSTR name, const DWORD *data )
279 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
282 static inline void service_set_string( struct reg_value *val,
283 LPCWSTR name, LPCWSTR string )
285 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
286 service_set_value( val, REG_SZ, name, string, len );
289 static inline void service_set_multi_string( struct reg_value *val,
290 LPCWSTR name, LPCWSTR string )
292 DWORD len = 0;
294 /* determine the length of a double null terminated multi string */
295 do {
296 len += (lstrlenW( &string[ len ] )+1);
297 } while ( string[ len++ ] );
299 len *= sizeof (WCHAR);
300 service_set_value( val, REG_MULTI_SZ, name, string, len );
303 static inline LONG service_write_values( HKEY hKey,
304 const struct reg_value *val, int n )
306 LONG r = ERROR_SUCCESS;
307 int i;
309 for( i=0; i<n; i++ )
311 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
312 (const BYTE*)val[i].data, val[i].size );
313 if( r != ERROR_SUCCESS )
314 break;
316 return r;
319 /******************************************************************************
320 * Service IPC functions
322 static LPWSTR service_get_pipe_name(LPCWSTR service)
324 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
325 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
326 LPWSTR name;
327 DWORD len;
329 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
330 name = HeapAlloc(GetProcessHeap(), 0, len);
331 strcpyW(name, prefix);
332 strcatW(name, service);
333 return name;
336 static HANDLE service_open_pipe(LPCWSTR service)
338 LPWSTR szPipe = service_get_pipe_name( service );
339 HANDLE handle = INVALID_HANDLE_VALUE;
341 do {
342 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
343 0, NULL, OPEN_ALWAYS, 0, NULL);
344 if (handle != INVALID_HANDLE_VALUE)
345 break;
346 if (GetLastError() != ERROR_PIPE_BUSY)
347 break;
348 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
349 SERV_free(szPipe);
351 return handle;
354 /******************************************************************************
355 * service_get_event_handle
357 static HANDLE service_get_event_handle(LPCWSTR service)
359 static const WCHAR prefix[] = {
360 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
361 LPWSTR name;
362 DWORD len;
363 HANDLE handle;
365 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
366 name = HeapAlloc(GetProcessHeap(), 0, len);
367 strcpyW(name, prefix);
368 strcatW(name, service);
369 handle = CreateEventW(NULL, TRUE, FALSE, name);
370 SERV_free(name);
371 return handle;
374 /******************************************************************************
375 * service_thread
377 * Call into the main service routine provided by StartServiceCtrlDispatcher.
379 static DWORD WINAPI service_thread(LPVOID arg)
381 service_data *info = arg;
382 LPWSTR str = info->args;
383 DWORD argc = 0, len = 0;
385 TRACE("%p\n", arg);
387 while (str[len])
389 len += strlenW(&str[len]) + 1;
390 argc++;
393 if (!argc)
395 if (info->unicode)
396 info->proc.w(0, NULL);
397 else
398 info->proc.a(0, NULL);
399 return 0;
402 if (info->unicode)
404 LPWSTR *argv, p;
406 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
407 for (argc=0, p=str; *p; p += strlenW(p) + 1)
408 argv[argc++] = p;
409 argv[argc] = NULL;
411 info->proc.w(argc, argv);
412 HeapFree(GetProcessHeap(), 0, argv);
414 else
416 LPSTR strA, *argv, p;
417 DWORD lenA;
419 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
420 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
421 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
423 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
424 for (argc=0, p=strA; *p; p += strlen(p) + 1)
425 argv[argc++] = p;
426 argv[argc] = NULL;
428 info->proc.a(argc, argv);
429 HeapFree(GetProcessHeap(), 0, argv);
430 HeapFree(GetProcessHeap(), 0, strA);
432 return 0;
435 /******************************************************************************
436 * service_handle_start
438 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
440 DWORD read = 0, result = 0;
441 LPWSTR args;
442 BOOL r;
444 TRACE("%p %p %d\n", pipe, service, count);
446 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
447 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
448 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
450 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
451 r, count, read, debugstr_wn(args, count));
452 goto end;
455 if (service->thread)
457 ERR("service is not stopped\n");
458 goto end;
461 SERV_free(service->args);
462 service->args = args;
463 args = NULL;
464 service->thread = CreateThread( NULL, 0, service_thread,
465 service, 0, NULL );
467 end:
468 HeapFree(GetProcessHeap(), 0, args);
469 WriteFile( pipe, &result, sizeof result, &read, NULL );
471 return TRUE;
474 /******************************************************************************
475 * service_send_start_message
477 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
479 DWORD i, len, count, result;
480 service_start_info *ssi;
481 LPWSTR p;
482 BOOL r;
484 TRACE("%p %p %d\n", pipe, argv, argc);
486 /* calculate how much space do we need to send the startup info */
487 len = 1;
488 for (i=0; i<argc; i++)
489 len += strlenW(argv[i])+1;
491 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
492 ssi->cmd = WINESERV_STARTINFO;
493 ssi->size = len;
495 /* copy service args into a single buffer*/
496 p = &ssi->str[0];
497 for (i=0; i<argc; i++)
499 strcpyW(p, argv[i]);
500 p += strlenW(p) + 1;
502 *p=0;
504 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
505 if (r)
506 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
508 HeapFree(GetProcessHeap(),0,ssi);
510 return r;
513 /******************************************************************************
514 * service_handle_get_status
516 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
518 DWORD count = 0;
519 TRACE("\n");
520 return WriteFile(pipe, &service->status,
521 sizeof service->status, &count, NULL);
524 /******************************************************************************
525 * service_get_status
527 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
529 DWORD cmd[2], count = 0;
530 BOOL r;
532 cmd[0] = WINESERV_GETSTATUS;
533 cmd[1] = 0;
534 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
535 if (!r || count != sizeof cmd)
537 ERR("service protocol error - failed to write pipe!\n");
538 return r;
540 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
541 if (!r || count != sizeof *status)
542 ERR("service protocol error - failed to read pipe "
543 "r = %d count = %d!\n", r, count);
544 return r;
547 /******************************************************************************
548 * service_handle_set_processID
550 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
552 DWORD count, ret = ERROR_SUCCESS;
554 TRACE("received control %d\n", dwProcessId);
555 service->status.dwProcessId = dwProcessId;
556 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
559 /******************************************************************************
560 * service_set_processID
562 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
564 DWORD cmd[2], count = 0;
565 BOOL r;
567 cmd[0] = WINESERV_SETPID;
568 cmd[1] = dwprocessId;
569 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
570 if (!r || count != sizeof cmd)
572 ERR("service protocol error - failed to write pipe!\n");
573 return r;
575 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
576 if (!r || count != sizeof *dwResult)
577 ERR("service protocol error - failed to read pipe "
578 "r = %d count = %d!\n", r, count);
579 return r;
582 /******************************************************************************
583 * service_send_control
585 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
587 DWORD cmd[2], count = 0;
588 BOOL r;
590 cmd[0] = WINESERV_SENDCONTROL;
591 cmd[1] = dwControl;
592 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
593 if (!r || count != sizeof cmd)
595 ERR("service protocol error - failed to write pipe!\n");
596 return r;
598 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
599 if (!r || count != sizeof *result)
600 ERR("service protocol error - failed to read pipe "
601 "r = %d count = %d!\n", r, count);
602 return r;
605 /******************************************************************************
606 * service_accepts_control
608 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
610 DWORD a = service->status.dwControlsAccepted;
612 switch (dwControl)
614 case SERVICE_CONTROL_INTERROGATE:
615 return TRUE;
616 case SERVICE_CONTROL_STOP:
617 if (a&SERVICE_ACCEPT_STOP)
618 return TRUE;
619 break;
620 case SERVICE_CONTROL_SHUTDOWN:
621 if (a&SERVICE_ACCEPT_SHUTDOWN)
622 return TRUE;
623 break;
624 case SERVICE_CONTROL_PAUSE:
625 case SERVICE_CONTROL_CONTINUE:
626 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
627 return TRUE;
628 break;
629 case SERVICE_CONTROL_PARAMCHANGE:
630 if (a&SERVICE_ACCEPT_PARAMCHANGE)
631 return TRUE;
632 break;
633 case SERVICE_CONTROL_NETBINDADD:
634 case SERVICE_CONTROL_NETBINDREMOVE:
635 case SERVICE_CONTROL_NETBINDENABLE:
636 case SERVICE_CONTROL_NETBINDDISABLE:
637 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
638 return TRUE;
640 if (!service->extended)
641 return FALSE;
642 switch (dwControl)
644 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
645 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
646 return TRUE;
647 break;
648 case SERVICE_CONTROL_POWEREVENT:
649 if (a&SERVICE_ACCEPT_POWEREVENT)
650 return TRUE;
651 break;
652 case SERVICE_CONTROL_SESSIONCHANGE:
653 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
654 return TRUE;
655 break;
657 return FALSE;
660 /******************************************************************************
661 * service_handle_control
663 static BOOL service_handle_control(HANDLE pipe, service_data *service,
664 DWORD dwControl)
666 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
668 TRACE("received control %d\n", dwControl);
670 if (service_accepts_control(service, dwControl))
672 if (service->extended && service->handler.handler_ex)
674 service->handler.handler_ex(dwControl, 0, NULL, service->context);
675 ret = ERROR_SUCCESS;
677 else if (service->handler.handler)
679 service->handler.handler(dwControl);
680 ret = ERROR_SUCCESS;
683 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
686 /******************************************************************************
687 * service_reap_thread
689 static DWORD service_reap_thread(service_data *service)
691 DWORD exitcode = 0;
693 if (!service->thread)
694 return 0;
695 GetExitCodeThread(service->thread, &exitcode);
696 if (exitcode!=STILL_ACTIVE)
698 CloseHandle(service->thread);
699 service->thread = 0;
701 return exitcode;
704 /******************************************************************************
705 * service_control_dispatcher
707 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
709 service_data *service = arg;
710 LPWSTR name;
711 HANDLE pipe, event;
713 TRACE("%p %s\n", service, debugstr_w(service->name));
715 /* create a pipe to talk to the rest of the world with */
716 name = service_get_pipe_name(service->name);
717 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
718 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
719 SERV_free(name);
721 /* let the process who started us know we've tried to create a pipe */
722 event = service_get_event_handle(service->name);
723 SetEvent(event);
724 CloseHandle(event);
726 if (pipe==INVALID_HANDLE_VALUE)
728 ERR("failed to create pipe for %s, error = %d\n",
729 debugstr_w(service->name), GetLastError());
730 return 0;
733 /* dispatcher loop */
734 while (1)
736 BOOL r;
737 DWORD count, req[2] = {0,0};
739 r = ConnectNamedPipe(pipe, NULL);
740 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
742 ERR("pipe connect failed\n");
743 break;
746 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
747 if (!r || count!=sizeof req)
749 ERR("pipe read failed\n");
750 break;
753 service_reap_thread(service);
755 /* handle the request */
756 switch (req[0])
758 case WINESERV_STARTINFO:
759 service_handle_start(pipe, service, req[1]);
760 break;
761 case WINESERV_GETSTATUS:
762 service_handle_get_status(pipe, service);
763 break;
764 case WINESERV_SENDCONTROL:
765 service_handle_control(pipe, service, req[1]);
766 break;
767 case WINESERV_SETPID:
768 service_handle_set_processID(pipe, service, req[1]);
769 break;
770 default:
771 ERR("received invalid command %d length %d\n", req[0], req[1]);
774 FlushFileBuffers(pipe);
775 DisconnectNamedPipe(pipe);
778 CloseHandle(pipe);
779 return 1;
782 /******************************************************************************
783 * service_run_threads
785 static BOOL service_run_threads(void)
787 service_data *service;
788 DWORD count, n = 0;
789 HANDLE *handles;
791 EnterCriticalSection( &service_cs );
793 count = list_count( &service_list );
795 TRACE("starting %d pipe listener threads\n", count);
797 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
799 handles[n++] = __wine_make_process_system();
801 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
802 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
803 service, 0, NULL );
804 assert(n == count + 1);
806 LeaveCriticalSection( &service_cs );
808 /* wait for all the threads to pack up and exit */
809 while (n > 1)
811 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
812 if (!ret) /* system process event */
814 TRACE( "last user process exited, shutting down\n" );
815 /* FIXME: we should maybe send a shutdown control to running services */
816 ExitProcess(0);
818 if (ret < MAXIMUM_WAIT_OBJECTS)
820 CloseHandle( handles[ret] );
821 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
822 n--;
824 else break;
827 while (n) CloseHandle( handles[--n] );
828 HeapFree(GetProcessHeap(), 0, handles);
830 return TRUE;
833 /******************************************************************************
834 * StartServiceCtrlDispatcherA [ADVAPI32.@]
836 * See StartServiceCtrlDispatcherW.
838 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
840 service_data *info;
841 DWORD sz, len;
842 BOOL ret = TRUE;
844 TRACE("%p\n", servent);
846 EnterCriticalSection( &service_cs );
847 while (servent->lpServiceName)
849 LPSTR name = servent->lpServiceName;
851 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
852 sz = len*sizeof(WCHAR) + sizeof *info;
853 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
854 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
855 info->proc.a = servent->lpServiceProc;
856 info->unicode = FALSE;
857 list_add_head( &service_list, &info->entry );
858 servent++;
860 LeaveCriticalSection( &service_cs );
862 service_run_threads();
864 return ret;
867 /******************************************************************************
868 * StartServiceCtrlDispatcherW [ADVAPI32.@]
870 * Connects a process containing one or more services to the service control
871 * manager.
873 * PARAMS
874 * servent [I] A list of the service names and service procedures
876 * RETURNS
877 * Success: TRUE.
878 * Failure: FALSE.
880 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
882 service_data *info;
883 DWORD sz, len;
884 BOOL ret = TRUE;
886 TRACE("%p\n", servent);
888 EnterCriticalSection( &service_cs );
889 while (servent->lpServiceName)
891 LPWSTR name = servent->lpServiceName;
893 len = strlenW(name);
894 sz = len*sizeof(WCHAR) + sizeof *info;
895 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
896 strcpyW(info->name, name);
897 info->proc.w = servent->lpServiceProc;
898 info->unicode = TRUE;
899 list_add_head( &service_list, &info->entry );
900 servent++;
902 LeaveCriticalSection( &service_cs );
904 service_run_threads();
906 return ret;
909 /******************************************************************************
910 * LockServiceDatabase [ADVAPI32.@]
912 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
914 HANDLE ret;
916 TRACE("%p\n",hSCManager);
918 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
919 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
921 CloseHandle( ret );
922 ret = NULL;
923 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
926 TRACE("returning %p\n", ret);
928 return ret;
931 /******************************************************************************
932 * UnlockServiceDatabase [ADVAPI32.@]
934 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
936 TRACE("%p\n",ScLock);
938 return CloseHandle( ScLock );
941 /******************************************************************************
942 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
944 SERVICE_STATUS_HANDLE WINAPI
945 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
947 LPWSTR lpServiceNameW;
948 SERVICE_STATUS_HANDLE ret;
950 lpServiceNameW = SERV_dup(lpServiceName);
951 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
952 SERV_free(lpServiceNameW);
953 return ret;
956 /******************************************************************************
957 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
959 * PARAMS
960 * lpServiceName []
961 * lpfHandler []
963 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
964 LPHANDLER_FUNCTION lpfHandler )
966 service_data *service;
967 SERVICE_STATUS_HANDLE handle = 0;
969 EnterCriticalSection( &service_cs );
970 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
972 if(!strcmpW(lpServiceName, service->name))
974 service->handler.handler = lpfHandler;
975 handle = (SERVICE_STATUS_HANDLE)service;
976 break;
979 LeaveCriticalSection( &service_cs );
980 return handle;
983 /******************************************************************************
984 * SetServiceStatus [ADVAPI32.@]
986 * PARAMS
987 * hService []
988 * lpStatus []
990 BOOL WINAPI
991 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
993 service_data *service;
994 BOOL r = FALSE;
996 TRACE("%p %x %x %x %x %x %x %x\n", hService,
997 lpStatus->dwServiceType, lpStatus->dwCurrentState,
998 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
999 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
1000 lpStatus->dwWaitHint);
1002 EnterCriticalSection( &service_cs );
1003 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
1005 if(service == (service_data*)hService)
1007 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
1008 TRACE("Set service status to %d\n",service->status.dwCurrentState);
1009 r = TRUE;
1010 break;
1013 LeaveCriticalSection( &service_cs );
1015 return r;
1019 /******************************************************************************
1020 * OpenSCManagerA [ADVAPI32.@]
1022 * Establish a connection to the service control manager and open its database.
1024 * PARAMS
1025 * lpMachineName [I] Pointer to machine name string
1026 * lpDatabaseName [I] Pointer to database name string
1027 * dwDesiredAccess [I] Type of access
1029 * RETURNS
1030 * Success: A Handle to the service control manager database
1031 * Failure: NULL
1033 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1034 DWORD dwDesiredAccess )
1036 LPWSTR lpMachineNameW, lpDatabaseNameW;
1037 SC_HANDLE ret;
1039 lpMachineNameW = SERV_dup(lpMachineName);
1040 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1041 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1042 SERV_free(lpDatabaseNameW);
1043 SERV_free(lpMachineNameW);
1044 return ret;
1047 /******************************************************************************
1048 * OpenSCManagerW [ADVAPI32.@]
1050 * See OpenSCManagerA.
1052 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1053 DWORD dwDesiredAccess )
1055 struct sc_manager *manager;
1056 HKEY hReg;
1057 LONG r;
1058 DWORD new_mask = dwDesiredAccess;
1060 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1061 debugstr_w(lpDatabaseName), dwDesiredAccess);
1063 if( lpDatabaseName && lpDatabaseName[0] )
1065 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1067 /* noop, all right */
1069 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1071 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1072 return NULL;
1074 else
1076 SetLastError( ERROR_INVALID_NAME );
1077 return NULL;
1081 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1082 sc_handle_destroy_manager );
1083 if (!manager)
1084 return NULL;
1086 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1087 if (r!=ERROR_SUCCESS)
1088 goto error;
1090 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1091 RegCloseKey( hReg );
1092 if (r!=ERROR_SUCCESS)
1093 goto error;
1095 RtlMapGenericMask(&new_mask, &scm_generic);
1096 manager->dwAccess = new_mask;
1097 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1099 return (SC_HANDLE) &manager->hdr;
1101 error:
1102 sc_handle_free( &manager->hdr );
1103 SetLastError( r);
1104 return NULL;
1107 /******************************************************************************
1108 * ControlService [ADVAPI32.@]
1110 * Send a control code to a service.
1112 * PARAMS
1113 * hService [I] Handle of the service control manager database
1114 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1115 * lpServiceStatus [O] Destination for the status of the service, if available
1117 * RETURNS
1118 * Success: TRUE.
1119 * Failure: FALSE.
1121 * BUGS
1122 * Unlike M$' implementation, control requests are not serialized and may be
1123 * processed asynchronously.
1125 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1126 LPSERVICE_STATUS lpServiceStatus )
1128 struct sc_service *hsvc;
1129 BOOL ret = FALSE;
1130 HANDLE handle;
1132 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1134 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1135 if (!hsvc)
1137 SetLastError( ERROR_INVALID_HANDLE );
1138 return FALSE;
1141 ret = QueryServiceStatus(hService, lpServiceStatus);
1142 if (!ret)
1144 ERR("failed to query service status\n");
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1146 return FALSE;
1149 switch (lpServiceStatus->dwCurrentState)
1151 case SERVICE_STOPPED:
1152 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1153 return FALSE;
1154 case SERVICE_START_PENDING:
1155 if (dwControl==SERVICE_CONTROL_STOP)
1156 break;
1157 /* fall thru */
1158 case SERVICE_STOP_PENDING:
1159 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1160 return FALSE;
1163 handle = service_open_pipe(hsvc->name);
1164 if (handle!=INVALID_HANDLE_VALUE)
1166 DWORD result = ERROR_SUCCESS;
1167 ret = service_send_control(handle, dwControl, &result);
1168 CloseHandle(handle);
1169 if (result!=ERROR_SUCCESS)
1171 SetLastError(result);
1172 ret = FALSE;
1176 return ret;
1179 /******************************************************************************
1180 * CloseServiceHandle [ADVAPI32.@]
1182 * Close a handle to a service or the service control manager database.
1184 * PARAMS
1185 * hSCObject [I] Handle to service or service control manager database
1187 * RETURNS
1188 * Success: TRUE
1189 * Failure: FALSE
1191 BOOL WINAPI
1192 CloseServiceHandle( SC_HANDLE hSCObject )
1194 TRACE("%p\n", hSCObject);
1196 sc_handle_free( (struct sc_handle*) hSCObject );
1198 return TRUE;
1202 /******************************************************************************
1203 * OpenServiceA [ADVAPI32.@]
1205 * Open a handle to a service.
1207 * PARAMS
1208 * hSCManager [I] Handle of the service control manager database
1209 * lpServiceName [I] Name of the service to open
1210 * dwDesiredAccess [I] Access required to the service
1212 * RETURNS
1213 * Success: Handle to the service
1214 * Failure: NULL
1216 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1217 DWORD dwDesiredAccess )
1219 LPWSTR lpServiceNameW;
1220 SC_HANDLE ret;
1222 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1224 lpServiceNameW = SERV_dup(lpServiceName);
1225 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1226 SERV_free(lpServiceNameW);
1227 return ret;
1231 /******************************************************************************
1232 * OpenServiceW [ADVAPI32.@]
1234 * See OpenServiceA.
1236 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1237 DWORD dwDesiredAccess)
1239 struct sc_manager *hscm;
1240 struct sc_service *hsvc;
1241 HKEY hKey;
1242 long r;
1243 DWORD len;
1244 DWORD new_mask = dwDesiredAccess;
1246 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1248 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1249 if (!hscm)
1251 SetLastError( ERROR_INVALID_HANDLE );
1252 return FALSE;
1255 if (!lpServiceName)
1257 SetLastError(ERROR_INVALID_ADDRESS);
1258 return NULL;
1261 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1262 if (r!=ERROR_SUCCESS)
1264 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1265 return NULL;
1268 len = strlenW(lpServiceName)+1;
1269 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1270 sizeof (struct sc_service) + len*sizeof(WCHAR),
1271 sc_handle_destroy_service );
1272 if (!hsvc)
1274 RegCloseKey(hKey);
1275 return NULL;
1277 strcpyW( hsvc->name, lpServiceName );
1278 hsvc->hkey = hKey;
1280 RtlMapGenericMask(&new_mask, &svc_generic);
1281 hsvc->dwAccess = new_mask;
1283 /* add reference to SCM handle */
1284 hscm->hdr.ref_count++;
1285 hsvc->scm = hscm;
1287 TRACE("returning %p\n",hsvc);
1289 return (SC_HANDLE) &hsvc->hdr;
1292 /******************************************************************************
1293 * CreateServiceW [ADVAPI32.@]
1295 SC_HANDLE WINAPI
1296 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1297 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1298 DWORD dwServiceType, DWORD dwStartType,
1299 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1300 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1301 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1302 LPCWSTR lpPassword )
1304 struct sc_manager *hscm;
1305 struct sc_service *hsvc = NULL;
1306 HKEY hKey;
1307 LONG r;
1308 DWORD dp, len;
1309 struct reg_value val[10];
1310 int n = 0;
1311 DWORD new_mask = dwDesiredAccess;
1312 DWORD index = 0;
1313 WCHAR buffer[MAX_PATH];
1314 BOOL displayname_exists = FALSE;
1316 TRACE("%p %s %s\n", hSCManager,
1317 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1319 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1320 if (!hscm)
1322 SetLastError( ERROR_INVALID_HANDLE );
1323 return NULL;
1326 if (!lpServiceName || !lpBinaryPathName)
1328 SetLastError(ERROR_INVALID_ADDRESS);
1329 return NULL;
1332 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1334 SetLastError(ERROR_ACCESS_DENIED);
1335 return NULL;
1338 if (!lpServiceName[0])
1340 SetLastError(ERROR_INVALID_NAME);
1341 return NULL;
1344 if (!lpBinaryPathName[0])
1346 SetLastError(ERROR_INVALID_PARAMETER);
1347 return NULL;
1350 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1351 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1352 * runs under the LocalSystem account)
1354 switch (dwServiceType)
1356 case SERVICE_KERNEL_DRIVER:
1357 case SERVICE_FILE_SYSTEM_DRIVER:
1358 case SERVICE_WIN32_OWN_PROCESS:
1359 case SERVICE_WIN32_SHARE_PROCESS:
1360 /* No problem */
1361 break;
1362 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1363 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1364 /* FIXME : Do we need a more thorough check? */
1365 if (lpServiceStartName)
1367 SetLastError(ERROR_INVALID_PARAMETER);
1368 return NULL;
1370 break;
1371 default:
1372 SetLastError(ERROR_INVALID_PARAMETER);
1373 return NULL;
1376 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1377 if (dwStartType > SERVICE_DISABLED)
1379 SetLastError(ERROR_INVALID_PARAMETER);
1380 return NULL;
1383 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1384 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1385 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1387 SetLastError(ERROR_INVALID_PARAMETER);
1388 return NULL;
1391 /* Loop through the registry to check if the service already exists and to
1392 * check if we can use the given displayname.
1393 * FIXME: Should we use EnumServicesStatusEx?
1395 len = sizeof(buffer);
1396 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1398 HKEY service_key;
1400 /* The service already exists, so bail out */
1401 if(!lstrcmpiW(lpServiceName, buffer))
1403 SetLastError(ERROR_SERVICE_EXISTS);
1404 return NULL;
1407 /* The given displayname matches the found servicename. We don't bail out
1408 * as servicename is checked before a duplicate displayname
1410 if(!lstrcmpiW(lpDisplayName, buffer))
1411 displayname_exists = TRUE;
1413 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1415 WCHAR name[MAX_PATH];
1416 DWORD size = sizeof(name);
1418 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1420 /* The given displayname matches the found displayname */
1421 if (!lstrcmpiW(lpDisplayName, name))
1422 displayname_exists = TRUE;
1424 RegCloseKey(service_key);
1426 index++;
1427 len = sizeof(buffer);
1430 if (lpDisplayName && displayname_exists)
1432 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1433 return NULL;
1436 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1437 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1438 if (r!=ERROR_SUCCESS)
1440 /* FIXME: Should we set an error? */
1441 return NULL;
1444 if( lpDisplayName )
1445 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1447 service_set_dword( &val[n++], szType, &dwServiceType );
1448 service_set_dword( &val[n++], szStart, &dwStartType );
1449 service_set_dword( &val[n++], szError, &dwErrorControl );
1451 if( lpBinaryPathName )
1452 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1454 if( lpLoadOrderGroup )
1455 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1457 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1458 * There is no such key as what szDependencies refers to */
1459 if( lpDependencies )
1460 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1462 if( lpPassword )
1463 FIXME("Don't know how to add a Password for a service.\n");
1465 if( lpServiceStartName )
1466 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1468 r = service_write_values( hKey, val, n );
1469 if( r != ERROR_SUCCESS )
1470 goto error;
1472 len = strlenW(lpServiceName)+1;
1473 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1474 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1475 if( !hsvc )
1476 goto error;
1477 lstrcpyW( hsvc->name, lpServiceName );
1478 hsvc->hkey = hKey;
1480 RtlMapGenericMask(&new_mask, &svc_generic);
1481 hsvc->dwAccess = new_mask;
1483 hsvc->scm = hscm;
1484 hscm->hdr.ref_count++;
1486 return (SC_HANDLE) &hsvc->hdr;
1488 error:
1489 RegCloseKey( hKey );
1490 return NULL;
1494 /******************************************************************************
1495 * CreateServiceA [ADVAPI32.@]
1497 SC_HANDLE WINAPI
1498 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1499 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1500 DWORD dwServiceType, DWORD dwStartType,
1501 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1502 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1503 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1504 LPCSTR lpPassword )
1506 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1507 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1508 SC_HANDLE r;
1510 TRACE("%p %s %s\n", hSCManager,
1511 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1513 lpServiceNameW = SERV_dup( lpServiceName );
1514 lpDisplayNameW = SERV_dup( lpDisplayName );
1515 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1516 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1517 lpDependenciesW = SERV_dupmulti( lpDependencies );
1518 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1519 lpPasswordW = SERV_dup( lpPassword );
1521 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1522 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1523 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1524 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1526 SERV_free( lpServiceNameW );
1527 SERV_free( lpDisplayNameW );
1528 SERV_free( lpBinaryPathNameW );
1529 SERV_free( lpLoadOrderGroupW );
1530 SERV_free( lpDependenciesW );
1531 SERV_free( lpServiceStartNameW );
1532 SERV_free( lpPasswordW );
1534 return r;
1538 /******************************************************************************
1539 * DeleteService [ADVAPI32.@]
1541 * Delete a service from the service control manager database.
1543 * PARAMS
1544 * hService [I] Handle of the service to delete
1546 * RETURNS
1547 * Success: TRUE
1548 * Failure: FALSE
1550 BOOL WINAPI DeleteService( SC_HANDLE hService )
1552 struct sc_service *hsvc;
1554 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1555 if (!hsvc)
1557 SetLastError( ERROR_INVALID_HANDLE );
1558 return FALSE;
1561 if (!(hsvc->dwAccess & DELETE))
1563 SetLastError(ERROR_ACCESS_DENIED);
1564 return FALSE;
1567 /* Close the key to the service */
1568 RegCloseKey(hsvc->hkey);
1570 /* Delete the service under the Service Control Manager key */
1571 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1573 hsvc->hkey = NULL;
1575 return TRUE;
1579 /******************************************************************************
1580 * StartServiceA [ADVAPI32.@]
1582 * Start a service
1584 * PARAMS
1585 * hService [I] Handle of service
1586 * dwNumServiceArgs [I] Number of arguments
1587 * lpServiceArgVectors [I] Address of array of argument strings
1589 * NOTES
1590 * - NT implements this function using an obscure RPC call.
1591 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1592 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1593 * - This will only work for shared address space. How should the service
1594 * args be transferred when address spaces are separated?
1595 * - Can only start one service at a time.
1596 * - Has no concept of privilege.
1598 * RETURNS
1599 * Success: TRUE.
1600 * Failure: FALSE
1602 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1603 LPCSTR *lpServiceArgVectors )
1605 LPWSTR *lpwstr=NULL;
1606 unsigned int i;
1607 BOOL r;
1609 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1611 if (dwNumServiceArgs)
1612 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1613 dwNumServiceArgs*sizeof(LPWSTR) );
1615 for(i=0; i<dwNumServiceArgs; i++)
1616 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1618 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1620 if (dwNumServiceArgs)
1622 for(i=0; i<dwNumServiceArgs; i++)
1623 SERV_free(lpwstr[i]);
1624 HeapFree(GetProcessHeap(), 0, lpwstr);
1627 return r;
1630 /******************************************************************************
1631 * service_start_process [INTERNAL]
1633 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1635 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1636 PROCESS_INFORMATION pi;
1637 STARTUPINFOW si;
1638 LPWSTR path = NULL, str;
1639 DWORD type, size, ret, svc_type;
1640 HANDLE handles[2];
1641 BOOL r;
1643 size = sizeof(svc_type);
1644 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1645 svc_type = 0;
1647 if (svc_type == SERVICE_KERNEL_DRIVER)
1649 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1650 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1652 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1653 GetSystemDirectoryW( path, len );
1654 lstrcatW( path, winedeviceW );
1655 lstrcatW( path, hsvc->name );
1657 else
1659 /* read the executable path from the registry */
1660 size = 0;
1661 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1662 if (ret!=ERROR_SUCCESS)
1663 return FALSE;
1664 str = HeapAlloc(GetProcessHeap(),0,size);
1665 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1666 if (ret==ERROR_SUCCESS)
1668 size = ExpandEnvironmentStringsW(str,NULL,0);
1669 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1670 ExpandEnvironmentStringsW(str,path,size);
1672 HeapFree(GetProcessHeap(),0,str);
1673 if (!path)
1674 return FALSE;
1677 /* wait for the process to start and set an event or terminate */
1678 handles[0] = service_get_event_handle( hsvc->name );
1679 ZeroMemory(&si, sizeof(STARTUPINFOW));
1680 si.cb = sizeof(STARTUPINFOW);
1681 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1682 if (r)
1684 if (ppid) *ppid = pi.dwProcessId;
1686 handles[1] = pi.hProcess;
1687 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1688 if(ret != WAIT_OBJECT_0)
1690 SetLastError(ERROR_IO_PENDING);
1691 r = FALSE;
1694 CloseHandle( pi.hThread );
1695 CloseHandle( pi.hProcess );
1697 CloseHandle( handles[0] );
1698 HeapFree(GetProcessHeap(),0,path);
1699 return r;
1702 static BOOL service_wait_for_startup(SC_HANDLE hService)
1704 DWORD i;
1705 SERVICE_STATUS status;
1706 BOOL r = FALSE;
1708 TRACE("%p\n", hService);
1710 for (i=0; i<30; i++)
1712 status.dwCurrentState = 0;
1713 r = QueryServiceStatus(hService, &status);
1714 if (!r)
1715 break;
1716 if (status.dwCurrentState == SERVICE_RUNNING)
1718 TRACE("Service started successfully\n");
1719 break;
1721 r = FALSE;
1722 Sleep(1000);
1724 return r;
1727 /******************************************************************************
1728 * StartServiceW [ADVAPI32.@]
1730 * See StartServiceA.
1732 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1733 LPCWSTR *lpServiceArgVectors)
1735 struct sc_service *hsvc;
1736 BOOL r = FALSE;
1737 DWORD dwResult, dwProcessId = 0;
1738 SC_LOCK hLock;
1739 HANDLE handle = INVALID_HANDLE_VALUE;
1741 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1743 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1744 if (!hsvc)
1746 SetLastError(ERROR_INVALID_HANDLE);
1747 return r;
1750 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1751 if (!hLock)
1752 return r;
1754 handle = service_open_pipe(hsvc->name);
1755 if (handle==INVALID_HANDLE_VALUE)
1757 /* start the service process */
1758 if (service_start_process(hsvc, &dwProcessId))
1759 handle = service_open_pipe(hsvc->name);
1762 if (handle != INVALID_HANDLE_VALUE)
1764 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1765 CloseHandle(handle);
1768 handle = service_open_pipe(hsvc->name);
1769 if (handle != INVALID_HANDLE_VALUE)
1771 service_set_processID(handle, dwProcessId, &dwResult);
1772 CloseHandle(handle);
1775 UnlockServiceDatabase( hLock );
1777 TRACE("returning %d\n", r);
1779 if (r)
1780 service_wait_for_startup(hService);
1782 return r;
1785 /******************************************************************************
1786 * QueryServiceStatus [ADVAPI32.@]
1788 * PARAMS
1789 * hService [I] Handle to service to get information about
1790 * lpservicestatus [O] buffer to receive the status information for the service
1793 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1794 LPSERVICE_STATUS lpservicestatus)
1796 SERVICE_STATUS_PROCESS SvcStatusData;
1797 BOOL ret;
1799 TRACE("%p %p\n", hService, lpservicestatus);
1801 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1802 sizeof(SERVICE_STATUS_PROCESS), NULL);
1803 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1804 return ret;
1808 /******************************************************************************
1809 * QueryServiceStatusEx [ADVAPI32.@]
1811 * Get information about a service.
1813 * PARAMS
1814 * hService [I] Handle to service to get information about
1815 * InfoLevel [I] Level of information to get
1816 * lpBuffer [O] Destination for requested information
1817 * cbBufSize [I] Size of lpBuffer in bytes
1818 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1820 * RETURNS
1821 * Success: TRUE
1822 * FAILURE: FALSE
1824 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1825 LPBYTE lpBuffer, DWORD cbBufSize,
1826 LPDWORD pcbBytesNeeded)
1828 struct sc_service *hsvc;
1829 DWORD size, type, val;
1830 HANDLE pipe;
1831 LONG r;
1832 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1834 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1836 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1838 SetLastError( ERROR_INVALID_LEVEL);
1839 return FALSE;
1842 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1843 if (pSvcStatusData == NULL)
1845 SetLastError( ERROR_INVALID_PARAMETER);
1846 return FALSE;
1849 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1851 if( pcbBytesNeeded != NULL)
1852 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1854 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1855 return FALSE;
1858 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1859 if (!hsvc)
1861 SetLastError( ERROR_INVALID_HANDLE );
1862 return FALSE;
1865 pipe = service_open_pipe(hsvc->name);
1866 if (pipe != INVALID_HANDLE_VALUE)
1868 r = service_get_status(pipe, pSvcStatusData);
1869 CloseHandle(pipe);
1870 if (r)
1871 return TRUE;
1874 TRACE("Failed to read service status\n");
1876 /* read the service type from the registry */
1877 size = sizeof(val);
1878 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1879 if (r != ERROR_SUCCESS || type != REG_DWORD)
1880 val = 0;
1882 pSvcStatusData->dwServiceType = val;
1883 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1884 pSvcStatusData->dwControlsAccepted = 0;
1885 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1886 pSvcStatusData->dwServiceSpecificExitCode = 0;
1887 pSvcStatusData->dwCheckPoint = 0;
1888 pSvcStatusData->dwWaitHint = 0;
1890 return TRUE;
1893 /******************************************************************************
1894 * QueryServiceConfigA [ADVAPI32.@]
1896 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1897 DWORD size, LPDWORD needed )
1899 DWORD n;
1900 LPSTR p, buffer;
1901 BOOL ret;
1902 QUERY_SERVICE_CONFIGW *configW;
1904 TRACE("%p %p %d %p\n", hService, config, size, needed);
1906 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1908 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1909 return FALSE;
1911 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1912 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1913 if (!ret) goto done;
1915 config->dwServiceType = configW->dwServiceType;
1916 config->dwStartType = configW->dwStartType;
1917 config->dwErrorControl = configW->dwErrorControl;
1918 config->lpBinaryPathName = NULL;
1919 config->lpLoadOrderGroup = NULL;
1920 config->dwTagId = configW->dwTagId;
1921 config->lpDependencies = NULL;
1922 config->lpServiceStartName = NULL;
1923 config->lpDisplayName = NULL;
1925 p = (LPSTR)(config + 1);
1926 n = size - sizeof(*config);
1927 ret = FALSE;
1929 #define MAP_STR(str) \
1930 do { \
1931 if (configW->str) \
1933 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1934 if (!sz) goto done; \
1935 config->str = p; \
1936 p += sz; \
1937 n -= sz; \
1939 } while (0)
1941 MAP_STR( lpBinaryPathName );
1942 MAP_STR( lpLoadOrderGroup );
1943 MAP_STR( lpDependencies );
1944 MAP_STR( lpServiceStartName );
1945 MAP_STR( lpDisplayName );
1946 #undef MAP_STR
1948 *needed = p - (LPSTR)config;
1949 ret = TRUE;
1951 done:
1952 HeapFree( GetProcessHeap(), 0, buffer );
1953 return ret;
1956 /******************************************************************************
1957 * QueryServiceConfigW [ADVAPI32.@]
1959 BOOL WINAPI
1960 QueryServiceConfigW( SC_HANDLE hService,
1961 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1962 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1964 WCHAR str_buffer[ MAX_PATH ];
1965 LONG r;
1966 DWORD type, val, sz, total, n;
1967 LPBYTE p;
1968 HKEY hKey;
1969 struct sc_service *hsvc;
1971 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1972 cbBufSize, pcbBytesNeeded);
1974 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1975 if (!hsvc)
1977 SetLastError( ERROR_INVALID_HANDLE );
1978 return FALSE;
1980 hKey = hsvc->hkey;
1982 /* TODO: Check which members are mandatory and what the registry types
1983 * should be. This should of course also be tested when a service is
1984 * created.
1987 /* calculate the size required first */
1988 total = sizeof (QUERY_SERVICE_CONFIGW);
1990 sz = sizeof(str_buffer);
1991 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1992 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1994 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1995 if( 0 == sz ) return FALSE;
1997 total += sizeof(WCHAR) * sz;
1999 else
2001 /* FIXME: set last error */
2002 return FALSE;
2005 sz = 0;
2006 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
2007 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2008 total += sz;
2009 else
2010 total += sizeof(WCHAR);
2012 sz = 0;
2013 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
2014 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
2015 total += sz;
2016 else
2017 total += sizeof(WCHAR);
2019 sz = 0;
2020 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
2021 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2022 total += sz;
2023 else
2024 total += sizeof(WCHAR);
2026 sz = 0;
2027 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
2028 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2029 total += sz;
2030 else
2031 total += sizeof(WCHAR);
2033 *pcbBytesNeeded = total;
2035 /* if there's not enough memory, return an error */
2036 if( total > cbBufSize )
2038 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2039 return FALSE;
2042 ZeroMemory( lpServiceConfig, total );
2044 sz = sizeof val;
2045 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2046 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2047 lpServiceConfig->dwServiceType = val;
2049 sz = sizeof val;
2050 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2051 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2052 lpServiceConfig->dwStartType = val;
2054 sz = sizeof val;
2055 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2056 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2057 lpServiceConfig->dwErrorControl = val;
2059 sz = sizeof val;
2060 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2061 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2062 lpServiceConfig->dwTagId = val;
2064 /* now do the strings */
2065 p = (LPBYTE) &lpServiceConfig[1];
2066 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2068 sz = sizeof(str_buffer);
2069 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2070 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2072 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2073 sz *= sizeof(WCHAR);
2074 if( 0 == sz || sz > n ) return FALSE;
2076 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2077 p += sz;
2078 n -= sz;
2080 else
2082 /* FIXME: set last error */
2083 return FALSE;
2086 sz = n;
2087 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2088 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2089 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2091 p += sz;
2092 n -= sz;
2094 else
2096 *(WCHAR *) p = 0;
2097 p += sizeof(WCHAR);
2098 n -= sizeof(WCHAR);
2101 sz = n;
2102 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2103 lpServiceConfig->lpDependencies = (LPWSTR) p;
2104 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2106 p += sz;
2107 n -= sz;
2109 else
2111 *(WCHAR *) p = 0;
2112 p += sizeof(WCHAR);
2113 n -= sizeof(WCHAR);
2116 sz = n;
2117 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2118 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2119 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2121 p += sz;
2122 n -= sz;
2124 else
2126 *(WCHAR *) p = 0;
2127 p += sizeof(WCHAR);
2128 n -= sizeof(WCHAR);
2131 sz = n;
2132 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2133 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2134 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2136 p += sz;
2137 n -= sz;
2139 else
2141 *(WCHAR *) p = 0;
2142 p += sizeof(WCHAR);
2143 n -= sizeof(WCHAR);
2146 if( n < 0 )
2147 ERR("Buffer overflow!\n");
2149 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2150 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2151 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2152 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2153 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2155 return TRUE;
2158 /******************************************************************************
2159 * EnumServicesStatusA [ADVAPI32.@]
2161 BOOL WINAPI
2162 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2163 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2164 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2165 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2167 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2168 dwServiceType, dwServiceState, lpServices, cbBufSize,
2169 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2170 SetLastError (ERROR_ACCESS_DENIED);
2171 return FALSE;
2174 /******************************************************************************
2175 * EnumServicesStatusW [ADVAPI32.@]
2177 BOOL WINAPI
2178 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2179 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2180 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2181 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2183 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2184 dwServiceType, dwServiceState, lpServices, cbBufSize,
2185 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2186 SetLastError (ERROR_ACCESS_DENIED);
2187 return FALSE;
2190 /******************************************************************************
2191 * EnumServicesStatusExA [ADVAPI32.@]
2193 BOOL WINAPI
2194 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2195 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2196 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2198 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2199 dwServiceType, dwServiceState, lpServices, cbBufSize,
2200 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2201 SetLastError (ERROR_ACCESS_DENIED);
2202 return FALSE;
2205 /******************************************************************************
2206 * EnumServicesStatusExW [ADVAPI32.@]
2208 BOOL WINAPI
2209 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2210 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2211 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2213 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2214 dwServiceType, dwServiceState, lpServices, cbBufSize,
2215 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2216 SetLastError (ERROR_ACCESS_DENIED);
2217 return FALSE;
2220 /******************************************************************************
2221 * GetServiceKeyNameA [ADVAPI32.@]
2223 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2224 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2226 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2227 return FALSE;
2230 /******************************************************************************
2231 * GetServiceKeyNameW [ADVAPI32.@]
2233 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2234 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2236 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2237 return FALSE;
2240 /******************************************************************************
2241 * QueryServiceLockStatusA [ADVAPI32.@]
2243 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2244 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2245 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2247 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2249 return FALSE;
2252 /******************************************************************************
2253 * QueryServiceLockStatusW [ADVAPI32.@]
2255 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2256 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2257 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2259 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2261 return FALSE;
2264 /******************************************************************************
2265 * GetServiceDisplayNameA [ADVAPI32.@]
2267 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2268 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2270 struct sc_manager *hscm;
2271 DWORD type, size;
2272 LONG ret;
2274 TRACE("%p %s %p %p\n", hSCManager,
2275 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2277 if (!lpServiceName)
2279 SetLastError(ERROR_INVALID_PARAMETER);
2280 return FALSE;
2283 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2284 if (!hscm)
2286 SetLastError(ERROR_INVALID_HANDLE);
2287 return FALSE;
2290 size = *lpcchBuffer;
2291 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2292 if (!ret && !lpDisplayName && size)
2293 ret = ERROR_MORE_DATA;
2295 if (ret)
2297 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2299 if (ret == ERROR_MORE_DATA)
2301 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2302 *lpcchBuffer = size - 1;
2304 else
2305 SetLastError(ret);
2306 return FALSE;
2308 return TRUE;
2311 /******************************************************************************
2312 * GetServiceDisplayNameW [ADVAPI32.@]
2314 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2315 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2317 struct sc_manager *hscm;
2318 DWORD type, size;
2319 LONG ret;
2321 TRACE("%p %s %p %p\n", hSCManager,
2322 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2324 if (!lpServiceName)
2326 SetLastError(ERROR_INVALID_PARAMETER);
2327 return FALSE;
2330 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2331 if (!hscm)
2333 SetLastError(ERROR_INVALID_HANDLE);
2334 return FALSE;
2337 size = *lpcchBuffer * sizeof(WCHAR);
2338 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2339 if (!ret && !lpDisplayName && size)
2340 ret = ERROR_MORE_DATA;
2342 if (ret)
2344 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2346 if (ret == ERROR_MORE_DATA)
2348 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2349 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2351 else
2352 SetLastError(ret);
2353 return FALSE;
2355 return TRUE;
2358 /******************************************************************************
2359 * ChangeServiceConfigW [ADVAPI32.@]
2361 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2362 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2363 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2364 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2366 struct reg_value val[10];
2367 struct sc_service *hsvc;
2368 DWORD r = ERROR_SUCCESS;
2369 HKEY hKey;
2370 int n = 0;
2372 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2373 hService, dwServiceType, dwStartType, dwErrorControl,
2374 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2375 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2376 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2378 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2379 if (!hsvc)
2381 SetLastError( ERROR_INVALID_HANDLE );
2382 return FALSE;
2384 hKey = hsvc->hkey;
2386 if( dwServiceType != SERVICE_NO_CHANGE )
2387 service_set_dword( &val[n++], szType, &dwServiceType );
2389 if( dwStartType != SERVICE_NO_CHANGE )
2390 service_set_dword( &val[n++], szStart, &dwStartType );
2392 if( dwErrorControl != SERVICE_NO_CHANGE )
2393 service_set_dword( &val[n++], szError, &dwErrorControl );
2395 if( lpBinaryPathName )
2396 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2398 if( lpLoadOrderGroup )
2399 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2401 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2402 * There is no such key as what szDependencies refers to */
2403 if( lpDependencies )
2404 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2406 if( lpPassword )
2407 FIXME("ignoring password\n");
2409 if( lpServiceStartName )
2410 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2412 r = service_write_values( hsvc->hkey, val, n );
2414 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2417 /******************************************************************************
2418 * ChangeServiceConfigA [ADVAPI32.@]
2420 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2421 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2422 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2423 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2425 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2426 LPWSTR wServiceStartName, wPassword, wDisplayName;
2427 BOOL r;
2429 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2430 hService, dwServiceType, dwStartType, dwErrorControl,
2431 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2432 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2433 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2435 wBinaryPathName = SERV_dup( lpBinaryPathName );
2436 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2437 wDependencies = SERV_dupmulti( lpDependencies );
2438 wServiceStartName = SERV_dup( lpServiceStartName );
2439 wPassword = SERV_dup( lpPassword );
2440 wDisplayName = SERV_dup( lpDisplayName );
2442 r = ChangeServiceConfigW( hService, dwServiceType,
2443 dwStartType, dwErrorControl, wBinaryPathName,
2444 wLoadOrderGroup, lpdwTagId, wDependencies,
2445 wServiceStartName, wPassword, wDisplayName);
2447 SERV_free( wBinaryPathName );
2448 SERV_free( wLoadOrderGroup );
2449 SERV_free( wDependencies );
2450 SERV_free( wServiceStartName );
2451 SERV_free( wPassword );
2452 SERV_free( wDisplayName );
2454 return r;
2457 /******************************************************************************
2458 * ChangeServiceConfig2A [ADVAPI32.@]
2460 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2461 LPVOID lpInfo)
2463 BOOL r = FALSE;
2465 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2467 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2469 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2470 SERVICE_DESCRIPTIONW sdw;
2472 sdw.lpDescription = SERV_dup( sd->lpDescription );
2474 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2476 SERV_free( sdw.lpDescription );
2478 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2480 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2481 SERVICE_FAILURE_ACTIONSW faw;
2483 faw.dwResetPeriod = fa->dwResetPeriod;
2484 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2485 faw.lpCommand = SERV_dup( fa->lpCommand );
2486 faw.cActions = fa->cActions;
2487 faw.lpsaActions = fa->lpsaActions;
2489 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2491 SERV_free( faw.lpRebootMsg );
2492 SERV_free( faw.lpCommand );
2494 else
2495 SetLastError( ERROR_INVALID_PARAMETER );
2497 return r;
2500 /******************************************************************************
2501 * ChangeServiceConfig2W [ADVAPI32.@]
2503 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2504 LPVOID lpInfo)
2506 HKEY hKey;
2507 struct sc_service *hsvc;
2509 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2510 if (!hsvc)
2512 SetLastError( ERROR_INVALID_HANDLE );
2513 return FALSE;
2515 hKey = hsvc->hkey;
2517 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2519 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2520 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2521 if (sd->lpDescription)
2523 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2524 if (sd->lpDescription[0] == 0)
2525 RegDeleteValueW(hKey,szDescription);
2526 else
2527 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2528 (LPVOID)sd->lpDescription,
2529 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2532 else
2533 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2534 return TRUE;
2537 /******************************************************************************
2538 * QueryServiceObjectSecurity [ADVAPI32.@]
2540 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2541 SECURITY_INFORMATION dwSecurityInformation,
2542 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2543 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2545 PACL pACL = NULL;
2547 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2548 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2550 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2552 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2553 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2554 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2555 return TRUE;
2558 /******************************************************************************
2559 * SetServiceObjectSecurity [ADVAPI32.@]
2561 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2562 SECURITY_INFORMATION dwSecurityInformation,
2563 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2565 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2566 return TRUE;
2569 /******************************************************************************
2570 * SetServiceBits [ADVAPI32.@]
2572 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2573 DWORD dwServiceBits,
2574 BOOL bSetBitsOn,
2575 BOOL bUpdateImmediately)
2577 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2578 bSetBitsOn, bUpdateImmediately);
2579 return TRUE;
2582 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2583 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2585 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2586 return 0;
2589 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2590 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2592 service_data *service;
2593 SERVICE_STATUS_HANDLE handle = 0;
2595 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2597 EnterCriticalSection( &service_cs );
2598 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2600 if(!strcmpW(lpServiceName, service->name))
2602 service->handler.handler_ex = lpHandlerProc;
2603 service->context = lpContext;
2604 service->extended = TRUE;
2605 handle = (SERVICE_STATUS_HANDLE)service;
2606 break;
2609 LeaveCriticalSection( &service_cs );
2611 return handle;