user32/tests: Remove an unneeded cast.
[wine/testsucceed.git] / dlls / advapi32 / service.c
blob3ebcfe470e5bdc4f2233e6c256208067c61d7a49
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 szLocalSystem[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
43 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
44 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
45 'S','e','r','v','i','c','e','s',0 };
46 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
47 'L','O','C','K',0};
49 static const GENERIC_MAPPING scm_generic = {
50 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
51 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
52 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
53 SC_MANAGER_ALL_ACCESS
56 static const GENERIC_MAPPING svc_generic = {
57 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
58 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
59 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
60 SERVICE_ALL_ACCESS
63 typedef struct service_start_info_t
65 DWORD cmd;
66 DWORD size;
67 WCHAR str[1];
68 } service_start_info;
70 #define WINESERV_STARTINFO 1
71 #define WINESERV_GETSTATUS 2
72 #define WINESERV_SENDCONTROL 3
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 (same behaviour as strdup)
202 * NOTE: the caller of those functions is responsible for calling HeapFree
203 * in order to release the memory allocated by those functions.
205 static inline LPWSTR SERV_dup( LPCSTR str )
207 UINT len;
208 LPWSTR wstr;
210 if( !str )
211 return NULL;
212 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
213 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
214 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
215 return wstr;
218 static inline LPWSTR SERV_dupmulti(LPCSTR str)
220 UINT len = 0, n = 0;
221 LPWSTR wstr;
223 if( !str )
224 return NULL;
225 do {
226 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
227 n += (strlen( &str[n] ) + 1);
228 } while (str[n]);
229 len++;
230 n++;
232 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
233 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
234 return wstr;
237 /******************************************************************************
238 * registry access functions and data
240 static const WCHAR szDisplayName[] = {
241 'D','i','s','p','l','a','y','N','a','m','e', 0 };
242 static const WCHAR szType[] = {'T','y','p','e',0};
243 static const WCHAR szStart[] = {'S','t','a','r','t',0};
244 static const WCHAR szError[] = {
245 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
246 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
247 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
248 static const WCHAR szDependencies[] = {
249 'D','e','p','e','n','d','e','n','c','i','e','s',0};
250 static const WCHAR szDependOnService[] = {
251 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
252 static const WCHAR szObjectName[] = {
253 'O','b','j','e','c','t','N','a','m','e',0};
254 static const WCHAR szTag[] = {
255 'T','a','g',0};
257 struct reg_value {
258 DWORD type;
259 DWORD size;
260 LPCWSTR name;
261 LPCVOID data;
264 static inline void service_set_value( struct reg_value *val,
265 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
267 val->name = name;
268 val->type = type;
269 val->data = data;
270 val->size = size;
273 static inline void service_set_dword( struct reg_value *val,
274 LPCWSTR name, const DWORD *data )
276 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
279 static inline void service_set_string( struct reg_value *val,
280 LPCWSTR name, LPCWSTR string )
282 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
283 service_set_value( val, REG_SZ, name, string, len );
286 static inline void service_set_multi_string( struct reg_value *val,
287 LPCWSTR name, LPCWSTR string )
289 DWORD len = 0;
291 /* determine the length of a double null terminated multi string */
292 do {
293 len += (lstrlenW( &string[ len ] )+1);
294 } while ( string[ len++ ] );
296 len *= sizeof (WCHAR);
297 service_set_value( val, REG_MULTI_SZ, name, string, len );
300 static inline LONG service_write_values( HKEY hKey,
301 const struct reg_value *val, int n )
303 LONG r = ERROR_SUCCESS;
304 int i;
306 for( i=0; i<n; i++ )
308 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
309 (const BYTE*)val[i].data, val[i].size );
310 if( r != ERROR_SUCCESS )
311 break;
313 return r;
316 /******************************************************************************
317 * Service IPC functions
319 static LPWSTR service_get_pipe_name(LPCWSTR service)
321 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
322 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
323 LPWSTR name;
324 DWORD len;
326 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
327 name = HeapAlloc(GetProcessHeap(), 0, len);
328 strcpyW(name, prefix);
329 strcatW(name, service);
330 return name;
333 static HANDLE service_open_pipe(LPCWSTR service)
335 LPWSTR szPipe = service_get_pipe_name( service );
336 HANDLE handle = INVALID_HANDLE_VALUE;
338 do {
339 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
340 0, NULL, OPEN_ALWAYS, 0, NULL);
341 if (handle != INVALID_HANDLE_VALUE)
342 break;
343 if (GetLastError() != ERROR_PIPE_BUSY)
344 break;
345 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
346 HeapFree(GetProcessHeap(), 0, szPipe);
348 return handle;
351 /******************************************************************************
352 * service_get_event_handle
354 static HANDLE service_get_event_handle(LPCWSTR service)
356 static const WCHAR prefix[] = {
357 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
358 LPWSTR name;
359 DWORD len;
360 HANDLE handle;
362 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
363 name = HeapAlloc(GetProcessHeap(), 0, len);
364 strcpyW(name, prefix);
365 strcatW(name, service);
366 handle = CreateEventW(NULL, TRUE, FALSE, name);
367 HeapFree(GetProcessHeap(), 0, name);
368 return handle;
371 /******************************************************************************
372 * service_thread
374 * Call into the main service routine provided by StartServiceCtrlDispatcher.
376 static DWORD WINAPI service_thread(LPVOID arg)
378 service_data *info = arg;
379 LPWSTR str = info->args;
380 DWORD argc = 0, len = 0;
382 TRACE("%p\n", arg);
384 while (str[len])
386 len += strlenW(&str[len]) + 1;
387 argc++;
390 if (!argc)
392 if (info->unicode)
393 info->proc.w(0, NULL);
394 else
395 info->proc.a(0, NULL);
396 return 0;
399 if (info->unicode)
401 LPWSTR *argv, p;
403 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
404 for (argc=0, p=str; *p; p += strlenW(p) + 1)
405 argv[argc++] = p;
406 argv[argc] = NULL;
408 info->proc.w(argc, argv);
409 HeapFree(GetProcessHeap(), 0, argv);
411 else
413 LPSTR strA, *argv, p;
414 DWORD lenA;
416 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
417 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
418 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
420 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
421 for (argc=0, p=strA; *p; p += strlen(p) + 1)
422 argv[argc++] = p;
423 argv[argc] = NULL;
425 info->proc.a(argc, argv);
426 HeapFree(GetProcessHeap(), 0, argv);
427 HeapFree(GetProcessHeap(), 0, strA);
429 return 0;
432 /******************************************************************************
433 * service_handle_start
435 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
437 DWORD read = 0, result = 0;
438 LPWSTR args;
439 BOOL r;
441 TRACE("%p %p %d\n", pipe, service, count);
443 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
444 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
445 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
447 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
448 r, count, read, debugstr_wn(args, count));
449 goto end;
452 if (service->thread)
454 WARN("service is not stopped\n");
455 result = ERROR_SERVICE_ALREADY_RUNNING;
456 goto end;
459 HeapFree(GetProcessHeap(), 0, service->args);
460 service->args = args;
461 args = NULL;
462 service->thread = CreateThread( NULL, 0, service_thread,
463 service, 0, NULL );
465 end:
466 HeapFree(GetProcessHeap(), 0, args);
467 WriteFile( pipe, &result, sizeof result, &read, NULL );
469 return TRUE;
472 /******************************************************************************
473 * service_send_start_message
475 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
477 DWORD i, len, count, result;
478 service_start_info *ssi;
479 LPWSTR p;
480 BOOL r;
482 TRACE("%p %p %d\n", pipe, argv, argc);
484 /* calculate how much space do we need to send the startup info */
485 len = 1;
486 for (i=0; i<argc; i++)
487 len += strlenW(argv[i])+1;
489 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
490 ssi->cmd = WINESERV_STARTINFO;
491 ssi->size = len;
493 /* copy service args into a single buffer*/
494 p = &ssi->str[0];
495 for (i=0; i<argc; i++)
497 strcpyW(p, argv[i]);
498 p += strlenW(p) + 1;
500 *p=0;
502 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
503 if (r)
505 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
506 if (r && result)
508 SetLastError(result);
509 r = FALSE;
513 HeapFree(GetProcessHeap(),0,ssi);
515 return r;
518 /******************************************************************************
519 * service_handle_get_status
521 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
523 DWORD count = 0;
524 TRACE("\n");
525 return WriteFile(pipe, &service->status,
526 sizeof service->status, &count, NULL);
529 /******************************************************************************
530 * service_get_status
532 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
534 DWORD cmd[2], count = 0;
535 BOOL r;
537 cmd[0] = WINESERV_GETSTATUS;
538 cmd[1] = 0;
539 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
540 if (!r || count != sizeof cmd)
542 ERR("service protocol error - failed to write pipe!\n");
543 return r;
545 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
546 if (!r || count != sizeof *status)
547 ERR("service protocol error - failed to read pipe "
548 "r = %d count = %d!\n", r, count);
549 return r;
552 /******************************************************************************
553 * service_send_control
555 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
557 DWORD cmd[2], count = 0;
558 BOOL r;
560 cmd[0] = WINESERV_SENDCONTROL;
561 cmd[1] = dwControl;
562 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
563 if (!r || count != sizeof cmd)
565 ERR("service protocol error - failed to write pipe!\n");
566 return r;
568 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
569 if (!r || count != sizeof *result)
570 ERR("service protocol error - failed to read pipe "
571 "r = %d count = %d!\n", r, count);
572 return r;
575 /******************************************************************************
576 * service_accepts_control
578 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
580 DWORD a = service->status.dwControlsAccepted;
582 switch (dwControl)
584 case SERVICE_CONTROL_INTERROGATE:
585 return TRUE;
586 case SERVICE_CONTROL_STOP:
587 if (a&SERVICE_ACCEPT_STOP)
588 return TRUE;
589 break;
590 case SERVICE_CONTROL_SHUTDOWN:
591 if (a&SERVICE_ACCEPT_SHUTDOWN)
592 return TRUE;
593 break;
594 case SERVICE_CONTROL_PAUSE:
595 case SERVICE_CONTROL_CONTINUE:
596 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
597 return TRUE;
598 break;
599 case SERVICE_CONTROL_PARAMCHANGE:
600 if (a&SERVICE_ACCEPT_PARAMCHANGE)
601 return TRUE;
602 break;
603 case SERVICE_CONTROL_NETBINDADD:
604 case SERVICE_CONTROL_NETBINDREMOVE:
605 case SERVICE_CONTROL_NETBINDENABLE:
606 case SERVICE_CONTROL_NETBINDDISABLE:
607 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
608 return TRUE;
610 if (!service->extended)
611 return FALSE;
612 switch (dwControl)
614 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
615 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
616 return TRUE;
617 break;
618 case SERVICE_CONTROL_POWEREVENT:
619 if (a&SERVICE_ACCEPT_POWEREVENT)
620 return TRUE;
621 break;
622 case SERVICE_CONTROL_SESSIONCHANGE:
623 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
624 return TRUE;
625 break;
627 return FALSE;
630 /******************************************************************************
631 * service_handle_control
633 static BOOL service_handle_control(HANDLE pipe, service_data *service,
634 DWORD dwControl)
636 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
638 TRACE("received control %d\n", dwControl);
640 if (service_accepts_control(service, dwControl))
642 if (service->extended && service->handler.handler_ex)
644 service->handler.handler_ex(dwControl, 0, NULL, service->context);
645 ret = ERROR_SUCCESS;
647 else if (service->handler.handler)
649 service->handler.handler(dwControl);
650 ret = ERROR_SUCCESS;
653 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
656 /******************************************************************************
657 * service_reap_thread
659 static DWORD service_reap_thread(service_data *service)
661 DWORD exitcode = 0;
663 if (!service->thread)
664 return 0;
665 GetExitCodeThread(service->thread, &exitcode);
666 if (exitcode!=STILL_ACTIVE)
668 CloseHandle(service->thread);
669 service->thread = 0;
671 return exitcode;
674 /******************************************************************************
675 * service_control_dispatcher
677 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
679 service_data *service = arg;
680 LPWSTR name;
681 HANDLE pipe, event;
683 TRACE("%p %s\n", service, debugstr_w(service->name));
685 /* create a pipe to talk to the rest of the world with */
686 name = service_get_pipe_name(service->name);
687 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
688 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
689 HeapFree(GetProcessHeap(), 0, name);
691 /* let the process who started us know we've tried to create a pipe */
692 event = service_get_event_handle(service->name);
693 SetEvent(event);
694 CloseHandle(event);
696 if (pipe==INVALID_HANDLE_VALUE)
698 ERR("failed to create pipe for %s, error = %d\n",
699 debugstr_w(service->name), GetLastError());
700 return 0;
703 /* dispatcher loop */
704 while (1)
706 BOOL r;
707 DWORD count, req[2] = {0,0};
709 r = ConnectNamedPipe(pipe, NULL);
710 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
712 ERR("pipe connect failed\n");
713 break;
716 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
717 if (!r || count!=sizeof req)
719 ERR("pipe read failed\n");
720 break;
723 service_reap_thread(service);
725 /* handle the request */
726 switch (req[0])
728 case WINESERV_STARTINFO:
729 service_handle_start(pipe, service, req[1]);
730 break;
731 case WINESERV_GETSTATUS:
732 service_handle_get_status(pipe, service);
733 break;
734 case WINESERV_SENDCONTROL:
735 service_handle_control(pipe, service, req[1]);
736 break;
737 default:
738 ERR("received invalid command %d length %d\n", req[0], req[1]);
741 FlushFileBuffers(pipe);
742 DisconnectNamedPipe(pipe);
745 CloseHandle(pipe);
746 return 1;
749 /******************************************************************************
750 * service_run_threads
752 static BOOL service_run_threads(void)
754 service_data *service;
755 DWORD count, n = 0;
756 HANDLE *handles;
758 EnterCriticalSection( &service_cs );
760 count = list_count( &service_list );
762 TRACE("Starting %d pipe listener threads. Services running as process %d\n", count, GetCurrentProcessId());
764 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
766 handles[n++] = __wine_make_process_system();
768 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
770 service->status.dwProcessId = GetCurrentProcessId();
771 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
772 service, 0, NULL );
774 assert(n == count + 1);
776 LeaveCriticalSection( &service_cs );
778 /* wait for all the threads to pack up and exit */
779 while (n > 1)
781 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
782 if (!ret) /* system process event */
784 TRACE( "last user process exited, shutting down\n" );
785 /* FIXME: we should maybe send a shutdown control to running services */
786 ExitProcess(0);
788 if (ret < MAXIMUM_WAIT_OBJECTS)
790 CloseHandle( handles[ret] );
791 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
792 n--;
794 else break;
797 while (n) CloseHandle( handles[--n] );
798 HeapFree(GetProcessHeap(), 0, handles);
800 return TRUE;
803 /******************************************************************************
804 * StartServiceCtrlDispatcherA [ADVAPI32.@]
806 * See StartServiceCtrlDispatcherW.
808 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
810 service_data *info;
811 DWORD sz, len;
812 BOOL ret = TRUE;
814 TRACE("%p\n", servent);
816 EnterCriticalSection( &service_cs );
817 while (servent->lpServiceName)
819 LPSTR name = servent->lpServiceName;
821 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
822 sz = len*sizeof(WCHAR) + sizeof *info;
823 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
824 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
825 info->proc.a = servent->lpServiceProc;
826 info->unicode = FALSE;
827 list_add_head( &service_list, &info->entry );
828 servent++;
830 LeaveCriticalSection( &service_cs );
832 service_run_threads();
834 return ret;
837 /******************************************************************************
838 * StartServiceCtrlDispatcherW [ADVAPI32.@]
840 * Connects a process containing one or more services to the service control
841 * manager.
843 * PARAMS
844 * servent [I] A list of the service names and service procedures
846 * RETURNS
847 * Success: TRUE.
848 * Failure: FALSE.
850 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
852 service_data *info;
853 DWORD sz, len;
854 BOOL ret = TRUE;
856 TRACE("%p\n", servent);
858 EnterCriticalSection( &service_cs );
859 while (servent->lpServiceName)
861 LPWSTR name = servent->lpServiceName;
863 len = strlenW(name);
864 sz = len*sizeof(WCHAR) + sizeof *info;
865 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
866 strcpyW(info->name, name);
867 info->proc.w = servent->lpServiceProc;
868 info->unicode = TRUE;
869 list_add_head( &service_list, &info->entry );
870 servent++;
872 LeaveCriticalSection( &service_cs );
874 service_run_threads();
876 return ret;
879 /******************************************************************************
880 * LockServiceDatabase [ADVAPI32.@]
882 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
884 HANDLE ret;
886 TRACE("%p\n",hSCManager);
888 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
889 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
891 CloseHandle( ret );
892 ret = NULL;
893 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
896 TRACE("returning %p\n", ret);
898 return ret;
901 /******************************************************************************
902 * UnlockServiceDatabase [ADVAPI32.@]
904 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
906 TRACE("%p\n",ScLock);
908 return CloseHandle( ScLock );
911 /******************************************************************************
912 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
914 SERVICE_STATUS_HANDLE WINAPI
915 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
917 LPWSTR lpServiceNameW;
918 SERVICE_STATUS_HANDLE ret;
920 lpServiceNameW = SERV_dup(lpServiceName);
921 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
922 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
923 return ret;
926 /******************************************************************************
927 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
929 * PARAMS
930 * lpServiceName []
931 * lpfHandler []
933 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
934 LPHANDLER_FUNCTION lpfHandler )
936 service_data *service;
937 SERVICE_STATUS_HANDLE handle = 0;
939 EnterCriticalSection( &service_cs );
940 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
942 if(!strcmpW(lpServiceName, service->name))
944 service->handler.handler = lpfHandler;
945 handle = (SERVICE_STATUS_HANDLE)service;
946 break;
949 LeaveCriticalSection( &service_cs );
950 return handle;
953 /******************************************************************************
954 * SetServiceStatus [ADVAPI32.@]
956 * PARAMS
957 * hService []
958 * lpStatus []
960 BOOL WINAPI
961 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
963 service_data *service;
964 BOOL r = FALSE;
966 TRACE("%p %x %x %x %x %x %x %x\n", hService,
967 lpStatus->dwServiceType, lpStatus->dwCurrentState,
968 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
969 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
970 lpStatus->dwWaitHint);
972 EnterCriticalSection( &service_cs );
973 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
975 if(service == (service_data*)hService)
977 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
978 TRACE("Set service status to %d\n",service->status.dwCurrentState);
979 r = TRUE;
980 break;
983 LeaveCriticalSection( &service_cs );
985 return r;
989 /******************************************************************************
990 * OpenSCManagerA [ADVAPI32.@]
992 * Establish a connection to the service control manager and open its database.
994 * PARAMS
995 * lpMachineName [I] Pointer to machine name string
996 * lpDatabaseName [I] Pointer to database name string
997 * dwDesiredAccess [I] Type of access
999 * RETURNS
1000 * Success: A Handle to the service control manager database
1001 * Failure: NULL
1003 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1004 DWORD dwDesiredAccess )
1006 LPWSTR lpMachineNameW, lpDatabaseNameW;
1007 SC_HANDLE ret;
1009 lpMachineNameW = SERV_dup(lpMachineName);
1010 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1011 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1012 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
1013 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
1014 return ret;
1017 /******************************************************************************
1018 * OpenSCManagerW [ADVAPI32.@]
1020 * See OpenSCManagerA.
1022 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1023 DWORD dwDesiredAccess )
1025 struct sc_manager *manager;
1026 HKEY hReg;
1027 LONG r;
1028 DWORD new_mask = dwDesiredAccess;
1030 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1031 debugstr_w(lpDatabaseName), dwDesiredAccess);
1033 if( lpDatabaseName && lpDatabaseName[0] )
1035 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1037 /* noop, all right */
1039 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1041 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1042 return NULL;
1044 else
1046 SetLastError( ERROR_INVALID_NAME );
1047 return NULL;
1051 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1052 sc_handle_destroy_manager );
1053 if (!manager)
1054 return NULL;
1056 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1057 if (r!=ERROR_SUCCESS)
1058 goto error;
1060 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1061 RegCloseKey( hReg );
1062 if (r!=ERROR_SUCCESS)
1063 goto error;
1065 RtlMapGenericMask(&new_mask, &scm_generic);
1066 manager->dwAccess = new_mask;
1067 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1069 return (SC_HANDLE) &manager->hdr;
1071 error:
1072 sc_handle_free( &manager->hdr );
1073 SetLastError( r);
1074 return NULL;
1077 /******************************************************************************
1078 * ControlService [ADVAPI32.@]
1080 * Send a control code to a service.
1082 * PARAMS
1083 * hService [I] Handle of the service control manager database
1084 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1085 * lpServiceStatus [O] Destination for the status of the service, if available
1087 * RETURNS
1088 * Success: TRUE.
1089 * Failure: FALSE.
1091 * BUGS
1092 * Unlike M$' implementation, control requests are not serialized and may be
1093 * processed asynchronously.
1095 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1096 LPSERVICE_STATUS lpServiceStatus )
1098 struct sc_service *hsvc;
1099 BOOL ret = FALSE;
1100 HANDLE handle;
1102 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1104 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1105 if (!hsvc)
1107 SetLastError( ERROR_INVALID_HANDLE );
1108 return FALSE;
1111 ret = QueryServiceStatus(hService, lpServiceStatus);
1112 if (!ret)
1114 ERR("failed to query service status\n");
1115 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1116 return FALSE;
1119 switch (lpServiceStatus->dwCurrentState)
1121 case SERVICE_STOPPED:
1122 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1123 return FALSE;
1124 case SERVICE_START_PENDING:
1125 if (dwControl==SERVICE_CONTROL_STOP)
1126 break;
1127 /* fall thru */
1128 case SERVICE_STOP_PENDING:
1129 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1130 return FALSE;
1133 handle = service_open_pipe(hsvc->name);
1134 if (handle!=INVALID_HANDLE_VALUE)
1136 DWORD result = ERROR_SUCCESS;
1137 ret = service_send_control(handle, dwControl, &result);
1138 CloseHandle(handle);
1139 if (result!=ERROR_SUCCESS)
1141 SetLastError(result);
1142 ret = FALSE;
1146 return ret;
1149 /******************************************************************************
1150 * CloseServiceHandle [ADVAPI32.@]
1152 * Close a handle to a service or the service control manager database.
1154 * PARAMS
1155 * hSCObject [I] Handle to service or service control manager database
1157 * RETURNS
1158 * Success: TRUE
1159 * Failure: FALSE
1161 BOOL WINAPI
1162 CloseServiceHandle( SC_HANDLE hSCObject )
1164 TRACE("%p\n", hSCObject);
1166 sc_handle_free( (struct sc_handle*) hSCObject );
1168 return TRUE;
1172 /******************************************************************************
1173 * OpenServiceA [ADVAPI32.@]
1175 * Open a handle to a service.
1177 * PARAMS
1178 * hSCManager [I] Handle of the service control manager database
1179 * lpServiceName [I] Name of the service to open
1180 * dwDesiredAccess [I] Access required to the service
1182 * RETURNS
1183 * Success: Handle to the service
1184 * Failure: NULL
1186 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1187 DWORD dwDesiredAccess )
1189 LPWSTR lpServiceNameW;
1190 SC_HANDLE ret;
1192 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1194 lpServiceNameW = SERV_dup(lpServiceName);
1195 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1196 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1197 return ret;
1201 /******************************************************************************
1202 * OpenServiceW [ADVAPI32.@]
1204 * See OpenServiceA.
1206 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1207 DWORD dwDesiredAccess)
1209 struct sc_manager *hscm;
1210 struct sc_service *hsvc;
1211 HKEY hKey;
1212 long r;
1213 DWORD len;
1214 DWORD new_mask = dwDesiredAccess;
1216 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1218 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1219 if (!hscm)
1221 SetLastError( ERROR_INVALID_HANDLE );
1222 return FALSE;
1225 if (!lpServiceName)
1227 SetLastError(ERROR_INVALID_ADDRESS);
1228 return NULL;
1231 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1232 if (r!=ERROR_SUCCESS)
1234 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1235 return NULL;
1238 len = strlenW(lpServiceName)+1;
1239 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1240 sizeof (struct sc_service) + len*sizeof(WCHAR),
1241 sc_handle_destroy_service );
1242 if (!hsvc)
1244 RegCloseKey(hKey);
1245 return NULL;
1247 strcpyW( hsvc->name, lpServiceName );
1248 hsvc->hkey = hKey;
1250 RtlMapGenericMask(&new_mask, &svc_generic);
1251 hsvc->dwAccess = new_mask;
1253 /* add reference to SCM handle */
1254 hscm->hdr.ref_count++;
1255 hsvc->scm = hscm;
1257 TRACE("returning %p\n",hsvc);
1259 return (SC_HANDLE) &hsvc->hdr;
1262 /******************************************************************************
1263 * CreateServiceW [ADVAPI32.@]
1265 SC_HANDLE WINAPI
1266 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1267 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1268 DWORD dwServiceType, DWORD dwStartType,
1269 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1270 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1271 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1272 LPCWSTR lpPassword )
1274 struct sc_manager *hscm;
1275 struct sc_service *hsvc = NULL;
1276 HKEY hKey;
1277 LONG r;
1278 DWORD dp, len;
1279 struct reg_value val[10];
1280 int n = 0;
1281 DWORD new_mask = dwDesiredAccess;
1282 DWORD index = 0;
1283 WCHAR buffer[MAX_PATH];
1284 BOOL displayname_exists = FALSE;
1286 TRACE("%p %s %s\n", hSCManager,
1287 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1289 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1290 if (!hscm)
1292 SetLastError( ERROR_INVALID_HANDLE );
1293 return NULL;
1296 if (!lpServiceName || !lpBinaryPathName)
1298 SetLastError(ERROR_INVALID_ADDRESS);
1299 return NULL;
1302 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1304 SetLastError(ERROR_ACCESS_DENIED);
1305 return NULL;
1308 if (!lpServiceName[0])
1310 SetLastError(ERROR_INVALID_NAME);
1311 return NULL;
1314 if (!lpBinaryPathName[0])
1316 SetLastError(ERROR_INVALID_PARAMETER);
1317 return NULL;
1320 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1321 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1322 * runs under the LocalSystem account)
1324 switch (dwServiceType)
1326 case SERVICE_KERNEL_DRIVER:
1327 case SERVICE_FILE_SYSTEM_DRIVER:
1328 case SERVICE_WIN32_OWN_PROCESS:
1329 case SERVICE_WIN32_SHARE_PROCESS:
1330 /* No problem */
1331 break;
1332 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1333 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1334 /* FIXME : Do we need a more thorough check? */
1335 if (lpServiceStartName)
1337 SetLastError(ERROR_INVALID_PARAMETER);
1338 return NULL;
1340 break;
1341 default:
1342 SetLastError(ERROR_INVALID_PARAMETER);
1343 return NULL;
1346 if (!lpServiceStartName && (dwServiceType & SERVICE_WIN32))
1347 lpServiceStartName = szLocalSystem;
1349 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1350 if (dwStartType > SERVICE_DISABLED)
1352 SetLastError(ERROR_INVALID_PARAMETER);
1353 return NULL;
1356 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1357 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1358 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1360 SetLastError(ERROR_INVALID_PARAMETER);
1361 return NULL;
1364 /* Loop through the registry to check if the service already exists and to
1365 * check if we can use the given displayname.
1366 * FIXME: Should we use EnumServicesStatusEx?
1368 len = sizeof(buffer);
1369 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1371 HKEY service_key;
1373 /* The service already exists, so bail out */
1374 if(!lstrcmpiW(lpServiceName, buffer))
1376 SetLastError(ERROR_SERVICE_EXISTS);
1377 return NULL;
1380 /* The given displayname matches the found servicename. We don't bail out
1381 * as servicename is checked before a duplicate displayname
1383 if(!lstrcmpiW(lpDisplayName, buffer))
1384 displayname_exists = TRUE;
1386 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1388 WCHAR name[MAX_PATH];
1389 DWORD size = sizeof(name);
1391 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1393 /* The given displayname matches the found displayname */
1394 if (!lstrcmpiW(lpDisplayName, name))
1395 displayname_exists = TRUE;
1397 RegCloseKey(service_key);
1399 index++;
1400 len = sizeof(buffer);
1403 if (lpDisplayName && displayname_exists)
1405 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1406 return NULL;
1409 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1410 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1411 if (r!=ERROR_SUCCESS)
1413 /* FIXME: Should we set an error? */
1414 return NULL;
1417 if( lpDisplayName )
1418 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1420 service_set_dword( &val[n++], szType, &dwServiceType );
1421 service_set_dword( &val[n++], szStart, &dwStartType );
1422 service_set_dword( &val[n++], szError, &dwErrorControl );
1424 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1426 if( lpLoadOrderGroup )
1427 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1429 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1430 * There is no such key as what szDependencies refers to */
1431 if( lpDependencies )
1432 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1434 if( lpPassword )
1435 FIXME("Don't know how to add a Password for a service.\n");
1437 if( lpServiceStartName )
1438 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1440 r = service_write_values( hKey, val, n );
1441 if( r != ERROR_SUCCESS )
1442 goto error;
1444 len = strlenW(lpServiceName)+1;
1445 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1446 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1447 if( !hsvc )
1448 goto error;
1449 lstrcpyW( hsvc->name, lpServiceName );
1450 hsvc->hkey = hKey;
1452 RtlMapGenericMask(&new_mask, &svc_generic);
1453 hsvc->dwAccess = new_mask;
1455 hsvc->scm = hscm;
1456 hscm->hdr.ref_count++;
1458 return (SC_HANDLE) &hsvc->hdr;
1460 error:
1461 RegCloseKey( hKey );
1462 return NULL;
1466 /******************************************************************************
1467 * CreateServiceA [ADVAPI32.@]
1469 SC_HANDLE WINAPI
1470 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1471 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1472 DWORD dwServiceType, DWORD dwStartType,
1473 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1474 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1475 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1476 LPCSTR lpPassword )
1478 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1479 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1480 SC_HANDLE r;
1482 TRACE("%p %s %s\n", hSCManager,
1483 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1485 lpServiceNameW = SERV_dup( lpServiceName );
1486 lpDisplayNameW = SERV_dup( lpDisplayName );
1487 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1488 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1489 lpDependenciesW = SERV_dupmulti( lpDependencies );
1490 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1491 lpPasswordW = SERV_dup( lpPassword );
1493 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1494 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1495 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1496 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1498 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1499 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1500 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1501 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1502 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1503 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1504 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1506 return r;
1510 /******************************************************************************
1511 * DeleteService [ADVAPI32.@]
1513 * Delete a service from the service control manager database.
1515 * PARAMS
1516 * hService [I] Handle of the service to delete
1518 * RETURNS
1519 * Success: TRUE
1520 * Failure: FALSE
1522 BOOL WINAPI DeleteService( SC_HANDLE hService )
1524 struct sc_service *hsvc;
1526 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1527 if (!hsvc)
1529 SetLastError( ERROR_INVALID_HANDLE );
1530 return FALSE;
1533 if (!(hsvc->dwAccess & DELETE))
1535 SetLastError(ERROR_ACCESS_DENIED);
1536 return FALSE;
1539 /* Close the key to the service */
1540 RegCloseKey(hsvc->hkey);
1542 /* Delete the service under the Service Control Manager key */
1543 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1545 hsvc->hkey = NULL;
1547 return TRUE;
1551 /******************************************************************************
1552 * StartServiceA [ADVAPI32.@]
1554 * Start a service
1556 * PARAMS
1557 * hService [I] Handle of service
1558 * dwNumServiceArgs [I] Number of arguments
1559 * lpServiceArgVectors [I] Address of array of argument strings
1561 * NOTES
1562 * - NT implements this function using an obscure RPC call.
1563 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1564 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1565 * - This will only work for shared address space. How should the service
1566 * args be transferred when address spaces are separated?
1567 * - Can only start one service at a time.
1568 * - Has no concept of privilege.
1570 * RETURNS
1571 * Success: TRUE.
1572 * Failure: FALSE
1574 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1575 LPCSTR *lpServiceArgVectors )
1577 LPWSTR *lpwstr=NULL;
1578 unsigned int i;
1579 BOOL r;
1581 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1583 if (dwNumServiceArgs)
1584 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1585 dwNumServiceArgs*sizeof(LPWSTR) );
1587 for(i=0; i<dwNumServiceArgs; i++)
1588 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1590 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1592 if (dwNumServiceArgs)
1594 for(i=0; i<dwNumServiceArgs; i++)
1595 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1596 HeapFree(GetProcessHeap(), 0, lpwstr);
1599 return r;
1602 /******************************************************************************
1603 * service_start_process [INTERNAL]
1605 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1607 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1608 PROCESS_INFORMATION pi;
1609 STARTUPINFOW si;
1610 LPWSTR path = NULL, str;
1611 DWORD type, size, ret, svc_type;
1612 HANDLE handles[2];
1613 BOOL r;
1615 size = sizeof(svc_type);
1616 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1617 svc_type = 0;
1619 if (svc_type == SERVICE_KERNEL_DRIVER)
1621 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1622 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1624 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1625 GetSystemDirectoryW( path, len );
1626 lstrcatW( path, winedeviceW );
1627 lstrcatW( path, hsvc->name );
1629 else
1631 /* read the executable path from the registry */
1632 size = 0;
1633 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1634 if (ret!=ERROR_SUCCESS)
1635 return FALSE;
1636 str = HeapAlloc(GetProcessHeap(),0,size);
1637 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1638 if (ret==ERROR_SUCCESS)
1640 size = ExpandEnvironmentStringsW(str,NULL,0);
1641 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1642 ExpandEnvironmentStringsW(str,path,size);
1644 HeapFree(GetProcessHeap(),0,str);
1645 if (!path)
1646 return FALSE;
1649 /* wait for the process to start and set an event or terminate */
1650 handles[0] = service_get_event_handle( hsvc->name );
1651 ZeroMemory(&si, sizeof(STARTUPINFOW));
1652 si.cb = sizeof(STARTUPINFOW);
1653 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1654 if (r)
1656 if (ppid) *ppid = pi.dwProcessId;
1658 handles[1] = pi.hProcess;
1659 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1660 if(ret != WAIT_OBJECT_0)
1662 SetLastError(ERROR_IO_PENDING);
1663 r = FALSE;
1666 CloseHandle( pi.hThread );
1667 CloseHandle( pi.hProcess );
1669 CloseHandle( handles[0] );
1670 HeapFree(GetProcessHeap(),0,path);
1671 return r;
1674 static BOOL service_wait_for_startup(SC_HANDLE hService)
1676 DWORD i;
1677 SERVICE_STATUS status;
1678 BOOL r = FALSE;
1680 TRACE("%p\n", hService);
1682 for (i=0; i<30; i++)
1684 status.dwCurrentState = 0;
1685 r = QueryServiceStatus(hService, &status);
1686 if (!r)
1687 break;
1688 if (status.dwCurrentState == SERVICE_RUNNING)
1690 TRACE("Service started successfully\n");
1691 break;
1693 r = FALSE;
1694 Sleep(1000);
1696 return r;
1699 /******************************************************************************
1700 * StartServiceW [ADVAPI32.@]
1702 * See StartServiceA.
1704 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1705 LPCWSTR *lpServiceArgVectors)
1707 struct sc_service *hsvc;
1708 BOOL r = FALSE;
1709 SC_LOCK hLock;
1710 HANDLE handle = INVALID_HANDLE_VALUE;
1712 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1714 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1715 if (!hsvc)
1717 SetLastError(ERROR_INVALID_HANDLE);
1718 return r;
1721 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1722 if (!hLock)
1723 return r;
1725 handle = service_open_pipe(hsvc->name);
1726 if (handle==INVALID_HANDLE_VALUE)
1728 /* start the service process */
1729 if (service_start_process(hsvc, NULL))
1730 handle = service_open_pipe(hsvc->name);
1733 if (handle != INVALID_HANDLE_VALUE)
1735 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1736 CloseHandle(handle);
1739 UnlockServiceDatabase( hLock );
1741 TRACE("returning %d\n", r);
1743 if (r)
1744 service_wait_for_startup(hService);
1746 return r;
1749 /******************************************************************************
1750 * QueryServiceStatus [ADVAPI32.@]
1752 * PARAMS
1753 * hService [I] Handle to service to get information about
1754 * lpservicestatus [O] buffer to receive the status information for the service
1757 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1758 LPSERVICE_STATUS lpservicestatus)
1760 SERVICE_STATUS_PROCESS SvcStatusData;
1761 BOOL ret;
1763 TRACE("%p %p\n", hService, lpservicestatus);
1765 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1766 sizeof(SERVICE_STATUS_PROCESS), NULL);
1767 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1768 return ret;
1772 /******************************************************************************
1773 * QueryServiceStatusEx [ADVAPI32.@]
1775 * Get information about a service.
1777 * PARAMS
1778 * hService [I] Handle to service to get information about
1779 * InfoLevel [I] Level of information to get
1780 * lpBuffer [O] Destination for requested information
1781 * cbBufSize [I] Size of lpBuffer in bytes
1782 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1784 * RETURNS
1785 * Success: TRUE
1786 * FAILURE: FALSE
1788 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1789 LPBYTE lpBuffer, DWORD cbBufSize,
1790 LPDWORD pcbBytesNeeded)
1792 struct sc_service *hsvc;
1793 DWORD size, type, val;
1794 HANDLE pipe;
1795 LONG r;
1796 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1798 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1800 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1802 SetLastError( ERROR_INVALID_LEVEL);
1803 return FALSE;
1806 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1807 if (pSvcStatusData == NULL)
1809 SetLastError( ERROR_INVALID_PARAMETER);
1810 return FALSE;
1813 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1815 if( pcbBytesNeeded != NULL)
1816 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1818 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1819 return FALSE;
1822 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1823 if (!hsvc)
1825 SetLastError( ERROR_INVALID_HANDLE );
1826 return FALSE;
1829 pipe = service_open_pipe(hsvc->name);
1830 if (pipe != INVALID_HANDLE_VALUE)
1832 r = service_get_status(pipe, pSvcStatusData);
1833 CloseHandle(pipe);
1834 if (r)
1835 return TRUE;
1838 TRACE("Failed to read service status\n");
1840 /* read the service type from the registry */
1841 size = sizeof(val);
1842 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1843 if (r != ERROR_SUCCESS || type != REG_DWORD)
1844 val = 0;
1846 pSvcStatusData->dwServiceType = val;
1847 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1848 pSvcStatusData->dwControlsAccepted = 0;
1849 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1850 pSvcStatusData->dwServiceSpecificExitCode = 0;
1851 pSvcStatusData->dwCheckPoint = 0;
1852 pSvcStatusData->dwWaitHint = 0;
1854 return TRUE;
1857 /******************************************************************************
1858 * QueryServiceConfigA [ADVAPI32.@]
1860 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1861 DWORD size, LPDWORD needed )
1863 DWORD n;
1864 LPSTR p, buffer;
1865 BOOL ret;
1866 QUERY_SERVICE_CONFIGW *configW;
1868 TRACE("%p %p %d %p\n", hService, config, size, needed);
1870 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1872 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1873 return FALSE;
1875 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1876 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1877 if (!ret) goto done;
1879 config->dwServiceType = configW->dwServiceType;
1880 config->dwStartType = configW->dwStartType;
1881 config->dwErrorControl = configW->dwErrorControl;
1882 config->lpBinaryPathName = NULL;
1883 config->lpLoadOrderGroup = NULL;
1884 config->dwTagId = configW->dwTagId;
1885 config->lpDependencies = NULL;
1886 config->lpServiceStartName = NULL;
1887 config->lpDisplayName = NULL;
1889 p = (LPSTR)(config + 1);
1890 n = size - sizeof(*config);
1891 ret = FALSE;
1893 #define MAP_STR(str) \
1894 do { \
1895 if (configW->str) \
1897 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1898 if (!sz) goto done; \
1899 config->str = p; \
1900 p += sz; \
1901 n -= sz; \
1903 } while (0)
1905 MAP_STR( lpBinaryPathName );
1906 MAP_STR( lpLoadOrderGroup );
1907 MAP_STR( lpDependencies );
1908 MAP_STR( lpServiceStartName );
1909 MAP_STR( lpDisplayName );
1910 #undef MAP_STR
1912 *needed = p - (LPSTR)config;
1913 ret = TRUE;
1915 done:
1916 HeapFree( GetProcessHeap(), 0, buffer );
1917 return ret;
1920 /******************************************************************************
1921 * QueryServiceConfigW [ADVAPI32.@]
1923 BOOL WINAPI
1924 QueryServiceConfigW( SC_HANDLE hService,
1925 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1926 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1928 WCHAR str_buffer[ MAX_PATH ];
1929 LONG r;
1930 DWORD type, val, sz, total, n;
1931 LPBYTE p;
1932 HKEY hKey;
1933 struct sc_service *hsvc;
1935 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1936 cbBufSize, pcbBytesNeeded);
1938 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1939 if (!hsvc)
1941 SetLastError( ERROR_INVALID_HANDLE );
1942 return FALSE;
1944 hKey = hsvc->hkey;
1946 /* TODO: Check which members are mandatory and what the registry types
1947 * should be. This should of course also be tested when a service is
1948 * created.
1951 /* calculate the size required first */
1952 total = sizeof (QUERY_SERVICE_CONFIGW);
1954 sz = sizeof(str_buffer);
1955 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1956 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1958 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1959 if( 0 == sz ) return FALSE;
1961 total += sizeof(WCHAR) * sz;
1963 else
1965 /* FIXME: set last error */
1966 return FALSE;
1969 sz = 0;
1970 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1971 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1972 total += sz;
1973 else
1974 total += sizeof(WCHAR);
1976 sz = 0;
1977 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1978 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1979 total += sz;
1980 else
1981 total += sizeof(WCHAR);
1983 sz = 0;
1984 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1985 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1986 total += sz;
1987 else
1988 total += sizeof(WCHAR);
1990 sz = 0;
1991 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1992 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1993 total += sz;
1994 else
1995 total += sizeof(WCHAR);
1997 *pcbBytesNeeded = total;
1999 /* if there's not enough memory, return an error */
2000 if( total > cbBufSize )
2002 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2003 return FALSE;
2006 ZeroMemory( lpServiceConfig, total );
2008 sz = sizeof val;
2009 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2010 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2011 lpServiceConfig->dwServiceType = val;
2013 sz = sizeof val;
2014 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2015 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2016 lpServiceConfig->dwStartType = val;
2018 sz = sizeof val;
2019 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2020 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2021 lpServiceConfig->dwErrorControl = val;
2023 sz = sizeof val;
2024 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2025 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2026 lpServiceConfig->dwTagId = val;
2028 /* now do the strings */
2029 p = (LPBYTE) &lpServiceConfig[1];
2030 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2032 sz = sizeof(str_buffer);
2033 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2034 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2036 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2037 sz *= sizeof(WCHAR);
2038 if( 0 == sz || sz > n ) return FALSE;
2040 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2041 p += sz;
2042 n -= sz;
2044 else
2046 /* FIXME: set last error */
2047 return FALSE;
2050 sz = n;
2051 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2052 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2053 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2055 p += sz;
2056 n -= sz;
2058 else
2060 *(WCHAR *) p = 0;
2061 p += sizeof(WCHAR);
2062 n -= sizeof(WCHAR);
2065 sz = n;
2066 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2067 lpServiceConfig->lpDependencies = (LPWSTR) p;
2068 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2070 p += sz;
2071 n -= sz;
2073 else
2075 *(WCHAR *) p = 0;
2076 p += sizeof(WCHAR);
2077 n -= sizeof(WCHAR);
2080 sz = n;
2081 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2082 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2083 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2085 p += sz;
2086 n -= sz;
2088 else
2090 *(WCHAR *) p = 0;
2091 p += sizeof(WCHAR);
2092 n -= sizeof(WCHAR);
2095 sz = n;
2096 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2097 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2098 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2100 p += sz;
2101 n -= sz;
2103 else
2105 *(WCHAR *) p = 0;
2106 p += sizeof(WCHAR);
2107 n -= sizeof(WCHAR);
2110 if( n < 0 )
2111 ERR("Buffer overflow!\n");
2113 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2114 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2115 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2116 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2117 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2119 return TRUE;
2122 /******************************************************************************
2123 * EnumServicesStatusA [ADVAPI32.@]
2125 BOOL WINAPI
2126 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2127 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2128 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2129 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2131 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2132 dwServiceType, dwServiceState, lpServices, cbBufSize,
2133 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2134 SetLastError (ERROR_ACCESS_DENIED);
2135 return FALSE;
2138 /******************************************************************************
2139 * EnumServicesStatusW [ADVAPI32.@]
2141 BOOL WINAPI
2142 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2143 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2144 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2145 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2147 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2148 dwServiceType, dwServiceState, lpServices, cbBufSize,
2149 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2150 SetLastError (ERROR_ACCESS_DENIED);
2151 return FALSE;
2154 /******************************************************************************
2155 * EnumServicesStatusExA [ADVAPI32.@]
2157 BOOL WINAPI
2158 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2159 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2160 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2162 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2163 dwServiceType, dwServiceState, lpServices, cbBufSize,
2164 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2165 SetLastError (ERROR_ACCESS_DENIED);
2166 return FALSE;
2169 /******************************************************************************
2170 * EnumServicesStatusExW [ADVAPI32.@]
2172 BOOL WINAPI
2173 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2174 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2175 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2177 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2178 dwServiceType, dwServiceState, lpServices, cbBufSize,
2179 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2180 SetLastError (ERROR_ACCESS_DENIED);
2181 return FALSE;
2184 /******************************************************************************
2185 * GetServiceKeyNameA [ADVAPI32.@]
2187 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2188 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2190 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2191 return FALSE;
2194 /******************************************************************************
2195 * GetServiceKeyNameW [ADVAPI32.@]
2197 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2198 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2200 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2201 return FALSE;
2204 /******************************************************************************
2205 * QueryServiceLockStatusA [ADVAPI32.@]
2207 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2208 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2209 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2211 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2213 return FALSE;
2216 /******************************************************************************
2217 * QueryServiceLockStatusW [ADVAPI32.@]
2219 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2220 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2221 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2223 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2225 return FALSE;
2228 /******************************************************************************
2229 * GetServiceDisplayNameA [ADVAPI32.@]
2231 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2232 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2234 LPWSTR lpServiceNameW, lpDisplayNameW;
2235 DWORD sizeW;
2236 BOOL ret = FALSE;
2238 TRACE("%p %s %p %p\n", hSCManager,
2239 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2241 lpServiceNameW = SERV_dup(lpServiceName);
2242 if (lpDisplayName)
2243 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2244 else
2245 lpDisplayNameW = NULL;
2247 sizeW = *lpcchBuffer;
2248 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2250 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
2251 goto cleanup;
2254 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2255 *lpcchBuffer, NULL, NULL ))
2257 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2258 goto cleanup;
2261 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2262 * (but if the function succeeded it means that is a good upper estimation of the size) */
2263 ret = TRUE;
2265 cleanup:
2266 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2267 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2268 return ret;
2271 /******************************************************************************
2272 * GetServiceDisplayNameW [ADVAPI32.@]
2274 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2275 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2277 struct sc_manager *hscm;
2278 DWORD type, size;
2279 LONG ret;
2281 TRACE("%p %s %p %p\n", hSCManager,
2282 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2284 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2285 if (!hscm)
2287 SetLastError(ERROR_INVALID_HANDLE);
2288 return FALSE;
2291 if (!lpServiceName)
2293 SetLastError(ERROR_INVALID_ADDRESS);
2294 return FALSE;
2297 size = *lpcchBuffer * sizeof(WCHAR);
2298 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2299 if (!ret && !lpDisplayName && size)
2300 ret = ERROR_MORE_DATA;
2302 if (ret)
2304 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2306 if (ret == ERROR_MORE_DATA)
2308 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2309 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2311 else if (ret == ERROR_FILE_NOT_FOUND)
2313 HKEY hkey;
2315 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2317 UINT len = lstrlenW(lpServiceName);
2318 BOOL r = FALSE;
2320 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2321 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2322 else if (lpDisplayName && *lpcchBuffer)
2324 /* No displayname, but the service exists and the buffer
2325 * is big enough. We should return the servicename.
2327 lstrcpyW(lpDisplayName, lpServiceName);
2328 r = TRUE;
2331 *lpcchBuffer = len;
2332 RegCloseKey(hkey);
2333 return r;
2335 else
2336 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2338 else
2339 SetLastError(ret);
2340 return FALSE;
2343 /* Always return the correct needed size on success */
2344 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2346 return TRUE;
2349 /******************************************************************************
2350 * ChangeServiceConfigW [ADVAPI32.@]
2352 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2353 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2354 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2355 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2357 struct reg_value val[10];
2358 struct sc_service *hsvc;
2359 DWORD r = ERROR_SUCCESS;
2360 HKEY hKey;
2361 int n = 0;
2363 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2364 hService, dwServiceType, dwStartType, dwErrorControl,
2365 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2366 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2367 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2369 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2370 if (!hsvc)
2372 SetLastError( ERROR_INVALID_HANDLE );
2373 return FALSE;
2375 hKey = hsvc->hkey;
2377 if( dwServiceType != SERVICE_NO_CHANGE )
2378 service_set_dword( &val[n++], szType, &dwServiceType );
2380 if( dwStartType != SERVICE_NO_CHANGE )
2381 service_set_dword( &val[n++], szStart, &dwStartType );
2383 if( dwErrorControl != SERVICE_NO_CHANGE )
2384 service_set_dword( &val[n++], szError, &dwErrorControl );
2386 if( lpBinaryPathName )
2387 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2389 if( lpLoadOrderGroup )
2390 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2392 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2393 * There is no such key as what szDependencies refers to */
2394 if( lpDependencies )
2395 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2397 if( lpPassword )
2398 FIXME("ignoring password\n");
2400 if( lpServiceStartName )
2401 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2403 r = service_write_values( hsvc->hkey, val, n );
2405 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2408 /******************************************************************************
2409 * ChangeServiceConfigA [ADVAPI32.@]
2411 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2412 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2413 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2414 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2416 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2417 LPWSTR wServiceStartName, wPassword, wDisplayName;
2418 BOOL r;
2420 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2421 hService, dwServiceType, dwStartType, dwErrorControl,
2422 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2423 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2424 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2426 wBinaryPathName = SERV_dup( lpBinaryPathName );
2427 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2428 wDependencies = SERV_dupmulti( lpDependencies );
2429 wServiceStartName = SERV_dup( lpServiceStartName );
2430 wPassword = SERV_dup( lpPassword );
2431 wDisplayName = SERV_dup( lpDisplayName );
2433 r = ChangeServiceConfigW( hService, dwServiceType,
2434 dwStartType, dwErrorControl, wBinaryPathName,
2435 wLoadOrderGroup, lpdwTagId, wDependencies,
2436 wServiceStartName, wPassword, wDisplayName);
2438 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2439 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2440 HeapFree( GetProcessHeap(), 0, wDependencies );
2441 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2442 HeapFree( GetProcessHeap(), 0, wPassword );
2443 HeapFree( GetProcessHeap(), 0, wDisplayName );
2445 return r;
2448 /******************************************************************************
2449 * ChangeServiceConfig2A [ADVAPI32.@]
2451 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2452 LPVOID lpInfo)
2454 BOOL r = FALSE;
2456 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2458 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2460 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2461 SERVICE_DESCRIPTIONW sdw;
2463 sdw.lpDescription = SERV_dup( sd->lpDescription );
2465 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2467 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2469 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2471 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2472 SERVICE_FAILURE_ACTIONSW faw;
2474 faw.dwResetPeriod = fa->dwResetPeriod;
2475 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2476 faw.lpCommand = SERV_dup( fa->lpCommand );
2477 faw.cActions = fa->cActions;
2478 faw.lpsaActions = fa->lpsaActions;
2480 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2482 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2483 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2485 else
2486 SetLastError( ERROR_INVALID_PARAMETER );
2488 return r;
2491 /******************************************************************************
2492 * ChangeServiceConfig2W [ADVAPI32.@]
2494 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2495 LPVOID lpInfo)
2497 HKEY hKey;
2498 struct sc_service *hsvc;
2500 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2501 if (!hsvc)
2503 SetLastError( ERROR_INVALID_HANDLE );
2504 return FALSE;
2506 hKey = hsvc->hkey;
2508 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2510 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2511 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2512 if (sd->lpDescription)
2514 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2515 if (sd->lpDescription[0] == 0)
2516 RegDeleteValueW(hKey,szDescription);
2517 else
2518 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2519 (LPVOID)sd->lpDescription,
2520 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2523 else
2524 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2525 return TRUE;
2528 /******************************************************************************
2529 * QueryServiceObjectSecurity [ADVAPI32.@]
2531 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2532 SECURITY_INFORMATION dwSecurityInformation,
2533 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2534 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2536 SECURITY_DESCRIPTOR descriptor;
2537 DWORD size;
2538 BOOL succ;
2539 ACL acl;
2541 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2542 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2544 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2545 FIXME("information %d not supported\n", dwSecurityInformation);
2547 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2549 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2550 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2552 size = cbBufSize;
2553 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2554 *pcbBytesNeeded = size;
2555 return succ;
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;