push b72af2511d67bded8ece08d825ff0eb4a60c20a6
[wine/hacks.git] / dlls / advapi32 / service.c
bloba698f116b1e1005ce0c78df9e1a826f6a01bcc6d
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
73 typedef struct service_data_t
75 struct list entry;
76 union {
77 LPHANDLER_FUNCTION handler;
78 LPHANDLER_FUNCTION_EX handler_ex;
79 } handler;
80 LPVOID context;
81 SERVICE_STATUS_PROCESS status;
82 HANDLE thread;
83 BOOL unicode : 1;
84 BOOL extended : 1; /* uses handler_ex instead of handler? */
85 union {
86 LPSERVICE_MAIN_FUNCTIONA a;
87 LPSERVICE_MAIN_FUNCTIONW w;
88 } proc;
89 LPWSTR args;
90 WCHAR name[1];
91 } service_data;
93 static CRITICAL_SECTION service_cs;
94 static CRITICAL_SECTION_DEBUG service_cs_debug =
96 0, 0, &service_cs,
97 { &service_cs_debug.ProcessLocksList,
98 &service_cs_debug.ProcessLocksList },
99 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
101 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
103 static struct list service_list = LIST_INIT(service_list);
105 extern HANDLE __wine_make_process_system(void);
107 /******************************************************************************
108 * SC_HANDLEs
111 #define MAX_SERVICE_NAME 256
113 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
115 struct sc_handle;
116 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
118 struct sc_handle
120 SC_HANDLE_TYPE htype;
121 DWORD ref_count;
122 sc_handle_destructor destroy;
125 struct sc_manager /* service control manager handle */
127 struct sc_handle hdr;
128 HKEY hkey; /* handle to services database in the registry */
129 DWORD dwAccess;
132 struct sc_service /* service handle */
134 struct sc_handle hdr;
135 HKEY hkey; /* handle to service entry in the registry (under hkey) */
136 DWORD dwAccess;
137 struct sc_manager *scm; /* pointer to SCM handle */
138 WCHAR name[1];
141 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
142 sc_handle_destructor destroy)
144 struct sc_handle *hdr;
146 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
147 if (hdr)
149 hdr->htype = htype;
150 hdr->ref_count = 1;
151 hdr->destroy = destroy;
153 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
154 return hdr;
157 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
159 struct sc_handle *hdr = (struct sc_handle *) handle;
161 if (!hdr)
162 return NULL;
163 if (hdr->htype != htype)
164 return NULL;
165 return hdr;
168 static void sc_handle_free(struct sc_handle* hdr)
170 if (!hdr)
171 return;
172 if (--hdr->ref_count)
173 return;
174 hdr->destroy(hdr);
175 HeapFree(GetProcessHeap(), 0, hdr);
178 static void sc_handle_destroy_manager(struct sc_handle *handle)
180 struct sc_manager *mgr = (struct sc_manager*) handle;
182 TRACE("destroying SC Manager %p\n", mgr);
183 if (mgr->hkey)
184 RegCloseKey(mgr->hkey);
187 static void sc_handle_destroy_service(struct sc_handle *handle)
189 struct sc_service *svc = (struct sc_service*) handle;
191 TRACE("destroying service %p\n", svc);
192 if (svc->hkey)
193 RegCloseKey(svc->hkey);
194 svc->hkey = NULL;
195 sc_handle_free(&svc->scm->hdr);
196 svc->scm = NULL;
199 /******************************************************************************
200 * String management functions (same behaviour as strdup)
201 * NOTE: the caller of those functions is responsible for calling HeapFree
202 * in order to release the memory allocated by those functions.
204 static inline LPWSTR SERV_dup( LPCSTR str )
206 UINT len;
207 LPWSTR wstr;
209 if( !str )
210 return NULL;
211 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
212 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
213 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
214 return wstr;
217 static inline LPWSTR SERV_dupmulti(LPCSTR str)
219 UINT len = 0, n = 0;
220 LPWSTR wstr;
222 if( !str )
223 return NULL;
224 do {
225 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
226 n += (strlen( &str[n] ) + 1);
227 } while (str[n]);
228 len++;
229 n++;
231 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
232 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
233 return wstr;
236 /******************************************************************************
237 * registry access functions and data
239 static const WCHAR szDisplayName[] = {
240 'D','i','s','p','l','a','y','N','a','m','e', 0 };
241 static const WCHAR szType[] = {'T','y','p','e',0};
242 static const WCHAR szStart[] = {'S','t','a','r','t',0};
243 static const WCHAR szError[] = {
244 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
245 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
246 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
247 static const WCHAR szDependencies[] = {
248 'D','e','p','e','n','d','e','n','c','i','e','s',0};
249 static const WCHAR szDependOnService[] = {
250 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
251 static const WCHAR szObjectName[] = {
252 'O','b','j','e','c','t','N','a','m','e',0};
253 static const WCHAR szTag[] = {
254 'T','a','g',0};
256 struct reg_value {
257 DWORD type;
258 DWORD size;
259 LPCWSTR name;
260 LPCVOID data;
263 static inline void service_set_value( struct reg_value *val,
264 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
266 val->name = name;
267 val->type = type;
268 val->data = data;
269 val->size = size;
272 static inline void service_set_dword( struct reg_value *val,
273 LPCWSTR name, const DWORD *data )
275 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
278 static inline void service_set_string( struct reg_value *val,
279 LPCWSTR name, LPCWSTR string )
281 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
282 service_set_value( val, REG_SZ, name, string, len );
285 static inline void service_set_multi_string( struct reg_value *val,
286 LPCWSTR name, LPCWSTR string )
288 DWORD len = 0;
290 /* determine the length of a double null terminated multi string */
291 do {
292 len += (lstrlenW( &string[ len ] )+1);
293 } while ( string[ len++ ] );
295 len *= sizeof (WCHAR);
296 service_set_value( val, REG_MULTI_SZ, name, string, len );
299 static inline LONG service_write_values( HKEY hKey,
300 const struct reg_value *val, int n )
302 LONG r = ERROR_SUCCESS;
303 int i;
305 for( i=0; i<n; i++ )
307 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
308 (const BYTE*)val[i].data, val[i].size );
309 if( r != ERROR_SUCCESS )
310 break;
312 return r;
315 /******************************************************************************
316 * Service IPC functions
318 static LPWSTR service_get_pipe_name(LPCWSTR service)
320 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
321 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
322 LPWSTR name;
323 DWORD len;
325 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
326 name = HeapAlloc(GetProcessHeap(), 0, len);
327 strcpyW(name, prefix);
328 strcatW(name, service);
329 return name;
332 static HANDLE service_open_pipe(LPCWSTR service)
334 LPWSTR szPipe = service_get_pipe_name( service );
335 HANDLE handle = INVALID_HANDLE_VALUE;
337 do {
338 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
339 0, NULL, OPEN_ALWAYS, 0, NULL);
340 if (handle != INVALID_HANDLE_VALUE)
341 break;
342 if (GetLastError() != ERROR_PIPE_BUSY)
343 break;
344 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
345 HeapFree(GetProcessHeap(), 0, szPipe);
347 return handle;
350 /******************************************************************************
351 * service_get_event_handle
353 static HANDLE service_get_event_handle(LPCWSTR service)
355 static const WCHAR prefix[] = {
356 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
357 LPWSTR name;
358 DWORD len;
359 HANDLE handle;
361 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
362 name = HeapAlloc(GetProcessHeap(), 0, len);
363 strcpyW(name, prefix);
364 strcatW(name, service);
365 handle = CreateEventW(NULL, TRUE, FALSE, name);
366 HeapFree(GetProcessHeap(), 0, name);
367 return handle;
370 /******************************************************************************
371 * service_thread
373 * Call into the main service routine provided by StartServiceCtrlDispatcher.
375 static DWORD WINAPI service_thread(LPVOID arg)
377 service_data *info = arg;
378 LPWSTR str = info->args;
379 DWORD argc = 0, len = 0;
381 TRACE("%p\n", arg);
383 while (str[len])
385 len += strlenW(&str[len]) + 1;
386 argc++;
389 if (!argc)
391 if (info->unicode)
392 info->proc.w(0, NULL);
393 else
394 info->proc.a(0, NULL);
395 return 0;
398 if (info->unicode)
400 LPWSTR *argv, p;
402 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
403 for (argc=0, p=str; *p; p += strlenW(p) + 1)
404 argv[argc++] = p;
405 argv[argc] = NULL;
407 info->proc.w(argc, argv);
408 HeapFree(GetProcessHeap(), 0, argv);
410 else
412 LPSTR strA, *argv, p;
413 DWORD lenA;
415 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
416 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
417 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
419 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
420 for (argc=0, p=strA; *p; p += strlen(p) + 1)
421 argv[argc++] = p;
422 argv[argc] = NULL;
424 info->proc.a(argc, argv);
425 HeapFree(GetProcessHeap(), 0, argv);
426 HeapFree(GetProcessHeap(), 0, strA);
428 return 0;
431 /******************************************************************************
432 * service_handle_start
434 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
436 DWORD read = 0, result = 0;
437 LPWSTR args;
438 BOOL r;
440 TRACE("%p %p %d\n", pipe, service, count);
442 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
443 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
444 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
446 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
447 r, count, read, debugstr_wn(args, count));
448 goto end;
451 if (service->thread)
453 WARN("service is not stopped\n");
454 result = ERROR_SERVICE_ALREADY_RUNNING;
455 goto end;
458 HeapFree(GetProcessHeap(), 0, service->args);
459 service->args = args;
460 args = NULL;
461 service->thread = CreateThread( NULL, 0, service_thread,
462 service, 0, NULL );
464 end:
465 HeapFree(GetProcessHeap(), 0, args);
466 WriteFile( pipe, &result, sizeof result, &read, NULL );
468 return TRUE;
471 /******************************************************************************
472 * service_send_start_message
474 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
476 DWORD i, len, count, result;
477 service_start_info *ssi;
478 LPWSTR p;
479 BOOL r;
481 TRACE("%p %p %d\n", pipe, argv, argc);
483 /* calculate how much space do we need to send the startup info */
484 len = 1;
485 for (i=0; i<argc; i++)
486 len += strlenW(argv[i])+1;
488 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
489 ssi->cmd = WINESERV_STARTINFO;
490 ssi->size = len;
492 /* copy service args into a single buffer*/
493 p = &ssi->str[0];
494 for (i=0; i<argc; i++)
496 strcpyW(p, argv[i]);
497 p += strlenW(p) + 1;
499 *p=0;
501 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
502 if (r)
504 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
505 if (r && result)
507 SetLastError(result);
508 r = FALSE;
512 HeapFree(GetProcessHeap(),0,ssi);
514 return r;
517 /******************************************************************************
518 * service_handle_get_status
520 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
522 DWORD count = 0;
523 TRACE("\n");
524 return WriteFile(pipe, &service->status,
525 sizeof service->status, &count, NULL);
528 /******************************************************************************
529 * service_get_status
531 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
533 DWORD cmd[2], count = 0;
534 BOOL r;
536 cmd[0] = WINESERV_GETSTATUS;
537 cmd[1] = 0;
538 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
539 if (!r || count != sizeof cmd)
541 ERR("service protocol error - failed to write pipe!\n");
542 return r;
544 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
545 if (!r || count != sizeof *status)
546 ERR("service protocol error - failed to read pipe "
547 "r = %d count = %d!\n", r, count);
548 return r;
551 /******************************************************************************
552 * service_send_control
554 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
556 DWORD cmd[2], count = 0;
557 BOOL r;
559 cmd[0] = WINESERV_SENDCONTROL;
560 cmd[1] = dwControl;
561 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
562 if (!r || count != sizeof cmd)
564 ERR("service protocol error - failed to write pipe!\n");
565 return r;
567 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
568 if (!r || count != sizeof *result)
569 ERR("service protocol error - failed to read pipe "
570 "r = %d count = %d!\n", r, count);
571 return r;
574 /******************************************************************************
575 * service_accepts_control
577 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
579 DWORD a = service->status.dwControlsAccepted;
581 switch (dwControl)
583 case SERVICE_CONTROL_INTERROGATE:
584 return TRUE;
585 case SERVICE_CONTROL_STOP:
586 if (a&SERVICE_ACCEPT_STOP)
587 return TRUE;
588 break;
589 case SERVICE_CONTROL_SHUTDOWN:
590 if (a&SERVICE_ACCEPT_SHUTDOWN)
591 return TRUE;
592 break;
593 case SERVICE_CONTROL_PAUSE:
594 case SERVICE_CONTROL_CONTINUE:
595 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
596 return TRUE;
597 break;
598 case SERVICE_CONTROL_PARAMCHANGE:
599 if (a&SERVICE_ACCEPT_PARAMCHANGE)
600 return TRUE;
601 break;
602 case SERVICE_CONTROL_NETBINDADD:
603 case SERVICE_CONTROL_NETBINDREMOVE:
604 case SERVICE_CONTROL_NETBINDENABLE:
605 case SERVICE_CONTROL_NETBINDDISABLE:
606 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
607 return TRUE;
609 if (!service->extended)
610 return FALSE;
611 switch (dwControl)
613 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
614 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
615 return TRUE;
616 break;
617 case SERVICE_CONTROL_POWEREVENT:
618 if (a&SERVICE_ACCEPT_POWEREVENT)
619 return TRUE;
620 break;
621 case SERVICE_CONTROL_SESSIONCHANGE:
622 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
623 return TRUE;
624 break;
626 return FALSE;
629 /******************************************************************************
630 * service_handle_control
632 static BOOL service_handle_control(HANDLE pipe, service_data *service,
633 DWORD dwControl)
635 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
637 TRACE("received control %d\n", dwControl);
639 if (service_accepts_control(service, dwControl))
641 if (service->extended && service->handler.handler_ex)
643 service->handler.handler_ex(dwControl, 0, NULL, service->context);
644 ret = ERROR_SUCCESS;
646 else if (service->handler.handler)
648 service->handler.handler(dwControl);
649 ret = ERROR_SUCCESS;
652 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
655 /******************************************************************************
656 * service_reap_thread
658 static DWORD service_reap_thread(service_data *service)
660 DWORD exitcode = 0;
662 if (!service->thread)
663 return 0;
664 GetExitCodeThread(service->thread, &exitcode);
665 if (exitcode!=STILL_ACTIVE)
667 CloseHandle(service->thread);
668 service->thread = 0;
670 return exitcode;
673 /******************************************************************************
674 * service_control_dispatcher
676 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
678 service_data *service = arg;
679 LPWSTR name;
680 HANDLE pipe, event;
682 TRACE("%p %s\n", service, debugstr_w(service->name));
684 /* create a pipe to talk to the rest of the world with */
685 name = service_get_pipe_name(service->name);
686 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
687 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
688 HeapFree(GetProcessHeap(), 0, name);
690 /* let the process who started us know we've tried to create a pipe */
691 event = service_get_event_handle(service->name);
692 SetEvent(event);
693 CloseHandle(event);
695 if (pipe==INVALID_HANDLE_VALUE)
697 ERR("failed to create pipe for %s, error = %d\n",
698 debugstr_w(service->name), GetLastError());
699 return 0;
702 /* dispatcher loop */
703 while (1)
705 BOOL r;
706 DWORD count, req[2] = {0,0};
708 r = ConnectNamedPipe(pipe, NULL);
709 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
711 ERR("pipe connect failed\n");
712 break;
715 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
716 if (!r || count!=sizeof req)
718 ERR("pipe read failed\n");
719 break;
722 service_reap_thread(service);
724 /* handle the request */
725 switch (req[0])
727 case WINESERV_STARTINFO:
728 service_handle_start(pipe, service, req[1]);
729 break;
730 case WINESERV_GETSTATUS:
731 service_handle_get_status(pipe, service);
732 break;
733 case WINESERV_SENDCONTROL:
734 service_handle_control(pipe, service, req[1]);
735 break;
736 default:
737 ERR("received invalid command %d length %d\n", req[0], req[1]);
740 FlushFileBuffers(pipe);
741 DisconnectNamedPipe(pipe);
744 CloseHandle(pipe);
745 return 1;
748 /******************************************************************************
749 * service_run_threads
751 static BOOL service_run_threads(void)
753 service_data *service;
754 DWORD count, n = 0;
755 HANDLE *handles;
757 EnterCriticalSection( &service_cs );
759 count = list_count( &service_list );
761 TRACE("Starting %d pipe listener threads. Services running as process %d\n", count, GetCurrentProcessId());
763 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
765 handles[n++] = __wine_make_process_system();
767 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
769 service->status.dwProcessId = GetCurrentProcessId();
770 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
771 service, 0, NULL );
773 assert(n == count + 1);
775 LeaveCriticalSection( &service_cs );
777 /* wait for all the threads to pack up and exit */
778 while (n > 1)
780 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
781 if (!ret) /* system process event */
783 TRACE( "last user process exited, shutting down\n" );
784 /* FIXME: we should maybe send a shutdown control to running services */
785 ExitProcess(0);
787 if (ret < MAXIMUM_WAIT_OBJECTS)
789 CloseHandle( handles[ret] );
790 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
791 n--;
793 else break;
796 while (n) CloseHandle( handles[--n] );
797 HeapFree(GetProcessHeap(), 0, handles);
799 return TRUE;
802 /******************************************************************************
803 * StartServiceCtrlDispatcherA [ADVAPI32.@]
805 * See StartServiceCtrlDispatcherW.
807 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
809 service_data *info;
810 DWORD sz, len;
811 BOOL ret = TRUE;
813 TRACE("%p\n", servent);
815 EnterCriticalSection( &service_cs );
816 while (servent->lpServiceName)
818 LPSTR name = servent->lpServiceName;
820 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
821 sz = len*sizeof(WCHAR) + sizeof *info;
822 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
823 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
824 info->proc.a = servent->lpServiceProc;
825 info->unicode = FALSE;
826 list_add_head( &service_list, &info->entry );
827 servent++;
829 LeaveCriticalSection( &service_cs );
831 service_run_threads();
833 return ret;
836 /******************************************************************************
837 * StartServiceCtrlDispatcherW [ADVAPI32.@]
839 * Connects a process containing one or more services to the service control
840 * manager.
842 * PARAMS
843 * servent [I] A list of the service names and service procedures
845 * RETURNS
846 * Success: TRUE.
847 * Failure: FALSE.
849 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
851 service_data *info;
852 DWORD sz, len;
853 BOOL ret = TRUE;
855 TRACE("%p\n", servent);
857 EnterCriticalSection( &service_cs );
858 while (servent->lpServiceName)
860 LPWSTR name = servent->lpServiceName;
862 len = strlenW(name);
863 sz = len*sizeof(WCHAR) + sizeof *info;
864 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
865 strcpyW(info->name, name);
866 info->proc.w = servent->lpServiceProc;
867 info->unicode = TRUE;
868 list_add_head( &service_list, &info->entry );
869 servent++;
871 LeaveCriticalSection( &service_cs );
873 service_run_threads();
875 return ret;
878 /******************************************************************************
879 * LockServiceDatabase [ADVAPI32.@]
881 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
883 HANDLE ret;
885 TRACE("%p\n",hSCManager);
887 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
888 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
890 CloseHandle( ret );
891 ret = NULL;
892 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
895 TRACE("returning %p\n", ret);
897 return ret;
900 /******************************************************************************
901 * UnlockServiceDatabase [ADVAPI32.@]
903 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
905 TRACE("%p\n",ScLock);
907 return CloseHandle( ScLock );
910 /******************************************************************************
911 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
913 SERVICE_STATUS_HANDLE WINAPI
914 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
916 LPWSTR lpServiceNameW;
917 SERVICE_STATUS_HANDLE ret;
919 lpServiceNameW = SERV_dup(lpServiceName);
920 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
921 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
922 return ret;
925 /******************************************************************************
926 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
928 * PARAMS
929 * lpServiceName []
930 * lpfHandler []
932 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
933 LPHANDLER_FUNCTION lpfHandler )
935 service_data *service;
936 SERVICE_STATUS_HANDLE handle = 0;
938 EnterCriticalSection( &service_cs );
939 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
941 if(!strcmpW(lpServiceName, service->name))
943 service->handler.handler = lpfHandler;
944 handle = (SERVICE_STATUS_HANDLE)service;
945 break;
948 LeaveCriticalSection( &service_cs );
949 return handle;
952 /******************************************************************************
953 * SetServiceStatus [ADVAPI32.@]
955 * PARAMS
956 * hService []
957 * lpStatus []
959 BOOL WINAPI
960 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
962 service_data *service;
963 BOOL r = FALSE;
965 TRACE("%p %x %x %x %x %x %x %x\n", hService,
966 lpStatus->dwServiceType, lpStatus->dwCurrentState,
967 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
968 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
969 lpStatus->dwWaitHint);
971 EnterCriticalSection( &service_cs );
972 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
974 if(service == (service_data*)hService)
976 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
977 TRACE("Set service status to %d\n",service->status.dwCurrentState);
978 r = TRUE;
979 break;
982 LeaveCriticalSection( &service_cs );
984 return r;
988 /******************************************************************************
989 * OpenSCManagerA [ADVAPI32.@]
991 * Establish a connection to the service control manager and open its database.
993 * PARAMS
994 * lpMachineName [I] Pointer to machine name string
995 * lpDatabaseName [I] Pointer to database name string
996 * dwDesiredAccess [I] Type of access
998 * RETURNS
999 * Success: A Handle to the service control manager database
1000 * Failure: NULL
1002 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1003 DWORD dwDesiredAccess )
1005 LPWSTR lpMachineNameW, lpDatabaseNameW;
1006 SC_HANDLE ret;
1008 lpMachineNameW = SERV_dup(lpMachineName);
1009 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1010 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1011 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
1012 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
1013 return ret;
1016 /******************************************************************************
1017 * OpenSCManagerW [ADVAPI32.@]
1019 * See OpenSCManagerA.
1021 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1022 DWORD dwDesiredAccess )
1024 struct sc_manager *manager;
1025 HKEY hReg;
1026 LONG r;
1027 DWORD new_mask = dwDesiredAccess;
1029 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1030 debugstr_w(lpDatabaseName), dwDesiredAccess);
1032 if( lpDatabaseName && lpDatabaseName[0] )
1034 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1036 /* noop, all right */
1038 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1040 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1041 return NULL;
1043 else
1045 SetLastError( ERROR_INVALID_NAME );
1046 return NULL;
1050 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1051 sc_handle_destroy_manager );
1052 if (!manager)
1053 return NULL;
1055 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1056 if (r!=ERROR_SUCCESS)
1057 goto error;
1059 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1060 RegCloseKey( hReg );
1061 if (r!=ERROR_SUCCESS)
1062 goto error;
1064 RtlMapGenericMask(&new_mask, &scm_generic);
1065 manager->dwAccess = new_mask;
1066 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1068 return (SC_HANDLE) &manager->hdr;
1070 error:
1071 sc_handle_free( &manager->hdr );
1072 SetLastError( r);
1073 return NULL;
1076 /******************************************************************************
1077 * ControlService [ADVAPI32.@]
1079 * Send a control code to a service.
1081 * PARAMS
1082 * hService [I] Handle of the service control manager database
1083 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1084 * lpServiceStatus [O] Destination for the status of the service, if available
1086 * RETURNS
1087 * Success: TRUE.
1088 * Failure: FALSE.
1090 * BUGS
1091 * Unlike M$' implementation, control requests are not serialized and may be
1092 * processed asynchronously.
1094 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1095 LPSERVICE_STATUS lpServiceStatus )
1097 struct sc_service *hsvc;
1098 BOOL ret = FALSE;
1099 HANDLE handle;
1101 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1103 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1104 if (!hsvc)
1106 SetLastError( ERROR_INVALID_HANDLE );
1107 return FALSE;
1110 ret = QueryServiceStatus(hService, lpServiceStatus);
1111 if (!ret)
1113 ERR("failed to query service status\n");
1114 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1115 return FALSE;
1118 switch (lpServiceStatus->dwCurrentState)
1120 case SERVICE_STOPPED:
1121 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1122 return FALSE;
1123 case SERVICE_START_PENDING:
1124 if (dwControl==SERVICE_CONTROL_STOP)
1125 break;
1126 /* fall thru */
1127 case SERVICE_STOP_PENDING:
1128 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1129 return FALSE;
1132 handle = service_open_pipe(hsvc->name);
1133 if (handle!=INVALID_HANDLE_VALUE)
1135 DWORD result = ERROR_SUCCESS;
1136 ret = service_send_control(handle, dwControl, &result);
1137 CloseHandle(handle);
1138 if (result!=ERROR_SUCCESS)
1140 SetLastError(result);
1141 ret = FALSE;
1145 return ret;
1148 /******************************************************************************
1149 * CloseServiceHandle [ADVAPI32.@]
1151 * Close a handle to a service or the service control manager database.
1153 * PARAMS
1154 * hSCObject [I] Handle to service or service control manager database
1156 * RETURNS
1157 * Success: TRUE
1158 * Failure: FALSE
1160 BOOL WINAPI
1161 CloseServiceHandle( SC_HANDLE hSCObject )
1163 TRACE("%p\n", hSCObject);
1165 sc_handle_free( (struct sc_handle*) hSCObject );
1167 return TRUE;
1171 /******************************************************************************
1172 * OpenServiceA [ADVAPI32.@]
1174 * Open a handle to a service.
1176 * PARAMS
1177 * hSCManager [I] Handle of the service control manager database
1178 * lpServiceName [I] Name of the service to open
1179 * dwDesiredAccess [I] Access required to the service
1181 * RETURNS
1182 * Success: Handle to the service
1183 * Failure: NULL
1185 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1186 DWORD dwDesiredAccess )
1188 LPWSTR lpServiceNameW;
1189 SC_HANDLE ret;
1191 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1193 lpServiceNameW = SERV_dup(lpServiceName);
1194 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1195 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1196 return ret;
1200 /******************************************************************************
1201 * OpenServiceW [ADVAPI32.@]
1203 * See OpenServiceA.
1205 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1206 DWORD dwDesiredAccess)
1208 struct sc_manager *hscm;
1209 struct sc_service *hsvc;
1210 HKEY hKey;
1211 long r;
1212 DWORD len;
1213 DWORD new_mask = dwDesiredAccess;
1215 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1217 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1218 if (!hscm)
1220 SetLastError( ERROR_INVALID_HANDLE );
1221 return FALSE;
1224 if (!lpServiceName)
1226 SetLastError(ERROR_INVALID_ADDRESS);
1227 return NULL;
1230 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1231 if (r!=ERROR_SUCCESS)
1233 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1234 return NULL;
1237 len = strlenW(lpServiceName)+1;
1238 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1239 sizeof (struct sc_service) + len*sizeof(WCHAR),
1240 sc_handle_destroy_service );
1241 if (!hsvc)
1243 RegCloseKey(hKey);
1244 return NULL;
1246 strcpyW( hsvc->name, lpServiceName );
1247 hsvc->hkey = hKey;
1249 RtlMapGenericMask(&new_mask, &svc_generic);
1250 hsvc->dwAccess = new_mask;
1252 /* add reference to SCM handle */
1253 hscm->hdr.ref_count++;
1254 hsvc->scm = hscm;
1256 TRACE("returning %p\n",hsvc);
1258 return (SC_HANDLE) &hsvc->hdr;
1261 /******************************************************************************
1262 * CreateServiceW [ADVAPI32.@]
1264 SC_HANDLE WINAPI
1265 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1266 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1267 DWORD dwServiceType, DWORD dwStartType,
1268 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1269 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1270 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1271 LPCWSTR lpPassword )
1273 struct sc_manager *hscm;
1274 struct sc_service *hsvc = NULL;
1275 HKEY hKey;
1276 LONG r;
1277 DWORD dp, len;
1278 struct reg_value val[10];
1279 int n = 0;
1280 DWORD new_mask = dwDesiredAccess;
1281 DWORD index = 0;
1282 WCHAR buffer[MAX_PATH];
1283 BOOL displayname_exists = FALSE;
1285 TRACE("%p %s %s\n", hSCManager,
1286 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1288 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1289 if (!hscm)
1291 SetLastError( ERROR_INVALID_HANDLE );
1292 return NULL;
1295 if (!lpServiceName || !lpBinaryPathName)
1297 SetLastError(ERROR_INVALID_ADDRESS);
1298 return NULL;
1301 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1303 SetLastError(ERROR_ACCESS_DENIED);
1304 return NULL;
1307 if (!lpServiceName[0])
1309 SetLastError(ERROR_INVALID_NAME);
1310 return NULL;
1313 if (!lpBinaryPathName[0])
1315 SetLastError(ERROR_INVALID_PARAMETER);
1316 return NULL;
1319 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1320 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1321 * runs under the LocalSystem account)
1323 switch (dwServiceType)
1325 case SERVICE_KERNEL_DRIVER:
1326 case SERVICE_FILE_SYSTEM_DRIVER:
1327 case SERVICE_WIN32_OWN_PROCESS:
1328 case SERVICE_WIN32_SHARE_PROCESS:
1329 /* No problem */
1330 break;
1331 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1332 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1333 /* FIXME : Do we need a more thorough check? */
1334 if (lpServiceStartName)
1336 SetLastError(ERROR_INVALID_PARAMETER);
1337 return NULL;
1339 break;
1340 default:
1341 SetLastError(ERROR_INVALID_PARAMETER);
1342 return NULL;
1345 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1346 if (dwStartType > SERVICE_DISABLED)
1348 SetLastError(ERROR_INVALID_PARAMETER);
1349 return NULL;
1352 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1353 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1354 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1356 SetLastError(ERROR_INVALID_PARAMETER);
1357 return NULL;
1360 /* Loop through the registry to check if the service already exists and to
1361 * check if we can use the given displayname.
1362 * FIXME: Should we use EnumServicesStatusEx?
1364 len = sizeof(buffer);
1365 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1367 HKEY service_key;
1369 /* The service already exists, so bail out */
1370 if(!lstrcmpiW(lpServiceName, buffer))
1372 SetLastError(ERROR_SERVICE_EXISTS);
1373 return NULL;
1376 /* The given displayname matches the found servicename. We don't bail out
1377 * as servicename is checked before a duplicate displayname
1379 if(!lstrcmpiW(lpDisplayName, buffer))
1380 displayname_exists = TRUE;
1382 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1384 WCHAR name[MAX_PATH];
1385 DWORD size = sizeof(name);
1387 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1389 /* The given displayname matches the found displayname */
1390 if (!lstrcmpiW(lpDisplayName, name))
1391 displayname_exists = TRUE;
1393 RegCloseKey(service_key);
1395 index++;
1396 len = sizeof(buffer);
1399 if (lpDisplayName && displayname_exists)
1401 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1402 return NULL;
1405 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1406 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1407 if (r!=ERROR_SUCCESS)
1409 /* FIXME: Should we set an error? */
1410 return NULL;
1413 if( lpDisplayName )
1414 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1416 service_set_dword( &val[n++], szType, &dwServiceType );
1417 service_set_dword( &val[n++], szStart, &dwStartType );
1418 service_set_dword( &val[n++], szError, &dwErrorControl );
1420 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1422 if( lpLoadOrderGroup )
1423 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1425 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1426 * There is no such key as what szDependencies refers to */
1427 if( lpDependencies )
1428 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1430 if( lpPassword )
1431 FIXME("Don't know how to add a Password for a service.\n");
1433 if( lpServiceStartName )
1434 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1436 r = service_write_values( hKey, val, n );
1437 if( r != ERROR_SUCCESS )
1438 goto error;
1440 len = strlenW(lpServiceName)+1;
1441 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1442 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1443 if( !hsvc )
1444 goto error;
1445 lstrcpyW( hsvc->name, lpServiceName );
1446 hsvc->hkey = hKey;
1448 RtlMapGenericMask(&new_mask, &svc_generic);
1449 hsvc->dwAccess = new_mask;
1451 hsvc->scm = hscm;
1452 hscm->hdr.ref_count++;
1454 return (SC_HANDLE) &hsvc->hdr;
1456 error:
1457 RegCloseKey( hKey );
1458 return NULL;
1462 /******************************************************************************
1463 * CreateServiceA [ADVAPI32.@]
1465 SC_HANDLE WINAPI
1466 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1467 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1468 DWORD dwServiceType, DWORD dwStartType,
1469 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1470 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1471 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1472 LPCSTR lpPassword )
1474 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1475 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1476 SC_HANDLE r;
1478 TRACE("%p %s %s\n", hSCManager,
1479 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1481 lpServiceNameW = SERV_dup( lpServiceName );
1482 lpDisplayNameW = SERV_dup( lpDisplayName );
1483 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1484 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1485 lpDependenciesW = SERV_dupmulti( lpDependencies );
1486 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1487 lpPasswordW = SERV_dup( lpPassword );
1489 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1490 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1491 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1492 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1494 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1495 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1496 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1497 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1498 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1499 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1500 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1502 return r;
1506 /******************************************************************************
1507 * DeleteService [ADVAPI32.@]
1509 * Delete a service from the service control manager database.
1511 * PARAMS
1512 * hService [I] Handle of the service to delete
1514 * RETURNS
1515 * Success: TRUE
1516 * Failure: FALSE
1518 BOOL WINAPI DeleteService( SC_HANDLE hService )
1520 struct sc_service *hsvc;
1522 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1523 if (!hsvc)
1525 SetLastError( ERROR_INVALID_HANDLE );
1526 return FALSE;
1529 if (!(hsvc->dwAccess & DELETE))
1531 SetLastError(ERROR_ACCESS_DENIED);
1532 return FALSE;
1535 /* Close the key to the service */
1536 RegCloseKey(hsvc->hkey);
1538 /* Delete the service under the Service Control Manager key */
1539 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1541 hsvc->hkey = NULL;
1543 return TRUE;
1547 /******************************************************************************
1548 * StartServiceA [ADVAPI32.@]
1550 * Start a service
1552 * PARAMS
1553 * hService [I] Handle of service
1554 * dwNumServiceArgs [I] Number of arguments
1555 * lpServiceArgVectors [I] Address of array of argument strings
1557 * NOTES
1558 * - NT implements this function using an obscure RPC call.
1559 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1560 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1561 * - This will only work for shared address space. How should the service
1562 * args be transferred when address spaces are separated?
1563 * - Can only start one service at a time.
1564 * - Has no concept of privilege.
1566 * RETURNS
1567 * Success: TRUE.
1568 * Failure: FALSE
1570 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1571 LPCSTR *lpServiceArgVectors )
1573 LPWSTR *lpwstr=NULL;
1574 unsigned int i;
1575 BOOL r;
1577 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1579 if (dwNumServiceArgs)
1580 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1581 dwNumServiceArgs*sizeof(LPWSTR) );
1583 for(i=0; i<dwNumServiceArgs; i++)
1584 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1586 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1588 if (dwNumServiceArgs)
1590 for(i=0; i<dwNumServiceArgs; i++)
1591 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1592 HeapFree(GetProcessHeap(), 0, lpwstr);
1595 return r;
1598 /******************************************************************************
1599 * service_start_process [INTERNAL]
1601 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1603 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1604 PROCESS_INFORMATION pi;
1605 STARTUPINFOW si;
1606 LPWSTR path = NULL, str;
1607 DWORD type, size, ret, svc_type;
1608 HANDLE handles[2];
1609 BOOL r;
1611 size = sizeof(svc_type);
1612 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1613 svc_type = 0;
1615 if (svc_type == SERVICE_KERNEL_DRIVER)
1617 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1618 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1620 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1621 GetSystemDirectoryW( path, len );
1622 lstrcatW( path, winedeviceW );
1623 lstrcatW( path, hsvc->name );
1625 else
1627 /* read the executable path from the registry */
1628 size = 0;
1629 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1630 if (ret!=ERROR_SUCCESS)
1631 return FALSE;
1632 str = HeapAlloc(GetProcessHeap(),0,size);
1633 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1634 if (ret==ERROR_SUCCESS)
1636 size = ExpandEnvironmentStringsW(str,NULL,0);
1637 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1638 ExpandEnvironmentStringsW(str,path,size);
1640 HeapFree(GetProcessHeap(),0,str);
1641 if (!path)
1642 return FALSE;
1645 /* wait for the process to start and set an event or terminate */
1646 handles[0] = service_get_event_handle( hsvc->name );
1647 ZeroMemory(&si, sizeof(STARTUPINFOW));
1648 si.cb = sizeof(STARTUPINFOW);
1649 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1650 if (r)
1652 if (ppid) *ppid = pi.dwProcessId;
1654 handles[1] = pi.hProcess;
1655 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1656 if(ret != WAIT_OBJECT_0)
1658 SetLastError(ERROR_IO_PENDING);
1659 r = FALSE;
1662 CloseHandle( pi.hThread );
1663 CloseHandle( pi.hProcess );
1665 CloseHandle( handles[0] );
1666 HeapFree(GetProcessHeap(),0,path);
1667 return r;
1670 static BOOL service_wait_for_startup(SC_HANDLE hService)
1672 DWORD i;
1673 SERVICE_STATUS status;
1674 BOOL r = FALSE;
1676 TRACE("%p\n", hService);
1678 for (i=0; i<30; i++)
1680 status.dwCurrentState = 0;
1681 r = QueryServiceStatus(hService, &status);
1682 if (!r)
1683 break;
1684 if (status.dwCurrentState == SERVICE_RUNNING)
1686 TRACE("Service started successfully\n");
1687 break;
1689 r = FALSE;
1690 Sleep(1000);
1692 return r;
1695 /******************************************************************************
1696 * StartServiceW [ADVAPI32.@]
1698 * See StartServiceA.
1700 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1701 LPCWSTR *lpServiceArgVectors)
1703 struct sc_service *hsvc;
1704 BOOL r = FALSE;
1705 SC_LOCK hLock;
1706 HANDLE handle = INVALID_HANDLE_VALUE;
1708 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1710 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1711 if (!hsvc)
1713 SetLastError(ERROR_INVALID_HANDLE);
1714 return r;
1717 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1718 if (!hLock)
1719 return r;
1721 handle = service_open_pipe(hsvc->name);
1722 if (handle==INVALID_HANDLE_VALUE)
1724 /* start the service process */
1725 if (service_start_process(hsvc, NULL))
1726 handle = service_open_pipe(hsvc->name);
1729 if (handle != INVALID_HANDLE_VALUE)
1731 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1732 CloseHandle(handle);
1735 UnlockServiceDatabase( hLock );
1737 TRACE("returning %d\n", r);
1739 if (r)
1740 service_wait_for_startup(hService);
1742 return r;
1745 /******************************************************************************
1746 * QueryServiceStatus [ADVAPI32.@]
1748 * PARAMS
1749 * hService [I] Handle to service to get information about
1750 * lpservicestatus [O] buffer to receive the status information for the service
1753 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1754 LPSERVICE_STATUS lpservicestatus)
1756 SERVICE_STATUS_PROCESS SvcStatusData;
1757 BOOL ret;
1759 TRACE("%p %p\n", hService, lpservicestatus);
1761 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1762 sizeof(SERVICE_STATUS_PROCESS), NULL);
1763 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1764 return ret;
1768 /******************************************************************************
1769 * QueryServiceStatusEx [ADVAPI32.@]
1771 * Get information about a service.
1773 * PARAMS
1774 * hService [I] Handle to service to get information about
1775 * InfoLevel [I] Level of information to get
1776 * lpBuffer [O] Destination for requested information
1777 * cbBufSize [I] Size of lpBuffer in bytes
1778 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1780 * RETURNS
1781 * Success: TRUE
1782 * FAILURE: FALSE
1784 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1785 LPBYTE lpBuffer, DWORD cbBufSize,
1786 LPDWORD pcbBytesNeeded)
1788 struct sc_service *hsvc;
1789 DWORD size, type, val;
1790 HANDLE pipe;
1791 LONG r;
1792 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1794 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1796 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1798 SetLastError( ERROR_INVALID_LEVEL);
1799 return FALSE;
1802 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1803 if (pSvcStatusData == NULL)
1805 SetLastError( ERROR_INVALID_PARAMETER);
1806 return FALSE;
1809 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1811 if( pcbBytesNeeded != NULL)
1812 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1814 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1815 return FALSE;
1818 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1819 if (!hsvc)
1821 SetLastError( ERROR_INVALID_HANDLE );
1822 return FALSE;
1825 pipe = service_open_pipe(hsvc->name);
1826 if (pipe != INVALID_HANDLE_VALUE)
1828 r = service_get_status(pipe, pSvcStatusData);
1829 CloseHandle(pipe);
1830 if (r)
1831 return TRUE;
1834 TRACE("Failed to read service status\n");
1836 /* read the service type from the registry */
1837 size = sizeof(val);
1838 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1839 if (r != ERROR_SUCCESS || type != REG_DWORD)
1840 val = 0;
1842 pSvcStatusData->dwServiceType = val;
1843 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1844 pSvcStatusData->dwControlsAccepted = 0;
1845 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1846 pSvcStatusData->dwServiceSpecificExitCode = 0;
1847 pSvcStatusData->dwCheckPoint = 0;
1848 pSvcStatusData->dwWaitHint = 0;
1850 return TRUE;
1853 /******************************************************************************
1854 * QueryServiceConfigA [ADVAPI32.@]
1856 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1857 DWORD size, LPDWORD needed )
1859 DWORD n;
1860 LPSTR p, buffer;
1861 BOOL ret;
1862 QUERY_SERVICE_CONFIGW *configW;
1864 TRACE("%p %p %d %p\n", hService, config, size, needed);
1866 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1868 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1869 return FALSE;
1871 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1872 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1873 if (!ret) goto done;
1875 config->dwServiceType = configW->dwServiceType;
1876 config->dwStartType = configW->dwStartType;
1877 config->dwErrorControl = configW->dwErrorControl;
1878 config->lpBinaryPathName = NULL;
1879 config->lpLoadOrderGroup = NULL;
1880 config->dwTagId = configW->dwTagId;
1881 config->lpDependencies = NULL;
1882 config->lpServiceStartName = NULL;
1883 config->lpDisplayName = NULL;
1885 p = (LPSTR)(config + 1);
1886 n = size - sizeof(*config);
1887 ret = FALSE;
1889 #define MAP_STR(str) \
1890 do { \
1891 if (configW->str) \
1893 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1894 if (!sz) goto done; \
1895 config->str = p; \
1896 p += sz; \
1897 n -= sz; \
1899 } while (0)
1901 MAP_STR( lpBinaryPathName );
1902 MAP_STR( lpLoadOrderGroup );
1903 MAP_STR( lpDependencies );
1904 MAP_STR( lpServiceStartName );
1905 MAP_STR( lpDisplayName );
1906 #undef MAP_STR
1908 *needed = p - (LPSTR)config;
1909 ret = TRUE;
1911 done:
1912 HeapFree( GetProcessHeap(), 0, buffer );
1913 return ret;
1916 /******************************************************************************
1917 * QueryServiceConfigW [ADVAPI32.@]
1919 BOOL WINAPI
1920 QueryServiceConfigW( SC_HANDLE hService,
1921 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1922 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1924 WCHAR str_buffer[ MAX_PATH ];
1925 LONG r;
1926 DWORD type, val, sz, total, n;
1927 LPBYTE p;
1928 HKEY hKey;
1929 struct sc_service *hsvc;
1931 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1932 cbBufSize, pcbBytesNeeded);
1934 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1935 if (!hsvc)
1937 SetLastError( ERROR_INVALID_HANDLE );
1938 return FALSE;
1940 hKey = hsvc->hkey;
1942 /* TODO: Check which members are mandatory and what the registry types
1943 * should be. This should of course also be tested when a service is
1944 * created.
1947 /* calculate the size required first */
1948 total = sizeof (QUERY_SERVICE_CONFIGW);
1950 sz = sizeof(str_buffer);
1951 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1952 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1954 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1955 if( 0 == sz ) return FALSE;
1957 total += sizeof(WCHAR) * sz;
1959 else
1961 /* FIXME: set last error */
1962 return FALSE;
1965 sz = 0;
1966 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1967 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1968 total += sz;
1969 else
1970 total += sizeof(WCHAR);
1972 sz = 0;
1973 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1974 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1975 total += sz;
1976 else
1977 total += sizeof(WCHAR);
1979 sz = 0;
1980 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1981 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1982 total += sz;
1983 else
1984 total += sizeof(WCHAR);
1986 sz = 0;
1987 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1988 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1989 total += sz;
1990 else
1991 total += sizeof(WCHAR);
1993 *pcbBytesNeeded = total;
1995 /* if there's not enough memory, return an error */
1996 if( total > cbBufSize )
1998 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1999 return FALSE;
2002 ZeroMemory( lpServiceConfig, total );
2004 sz = sizeof val;
2005 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2006 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2007 lpServiceConfig->dwServiceType = val;
2009 sz = sizeof val;
2010 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2011 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2012 lpServiceConfig->dwStartType = val;
2014 sz = sizeof val;
2015 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2016 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2017 lpServiceConfig->dwErrorControl = val;
2019 sz = sizeof val;
2020 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2021 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2022 lpServiceConfig->dwTagId = val;
2024 /* now do the strings */
2025 p = (LPBYTE) &lpServiceConfig[1];
2026 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2028 sz = sizeof(str_buffer);
2029 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2030 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2032 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2033 sz *= sizeof(WCHAR);
2034 if( 0 == sz || sz > n ) return FALSE;
2036 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2037 p += sz;
2038 n -= sz;
2040 else
2042 /* FIXME: set last error */
2043 return FALSE;
2046 sz = n;
2047 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2048 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2049 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2051 p += sz;
2052 n -= sz;
2054 else
2056 *(WCHAR *) p = 0;
2057 p += sizeof(WCHAR);
2058 n -= sizeof(WCHAR);
2061 sz = n;
2062 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2063 lpServiceConfig->lpDependencies = (LPWSTR) p;
2064 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2066 p += sz;
2067 n -= sz;
2069 else
2071 *(WCHAR *) p = 0;
2072 p += sizeof(WCHAR);
2073 n -= sizeof(WCHAR);
2076 sz = n;
2077 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2078 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2079 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2081 p += sz;
2082 n -= sz;
2084 else
2086 *(WCHAR *) p = 0;
2087 p += sizeof(WCHAR);
2088 n -= sizeof(WCHAR);
2091 sz = n;
2092 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2093 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2094 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2096 p += sz;
2097 n -= sz;
2099 else
2101 *(WCHAR *) p = 0;
2102 p += sizeof(WCHAR);
2103 n -= sizeof(WCHAR);
2106 if( n < 0 )
2107 ERR("Buffer overflow!\n");
2109 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2110 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2111 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2112 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2113 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2115 return TRUE;
2118 /******************************************************************************
2119 * EnumServicesStatusA [ADVAPI32.@]
2121 BOOL WINAPI
2122 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2123 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2124 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2125 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2127 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2128 dwServiceType, dwServiceState, lpServices, cbBufSize,
2129 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2130 SetLastError (ERROR_ACCESS_DENIED);
2131 return FALSE;
2134 /******************************************************************************
2135 * EnumServicesStatusW [ADVAPI32.@]
2137 BOOL WINAPI
2138 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2139 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2140 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2141 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2143 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2144 dwServiceType, dwServiceState, lpServices, cbBufSize,
2145 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2146 SetLastError (ERROR_ACCESS_DENIED);
2147 return FALSE;
2150 /******************************************************************************
2151 * EnumServicesStatusExA [ADVAPI32.@]
2153 BOOL WINAPI
2154 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2155 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2156 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2158 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2159 dwServiceType, dwServiceState, lpServices, cbBufSize,
2160 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2161 SetLastError (ERROR_ACCESS_DENIED);
2162 return FALSE;
2165 /******************************************************************************
2166 * EnumServicesStatusExW [ADVAPI32.@]
2168 BOOL WINAPI
2169 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2170 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2171 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2173 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2174 dwServiceType, dwServiceState, lpServices, cbBufSize,
2175 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2176 SetLastError (ERROR_ACCESS_DENIED);
2177 return FALSE;
2180 /******************************************************************************
2181 * GetServiceKeyNameA [ADVAPI32.@]
2183 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2184 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2186 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2187 return FALSE;
2190 /******************************************************************************
2191 * GetServiceKeyNameW [ADVAPI32.@]
2193 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2194 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2196 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2197 return FALSE;
2200 /******************************************************************************
2201 * QueryServiceLockStatusA [ADVAPI32.@]
2203 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2204 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2205 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2207 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2209 return FALSE;
2212 /******************************************************************************
2213 * QueryServiceLockStatusW [ADVAPI32.@]
2215 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2216 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2217 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2219 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2221 return FALSE;
2224 /******************************************************************************
2225 * GetServiceDisplayNameA [ADVAPI32.@]
2227 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2228 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2230 LPWSTR lpServiceNameW, lpDisplayNameW = NULL;
2231 DWORD size, sizeW, GLE;
2232 BOOL ret;
2234 TRACE("%p %s %p %p\n", hSCManager,
2235 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2237 lpServiceNameW = SERV_dup(lpServiceName);
2238 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2240 size = sizeW = *lpcchBuffer;
2241 ret = GetServiceDisplayNameW(hSCManager, lpServiceNameW,
2242 lpDisplayName ? lpDisplayNameW : NULL,
2243 &sizeW);
2244 /* Last error will be set by GetServiceDisplayNameW and must be preserved */
2245 GLE = GetLastError();
2247 if (!lpDisplayName && *lpcchBuffer && !ret && (GLE == ERROR_INSUFFICIENT_BUFFER))
2249 /* Request for buffersize.
2251 * Only set the size for ERROR_INSUFFICIENT_BUFFER
2253 size = sizeW * 2;
2255 else if (lpDisplayName && *lpcchBuffer && !ret)
2257 /* Request for displayname.
2259 * size only has to be set if this fails
2261 size = sizeW * 2;
2264 WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2265 *lpcchBuffer, NULL, NULL );
2267 *lpcchBuffer = size;
2269 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2270 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2272 SetLastError(GLE);
2273 return ret;
2276 /******************************************************************************
2277 * GetServiceDisplayNameW [ADVAPI32.@]
2279 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2280 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2282 struct sc_manager *hscm;
2283 DWORD type, size;
2284 LONG ret;
2286 TRACE("%p %s %p %p\n", hSCManager,
2287 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2289 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2290 if (!hscm)
2292 SetLastError(ERROR_INVALID_HANDLE);
2293 return FALSE;
2296 if (!lpServiceName)
2298 SetLastError(ERROR_INVALID_ADDRESS);
2299 return FALSE;
2302 size = *lpcchBuffer * sizeof(WCHAR);
2303 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2304 if (!ret && !lpDisplayName && size)
2305 ret = ERROR_MORE_DATA;
2307 if (ret)
2309 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2311 if (ret == ERROR_MORE_DATA)
2313 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2314 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2316 else if (ret == ERROR_FILE_NOT_FOUND)
2318 HKEY hkey;
2320 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2322 INT len = lstrlenW(lpServiceName);
2323 BOOL r = FALSE;
2325 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2326 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2327 else if (lpDisplayName && *lpcchBuffer)
2329 /* No displayname, but the service exists and the buffer
2330 * is big enough. We should return the servicename.
2332 lstrcpyW(lpDisplayName, lpServiceName);
2333 r = TRUE;
2336 *lpcchBuffer = len;
2337 RegCloseKey(hkey);
2338 return r;
2340 else
2341 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2343 else
2344 SetLastError(ret);
2345 return FALSE;
2348 /* Always return the correct needed size on success */
2349 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2351 return TRUE;
2354 /******************************************************************************
2355 * ChangeServiceConfigW [ADVAPI32.@]
2357 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2358 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2359 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2360 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2362 struct reg_value val[10];
2363 struct sc_service *hsvc;
2364 DWORD r = ERROR_SUCCESS;
2365 HKEY hKey;
2366 int n = 0;
2368 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2369 hService, dwServiceType, dwStartType, dwErrorControl,
2370 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2371 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2372 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2374 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2375 if (!hsvc)
2377 SetLastError( ERROR_INVALID_HANDLE );
2378 return FALSE;
2380 hKey = hsvc->hkey;
2382 if( dwServiceType != SERVICE_NO_CHANGE )
2383 service_set_dword( &val[n++], szType, &dwServiceType );
2385 if( dwStartType != SERVICE_NO_CHANGE )
2386 service_set_dword( &val[n++], szStart, &dwStartType );
2388 if( dwErrorControl != SERVICE_NO_CHANGE )
2389 service_set_dword( &val[n++], szError, &dwErrorControl );
2391 if( lpBinaryPathName )
2392 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2394 if( lpLoadOrderGroup )
2395 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2397 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2398 * There is no such key as what szDependencies refers to */
2399 if( lpDependencies )
2400 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2402 if( lpPassword )
2403 FIXME("ignoring password\n");
2405 if( lpServiceStartName )
2406 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2408 r = service_write_values( hsvc->hkey, val, n );
2410 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2413 /******************************************************************************
2414 * ChangeServiceConfigA [ADVAPI32.@]
2416 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2417 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2418 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2419 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2421 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2422 LPWSTR wServiceStartName, wPassword, wDisplayName;
2423 BOOL r;
2425 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2426 hService, dwServiceType, dwStartType, dwErrorControl,
2427 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2428 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2429 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2431 wBinaryPathName = SERV_dup( lpBinaryPathName );
2432 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2433 wDependencies = SERV_dupmulti( lpDependencies );
2434 wServiceStartName = SERV_dup( lpServiceStartName );
2435 wPassword = SERV_dup( lpPassword );
2436 wDisplayName = SERV_dup( lpDisplayName );
2438 r = ChangeServiceConfigW( hService, dwServiceType,
2439 dwStartType, dwErrorControl, wBinaryPathName,
2440 wLoadOrderGroup, lpdwTagId, wDependencies,
2441 wServiceStartName, wPassword, wDisplayName);
2443 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2444 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2445 HeapFree( GetProcessHeap(), 0, wDependencies );
2446 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2447 HeapFree( GetProcessHeap(), 0, wPassword );
2448 HeapFree( GetProcessHeap(), 0, wDisplayName );
2450 return r;
2453 /******************************************************************************
2454 * ChangeServiceConfig2A [ADVAPI32.@]
2456 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2457 LPVOID lpInfo)
2459 BOOL r = FALSE;
2461 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2463 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2465 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2466 SERVICE_DESCRIPTIONW sdw;
2468 sdw.lpDescription = SERV_dup( sd->lpDescription );
2470 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2472 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2474 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2476 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2477 SERVICE_FAILURE_ACTIONSW faw;
2479 faw.dwResetPeriod = fa->dwResetPeriod;
2480 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2481 faw.lpCommand = SERV_dup( fa->lpCommand );
2482 faw.cActions = fa->cActions;
2483 faw.lpsaActions = fa->lpsaActions;
2485 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2487 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2488 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2490 else
2491 SetLastError( ERROR_INVALID_PARAMETER );
2493 return r;
2496 /******************************************************************************
2497 * ChangeServiceConfig2W [ADVAPI32.@]
2499 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2500 LPVOID lpInfo)
2502 HKEY hKey;
2503 struct sc_service *hsvc;
2505 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2506 if (!hsvc)
2508 SetLastError( ERROR_INVALID_HANDLE );
2509 return FALSE;
2511 hKey = hsvc->hkey;
2513 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2515 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2516 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2517 if (sd->lpDescription)
2519 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2520 if (sd->lpDescription[0] == 0)
2521 RegDeleteValueW(hKey,szDescription);
2522 else
2523 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2524 (LPVOID)sd->lpDescription,
2525 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2528 else
2529 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2530 return TRUE;
2533 /******************************************************************************
2534 * QueryServiceObjectSecurity [ADVAPI32.@]
2536 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2537 SECURITY_INFORMATION dwSecurityInformation,
2538 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2539 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2541 PACL pACL = NULL;
2543 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2544 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2546 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2548 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2549 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2550 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2551 return TRUE;
2554 /******************************************************************************
2555 * SetServiceObjectSecurity [ADVAPI32.@]
2557 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2558 SECURITY_INFORMATION dwSecurityInformation,
2559 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2561 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2562 return TRUE;
2565 /******************************************************************************
2566 * SetServiceBits [ADVAPI32.@]
2568 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2569 DWORD dwServiceBits,
2570 BOOL bSetBitsOn,
2571 BOOL bUpdateImmediately)
2573 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2574 bSetBitsOn, bUpdateImmediately);
2575 return TRUE;
2578 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2579 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2581 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2582 return 0;
2585 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2586 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2588 service_data *service;
2589 SERVICE_STATUS_HANDLE handle = 0;
2591 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2593 EnterCriticalSection( &service_cs );
2594 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2596 if(!strcmpW(lpServiceName, service->name))
2598 service->handler.handler_ex = lpHandlerProc;
2599 service->context = lpContext;
2600 service->extended = TRUE;
2601 handle = (SERVICE_STATUS_HANDLE)service;
2602 break;
2605 LeaveCriticalSection( &service_cs );
2607 return handle;