push 599a9d3db769aad8dabfd10a59120f719b00f4ee
[wine/hacks.git] / dlls / advapi32 / service.c
blobfbc888dbf9ed7c0acf0631dc885bcd94b57aa10f
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
202 static inline LPWSTR SERV_dup( LPCSTR str )
204 UINT len;
205 LPWSTR wstr;
207 if( !str )
208 return NULL;
209 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
210 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
211 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
212 return wstr;
215 static inline LPWSTR SERV_dupmulti(LPCSTR str)
217 UINT len = 0, n = 0;
218 LPWSTR wstr;
220 if( !str )
221 return NULL;
222 do {
223 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
224 n += (strlen( &str[n] ) + 1);
225 } while (str[n]);
226 len++;
227 n++;
229 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
230 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
231 return wstr;
234 static inline VOID SERV_free( LPWSTR wstr )
236 HeapFree( GetProcessHeap(), 0, wstr );
239 /******************************************************************************
240 * registry access functions and data
242 static const WCHAR szDisplayName[] = {
243 'D','i','s','p','l','a','y','N','a','m','e', 0 };
244 static const WCHAR szType[] = {'T','y','p','e',0};
245 static const WCHAR szStart[] = {'S','t','a','r','t',0};
246 static const WCHAR szError[] = {
247 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
248 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
249 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
250 static const WCHAR szDependencies[] = {
251 'D','e','p','e','n','d','e','n','c','i','e','s',0};
252 static const WCHAR szDependOnService[] = {
253 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
254 static const WCHAR szObjectName[] = {
255 'O','b','j','e','c','t','N','a','m','e',0};
256 static const WCHAR szTag[] = {
257 'T','a','g',0};
259 struct reg_value {
260 DWORD type;
261 DWORD size;
262 LPCWSTR name;
263 LPCVOID data;
266 static inline void service_set_value( struct reg_value *val,
267 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
269 val->name = name;
270 val->type = type;
271 val->data = data;
272 val->size = size;
275 static inline void service_set_dword( struct reg_value *val,
276 LPCWSTR name, const DWORD *data )
278 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
281 static inline void service_set_string( struct reg_value *val,
282 LPCWSTR name, LPCWSTR string )
284 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
285 service_set_value( val, REG_SZ, name, string, len );
288 static inline void service_set_multi_string( struct reg_value *val,
289 LPCWSTR name, LPCWSTR string )
291 DWORD len = 0;
293 /* determine the length of a double null terminated multi string */
294 do {
295 len += (lstrlenW( &string[ len ] )+1);
296 } while ( string[ len++ ] );
298 len *= sizeof (WCHAR);
299 service_set_value( val, REG_MULTI_SZ, name, string, len );
302 static inline LONG service_write_values( HKEY hKey,
303 const struct reg_value *val, int n )
305 LONG r = ERROR_SUCCESS;
306 int i;
308 for( i=0; i<n; i++ )
310 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
311 (const BYTE*)val[i].data, val[i].size );
312 if( r != ERROR_SUCCESS )
313 break;
315 return r;
318 /******************************************************************************
319 * Service IPC functions
321 static LPWSTR service_get_pipe_name(LPCWSTR service)
323 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
324 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
325 LPWSTR name;
326 DWORD len;
328 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
329 name = HeapAlloc(GetProcessHeap(), 0, len);
330 strcpyW(name, prefix);
331 strcatW(name, service);
332 return name;
335 static HANDLE service_open_pipe(LPCWSTR service)
337 LPWSTR szPipe = service_get_pipe_name( service );
338 HANDLE handle = INVALID_HANDLE_VALUE;
340 do {
341 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
342 0, NULL, OPEN_ALWAYS, 0, NULL);
343 if (handle != INVALID_HANDLE_VALUE)
344 break;
345 if (GetLastError() != ERROR_PIPE_BUSY)
346 break;
347 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
348 SERV_free(szPipe);
350 return handle;
353 /******************************************************************************
354 * service_get_event_handle
356 static HANDLE service_get_event_handle(LPCWSTR service)
358 static const WCHAR prefix[] = {
359 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
360 LPWSTR name;
361 DWORD len;
362 HANDLE handle;
364 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
365 name = HeapAlloc(GetProcessHeap(), 0, len);
366 strcpyW(name, prefix);
367 strcatW(name, service);
368 handle = CreateEventW(NULL, TRUE, FALSE, name);
369 SERV_free(name);
370 return handle;
373 /******************************************************************************
374 * service_thread
376 * Call into the main service routine provided by StartServiceCtrlDispatcher.
378 static DWORD WINAPI service_thread(LPVOID arg)
380 service_data *info = arg;
381 LPWSTR str = info->args;
382 DWORD argc = 0, len = 0;
384 TRACE("%p\n", arg);
386 while (str[len])
388 len += strlenW(&str[len]) + 1;
389 argc++;
392 if (!argc)
394 if (info->unicode)
395 info->proc.w(0, NULL);
396 else
397 info->proc.a(0, NULL);
398 return 0;
401 if (info->unicode)
403 LPWSTR *argv, p;
405 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
406 for (argc=0, p=str; *p; p += strlenW(p) + 1)
407 argv[argc++] = p;
408 argv[argc] = NULL;
410 info->proc.w(argc, argv);
411 HeapFree(GetProcessHeap(), 0, argv);
413 else
415 LPSTR strA, *argv, p;
416 DWORD lenA;
418 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
419 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
420 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
422 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
423 for (argc=0, p=strA; *p; p += strlen(p) + 1)
424 argv[argc++] = p;
425 argv[argc] = NULL;
427 info->proc.a(argc, argv);
428 HeapFree(GetProcessHeap(), 0, argv);
429 HeapFree(GetProcessHeap(), 0, strA);
431 return 0;
434 /******************************************************************************
435 * service_handle_start
437 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
439 DWORD read = 0, result = 0;
440 LPWSTR args;
441 BOOL r;
443 TRACE("%p %p %d\n", pipe, service, count);
445 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
446 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
447 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
449 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
450 r, count, read, debugstr_wn(args, count));
451 goto end;
454 if (service->thread)
456 WARN("service is not stopped\n");
457 result = ERROR_SERVICE_ALREADY_RUNNING;
458 goto end;
461 SERV_free(service->args);
462 service->args = args;
463 args = NULL;
464 service->thread = CreateThread( NULL, 0, service_thread,
465 service, 0, NULL );
467 end:
468 HeapFree(GetProcessHeap(), 0, args);
469 WriteFile( pipe, &result, sizeof result, &read, NULL );
471 return TRUE;
474 /******************************************************************************
475 * service_send_start_message
477 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
479 DWORD i, len, count, result;
480 service_start_info *ssi;
481 LPWSTR p;
482 BOOL r;
484 TRACE("%p %p %d\n", pipe, argv, argc);
486 /* calculate how much space do we need to send the startup info */
487 len = 1;
488 for (i=0; i<argc; i++)
489 len += strlenW(argv[i])+1;
491 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
492 ssi->cmd = WINESERV_STARTINFO;
493 ssi->size = len;
495 /* copy service args into a single buffer*/
496 p = &ssi->str[0];
497 for (i=0; i<argc; i++)
499 strcpyW(p, argv[i]);
500 p += strlenW(p) + 1;
502 *p=0;
504 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
505 if (r)
507 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
508 if (r && result)
510 SetLastError(result);
511 r = FALSE;
515 HeapFree(GetProcessHeap(),0,ssi);
517 return r;
520 /******************************************************************************
521 * service_handle_get_status
523 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
525 DWORD count = 0;
526 TRACE("\n");
527 return WriteFile(pipe, &service->status,
528 sizeof service->status, &count, NULL);
531 /******************************************************************************
532 * service_get_status
534 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
536 DWORD cmd[2], count = 0;
537 BOOL r;
539 cmd[0] = WINESERV_GETSTATUS;
540 cmd[1] = 0;
541 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
542 if (!r || count != sizeof cmd)
544 ERR("service protocol error - failed to write pipe!\n");
545 return r;
547 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
548 if (!r || count != sizeof *status)
549 ERR("service protocol error - failed to read pipe "
550 "r = %d count = %d!\n", r, count);
551 return r;
554 /******************************************************************************
555 * service_send_control
557 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
559 DWORD cmd[2], count = 0;
560 BOOL r;
562 cmd[0] = WINESERV_SENDCONTROL;
563 cmd[1] = dwControl;
564 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
565 if (!r || count != sizeof cmd)
567 ERR("service protocol error - failed to write pipe!\n");
568 return r;
570 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
571 if (!r || count != sizeof *result)
572 ERR("service protocol error - failed to read pipe "
573 "r = %d count = %d!\n", r, count);
574 return r;
577 /******************************************************************************
578 * service_accepts_control
580 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
582 DWORD a = service->status.dwControlsAccepted;
584 switch (dwControl)
586 case SERVICE_CONTROL_INTERROGATE:
587 return TRUE;
588 case SERVICE_CONTROL_STOP:
589 if (a&SERVICE_ACCEPT_STOP)
590 return TRUE;
591 break;
592 case SERVICE_CONTROL_SHUTDOWN:
593 if (a&SERVICE_ACCEPT_SHUTDOWN)
594 return TRUE;
595 break;
596 case SERVICE_CONTROL_PAUSE:
597 case SERVICE_CONTROL_CONTINUE:
598 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
599 return TRUE;
600 break;
601 case SERVICE_CONTROL_PARAMCHANGE:
602 if (a&SERVICE_ACCEPT_PARAMCHANGE)
603 return TRUE;
604 break;
605 case SERVICE_CONTROL_NETBINDADD:
606 case SERVICE_CONTROL_NETBINDREMOVE:
607 case SERVICE_CONTROL_NETBINDENABLE:
608 case SERVICE_CONTROL_NETBINDDISABLE:
609 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
610 return TRUE;
612 if (!service->extended)
613 return FALSE;
614 switch (dwControl)
616 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
617 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
618 return TRUE;
619 break;
620 case SERVICE_CONTROL_POWEREVENT:
621 if (a&SERVICE_ACCEPT_POWEREVENT)
622 return TRUE;
623 break;
624 case SERVICE_CONTROL_SESSIONCHANGE:
625 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
626 return TRUE;
627 break;
629 return FALSE;
632 /******************************************************************************
633 * service_handle_control
635 static BOOL service_handle_control(HANDLE pipe, service_data *service,
636 DWORD dwControl)
638 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
640 TRACE("received control %d\n", dwControl);
642 if (service_accepts_control(service, dwControl))
644 if (service->extended && service->handler.handler_ex)
646 service->handler.handler_ex(dwControl, 0, NULL, service->context);
647 ret = ERROR_SUCCESS;
649 else if (service->handler.handler)
651 service->handler.handler(dwControl);
652 ret = ERROR_SUCCESS;
655 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
658 /******************************************************************************
659 * service_reap_thread
661 static DWORD service_reap_thread(service_data *service)
663 DWORD exitcode = 0;
665 if (!service->thread)
666 return 0;
667 GetExitCodeThread(service->thread, &exitcode);
668 if (exitcode!=STILL_ACTIVE)
670 CloseHandle(service->thread);
671 service->thread = 0;
673 return exitcode;
676 /******************************************************************************
677 * service_control_dispatcher
679 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
681 service_data *service = arg;
682 LPWSTR name;
683 HANDLE pipe, event;
685 TRACE("%p %s\n", service, debugstr_w(service->name));
687 /* create a pipe to talk to the rest of the world with */
688 name = service_get_pipe_name(service->name);
689 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
690 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
691 SERV_free(name);
693 /* let the process who started us know we've tried to create a pipe */
694 event = service_get_event_handle(service->name);
695 SetEvent(event);
696 CloseHandle(event);
698 if (pipe==INVALID_HANDLE_VALUE)
700 ERR("failed to create pipe for %s, error = %d\n",
701 debugstr_w(service->name), GetLastError());
702 return 0;
705 /* dispatcher loop */
706 while (1)
708 BOOL r;
709 DWORD count, req[2] = {0,0};
711 r = ConnectNamedPipe(pipe, NULL);
712 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
714 ERR("pipe connect failed\n");
715 break;
718 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
719 if (!r || count!=sizeof req)
721 ERR("pipe read failed\n");
722 break;
725 service_reap_thread(service);
727 /* handle the request */
728 switch (req[0])
730 case WINESERV_STARTINFO:
731 service_handle_start(pipe, service, req[1]);
732 break;
733 case WINESERV_GETSTATUS:
734 service_handle_get_status(pipe, service);
735 break;
736 case WINESERV_SENDCONTROL:
737 service_handle_control(pipe, service, req[1]);
738 break;
739 default:
740 ERR("received invalid command %d length %d\n", req[0], req[1]);
743 FlushFileBuffers(pipe);
744 DisconnectNamedPipe(pipe);
747 CloseHandle(pipe);
748 return 1;
751 /******************************************************************************
752 * service_run_threads
754 static BOOL service_run_threads(void)
756 service_data *service;
757 DWORD count, n = 0;
758 HANDLE *handles;
760 EnterCriticalSection( &service_cs );
762 count = list_count( &service_list );
764 TRACE("Starting %d pipe listener threads. Services running as process %d\n", count, GetCurrentProcessId());
766 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
768 handles[n++] = __wine_make_process_system();
770 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
772 service->status.dwProcessId = GetCurrentProcessId();
773 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
774 service, 0, NULL );
776 assert(n == count + 1);
778 LeaveCriticalSection( &service_cs );
780 /* wait for all the threads to pack up and exit */
781 while (n > 1)
783 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
784 if (!ret) /* system process event */
786 TRACE( "last user process exited, shutting down\n" );
787 /* FIXME: we should maybe send a shutdown control to running services */
788 ExitProcess(0);
790 if (ret < MAXIMUM_WAIT_OBJECTS)
792 CloseHandle( handles[ret] );
793 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
794 n--;
796 else break;
799 while (n) CloseHandle( handles[--n] );
800 HeapFree(GetProcessHeap(), 0, handles);
802 return TRUE;
805 /******************************************************************************
806 * StartServiceCtrlDispatcherA [ADVAPI32.@]
808 * See StartServiceCtrlDispatcherW.
810 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
812 service_data *info;
813 DWORD sz, len;
814 BOOL ret = TRUE;
816 TRACE("%p\n", servent);
818 EnterCriticalSection( &service_cs );
819 while (servent->lpServiceName)
821 LPSTR name = servent->lpServiceName;
823 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
824 sz = len*sizeof(WCHAR) + sizeof *info;
825 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
826 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
827 info->proc.a = servent->lpServiceProc;
828 info->unicode = FALSE;
829 list_add_head( &service_list, &info->entry );
830 servent++;
832 LeaveCriticalSection( &service_cs );
834 service_run_threads();
836 return ret;
839 /******************************************************************************
840 * StartServiceCtrlDispatcherW [ADVAPI32.@]
842 * Connects a process containing one or more services to the service control
843 * manager.
845 * PARAMS
846 * servent [I] A list of the service names and service procedures
848 * RETURNS
849 * Success: TRUE.
850 * Failure: FALSE.
852 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
854 service_data *info;
855 DWORD sz, len;
856 BOOL ret = TRUE;
858 TRACE("%p\n", servent);
860 EnterCriticalSection( &service_cs );
861 while (servent->lpServiceName)
863 LPWSTR name = servent->lpServiceName;
865 len = strlenW(name);
866 sz = len*sizeof(WCHAR) + sizeof *info;
867 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
868 strcpyW(info->name, name);
869 info->proc.w = servent->lpServiceProc;
870 info->unicode = TRUE;
871 list_add_head( &service_list, &info->entry );
872 servent++;
874 LeaveCriticalSection( &service_cs );
876 service_run_threads();
878 return ret;
881 /******************************************************************************
882 * LockServiceDatabase [ADVAPI32.@]
884 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
886 HANDLE ret;
888 TRACE("%p\n",hSCManager);
890 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
891 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
893 CloseHandle( ret );
894 ret = NULL;
895 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
898 TRACE("returning %p\n", ret);
900 return ret;
903 /******************************************************************************
904 * UnlockServiceDatabase [ADVAPI32.@]
906 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
908 TRACE("%p\n",ScLock);
910 return CloseHandle( ScLock );
913 /******************************************************************************
914 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
916 SERVICE_STATUS_HANDLE WINAPI
917 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
919 LPWSTR lpServiceNameW;
920 SERVICE_STATUS_HANDLE ret;
922 lpServiceNameW = SERV_dup(lpServiceName);
923 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
924 SERV_free(lpServiceNameW);
925 return ret;
928 /******************************************************************************
929 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
931 * PARAMS
932 * lpServiceName []
933 * lpfHandler []
935 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
936 LPHANDLER_FUNCTION lpfHandler )
938 service_data *service;
939 SERVICE_STATUS_HANDLE handle = 0;
941 EnterCriticalSection( &service_cs );
942 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
944 if(!strcmpW(lpServiceName, service->name))
946 service->handler.handler = lpfHandler;
947 handle = (SERVICE_STATUS_HANDLE)service;
948 break;
951 LeaveCriticalSection( &service_cs );
952 return handle;
955 /******************************************************************************
956 * SetServiceStatus [ADVAPI32.@]
958 * PARAMS
959 * hService []
960 * lpStatus []
962 BOOL WINAPI
963 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
965 service_data *service;
966 BOOL r = FALSE;
968 TRACE("%p %x %x %x %x %x %x %x\n", hService,
969 lpStatus->dwServiceType, lpStatus->dwCurrentState,
970 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
971 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
972 lpStatus->dwWaitHint);
974 EnterCriticalSection( &service_cs );
975 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
977 if(service == (service_data*)hService)
979 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
980 TRACE("Set service status to %d\n",service->status.dwCurrentState);
981 r = TRUE;
982 break;
985 LeaveCriticalSection( &service_cs );
987 return r;
991 /******************************************************************************
992 * OpenSCManagerA [ADVAPI32.@]
994 * Establish a connection to the service control manager and open its database.
996 * PARAMS
997 * lpMachineName [I] Pointer to machine name string
998 * lpDatabaseName [I] Pointer to database name string
999 * dwDesiredAccess [I] Type of access
1001 * RETURNS
1002 * Success: A Handle to the service control manager database
1003 * Failure: NULL
1005 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1006 DWORD dwDesiredAccess )
1008 LPWSTR lpMachineNameW, lpDatabaseNameW;
1009 SC_HANDLE ret;
1011 lpMachineNameW = SERV_dup(lpMachineName);
1012 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1013 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1014 SERV_free(lpDatabaseNameW);
1015 SERV_free(lpMachineNameW);
1016 return ret;
1019 /******************************************************************************
1020 * OpenSCManagerW [ADVAPI32.@]
1022 * See OpenSCManagerA.
1024 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1025 DWORD dwDesiredAccess )
1027 struct sc_manager *manager;
1028 HKEY hReg;
1029 LONG r;
1030 DWORD new_mask = dwDesiredAccess;
1032 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1033 debugstr_w(lpDatabaseName), dwDesiredAccess);
1035 if( lpDatabaseName && lpDatabaseName[0] )
1037 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1039 /* noop, all right */
1041 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1043 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1044 return NULL;
1046 else
1048 SetLastError( ERROR_INVALID_NAME );
1049 return NULL;
1053 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1054 sc_handle_destroy_manager );
1055 if (!manager)
1056 return NULL;
1058 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1059 if (r!=ERROR_SUCCESS)
1060 goto error;
1062 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1063 RegCloseKey( hReg );
1064 if (r!=ERROR_SUCCESS)
1065 goto error;
1067 RtlMapGenericMask(&new_mask, &scm_generic);
1068 manager->dwAccess = new_mask;
1069 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1071 return (SC_HANDLE) &manager->hdr;
1073 error:
1074 sc_handle_free( &manager->hdr );
1075 SetLastError( r);
1076 return NULL;
1079 /******************************************************************************
1080 * ControlService [ADVAPI32.@]
1082 * Send a control code to a service.
1084 * PARAMS
1085 * hService [I] Handle of the service control manager database
1086 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1087 * lpServiceStatus [O] Destination for the status of the service, if available
1089 * RETURNS
1090 * Success: TRUE.
1091 * Failure: FALSE.
1093 * BUGS
1094 * Unlike M$' implementation, control requests are not serialized and may be
1095 * processed asynchronously.
1097 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1098 LPSERVICE_STATUS lpServiceStatus )
1100 struct sc_service *hsvc;
1101 BOOL ret = FALSE;
1102 HANDLE handle;
1104 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1106 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1107 if (!hsvc)
1109 SetLastError( ERROR_INVALID_HANDLE );
1110 return FALSE;
1113 ret = QueryServiceStatus(hService, lpServiceStatus);
1114 if (!ret)
1116 ERR("failed to query service status\n");
1117 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1118 return FALSE;
1121 switch (lpServiceStatus->dwCurrentState)
1123 case SERVICE_STOPPED:
1124 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1125 return FALSE;
1126 case SERVICE_START_PENDING:
1127 if (dwControl==SERVICE_CONTROL_STOP)
1128 break;
1129 /* fall thru */
1130 case SERVICE_STOP_PENDING:
1131 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1132 return FALSE;
1135 handle = service_open_pipe(hsvc->name);
1136 if (handle!=INVALID_HANDLE_VALUE)
1138 DWORD result = ERROR_SUCCESS;
1139 ret = service_send_control(handle, dwControl, &result);
1140 CloseHandle(handle);
1141 if (result!=ERROR_SUCCESS)
1143 SetLastError(result);
1144 ret = FALSE;
1148 return ret;
1151 /******************************************************************************
1152 * CloseServiceHandle [ADVAPI32.@]
1154 * Close a handle to a service or the service control manager database.
1156 * PARAMS
1157 * hSCObject [I] Handle to service or service control manager database
1159 * RETURNS
1160 * Success: TRUE
1161 * Failure: FALSE
1163 BOOL WINAPI
1164 CloseServiceHandle( SC_HANDLE hSCObject )
1166 TRACE("%p\n", hSCObject);
1168 sc_handle_free( (struct sc_handle*) hSCObject );
1170 return TRUE;
1174 /******************************************************************************
1175 * OpenServiceA [ADVAPI32.@]
1177 * Open a handle to a service.
1179 * PARAMS
1180 * hSCManager [I] Handle of the service control manager database
1181 * lpServiceName [I] Name of the service to open
1182 * dwDesiredAccess [I] Access required to the service
1184 * RETURNS
1185 * Success: Handle to the service
1186 * Failure: NULL
1188 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1189 DWORD dwDesiredAccess )
1191 LPWSTR lpServiceNameW;
1192 SC_HANDLE ret;
1194 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1196 lpServiceNameW = SERV_dup(lpServiceName);
1197 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1198 SERV_free(lpServiceNameW);
1199 return ret;
1203 /******************************************************************************
1204 * OpenServiceW [ADVAPI32.@]
1206 * See OpenServiceA.
1208 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1209 DWORD dwDesiredAccess)
1211 struct sc_manager *hscm;
1212 struct sc_service *hsvc;
1213 HKEY hKey;
1214 long r;
1215 DWORD len;
1216 DWORD new_mask = dwDesiredAccess;
1218 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1220 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1221 if (!hscm)
1223 SetLastError( ERROR_INVALID_HANDLE );
1224 return FALSE;
1227 if (!lpServiceName)
1229 SetLastError(ERROR_INVALID_ADDRESS);
1230 return NULL;
1233 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1234 if (r!=ERROR_SUCCESS)
1236 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1237 return NULL;
1240 len = strlenW(lpServiceName)+1;
1241 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1242 sizeof (struct sc_service) + len*sizeof(WCHAR),
1243 sc_handle_destroy_service );
1244 if (!hsvc)
1246 RegCloseKey(hKey);
1247 return NULL;
1249 strcpyW( hsvc->name, lpServiceName );
1250 hsvc->hkey = hKey;
1252 RtlMapGenericMask(&new_mask, &svc_generic);
1253 hsvc->dwAccess = new_mask;
1255 /* add reference to SCM handle */
1256 hscm->hdr.ref_count++;
1257 hsvc->scm = hscm;
1259 TRACE("returning %p\n",hsvc);
1261 return (SC_HANDLE) &hsvc->hdr;
1264 /******************************************************************************
1265 * CreateServiceW [ADVAPI32.@]
1267 SC_HANDLE WINAPI
1268 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1269 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1270 DWORD dwServiceType, DWORD dwStartType,
1271 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1272 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1273 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1274 LPCWSTR lpPassword )
1276 struct sc_manager *hscm;
1277 struct sc_service *hsvc = NULL;
1278 HKEY hKey;
1279 LONG r;
1280 DWORD dp, len;
1281 struct reg_value val[10];
1282 int n = 0;
1283 DWORD new_mask = dwDesiredAccess;
1284 DWORD index = 0;
1285 WCHAR buffer[MAX_PATH];
1286 BOOL displayname_exists = FALSE;
1288 TRACE("%p %s %s\n", hSCManager,
1289 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1291 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1292 if (!hscm)
1294 SetLastError( ERROR_INVALID_HANDLE );
1295 return NULL;
1298 if (!lpServiceName || !lpBinaryPathName)
1300 SetLastError(ERROR_INVALID_ADDRESS);
1301 return NULL;
1304 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1306 SetLastError(ERROR_ACCESS_DENIED);
1307 return NULL;
1310 if (!lpServiceName[0])
1312 SetLastError(ERROR_INVALID_NAME);
1313 return NULL;
1316 if (!lpBinaryPathName[0])
1318 SetLastError(ERROR_INVALID_PARAMETER);
1319 return NULL;
1322 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1323 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1324 * runs under the LocalSystem account)
1326 switch (dwServiceType)
1328 case SERVICE_KERNEL_DRIVER:
1329 case SERVICE_FILE_SYSTEM_DRIVER:
1330 case SERVICE_WIN32_OWN_PROCESS:
1331 case SERVICE_WIN32_SHARE_PROCESS:
1332 /* No problem */
1333 break;
1334 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1335 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1336 /* FIXME : Do we need a more thorough check? */
1337 if (lpServiceStartName)
1339 SetLastError(ERROR_INVALID_PARAMETER);
1340 return NULL;
1342 break;
1343 default:
1344 SetLastError(ERROR_INVALID_PARAMETER);
1345 return NULL;
1348 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1349 if (dwStartType > SERVICE_DISABLED)
1351 SetLastError(ERROR_INVALID_PARAMETER);
1352 return NULL;
1355 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1356 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1357 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1359 SetLastError(ERROR_INVALID_PARAMETER);
1360 return NULL;
1363 /* Loop through the registry to check if the service already exists and to
1364 * check if we can use the given displayname.
1365 * FIXME: Should we use EnumServicesStatusEx?
1367 len = sizeof(buffer);
1368 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1370 HKEY service_key;
1372 /* The service already exists, so bail out */
1373 if(!lstrcmpiW(lpServiceName, buffer))
1375 SetLastError(ERROR_SERVICE_EXISTS);
1376 return NULL;
1379 /* The given displayname matches the found servicename. We don't bail out
1380 * as servicename is checked before a duplicate displayname
1382 if(!lstrcmpiW(lpDisplayName, buffer))
1383 displayname_exists = TRUE;
1385 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1387 WCHAR name[MAX_PATH];
1388 DWORD size = sizeof(name);
1390 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1392 /* The given displayname matches the found displayname */
1393 if (!lstrcmpiW(lpDisplayName, name))
1394 displayname_exists = TRUE;
1396 RegCloseKey(service_key);
1398 index++;
1399 len = sizeof(buffer);
1402 if (lpDisplayName && displayname_exists)
1404 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1405 return NULL;
1408 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1409 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1410 if (r!=ERROR_SUCCESS)
1412 /* FIXME: Should we set an error? */
1413 return NULL;
1416 if( lpDisplayName )
1417 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1419 service_set_dword( &val[n++], szType, &dwServiceType );
1420 service_set_dword( &val[n++], szStart, &dwStartType );
1421 service_set_dword( &val[n++], szError, &dwErrorControl );
1423 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1425 if( lpLoadOrderGroup )
1426 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1428 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1429 * There is no such key as what szDependencies refers to */
1430 if( lpDependencies )
1431 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1433 if( lpPassword )
1434 FIXME("Don't know how to add a Password for a service.\n");
1436 if( lpServiceStartName )
1437 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1439 r = service_write_values( hKey, val, n );
1440 if( r != ERROR_SUCCESS )
1441 goto error;
1443 len = strlenW(lpServiceName)+1;
1444 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1445 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1446 if( !hsvc )
1447 goto error;
1448 lstrcpyW( hsvc->name, lpServiceName );
1449 hsvc->hkey = hKey;
1451 RtlMapGenericMask(&new_mask, &svc_generic);
1452 hsvc->dwAccess = new_mask;
1454 hsvc->scm = hscm;
1455 hscm->hdr.ref_count++;
1457 return (SC_HANDLE) &hsvc->hdr;
1459 error:
1460 RegCloseKey( hKey );
1461 return NULL;
1465 /******************************************************************************
1466 * CreateServiceA [ADVAPI32.@]
1468 SC_HANDLE WINAPI
1469 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1470 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1471 DWORD dwServiceType, DWORD dwStartType,
1472 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1473 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1474 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1475 LPCSTR lpPassword )
1477 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1478 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1479 SC_HANDLE r;
1481 TRACE("%p %s %s\n", hSCManager,
1482 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1484 lpServiceNameW = SERV_dup( lpServiceName );
1485 lpDisplayNameW = SERV_dup( lpDisplayName );
1486 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1487 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1488 lpDependenciesW = SERV_dupmulti( lpDependencies );
1489 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1490 lpPasswordW = SERV_dup( lpPassword );
1492 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1493 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1494 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1495 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1497 SERV_free( lpServiceNameW );
1498 SERV_free( lpDisplayNameW );
1499 SERV_free( lpBinaryPathNameW );
1500 SERV_free( lpLoadOrderGroupW );
1501 SERV_free( lpDependenciesW );
1502 SERV_free( lpServiceStartNameW );
1503 SERV_free( lpPasswordW );
1505 return r;
1509 /******************************************************************************
1510 * DeleteService [ADVAPI32.@]
1512 * Delete a service from the service control manager database.
1514 * PARAMS
1515 * hService [I] Handle of the service to delete
1517 * RETURNS
1518 * Success: TRUE
1519 * Failure: FALSE
1521 BOOL WINAPI DeleteService( SC_HANDLE hService )
1523 struct sc_service *hsvc;
1525 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1526 if (!hsvc)
1528 SetLastError( ERROR_INVALID_HANDLE );
1529 return FALSE;
1532 if (!(hsvc->dwAccess & DELETE))
1534 SetLastError(ERROR_ACCESS_DENIED);
1535 return FALSE;
1538 /* Close the key to the service */
1539 RegCloseKey(hsvc->hkey);
1541 /* Delete the service under the Service Control Manager key */
1542 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1544 hsvc->hkey = NULL;
1546 return TRUE;
1550 /******************************************************************************
1551 * StartServiceA [ADVAPI32.@]
1553 * Start a service
1555 * PARAMS
1556 * hService [I] Handle of service
1557 * dwNumServiceArgs [I] Number of arguments
1558 * lpServiceArgVectors [I] Address of array of argument strings
1560 * NOTES
1561 * - NT implements this function using an obscure RPC call.
1562 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1563 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1564 * - This will only work for shared address space. How should the service
1565 * args be transferred when address spaces are separated?
1566 * - Can only start one service at a time.
1567 * - Has no concept of privilege.
1569 * RETURNS
1570 * Success: TRUE.
1571 * Failure: FALSE
1573 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1574 LPCSTR *lpServiceArgVectors )
1576 LPWSTR *lpwstr=NULL;
1577 unsigned int i;
1578 BOOL r;
1580 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1582 if (dwNumServiceArgs)
1583 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1584 dwNumServiceArgs*sizeof(LPWSTR) );
1586 for(i=0; i<dwNumServiceArgs; i++)
1587 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1589 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1591 if (dwNumServiceArgs)
1593 for(i=0; i<dwNumServiceArgs; i++)
1594 SERV_free(lpwstr[i]);
1595 HeapFree(GetProcessHeap(), 0, lpwstr);
1598 return r;
1601 /******************************************************************************
1602 * service_start_process [INTERNAL]
1604 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1606 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1607 PROCESS_INFORMATION pi;
1608 STARTUPINFOW si;
1609 LPWSTR path = NULL, str;
1610 DWORD type, size, ret, svc_type;
1611 HANDLE handles[2];
1612 BOOL r;
1614 size = sizeof(svc_type);
1615 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1616 svc_type = 0;
1618 if (svc_type == SERVICE_KERNEL_DRIVER)
1620 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1621 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1623 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1624 GetSystemDirectoryW( path, len );
1625 lstrcatW( path, winedeviceW );
1626 lstrcatW( path, hsvc->name );
1628 else
1630 /* read the executable path from the registry */
1631 size = 0;
1632 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1633 if (ret!=ERROR_SUCCESS)
1634 return FALSE;
1635 str = HeapAlloc(GetProcessHeap(),0,size);
1636 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1637 if (ret==ERROR_SUCCESS)
1639 size = ExpandEnvironmentStringsW(str,NULL,0);
1640 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1641 ExpandEnvironmentStringsW(str,path,size);
1643 HeapFree(GetProcessHeap(),0,str);
1644 if (!path)
1645 return FALSE;
1648 /* wait for the process to start and set an event or terminate */
1649 handles[0] = service_get_event_handle( hsvc->name );
1650 ZeroMemory(&si, sizeof(STARTUPINFOW));
1651 si.cb = sizeof(STARTUPINFOW);
1652 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1653 if (r)
1655 if (ppid) *ppid = pi.dwProcessId;
1657 handles[1] = pi.hProcess;
1658 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1659 if(ret != WAIT_OBJECT_0)
1661 SetLastError(ERROR_IO_PENDING);
1662 r = FALSE;
1665 CloseHandle( pi.hThread );
1666 CloseHandle( pi.hProcess );
1668 CloseHandle( handles[0] );
1669 HeapFree(GetProcessHeap(),0,path);
1670 return r;
1673 static BOOL service_wait_for_startup(SC_HANDLE hService)
1675 DWORD i;
1676 SERVICE_STATUS status;
1677 BOOL r = FALSE;
1679 TRACE("%p\n", hService);
1681 for (i=0; i<30; i++)
1683 status.dwCurrentState = 0;
1684 r = QueryServiceStatus(hService, &status);
1685 if (!r)
1686 break;
1687 if (status.dwCurrentState == SERVICE_RUNNING)
1689 TRACE("Service started successfully\n");
1690 break;
1692 r = FALSE;
1693 Sleep(1000);
1695 return r;
1698 /******************************************************************************
1699 * StartServiceW [ADVAPI32.@]
1701 * See StartServiceA.
1703 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1704 LPCWSTR *lpServiceArgVectors)
1706 struct sc_service *hsvc;
1707 BOOL r = FALSE;
1708 SC_LOCK hLock;
1709 HANDLE handle = INVALID_HANDLE_VALUE;
1711 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1713 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1714 if (!hsvc)
1716 SetLastError(ERROR_INVALID_HANDLE);
1717 return r;
1720 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1721 if (!hLock)
1722 return r;
1724 handle = service_open_pipe(hsvc->name);
1725 if (handle==INVALID_HANDLE_VALUE)
1727 /* start the service process */
1728 if (service_start_process(hsvc, NULL))
1729 handle = service_open_pipe(hsvc->name);
1732 if (handle != INVALID_HANDLE_VALUE)
1734 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1735 CloseHandle(handle);
1738 UnlockServiceDatabase( hLock );
1740 TRACE("returning %d\n", r);
1742 if (r)
1743 service_wait_for_startup(hService);
1745 return r;
1748 /******************************************************************************
1749 * QueryServiceStatus [ADVAPI32.@]
1751 * PARAMS
1752 * hService [I] Handle to service to get information about
1753 * lpservicestatus [O] buffer to receive the status information for the service
1756 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1757 LPSERVICE_STATUS lpservicestatus)
1759 SERVICE_STATUS_PROCESS SvcStatusData;
1760 BOOL ret;
1762 TRACE("%p %p\n", hService, lpservicestatus);
1764 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1765 sizeof(SERVICE_STATUS_PROCESS), NULL);
1766 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1767 return ret;
1771 /******************************************************************************
1772 * QueryServiceStatusEx [ADVAPI32.@]
1774 * Get information about a service.
1776 * PARAMS
1777 * hService [I] Handle to service to get information about
1778 * InfoLevel [I] Level of information to get
1779 * lpBuffer [O] Destination for requested information
1780 * cbBufSize [I] Size of lpBuffer in bytes
1781 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1783 * RETURNS
1784 * Success: TRUE
1785 * FAILURE: FALSE
1787 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1788 LPBYTE lpBuffer, DWORD cbBufSize,
1789 LPDWORD pcbBytesNeeded)
1791 struct sc_service *hsvc;
1792 DWORD size, type, val;
1793 HANDLE pipe;
1794 LONG r;
1795 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1797 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1799 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1801 SetLastError( ERROR_INVALID_LEVEL);
1802 return FALSE;
1805 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1806 if (pSvcStatusData == NULL)
1808 SetLastError( ERROR_INVALID_PARAMETER);
1809 return FALSE;
1812 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1814 if( pcbBytesNeeded != NULL)
1815 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1817 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1818 return FALSE;
1821 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1822 if (!hsvc)
1824 SetLastError( ERROR_INVALID_HANDLE );
1825 return FALSE;
1828 pipe = service_open_pipe(hsvc->name);
1829 if (pipe != INVALID_HANDLE_VALUE)
1831 r = service_get_status(pipe, pSvcStatusData);
1832 CloseHandle(pipe);
1833 if (r)
1834 return TRUE;
1837 TRACE("Failed to read service status\n");
1839 /* read the service type from the registry */
1840 size = sizeof(val);
1841 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1842 if (r != ERROR_SUCCESS || type != REG_DWORD)
1843 val = 0;
1845 pSvcStatusData->dwServiceType = val;
1846 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1847 pSvcStatusData->dwControlsAccepted = 0;
1848 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1849 pSvcStatusData->dwServiceSpecificExitCode = 0;
1850 pSvcStatusData->dwCheckPoint = 0;
1851 pSvcStatusData->dwWaitHint = 0;
1853 return TRUE;
1856 /******************************************************************************
1857 * QueryServiceConfigA [ADVAPI32.@]
1859 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1860 DWORD size, LPDWORD needed )
1862 DWORD n;
1863 LPSTR p, buffer;
1864 BOOL ret;
1865 QUERY_SERVICE_CONFIGW *configW;
1867 TRACE("%p %p %d %p\n", hService, config, size, needed);
1869 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1871 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1872 return FALSE;
1874 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1875 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1876 if (!ret) goto done;
1878 config->dwServiceType = configW->dwServiceType;
1879 config->dwStartType = configW->dwStartType;
1880 config->dwErrorControl = configW->dwErrorControl;
1881 config->lpBinaryPathName = NULL;
1882 config->lpLoadOrderGroup = NULL;
1883 config->dwTagId = configW->dwTagId;
1884 config->lpDependencies = NULL;
1885 config->lpServiceStartName = NULL;
1886 config->lpDisplayName = NULL;
1888 p = (LPSTR)(config + 1);
1889 n = size - sizeof(*config);
1890 ret = FALSE;
1892 #define MAP_STR(str) \
1893 do { \
1894 if (configW->str) \
1896 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1897 if (!sz) goto done; \
1898 config->str = p; \
1899 p += sz; \
1900 n -= sz; \
1902 } while (0)
1904 MAP_STR( lpBinaryPathName );
1905 MAP_STR( lpLoadOrderGroup );
1906 MAP_STR( lpDependencies );
1907 MAP_STR( lpServiceStartName );
1908 MAP_STR( lpDisplayName );
1909 #undef MAP_STR
1911 *needed = p - (LPSTR)config;
1912 ret = TRUE;
1914 done:
1915 HeapFree( GetProcessHeap(), 0, buffer );
1916 return ret;
1919 /******************************************************************************
1920 * QueryServiceConfigW [ADVAPI32.@]
1922 BOOL WINAPI
1923 QueryServiceConfigW( SC_HANDLE hService,
1924 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1925 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1927 WCHAR str_buffer[ MAX_PATH ];
1928 LONG r;
1929 DWORD type, val, sz, total, n;
1930 LPBYTE p;
1931 HKEY hKey;
1932 struct sc_service *hsvc;
1934 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1935 cbBufSize, pcbBytesNeeded);
1937 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1938 if (!hsvc)
1940 SetLastError( ERROR_INVALID_HANDLE );
1941 return FALSE;
1943 hKey = hsvc->hkey;
1945 /* TODO: Check which members are mandatory and what the registry types
1946 * should be. This should of course also be tested when a service is
1947 * created.
1950 /* calculate the size required first */
1951 total = sizeof (QUERY_SERVICE_CONFIGW);
1953 sz = sizeof(str_buffer);
1954 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1955 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1957 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1958 if( 0 == sz ) return FALSE;
1960 total += sizeof(WCHAR) * sz;
1962 else
1964 /* FIXME: set last error */
1965 return FALSE;
1968 sz = 0;
1969 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1970 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1971 total += sz;
1972 else
1973 total += sizeof(WCHAR);
1975 sz = 0;
1976 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1977 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1978 total += sz;
1979 else
1980 total += sizeof(WCHAR);
1982 sz = 0;
1983 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1984 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1985 total += sz;
1986 else
1987 total += sizeof(WCHAR);
1989 sz = 0;
1990 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1991 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1992 total += sz;
1993 else
1994 total += sizeof(WCHAR);
1996 *pcbBytesNeeded = total;
1998 /* if there's not enough memory, return an error */
1999 if( total > cbBufSize )
2001 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2002 return FALSE;
2005 ZeroMemory( lpServiceConfig, total );
2007 sz = sizeof val;
2008 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2009 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2010 lpServiceConfig->dwServiceType = val;
2012 sz = sizeof val;
2013 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2014 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2015 lpServiceConfig->dwStartType = val;
2017 sz = sizeof val;
2018 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2019 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2020 lpServiceConfig->dwErrorControl = val;
2022 sz = sizeof val;
2023 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2024 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2025 lpServiceConfig->dwTagId = val;
2027 /* now do the strings */
2028 p = (LPBYTE) &lpServiceConfig[1];
2029 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2031 sz = sizeof(str_buffer);
2032 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2033 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2035 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2036 sz *= sizeof(WCHAR);
2037 if( 0 == sz || sz > n ) return FALSE;
2039 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2040 p += sz;
2041 n -= sz;
2043 else
2045 /* FIXME: set last error */
2046 return FALSE;
2049 sz = n;
2050 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2051 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2052 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2054 p += sz;
2055 n -= sz;
2057 else
2059 *(WCHAR *) p = 0;
2060 p += sizeof(WCHAR);
2061 n -= sizeof(WCHAR);
2064 sz = n;
2065 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2066 lpServiceConfig->lpDependencies = (LPWSTR) p;
2067 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2069 p += sz;
2070 n -= sz;
2072 else
2074 *(WCHAR *) p = 0;
2075 p += sizeof(WCHAR);
2076 n -= sizeof(WCHAR);
2079 sz = n;
2080 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2081 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2082 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2084 p += sz;
2085 n -= sz;
2087 else
2089 *(WCHAR *) p = 0;
2090 p += sizeof(WCHAR);
2091 n -= sizeof(WCHAR);
2094 sz = n;
2095 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2096 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2097 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2099 p += sz;
2100 n -= sz;
2102 else
2104 *(WCHAR *) p = 0;
2105 p += sizeof(WCHAR);
2106 n -= sizeof(WCHAR);
2109 if( n < 0 )
2110 ERR("Buffer overflow!\n");
2112 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2113 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2114 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2115 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2116 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2118 return TRUE;
2121 /******************************************************************************
2122 * EnumServicesStatusA [ADVAPI32.@]
2124 BOOL WINAPI
2125 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2126 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2127 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2128 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2130 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2131 dwServiceType, dwServiceState, lpServices, cbBufSize,
2132 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2133 SetLastError (ERROR_ACCESS_DENIED);
2134 return FALSE;
2137 /******************************************************************************
2138 * EnumServicesStatusW [ADVAPI32.@]
2140 BOOL WINAPI
2141 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2142 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2143 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2144 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2146 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2147 dwServiceType, dwServiceState, lpServices, cbBufSize,
2148 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2149 SetLastError (ERROR_ACCESS_DENIED);
2150 return FALSE;
2153 /******************************************************************************
2154 * EnumServicesStatusExA [ADVAPI32.@]
2156 BOOL WINAPI
2157 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2158 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2159 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2161 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2162 dwServiceType, dwServiceState, lpServices, cbBufSize,
2163 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2164 SetLastError (ERROR_ACCESS_DENIED);
2165 return FALSE;
2168 /******************************************************************************
2169 * EnumServicesStatusExW [ADVAPI32.@]
2171 BOOL WINAPI
2172 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2173 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2174 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2176 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2177 dwServiceType, dwServiceState, lpServices, cbBufSize,
2178 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2179 SetLastError (ERROR_ACCESS_DENIED);
2180 return FALSE;
2183 /******************************************************************************
2184 * GetServiceKeyNameA [ADVAPI32.@]
2186 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2187 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2189 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2190 return FALSE;
2193 /******************************************************************************
2194 * GetServiceKeyNameW [ADVAPI32.@]
2196 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2197 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2199 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2200 return FALSE;
2203 /******************************************************************************
2204 * QueryServiceLockStatusA [ADVAPI32.@]
2206 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2207 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2208 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2210 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2212 return FALSE;
2215 /******************************************************************************
2216 * QueryServiceLockStatusW [ADVAPI32.@]
2218 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2219 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2220 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2222 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2224 return FALSE;
2227 /******************************************************************************
2228 * GetServiceDisplayNameA [ADVAPI32.@]
2230 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2231 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2233 LPWSTR lpServiceNameW, lpDisplayNameW = NULL;
2234 DWORD size, sizeW, GLE;
2235 BOOL ret;
2237 TRACE("%p %s %p %p\n", hSCManager,
2238 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2240 lpServiceNameW = SERV_dup(lpServiceName);
2241 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2243 size = sizeW = *lpcchBuffer;
2244 ret = GetServiceDisplayNameW(hSCManager, lpServiceNameW,
2245 lpDisplayName ? lpDisplayNameW : NULL,
2246 &sizeW);
2247 /* Last error will be set by GetServiceDisplayNameW and must be preserved */
2248 GLE = GetLastError();
2250 if (!lpDisplayName && *lpcchBuffer && !ret && (GLE == ERROR_INSUFFICIENT_BUFFER))
2252 /* Request for buffersize.
2254 * Only set the size for ERROR_INSUFFICIENT_BUFFER
2256 size = sizeW * 2;
2258 else if (lpDisplayName && *lpcchBuffer && !ret)
2260 /* Request for displayname.
2262 * size only has to be set if this fails
2264 size = sizeW * 2;
2267 WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2268 *lpcchBuffer, NULL, NULL );
2270 *lpcchBuffer = size;
2272 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2273 SERV_free(lpServiceNameW);
2275 SetLastError(GLE);
2276 return ret;
2279 /******************************************************************************
2280 * GetServiceDisplayNameW [ADVAPI32.@]
2282 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2283 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2285 struct sc_manager *hscm;
2286 DWORD type, size;
2287 LONG ret;
2289 TRACE("%p %s %p %p\n", hSCManager,
2290 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2292 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2293 if (!hscm)
2295 SetLastError(ERROR_INVALID_HANDLE);
2296 return FALSE;
2299 if (!lpServiceName)
2301 SetLastError(ERROR_INVALID_ADDRESS);
2302 return FALSE;
2305 size = *lpcchBuffer * sizeof(WCHAR);
2306 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2307 if (!ret && !lpDisplayName && size)
2308 ret = ERROR_MORE_DATA;
2310 if (ret)
2312 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2314 if (ret == ERROR_MORE_DATA)
2316 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2317 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2319 else if (ret == ERROR_FILE_NOT_FOUND)
2321 HKEY hkey;
2323 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2325 INT len = lstrlenW(lpServiceName);
2326 BOOL r = FALSE;
2328 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2329 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2330 else if (lpDisplayName && *lpcchBuffer)
2332 /* No displayname, but the service exists and the buffer
2333 * is big enough. We should return the servicename.
2335 lstrcpyW(lpDisplayName, lpServiceName);
2336 r = TRUE;
2339 *lpcchBuffer = len;
2340 RegCloseKey(hkey);
2341 return r;
2343 else
2344 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2346 else
2347 SetLastError(ret);
2348 return FALSE;
2351 /* Always return the correct needed size on success */
2352 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2354 return TRUE;
2357 /******************************************************************************
2358 * ChangeServiceConfigW [ADVAPI32.@]
2360 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2361 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2362 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2363 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2365 struct reg_value val[10];
2366 struct sc_service *hsvc;
2367 DWORD r = ERROR_SUCCESS;
2368 HKEY hKey;
2369 int n = 0;
2371 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2372 hService, dwServiceType, dwStartType, dwErrorControl,
2373 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2374 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2375 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2377 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2378 if (!hsvc)
2380 SetLastError( ERROR_INVALID_HANDLE );
2381 return FALSE;
2383 hKey = hsvc->hkey;
2385 if( dwServiceType != SERVICE_NO_CHANGE )
2386 service_set_dword( &val[n++], szType, &dwServiceType );
2388 if( dwStartType != SERVICE_NO_CHANGE )
2389 service_set_dword( &val[n++], szStart, &dwStartType );
2391 if( dwErrorControl != SERVICE_NO_CHANGE )
2392 service_set_dword( &val[n++], szError, &dwErrorControl );
2394 if( lpBinaryPathName )
2395 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2397 if( lpLoadOrderGroup )
2398 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2400 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2401 * There is no such key as what szDependencies refers to */
2402 if( lpDependencies )
2403 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2405 if( lpPassword )
2406 FIXME("ignoring password\n");
2408 if( lpServiceStartName )
2409 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2411 r = service_write_values( hsvc->hkey, val, n );
2413 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2416 /******************************************************************************
2417 * ChangeServiceConfigA [ADVAPI32.@]
2419 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2420 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2421 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2422 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2424 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2425 LPWSTR wServiceStartName, wPassword, wDisplayName;
2426 BOOL r;
2428 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2429 hService, dwServiceType, dwStartType, dwErrorControl,
2430 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2431 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2432 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2434 wBinaryPathName = SERV_dup( lpBinaryPathName );
2435 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2436 wDependencies = SERV_dupmulti( lpDependencies );
2437 wServiceStartName = SERV_dup( lpServiceStartName );
2438 wPassword = SERV_dup( lpPassword );
2439 wDisplayName = SERV_dup( lpDisplayName );
2441 r = ChangeServiceConfigW( hService, dwServiceType,
2442 dwStartType, dwErrorControl, wBinaryPathName,
2443 wLoadOrderGroup, lpdwTagId, wDependencies,
2444 wServiceStartName, wPassword, wDisplayName);
2446 SERV_free( wBinaryPathName );
2447 SERV_free( wLoadOrderGroup );
2448 SERV_free( wDependencies );
2449 SERV_free( wServiceStartName );
2450 SERV_free( wPassword );
2451 SERV_free( wDisplayName );
2453 return r;
2456 /******************************************************************************
2457 * ChangeServiceConfig2A [ADVAPI32.@]
2459 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2460 LPVOID lpInfo)
2462 BOOL r = FALSE;
2464 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2466 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2468 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2469 SERVICE_DESCRIPTIONW sdw;
2471 sdw.lpDescription = SERV_dup( sd->lpDescription );
2473 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2475 SERV_free( sdw.lpDescription );
2477 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2479 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2480 SERVICE_FAILURE_ACTIONSW faw;
2482 faw.dwResetPeriod = fa->dwResetPeriod;
2483 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2484 faw.lpCommand = SERV_dup( fa->lpCommand );
2485 faw.cActions = fa->cActions;
2486 faw.lpsaActions = fa->lpsaActions;
2488 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2490 SERV_free( faw.lpRebootMsg );
2491 SERV_free( faw.lpCommand );
2493 else
2494 SetLastError( ERROR_INVALID_PARAMETER );
2496 return r;
2499 /******************************************************************************
2500 * ChangeServiceConfig2W [ADVAPI32.@]
2502 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2503 LPVOID lpInfo)
2505 HKEY hKey;
2506 struct sc_service *hsvc;
2508 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2509 if (!hsvc)
2511 SetLastError( ERROR_INVALID_HANDLE );
2512 return FALSE;
2514 hKey = hsvc->hkey;
2516 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2518 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2519 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2520 if (sd->lpDescription)
2522 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2523 if (sd->lpDescription[0] == 0)
2524 RegDeleteValueW(hKey,szDescription);
2525 else
2526 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2527 (LPVOID)sd->lpDescription,
2528 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2531 else
2532 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2533 return TRUE;
2536 /******************************************************************************
2537 * QueryServiceObjectSecurity [ADVAPI32.@]
2539 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2540 SECURITY_INFORMATION dwSecurityInformation,
2541 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2542 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2544 PACL pACL = NULL;
2546 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2547 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2549 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2551 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2552 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2553 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2554 return TRUE;
2557 /******************************************************************************
2558 * SetServiceObjectSecurity [ADVAPI32.@]
2560 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2561 SECURITY_INFORMATION dwSecurityInformation,
2562 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2564 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2565 return TRUE;
2568 /******************************************************************************
2569 * SetServiceBits [ADVAPI32.@]
2571 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2572 DWORD dwServiceBits,
2573 BOOL bSetBitsOn,
2574 BOOL bUpdateImmediately)
2576 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2577 bSetBitsOn, bUpdateImmediately);
2578 return TRUE;
2581 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2582 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2584 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2585 return 0;
2588 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2589 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2591 service_data *service;
2592 SERVICE_STATUS_HANDLE handle = 0;
2594 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2596 EnterCriticalSection( &service_cs );
2597 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2599 if(!strcmpW(lpServiceName, service->name))
2601 service->handler.handler_ex = lpHandlerProc;
2602 service->context = lpContext;
2603 service->extended = TRUE;
2604 handle = (SERVICE_STATUS_HANDLE)service;
2605 break;
2608 LeaveCriticalSection( &service_cs );
2610 return handle;