push 4d5485f9b89f417d46b39b93e8d940437007f325
[wine/hacks.git] / dlls / advapi32 / service.c
blob458653c85fa0ade640ae4a2792f8ca5cf176265d
1 /*
2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <stdarg.h>
24 #include <string.h>
25 #include <time.h>
26 #include <assert.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winsvc.h"
31 #include "winerror.h"
32 #include "winreg.h"
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
35 #include "winternl.h"
36 #include "lmcons.h"
37 #include "lmserver.h"
38 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
42 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
43 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
44 'S','e','r','v','i','c','e','s',0 };
45 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
46 'L','O','C','K',0};
48 static const GENERIC_MAPPING scm_generic = {
49 (STANDARD_RIGHTS_READ | SC_MANAGER_ENUMERATE_SERVICE | SC_MANAGER_QUERY_LOCK_STATUS),
50 (STANDARD_RIGHTS_WRITE | SC_MANAGER_CREATE_SERVICE | SC_MANAGER_MODIFY_BOOT_CONFIG),
51 (STANDARD_RIGHTS_EXECUTE | SC_MANAGER_CONNECT | SC_MANAGER_LOCK),
52 SC_MANAGER_ALL_ACCESS
55 static const GENERIC_MAPPING svc_generic = {
56 (STANDARD_RIGHTS_READ | SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_INTERROGATE | SERVICE_ENUMERATE_DEPENDENTS),
57 (STANDARD_RIGHTS_WRITE | SERVICE_CHANGE_CONFIG),
58 (STANDARD_RIGHTS_EXECUTE | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_USER_DEFINED_CONTROL),
59 SERVICE_ALL_ACCESS
62 typedef struct service_start_info_t
64 DWORD cmd;
65 DWORD size;
66 WCHAR str[1];
67 } service_start_info;
69 #define WINESERV_STARTINFO 1
70 #define WINESERV_GETSTATUS 2
71 #define WINESERV_SENDCONTROL 3
72 #define WINESERV_SETPID 4
74 typedef struct service_data_t
76 struct list entry;
77 union {
78 LPHANDLER_FUNCTION handler;
79 LPHANDLER_FUNCTION_EX handler_ex;
80 } handler;
81 LPVOID context;
82 SERVICE_STATUS_PROCESS status;
83 HANDLE thread;
84 BOOL unicode : 1;
85 BOOL extended : 1; /* uses handler_ex instead of handler? */
86 union {
87 LPSERVICE_MAIN_FUNCTIONA a;
88 LPSERVICE_MAIN_FUNCTIONW w;
89 } proc;
90 LPWSTR args;
91 WCHAR name[1];
92 } service_data;
94 static CRITICAL_SECTION service_cs;
95 static CRITICAL_SECTION_DEBUG service_cs_debug =
97 0, 0, &service_cs,
98 { &service_cs_debug.ProcessLocksList,
99 &service_cs_debug.ProcessLocksList },
100 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
102 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
104 static struct list service_list = LIST_INIT(service_list);
106 extern HANDLE __wine_make_process_system(void);
108 /******************************************************************************
109 * SC_HANDLEs
112 #define MAX_SERVICE_NAME 256
114 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
116 struct sc_handle;
117 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
119 struct sc_handle
121 SC_HANDLE_TYPE htype;
122 DWORD ref_count;
123 sc_handle_destructor destroy;
126 struct sc_manager /* service control manager handle */
128 struct sc_handle hdr;
129 HKEY hkey; /* handle to services database in the registry */
130 DWORD dwAccess;
133 struct sc_service /* service handle */
135 struct sc_handle hdr;
136 HKEY hkey; /* handle to service entry in the registry (under hkey) */
137 DWORD dwAccess;
138 struct sc_manager *scm; /* pointer to SCM handle */
139 WCHAR name[1];
142 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
143 sc_handle_destructor destroy)
145 struct sc_handle *hdr;
147 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
148 if (hdr)
150 hdr->htype = htype;
151 hdr->ref_count = 1;
152 hdr->destroy = destroy;
154 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
155 return hdr;
158 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
160 struct sc_handle *hdr = (struct sc_handle *) handle;
162 if (!hdr)
163 return NULL;
164 if (hdr->htype != htype)
165 return NULL;
166 return hdr;
169 static void sc_handle_free(struct sc_handle* hdr)
171 if (!hdr)
172 return;
173 if (--hdr->ref_count)
174 return;
175 hdr->destroy(hdr);
176 HeapFree(GetProcessHeap(), 0, hdr);
179 static void sc_handle_destroy_manager(struct sc_handle *handle)
181 struct sc_manager *mgr = (struct sc_manager*) handle;
183 TRACE("destroying SC Manager %p\n", mgr);
184 if (mgr->hkey)
185 RegCloseKey(mgr->hkey);
188 static void sc_handle_destroy_service(struct sc_handle *handle)
190 struct sc_service *svc = (struct sc_service*) handle;
192 TRACE("destroying service %p\n", svc);
193 if (svc->hkey)
194 RegCloseKey(svc->hkey);
195 svc->hkey = NULL;
196 sc_handle_free(&svc->scm->hdr);
197 svc->scm = NULL;
200 /******************************************************************************
201 * String management functions
203 static inline LPWSTR SERV_dup( LPCSTR str )
205 UINT len;
206 LPWSTR wstr;
208 if( !str )
209 return NULL;
210 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
211 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
212 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
213 return wstr;
216 static inline LPWSTR SERV_dupmulti(LPCSTR str)
218 UINT len = 0, n = 0;
219 LPWSTR wstr;
221 if( !str )
222 return NULL;
223 do {
224 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
225 n += (strlen( &str[n] ) + 1);
226 } while (str[n]);
227 len++;
228 n++;
230 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
231 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
232 return wstr;
235 static inline VOID SERV_free( LPWSTR wstr )
237 HeapFree( GetProcessHeap(), 0, wstr );
240 /******************************************************************************
241 * registry access functions and data
243 static const WCHAR szDisplayName[] = {
244 'D','i','s','p','l','a','y','N','a','m','e', 0 };
245 static const WCHAR szType[] = {'T','y','p','e',0};
246 static const WCHAR szStart[] = {'S','t','a','r','t',0};
247 static const WCHAR szError[] = {
248 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
249 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
250 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
251 static const WCHAR szDependencies[] = {
252 'D','e','p','e','n','d','e','n','c','i','e','s',0};
253 static const WCHAR szDependOnService[] = {
254 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
255 static const WCHAR szObjectName[] = {
256 'O','b','j','e','c','t','N','a','m','e',0};
257 static const WCHAR szTag[] = {
258 'T','a','g',0};
260 struct reg_value {
261 DWORD type;
262 DWORD size;
263 LPCWSTR name;
264 LPCVOID data;
267 static inline void service_set_value( struct reg_value *val,
268 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
270 val->name = name;
271 val->type = type;
272 val->data = data;
273 val->size = size;
276 static inline void service_set_dword( struct reg_value *val,
277 LPCWSTR name, const DWORD *data )
279 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
282 static inline void service_set_string( struct reg_value *val,
283 LPCWSTR name, LPCWSTR string )
285 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
286 service_set_value( val, REG_SZ, name, string, len );
289 static inline void service_set_multi_string( struct reg_value *val,
290 LPCWSTR name, LPCWSTR string )
292 DWORD len = 0;
294 /* determine the length of a double null terminated multi string */
295 do {
296 len += (lstrlenW( &string[ len ] )+1);
297 } while ( string[ len++ ] );
299 len *= sizeof (WCHAR);
300 service_set_value( val, REG_MULTI_SZ, name, string, len );
303 static inline LONG service_write_values( HKEY hKey,
304 const struct reg_value *val, int n )
306 LONG r = ERROR_SUCCESS;
307 int i;
309 for( i=0; i<n; i++ )
311 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
312 (const BYTE*)val[i].data, val[i].size );
313 if( r != ERROR_SUCCESS )
314 break;
316 return r;
319 /******************************************************************************
320 * Service IPC functions
322 static LPWSTR service_get_pipe_name(LPCWSTR service)
324 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
325 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
326 LPWSTR name;
327 DWORD len;
329 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
330 name = HeapAlloc(GetProcessHeap(), 0, len);
331 strcpyW(name, prefix);
332 strcatW(name, service);
333 return name;
336 static HANDLE service_open_pipe(LPCWSTR service)
338 LPWSTR szPipe = service_get_pipe_name( service );
339 HANDLE handle = INVALID_HANDLE_VALUE;
341 do {
342 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
343 0, NULL, OPEN_ALWAYS, 0, NULL);
344 if (handle != INVALID_HANDLE_VALUE)
345 break;
346 if (GetLastError() != ERROR_PIPE_BUSY)
347 break;
348 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
349 SERV_free(szPipe);
351 return handle;
354 /******************************************************************************
355 * service_get_event_handle
357 static HANDLE service_get_event_handle(LPCWSTR service)
359 static const WCHAR prefix[] = {
360 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
361 LPWSTR name;
362 DWORD len;
363 HANDLE handle;
365 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
366 name = HeapAlloc(GetProcessHeap(), 0, len);
367 strcpyW(name, prefix);
368 strcatW(name, service);
369 handle = CreateEventW(NULL, TRUE, FALSE, name);
370 SERV_free(name);
371 return handle;
374 /******************************************************************************
375 * service_thread
377 * Call into the main service routine provided by StartServiceCtrlDispatcher.
379 static DWORD WINAPI service_thread(LPVOID arg)
381 service_data *info = arg;
382 LPWSTR str = info->args;
383 DWORD argc = 0, len = 0;
385 TRACE("%p\n", arg);
387 while (str[len])
389 len += strlenW(&str[len]) + 1;
390 argc++;
393 if (!argc)
395 if (info->unicode)
396 info->proc.w(0, NULL);
397 else
398 info->proc.a(0, NULL);
399 return 0;
402 if (info->unicode)
404 LPWSTR *argv, p;
406 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
407 for (argc=0, p=str; *p; p += strlenW(p) + 1)
408 argv[argc++] = p;
409 argv[argc] = NULL;
411 info->proc.w(argc, argv);
412 HeapFree(GetProcessHeap(), 0, argv);
414 else
416 LPSTR strA, *argv, p;
417 DWORD lenA;
419 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
420 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
421 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
423 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
424 for (argc=0, p=strA; *p; p += strlen(p) + 1)
425 argv[argc++] = p;
426 argv[argc] = NULL;
428 info->proc.a(argc, argv);
429 HeapFree(GetProcessHeap(), 0, argv);
430 HeapFree(GetProcessHeap(), 0, strA);
432 return 0;
435 /******************************************************************************
436 * service_handle_start
438 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
440 DWORD read = 0, result = 0;
441 LPWSTR args;
442 BOOL r;
444 TRACE("%p %p %d\n", pipe, service, count);
446 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
447 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
448 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
450 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
451 r, count, read, debugstr_wn(args, count));
452 goto end;
455 if (service->thread)
457 ERR("service is not stopped\n");
458 goto end;
461 SERV_free(service->args);
462 service->args = args;
463 args = NULL;
464 service->thread = CreateThread( NULL, 0, service_thread,
465 service, 0, NULL );
467 end:
468 HeapFree(GetProcessHeap(), 0, args);
469 WriteFile( pipe, &result, sizeof result, &read, NULL );
471 return TRUE;
474 /******************************************************************************
475 * service_send_start_message
477 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
479 DWORD i, len, count, result;
480 service_start_info *ssi;
481 LPWSTR p;
482 BOOL r;
484 TRACE("%p %p %d\n", pipe, argv, argc);
486 /* calculate how much space do we need to send the startup info */
487 len = 1;
488 for (i=0; i<argc; i++)
489 len += strlenW(argv[i])+1;
491 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
492 ssi->cmd = WINESERV_STARTINFO;
493 ssi->size = len;
495 /* copy service args into a single buffer*/
496 p = &ssi->str[0];
497 for (i=0; i<argc; i++)
499 strcpyW(p, argv[i]);
500 p += strlenW(p) + 1;
502 *p=0;
504 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
505 if (r)
506 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
508 HeapFree(GetProcessHeap(),0,ssi);
510 return r;
513 /******************************************************************************
514 * service_handle_get_status
516 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
518 DWORD count = 0;
519 TRACE("\n");
520 return WriteFile(pipe, &service->status,
521 sizeof service->status, &count, NULL);
524 /******************************************************************************
525 * service_get_status
527 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
529 DWORD cmd[2], count = 0;
530 BOOL r;
532 cmd[0] = WINESERV_GETSTATUS;
533 cmd[1] = 0;
534 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
535 if (!r || count != sizeof cmd)
537 ERR("service protocol error - failed to write pipe!\n");
538 return r;
540 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
541 if (!r || count != sizeof *status)
542 ERR("service protocol error - failed to read pipe "
543 "r = %d count = %d!\n", r, count);
544 return r;
547 /******************************************************************************
548 * service_handle_set_processID
550 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
552 DWORD count, ret = ERROR_SUCCESS;
554 TRACE("received control %d\n", dwProcessId);
555 service->status.dwProcessId = dwProcessId;
556 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
559 /******************************************************************************
560 * service_set_processID
562 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
564 DWORD cmd[2], count = 0;
565 BOOL r;
567 cmd[0] = WINESERV_SETPID;
568 cmd[1] = dwprocessId;
569 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
570 if (!r || count != sizeof cmd)
572 ERR("service protocol error - failed to write pipe!\n");
573 return r;
575 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
576 if (!r || count != sizeof *dwResult)
577 ERR("service protocol error - failed to read pipe "
578 "r = %d count = %d!\n", r, count);
579 return r;
582 /******************************************************************************
583 * service_send_control
585 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
587 DWORD cmd[2], count = 0;
588 BOOL r;
590 cmd[0] = WINESERV_SENDCONTROL;
591 cmd[1] = dwControl;
592 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
593 if (!r || count != sizeof cmd)
595 ERR("service protocol error - failed to write pipe!\n");
596 return r;
598 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
599 if (!r || count != sizeof *result)
600 ERR("service protocol error - failed to read pipe "
601 "r = %d count = %d!\n", r, count);
602 return r;
605 /******************************************************************************
606 * service_accepts_control
608 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
610 DWORD a = service->status.dwControlsAccepted;
612 switch (dwControl)
614 case SERVICE_CONTROL_INTERROGATE:
615 return TRUE;
616 case SERVICE_CONTROL_STOP:
617 if (a&SERVICE_ACCEPT_STOP)
618 return TRUE;
619 break;
620 case SERVICE_CONTROL_SHUTDOWN:
621 if (a&SERVICE_ACCEPT_SHUTDOWN)
622 return TRUE;
623 break;
624 case SERVICE_CONTROL_PAUSE:
625 case SERVICE_CONTROL_CONTINUE:
626 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
627 return TRUE;
628 break;
629 case SERVICE_CONTROL_PARAMCHANGE:
630 if (a&SERVICE_ACCEPT_PARAMCHANGE)
631 return TRUE;
632 break;
633 case SERVICE_CONTROL_NETBINDADD:
634 case SERVICE_CONTROL_NETBINDREMOVE:
635 case SERVICE_CONTROL_NETBINDENABLE:
636 case SERVICE_CONTROL_NETBINDDISABLE:
637 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
638 return TRUE;
640 if (!service->extended)
641 return FALSE;
642 switch (dwControl)
644 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
645 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
646 return TRUE;
647 break;
648 case SERVICE_CONTROL_POWEREVENT:
649 if (a&SERVICE_ACCEPT_POWEREVENT)
650 return TRUE;
651 break;
652 case SERVICE_CONTROL_SESSIONCHANGE:
653 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
654 return TRUE;
655 break;
657 return FALSE;
660 /******************************************************************************
661 * service_handle_control
663 static BOOL service_handle_control(HANDLE pipe, service_data *service,
664 DWORD dwControl)
666 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
668 TRACE("received control %d\n", dwControl);
670 if (service_accepts_control(service, dwControl))
672 if (service->extended && service->handler.handler_ex)
674 service->handler.handler_ex(dwControl, 0, NULL, service->context);
675 ret = ERROR_SUCCESS;
677 else if (service->handler.handler)
679 service->handler.handler(dwControl);
680 ret = ERROR_SUCCESS;
683 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
686 /******************************************************************************
687 * service_reap_thread
689 static DWORD service_reap_thread(service_data *service)
691 DWORD exitcode = 0;
693 if (!service->thread)
694 return 0;
695 GetExitCodeThread(service->thread, &exitcode);
696 if (exitcode!=STILL_ACTIVE)
698 CloseHandle(service->thread);
699 service->thread = 0;
701 return exitcode;
704 /******************************************************************************
705 * service_control_dispatcher
707 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
709 service_data *service = arg;
710 LPWSTR name;
711 HANDLE pipe, event;
713 TRACE("%p %s\n", service, debugstr_w(service->name));
715 /* create a pipe to talk to the rest of the world with */
716 name = service_get_pipe_name(service->name);
717 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
718 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
719 SERV_free(name);
721 /* let the process who started us know we've tried to create a pipe */
722 event = service_get_event_handle(service->name);
723 SetEvent(event);
724 CloseHandle(event);
726 if (pipe==INVALID_HANDLE_VALUE)
728 ERR("failed to create pipe for %s, error = %d\n",
729 debugstr_w(service->name), GetLastError());
730 return 0;
733 /* dispatcher loop */
734 while (1)
736 BOOL r;
737 DWORD count, req[2] = {0,0};
739 r = ConnectNamedPipe(pipe, NULL);
740 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
742 ERR("pipe connect failed\n");
743 break;
746 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
747 if (!r || count!=sizeof req)
749 ERR("pipe read failed\n");
750 break;
753 service_reap_thread(service);
755 /* handle the request */
756 switch (req[0])
758 case WINESERV_STARTINFO:
759 service_handle_start(pipe, service, req[1]);
760 break;
761 case WINESERV_GETSTATUS:
762 service_handle_get_status(pipe, service);
763 break;
764 case WINESERV_SENDCONTROL:
765 service_handle_control(pipe, service, req[1]);
766 break;
767 case WINESERV_SETPID:
768 service_handle_set_processID(pipe, service, req[1]);
769 break;
770 default:
771 ERR("received invalid command %d length %d\n", req[0], req[1]);
774 FlushFileBuffers(pipe);
775 DisconnectNamedPipe(pipe);
778 CloseHandle(pipe);
779 return 1;
782 /******************************************************************************
783 * service_run_threads
785 static BOOL service_run_threads(void)
787 service_data *service;
788 DWORD count, n = 0;
789 HANDLE *handles;
791 EnterCriticalSection( &service_cs );
793 count = list_count( &service_list );
795 TRACE("starting %d pipe listener threads\n", count);
797 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
799 handles[n++] = __wine_make_process_system();
801 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
802 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
803 service, 0, NULL );
804 assert(n == count + 1);
806 LeaveCriticalSection( &service_cs );
808 /* wait for all the threads to pack up and exit */
809 while (n > 1)
811 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
812 if (!ret) /* system process event */
814 TRACE( "last user process exited, shutting down\n" );
815 /* FIXME: we should maybe send a shutdown control to running services */
816 ExitProcess(0);
818 if (ret < MAXIMUM_WAIT_OBJECTS)
820 CloseHandle( handles[ret] );
821 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
822 n--;
824 else break;
827 while (n) CloseHandle( handles[--n] );
828 HeapFree(GetProcessHeap(), 0, handles);
830 return TRUE;
833 /******************************************************************************
834 * StartServiceCtrlDispatcherA [ADVAPI32.@]
836 * See StartServiceCtrlDispatcherW.
838 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
840 service_data *info;
841 DWORD sz, len;
842 BOOL ret = TRUE;
844 TRACE("%p\n", servent);
846 EnterCriticalSection( &service_cs );
847 while (servent->lpServiceName)
849 LPSTR name = servent->lpServiceName;
851 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
852 sz = len*sizeof(WCHAR) + sizeof *info;
853 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
854 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
855 info->proc.a = servent->lpServiceProc;
856 info->unicode = FALSE;
857 list_add_head( &service_list, &info->entry );
858 servent++;
860 LeaveCriticalSection( &service_cs );
862 service_run_threads();
864 return ret;
867 /******************************************************************************
868 * StartServiceCtrlDispatcherW [ADVAPI32.@]
870 * Connects a process containing one or more services to the service control
871 * manager.
873 * PARAMS
874 * servent [I] A list of the service names and service procedures
876 * RETURNS
877 * Success: TRUE.
878 * Failure: FALSE.
880 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
882 service_data *info;
883 DWORD sz, len;
884 BOOL ret = TRUE;
886 TRACE("%p\n", servent);
888 EnterCriticalSection( &service_cs );
889 while (servent->lpServiceName)
891 LPWSTR name = servent->lpServiceName;
893 len = strlenW(name);
894 sz = len*sizeof(WCHAR) + sizeof *info;
895 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
896 strcpyW(info->name, name);
897 info->proc.w = servent->lpServiceProc;
898 info->unicode = TRUE;
899 list_add_head( &service_list, &info->entry );
900 servent++;
902 LeaveCriticalSection( &service_cs );
904 service_run_threads();
906 return ret;
909 /******************************************************************************
910 * LockServiceDatabase [ADVAPI32.@]
912 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
914 HANDLE ret;
916 TRACE("%p\n",hSCManager);
918 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
919 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
921 CloseHandle( ret );
922 ret = NULL;
923 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
926 TRACE("returning %p\n", ret);
928 return ret;
931 /******************************************************************************
932 * UnlockServiceDatabase [ADVAPI32.@]
934 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
936 TRACE("%p\n",ScLock);
938 return CloseHandle( ScLock );
941 /******************************************************************************
942 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
944 SERVICE_STATUS_HANDLE WINAPI
945 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
947 LPWSTR lpServiceNameW;
948 SERVICE_STATUS_HANDLE ret;
950 lpServiceNameW = SERV_dup(lpServiceName);
951 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
952 SERV_free(lpServiceNameW);
953 return ret;
956 /******************************************************************************
957 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
959 * PARAMS
960 * lpServiceName []
961 * lpfHandler []
963 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
964 LPHANDLER_FUNCTION lpfHandler )
966 service_data *service;
967 SERVICE_STATUS_HANDLE handle = 0;
969 EnterCriticalSection( &service_cs );
970 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
972 if(!strcmpW(lpServiceName, service->name))
974 service->handler.handler = lpfHandler;
975 handle = (SERVICE_STATUS_HANDLE)service;
976 break;
979 LeaveCriticalSection( &service_cs );
980 return handle;
983 /******************************************************************************
984 * SetServiceStatus [ADVAPI32.@]
986 * PARAMS
987 * hService []
988 * lpStatus []
990 BOOL WINAPI
991 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
993 service_data *service;
994 BOOL r = FALSE;
996 TRACE("%p %x %x %x %x %x %x %x\n", hService,
997 lpStatus->dwServiceType, lpStatus->dwCurrentState,
998 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
999 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
1000 lpStatus->dwWaitHint);
1002 EnterCriticalSection( &service_cs );
1003 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
1005 if(service == (service_data*)hService)
1007 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
1008 TRACE("Set service status to %d\n",service->status.dwCurrentState);
1009 r = TRUE;
1010 break;
1013 LeaveCriticalSection( &service_cs );
1015 return r;
1019 /******************************************************************************
1020 * OpenSCManagerA [ADVAPI32.@]
1022 * Establish a connection to the service control manager and open its database.
1024 * PARAMS
1025 * lpMachineName [I] Pointer to machine name string
1026 * lpDatabaseName [I] Pointer to database name string
1027 * dwDesiredAccess [I] Type of access
1029 * RETURNS
1030 * Success: A Handle to the service control manager database
1031 * Failure: NULL
1033 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1034 DWORD dwDesiredAccess )
1036 LPWSTR lpMachineNameW, lpDatabaseNameW;
1037 SC_HANDLE ret;
1039 lpMachineNameW = SERV_dup(lpMachineName);
1040 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1041 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1042 SERV_free(lpDatabaseNameW);
1043 SERV_free(lpMachineNameW);
1044 return ret;
1047 /******************************************************************************
1048 * OpenSCManagerW [ADVAPI32.@]
1050 * See OpenSCManagerA.
1052 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1053 DWORD dwDesiredAccess )
1055 struct sc_manager *manager;
1056 HKEY hReg;
1057 LONG r;
1058 DWORD new_mask = dwDesiredAccess;
1060 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1061 debugstr_w(lpDatabaseName), dwDesiredAccess);
1063 if( lpDatabaseName && lpDatabaseName[0] )
1065 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1067 /* noop, all right */
1069 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1071 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1072 return NULL;
1074 else
1076 SetLastError( ERROR_INVALID_NAME );
1077 return NULL;
1081 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1082 sc_handle_destroy_manager );
1083 if (!manager)
1084 return NULL;
1086 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1087 if (r!=ERROR_SUCCESS)
1088 goto error;
1090 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1091 RegCloseKey( hReg );
1092 if (r!=ERROR_SUCCESS)
1093 goto error;
1095 RtlMapGenericMask(&new_mask, &scm_generic);
1096 manager->dwAccess = new_mask;
1097 TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1099 return (SC_HANDLE) &manager->hdr;
1101 error:
1102 sc_handle_free( &manager->hdr );
1103 SetLastError( r);
1104 return NULL;
1107 /******************************************************************************
1108 * ControlService [ADVAPI32.@]
1110 * Send a control code to a service.
1112 * PARAMS
1113 * hService [I] Handle of the service control manager database
1114 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1115 * lpServiceStatus [O] Destination for the status of the service, if available
1117 * RETURNS
1118 * Success: TRUE.
1119 * Failure: FALSE.
1121 * BUGS
1122 * Unlike M$' implementation, control requests are not serialized and may be
1123 * processed asynchronously.
1125 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1126 LPSERVICE_STATUS lpServiceStatus )
1128 struct sc_service *hsvc;
1129 BOOL ret = FALSE;
1130 HANDLE handle;
1132 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1134 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1135 if (!hsvc)
1137 SetLastError( ERROR_INVALID_HANDLE );
1138 return FALSE;
1141 ret = QueryServiceStatus(hService, lpServiceStatus);
1142 if (!ret)
1144 ERR("failed to query service status\n");
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1146 return FALSE;
1149 switch (lpServiceStatus->dwCurrentState)
1151 case SERVICE_STOPPED:
1152 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1153 return FALSE;
1154 case SERVICE_START_PENDING:
1155 if (dwControl==SERVICE_CONTROL_STOP)
1156 break;
1157 /* fall thru */
1158 case SERVICE_STOP_PENDING:
1159 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1160 return FALSE;
1163 handle = service_open_pipe(hsvc->name);
1164 if (handle!=INVALID_HANDLE_VALUE)
1166 DWORD result = ERROR_SUCCESS;
1167 ret = service_send_control(handle, dwControl, &result);
1168 CloseHandle(handle);
1169 if (result!=ERROR_SUCCESS)
1171 SetLastError(result);
1172 ret = FALSE;
1176 return ret;
1179 /******************************************************************************
1180 * CloseServiceHandle [ADVAPI32.@]
1182 * Close a handle to a service or the service control manager database.
1184 * PARAMS
1185 * hSCObject [I] Handle to service or service control manager database
1187 * RETURNS
1188 * Success: TRUE
1189 * Failure: FALSE
1191 BOOL WINAPI
1192 CloseServiceHandle( SC_HANDLE hSCObject )
1194 TRACE("%p\n", hSCObject);
1196 sc_handle_free( (struct sc_handle*) hSCObject );
1198 return TRUE;
1202 /******************************************************************************
1203 * OpenServiceA [ADVAPI32.@]
1205 * Open a handle to a service.
1207 * PARAMS
1208 * hSCManager [I] Handle of the service control manager database
1209 * lpServiceName [I] Name of the service to open
1210 * dwDesiredAccess [I] Access required to the service
1212 * RETURNS
1213 * Success: Handle to the service
1214 * Failure: NULL
1216 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1217 DWORD dwDesiredAccess )
1219 LPWSTR lpServiceNameW;
1220 SC_HANDLE ret;
1222 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1224 lpServiceNameW = SERV_dup(lpServiceName);
1225 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1226 SERV_free(lpServiceNameW);
1227 return ret;
1231 /******************************************************************************
1232 * OpenServiceW [ADVAPI32.@]
1234 * See OpenServiceA.
1236 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1237 DWORD dwDesiredAccess)
1239 struct sc_manager *hscm;
1240 struct sc_service *hsvc;
1241 HKEY hKey;
1242 long r;
1243 DWORD len;
1244 DWORD new_mask = dwDesiredAccess;
1246 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1248 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1249 if (!hscm)
1251 SetLastError( ERROR_INVALID_HANDLE );
1252 return FALSE;
1255 if (!lpServiceName)
1257 SetLastError(ERROR_INVALID_ADDRESS);
1258 return NULL;
1261 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1262 if (r!=ERROR_SUCCESS)
1264 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1265 return NULL;
1268 len = strlenW(lpServiceName)+1;
1269 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1270 sizeof (struct sc_service) + len*sizeof(WCHAR),
1271 sc_handle_destroy_service );
1272 if (!hsvc)
1274 RegCloseKey(hKey);
1275 return NULL;
1277 strcpyW( hsvc->name, lpServiceName );
1278 hsvc->hkey = hKey;
1280 RtlMapGenericMask(&new_mask, &svc_generic);
1281 hsvc->dwAccess = new_mask;
1283 /* add reference to SCM handle */
1284 hscm->hdr.ref_count++;
1285 hsvc->scm = hscm;
1287 TRACE("returning %p\n",hsvc);
1289 return (SC_HANDLE) &hsvc->hdr;
1292 /******************************************************************************
1293 * CreateServiceW [ADVAPI32.@]
1295 SC_HANDLE WINAPI
1296 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1297 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1298 DWORD dwServiceType, DWORD dwStartType,
1299 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1300 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1301 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1302 LPCWSTR lpPassword )
1304 struct sc_manager *hscm;
1305 struct sc_service *hsvc = NULL;
1306 HKEY hKey;
1307 LONG r;
1308 DWORD dp, len;
1309 struct reg_value val[10];
1310 int n = 0;
1311 DWORD new_mask = dwDesiredAccess;
1312 DWORD index = 0;
1313 WCHAR buffer[MAX_PATH];
1314 BOOL displayname_exists = FALSE;
1316 TRACE("%p %s %s\n", hSCManager,
1317 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1319 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1320 if (!hscm)
1322 SetLastError( ERROR_INVALID_HANDLE );
1323 return NULL;
1326 if (!lpServiceName || !lpBinaryPathName)
1328 SetLastError(ERROR_INVALID_ADDRESS);
1329 return NULL;
1332 if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1334 SetLastError(ERROR_ACCESS_DENIED);
1335 return NULL;
1338 if (!lpServiceName[0])
1340 SetLastError(ERROR_INVALID_NAME);
1341 return NULL;
1344 if (!lpBinaryPathName[0])
1346 SetLastError(ERROR_INVALID_PARAMETER);
1347 return NULL;
1350 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1351 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1352 * runs under the LocalSystem account)
1354 switch (dwServiceType)
1356 case SERVICE_KERNEL_DRIVER:
1357 case SERVICE_FILE_SYSTEM_DRIVER:
1358 case SERVICE_WIN32_OWN_PROCESS:
1359 case SERVICE_WIN32_SHARE_PROCESS:
1360 /* No problem */
1361 break;
1362 case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1363 case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1364 /* FIXME : Do we need a more thorough check? */
1365 if (lpServiceStartName)
1367 SetLastError(ERROR_INVALID_PARAMETER);
1368 return NULL;
1370 break;
1371 default:
1372 SetLastError(ERROR_INVALID_PARAMETER);
1373 return NULL;
1376 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1377 if (dwStartType > SERVICE_DISABLED)
1379 SetLastError(ERROR_INVALID_PARAMETER);
1380 return NULL;
1383 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1384 if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1385 ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1387 SetLastError(ERROR_INVALID_PARAMETER);
1388 return NULL;
1391 /* Loop through the registry to check if the service already exists and to
1392 * check if we can use the given displayname.
1393 * FIXME: Should we use EnumServicesStatusEx?
1395 len = sizeof(buffer);
1396 while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1398 HKEY service_key;
1400 /* The service already exists, so bail out */
1401 if(!lstrcmpiW(lpServiceName, buffer))
1403 SetLastError(ERROR_SERVICE_EXISTS);
1404 return NULL;
1407 /* The given displayname matches the found servicename. We don't bail out
1408 * as servicename is checked before a duplicate displayname
1410 if(!lstrcmpiW(lpDisplayName, buffer))
1411 displayname_exists = TRUE;
1413 if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1415 WCHAR name[MAX_PATH];
1416 DWORD size = sizeof(name);
1418 if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1420 /* The given displayname matches the found displayname */
1421 if (!lstrcmpiW(lpDisplayName, name))
1422 displayname_exists = TRUE;
1424 RegCloseKey(service_key);
1426 index++;
1427 len = sizeof(buffer);
1430 if (lpDisplayName && displayname_exists)
1432 SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1433 return NULL;
1436 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1437 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1438 if (r!=ERROR_SUCCESS)
1440 /* FIXME: Should we set an error? */
1441 return NULL;
1444 if( lpDisplayName )
1445 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1447 service_set_dword( &val[n++], szType, &dwServiceType );
1448 service_set_dword( &val[n++], szStart, &dwStartType );
1449 service_set_dword( &val[n++], szError, &dwErrorControl );
1451 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1453 if( lpLoadOrderGroup )
1454 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1456 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1457 * There is no such key as what szDependencies refers to */
1458 if( lpDependencies )
1459 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1461 if( lpPassword )
1462 FIXME("Don't know how to add a Password for a service.\n");
1464 if( lpServiceStartName )
1465 service_set_string( &val[n++], szObjectName, lpServiceStartName );
1467 r = service_write_values( hKey, val, n );
1468 if( r != ERROR_SUCCESS )
1469 goto error;
1471 len = strlenW(lpServiceName)+1;
1472 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1473 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1474 if( !hsvc )
1475 goto error;
1476 lstrcpyW( hsvc->name, lpServiceName );
1477 hsvc->hkey = hKey;
1479 RtlMapGenericMask(&new_mask, &svc_generic);
1480 hsvc->dwAccess = new_mask;
1482 hsvc->scm = hscm;
1483 hscm->hdr.ref_count++;
1485 return (SC_HANDLE) &hsvc->hdr;
1487 error:
1488 RegCloseKey( hKey );
1489 return NULL;
1493 /******************************************************************************
1494 * CreateServiceA [ADVAPI32.@]
1496 SC_HANDLE WINAPI
1497 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1498 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1499 DWORD dwServiceType, DWORD dwStartType,
1500 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1501 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1502 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1503 LPCSTR lpPassword )
1505 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1506 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1507 SC_HANDLE r;
1509 TRACE("%p %s %s\n", hSCManager,
1510 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1512 lpServiceNameW = SERV_dup( lpServiceName );
1513 lpDisplayNameW = SERV_dup( lpDisplayName );
1514 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1515 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1516 lpDependenciesW = SERV_dupmulti( lpDependencies );
1517 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1518 lpPasswordW = SERV_dup( lpPassword );
1520 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1521 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1522 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1523 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1525 SERV_free( lpServiceNameW );
1526 SERV_free( lpDisplayNameW );
1527 SERV_free( lpBinaryPathNameW );
1528 SERV_free( lpLoadOrderGroupW );
1529 SERV_free( lpDependenciesW );
1530 SERV_free( lpServiceStartNameW );
1531 SERV_free( lpPasswordW );
1533 return r;
1537 /******************************************************************************
1538 * DeleteService [ADVAPI32.@]
1540 * Delete a service from the service control manager database.
1542 * PARAMS
1543 * hService [I] Handle of the service to delete
1545 * RETURNS
1546 * Success: TRUE
1547 * Failure: FALSE
1549 BOOL WINAPI DeleteService( SC_HANDLE hService )
1551 struct sc_service *hsvc;
1553 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1554 if (!hsvc)
1556 SetLastError( ERROR_INVALID_HANDLE );
1557 return FALSE;
1560 if (!(hsvc->dwAccess & DELETE))
1562 SetLastError(ERROR_ACCESS_DENIED);
1563 return FALSE;
1566 /* Close the key to the service */
1567 RegCloseKey(hsvc->hkey);
1569 /* Delete the service under the Service Control Manager key */
1570 RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1572 hsvc->hkey = NULL;
1574 return TRUE;
1578 /******************************************************************************
1579 * StartServiceA [ADVAPI32.@]
1581 * Start a service
1583 * PARAMS
1584 * hService [I] Handle of service
1585 * dwNumServiceArgs [I] Number of arguments
1586 * lpServiceArgVectors [I] Address of array of argument strings
1588 * NOTES
1589 * - NT implements this function using an obscure RPC call.
1590 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1591 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1592 * - This will only work for shared address space. How should the service
1593 * args be transferred when address spaces are separated?
1594 * - Can only start one service at a time.
1595 * - Has no concept of privilege.
1597 * RETURNS
1598 * Success: TRUE.
1599 * Failure: FALSE
1601 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1602 LPCSTR *lpServiceArgVectors )
1604 LPWSTR *lpwstr=NULL;
1605 unsigned int i;
1606 BOOL r;
1608 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1610 if (dwNumServiceArgs)
1611 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1612 dwNumServiceArgs*sizeof(LPWSTR) );
1614 for(i=0; i<dwNumServiceArgs; i++)
1615 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1617 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1619 if (dwNumServiceArgs)
1621 for(i=0; i<dwNumServiceArgs; i++)
1622 SERV_free(lpwstr[i]);
1623 HeapFree(GetProcessHeap(), 0, lpwstr);
1626 return r;
1629 /******************************************************************************
1630 * service_start_process [INTERNAL]
1632 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1634 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1635 PROCESS_INFORMATION pi;
1636 STARTUPINFOW si;
1637 LPWSTR path = NULL, str;
1638 DWORD type, size, ret, svc_type;
1639 HANDLE handles[2];
1640 BOOL r;
1642 size = sizeof(svc_type);
1643 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1644 svc_type = 0;
1646 if (svc_type == SERVICE_KERNEL_DRIVER)
1648 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1649 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1651 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1652 GetSystemDirectoryW( path, len );
1653 lstrcatW( path, winedeviceW );
1654 lstrcatW( path, hsvc->name );
1656 else
1658 /* read the executable path from the registry */
1659 size = 0;
1660 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1661 if (ret!=ERROR_SUCCESS)
1662 return FALSE;
1663 str = HeapAlloc(GetProcessHeap(),0,size);
1664 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1665 if (ret==ERROR_SUCCESS)
1667 size = ExpandEnvironmentStringsW(str,NULL,0);
1668 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1669 ExpandEnvironmentStringsW(str,path,size);
1671 HeapFree(GetProcessHeap(),0,str);
1672 if (!path)
1673 return FALSE;
1676 /* wait for the process to start and set an event or terminate */
1677 handles[0] = service_get_event_handle( hsvc->name );
1678 ZeroMemory(&si, sizeof(STARTUPINFOW));
1679 si.cb = sizeof(STARTUPINFOW);
1680 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1681 if (r)
1683 if (ppid) *ppid = pi.dwProcessId;
1685 handles[1] = pi.hProcess;
1686 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1687 if(ret != WAIT_OBJECT_0)
1689 SetLastError(ERROR_IO_PENDING);
1690 r = FALSE;
1693 CloseHandle( pi.hThread );
1694 CloseHandle( pi.hProcess );
1696 CloseHandle( handles[0] );
1697 HeapFree(GetProcessHeap(),0,path);
1698 return r;
1701 static BOOL service_wait_for_startup(SC_HANDLE hService)
1703 DWORD i;
1704 SERVICE_STATUS status;
1705 BOOL r = FALSE;
1707 TRACE("%p\n", hService);
1709 for (i=0; i<30; i++)
1711 status.dwCurrentState = 0;
1712 r = QueryServiceStatus(hService, &status);
1713 if (!r)
1714 break;
1715 if (status.dwCurrentState == SERVICE_RUNNING)
1717 TRACE("Service started successfully\n");
1718 break;
1720 r = FALSE;
1721 Sleep(1000);
1723 return r;
1726 /******************************************************************************
1727 * StartServiceW [ADVAPI32.@]
1729 * See StartServiceA.
1731 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1732 LPCWSTR *lpServiceArgVectors)
1734 struct sc_service *hsvc;
1735 BOOL r = FALSE;
1736 DWORD dwResult, dwProcessId = 0;
1737 SC_LOCK hLock;
1738 HANDLE handle = INVALID_HANDLE_VALUE;
1740 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1742 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1743 if (!hsvc)
1745 SetLastError(ERROR_INVALID_HANDLE);
1746 return r;
1749 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1750 if (!hLock)
1751 return r;
1753 handle = service_open_pipe(hsvc->name);
1754 if (handle==INVALID_HANDLE_VALUE)
1756 /* start the service process */
1757 if (service_start_process(hsvc, &dwProcessId))
1758 handle = service_open_pipe(hsvc->name);
1761 if (handle != INVALID_HANDLE_VALUE)
1763 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1764 CloseHandle(handle);
1767 handle = service_open_pipe(hsvc->name);
1768 if (handle != INVALID_HANDLE_VALUE)
1770 service_set_processID(handle, dwProcessId, &dwResult);
1771 CloseHandle(handle);
1774 UnlockServiceDatabase( hLock );
1776 TRACE("returning %d\n", r);
1778 if (r)
1779 service_wait_for_startup(hService);
1781 return r;
1784 /******************************************************************************
1785 * QueryServiceStatus [ADVAPI32.@]
1787 * PARAMS
1788 * hService [I] Handle to service to get information about
1789 * lpservicestatus [O] buffer to receive the status information for the service
1792 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1793 LPSERVICE_STATUS lpservicestatus)
1795 SERVICE_STATUS_PROCESS SvcStatusData;
1796 BOOL ret;
1798 TRACE("%p %p\n", hService, lpservicestatus);
1800 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1801 sizeof(SERVICE_STATUS_PROCESS), NULL);
1802 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1803 return ret;
1807 /******************************************************************************
1808 * QueryServiceStatusEx [ADVAPI32.@]
1810 * Get information about a service.
1812 * PARAMS
1813 * hService [I] Handle to service to get information about
1814 * InfoLevel [I] Level of information to get
1815 * lpBuffer [O] Destination for requested information
1816 * cbBufSize [I] Size of lpBuffer in bytes
1817 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1819 * RETURNS
1820 * Success: TRUE
1821 * FAILURE: FALSE
1823 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1824 LPBYTE lpBuffer, DWORD cbBufSize,
1825 LPDWORD pcbBytesNeeded)
1827 struct sc_service *hsvc;
1828 DWORD size, type, val;
1829 HANDLE pipe;
1830 LONG r;
1831 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1833 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1835 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1837 SetLastError( ERROR_INVALID_LEVEL);
1838 return FALSE;
1841 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1842 if (pSvcStatusData == NULL)
1844 SetLastError( ERROR_INVALID_PARAMETER);
1845 return FALSE;
1848 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1850 if( pcbBytesNeeded != NULL)
1851 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1853 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1854 return FALSE;
1857 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1858 if (!hsvc)
1860 SetLastError( ERROR_INVALID_HANDLE );
1861 return FALSE;
1864 pipe = service_open_pipe(hsvc->name);
1865 if (pipe != INVALID_HANDLE_VALUE)
1867 r = service_get_status(pipe, pSvcStatusData);
1868 CloseHandle(pipe);
1869 if (r)
1870 return TRUE;
1873 TRACE("Failed to read service status\n");
1875 /* read the service type from the registry */
1876 size = sizeof(val);
1877 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1878 if (r != ERROR_SUCCESS || type != REG_DWORD)
1879 val = 0;
1881 pSvcStatusData->dwServiceType = val;
1882 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1883 pSvcStatusData->dwControlsAccepted = 0;
1884 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1885 pSvcStatusData->dwServiceSpecificExitCode = 0;
1886 pSvcStatusData->dwCheckPoint = 0;
1887 pSvcStatusData->dwWaitHint = 0;
1889 return TRUE;
1892 /******************************************************************************
1893 * QueryServiceConfigA [ADVAPI32.@]
1895 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1896 DWORD size, LPDWORD needed )
1898 DWORD n;
1899 LPSTR p, buffer;
1900 BOOL ret;
1901 QUERY_SERVICE_CONFIGW *configW;
1903 TRACE("%p %p %d %p\n", hService, config, size, needed);
1905 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1907 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1908 return FALSE;
1910 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1911 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1912 if (!ret) goto done;
1914 config->dwServiceType = configW->dwServiceType;
1915 config->dwStartType = configW->dwStartType;
1916 config->dwErrorControl = configW->dwErrorControl;
1917 config->lpBinaryPathName = NULL;
1918 config->lpLoadOrderGroup = NULL;
1919 config->dwTagId = configW->dwTagId;
1920 config->lpDependencies = NULL;
1921 config->lpServiceStartName = NULL;
1922 config->lpDisplayName = NULL;
1924 p = (LPSTR)(config + 1);
1925 n = size - sizeof(*config);
1926 ret = FALSE;
1928 #define MAP_STR(str) \
1929 do { \
1930 if (configW->str) \
1932 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1933 if (!sz) goto done; \
1934 config->str = p; \
1935 p += sz; \
1936 n -= sz; \
1938 } while (0)
1940 MAP_STR( lpBinaryPathName );
1941 MAP_STR( lpLoadOrderGroup );
1942 MAP_STR( lpDependencies );
1943 MAP_STR( lpServiceStartName );
1944 MAP_STR( lpDisplayName );
1945 #undef MAP_STR
1947 *needed = p - (LPSTR)config;
1948 ret = TRUE;
1950 done:
1951 HeapFree( GetProcessHeap(), 0, buffer );
1952 return ret;
1955 /******************************************************************************
1956 * QueryServiceConfigW [ADVAPI32.@]
1958 BOOL WINAPI
1959 QueryServiceConfigW( SC_HANDLE hService,
1960 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1961 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1963 WCHAR str_buffer[ MAX_PATH ];
1964 LONG r;
1965 DWORD type, val, sz, total, n;
1966 LPBYTE p;
1967 HKEY hKey;
1968 struct sc_service *hsvc;
1970 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1971 cbBufSize, pcbBytesNeeded);
1973 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1974 if (!hsvc)
1976 SetLastError( ERROR_INVALID_HANDLE );
1977 return FALSE;
1979 hKey = hsvc->hkey;
1981 /* TODO: Check which members are mandatory and what the registry types
1982 * should be. This should of course also be tested when a service is
1983 * created.
1986 /* calculate the size required first */
1987 total = sizeof (QUERY_SERVICE_CONFIGW);
1989 sz = sizeof(str_buffer);
1990 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1991 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1993 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1994 if( 0 == sz ) return FALSE;
1996 total += sizeof(WCHAR) * sz;
1998 else
2000 /* FIXME: set last error */
2001 return FALSE;
2004 sz = 0;
2005 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
2006 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2007 total += sz;
2008 else
2009 total += sizeof(WCHAR);
2011 sz = 0;
2012 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
2013 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
2014 total += sz;
2015 else
2016 total += sizeof(WCHAR);
2018 sz = 0;
2019 r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
2020 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2021 total += sz;
2022 else
2023 total += sizeof(WCHAR);
2025 sz = 0;
2026 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
2027 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2028 total += sz;
2029 else
2030 total += sizeof(WCHAR);
2032 *pcbBytesNeeded = total;
2034 /* if there's not enough memory, return an error */
2035 if( total > cbBufSize )
2037 SetLastError( ERROR_INSUFFICIENT_BUFFER );
2038 return FALSE;
2041 ZeroMemory( lpServiceConfig, total );
2043 sz = sizeof val;
2044 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
2045 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2046 lpServiceConfig->dwServiceType = val;
2048 sz = sizeof val;
2049 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
2050 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2051 lpServiceConfig->dwStartType = val;
2053 sz = sizeof val;
2054 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
2055 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2056 lpServiceConfig->dwErrorControl = val;
2058 sz = sizeof val;
2059 r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2060 if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2061 lpServiceConfig->dwTagId = val;
2063 /* now do the strings */
2064 p = (LPBYTE) &lpServiceConfig[1];
2065 n = total - sizeof (QUERY_SERVICE_CONFIGW);
2067 sz = sizeof(str_buffer);
2068 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2069 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2071 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2072 sz *= sizeof(WCHAR);
2073 if( 0 == sz || sz > n ) return FALSE;
2075 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2076 p += sz;
2077 n -= sz;
2079 else
2081 /* FIXME: set last error */
2082 return FALSE;
2085 sz = n;
2086 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2087 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2088 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2090 p += sz;
2091 n -= sz;
2093 else
2095 *(WCHAR *) p = 0;
2096 p += sizeof(WCHAR);
2097 n -= sizeof(WCHAR);
2100 sz = n;
2101 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2102 lpServiceConfig->lpDependencies = (LPWSTR) p;
2103 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2105 p += sz;
2106 n -= sz;
2108 else
2110 *(WCHAR *) p = 0;
2111 p += sizeof(WCHAR);
2112 n -= sizeof(WCHAR);
2115 sz = n;
2116 r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2117 lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2118 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2120 p += sz;
2121 n -= sz;
2123 else
2125 *(WCHAR *) p = 0;
2126 p += sizeof(WCHAR);
2127 n -= sizeof(WCHAR);
2130 sz = n;
2131 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2132 lpServiceConfig->lpDisplayName = (LPWSTR) p;
2133 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2135 p += sz;
2136 n -= sz;
2138 else
2140 *(WCHAR *) p = 0;
2141 p += sizeof(WCHAR);
2142 n -= sizeof(WCHAR);
2145 if( n < 0 )
2146 ERR("Buffer overflow!\n");
2148 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2149 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2150 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2151 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2152 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2154 return TRUE;
2157 /******************************************************************************
2158 * EnumServicesStatusA [ADVAPI32.@]
2160 BOOL WINAPI
2161 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2162 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2163 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2164 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2166 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2167 dwServiceType, dwServiceState, lpServices, cbBufSize,
2168 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2169 SetLastError (ERROR_ACCESS_DENIED);
2170 return FALSE;
2173 /******************************************************************************
2174 * EnumServicesStatusW [ADVAPI32.@]
2176 BOOL WINAPI
2177 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2178 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2179 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2180 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2182 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2183 dwServiceType, dwServiceState, lpServices, cbBufSize,
2184 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
2185 SetLastError (ERROR_ACCESS_DENIED);
2186 return FALSE;
2189 /******************************************************************************
2190 * EnumServicesStatusExA [ADVAPI32.@]
2192 BOOL WINAPI
2193 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2194 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2195 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2197 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2198 dwServiceType, dwServiceState, lpServices, cbBufSize,
2199 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2200 SetLastError (ERROR_ACCESS_DENIED);
2201 return FALSE;
2204 /******************************************************************************
2205 * EnumServicesStatusExW [ADVAPI32.@]
2207 BOOL WINAPI
2208 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2209 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2210 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2212 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2213 dwServiceType, dwServiceState, lpServices, cbBufSize,
2214 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2215 SetLastError (ERROR_ACCESS_DENIED);
2216 return FALSE;
2219 /******************************************************************************
2220 * GetServiceKeyNameA [ADVAPI32.@]
2222 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2223 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2225 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2226 return FALSE;
2229 /******************************************************************************
2230 * GetServiceKeyNameW [ADVAPI32.@]
2232 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2233 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2235 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2236 return FALSE;
2239 /******************************************************************************
2240 * QueryServiceLockStatusA [ADVAPI32.@]
2242 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2243 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2244 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2246 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2248 return FALSE;
2251 /******************************************************************************
2252 * QueryServiceLockStatusW [ADVAPI32.@]
2254 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2255 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2256 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2258 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2260 return FALSE;
2263 /******************************************************************************
2264 * GetServiceDisplayNameA [ADVAPI32.@]
2266 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2267 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2269 LPWSTR lpServiceNameW, lpDisplayNameW = NULL;
2270 DWORD size, sizeW, GLE;
2271 BOOL ret;
2273 TRACE("%p %s %p %p\n", hSCManager,
2274 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2276 lpServiceNameW = SERV_dup(lpServiceName);
2277 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2279 size = sizeW = *lpcchBuffer;
2280 ret = GetServiceDisplayNameW(hSCManager, lpServiceNameW,
2281 lpDisplayName ? lpDisplayNameW : NULL,
2282 &sizeW);
2283 /* Last error will be set by GetServiceDisplayNameW and must be preserved */
2284 GLE = GetLastError();
2286 if (!lpDisplayName && *lpcchBuffer && !ret && (GLE == ERROR_INSUFFICIENT_BUFFER))
2288 /* Request for buffersize.
2290 * Only set the size for ERROR_INSUFFICIENT_BUFFER
2292 size = sizeW * 2;
2294 else if (lpDisplayName && *lpcchBuffer && !ret)
2296 /* Request for displayname.
2298 * size only has to be set if this fails
2300 size = sizeW * 2;
2303 WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2304 *lpcchBuffer, NULL, NULL );
2306 *lpcchBuffer = size;
2308 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2309 SERV_free(lpServiceNameW);
2311 SetLastError(GLE);
2312 return ret;
2315 /******************************************************************************
2316 * GetServiceDisplayNameW [ADVAPI32.@]
2318 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2319 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2321 struct sc_manager *hscm;
2322 DWORD type, size;
2323 LONG ret;
2325 TRACE("%p %s %p %p\n", hSCManager,
2326 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2328 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2329 if (!hscm)
2331 SetLastError(ERROR_INVALID_HANDLE);
2332 return FALSE;
2335 if (!lpServiceName)
2337 SetLastError(ERROR_INVALID_ADDRESS);
2338 return FALSE;
2341 size = *lpcchBuffer * sizeof(WCHAR);
2342 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2343 if (!ret && !lpDisplayName && size)
2344 ret = ERROR_MORE_DATA;
2346 if (ret)
2348 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2350 if (ret == ERROR_MORE_DATA)
2352 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2353 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2355 else if (ret == ERROR_FILE_NOT_FOUND)
2357 HKEY hkey;
2359 if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2361 INT len = lstrlenW(lpServiceName);
2362 BOOL r = FALSE;
2364 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2365 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2366 else if (lpDisplayName && *lpcchBuffer)
2368 /* No displayname, but the service exists and the buffer
2369 * is big enough. We should return the servicename.
2371 lstrcpyW(lpDisplayName, lpServiceName);
2372 r = TRUE;
2375 *lpcchBuffer = len;
2376 RegCloseKey(hkey);
2377 return r;
2379 else
2380 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2382 else
2383 SetLastError(ret);
2384 return FALSE;
2387 /* Always return the correct needed size on success */
2388 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2390 return TRUE;
2393 /******************************************************************************
2394 * ChangeServiceConfigW [ADVAPI32.@]
2396 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2397 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2398 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2399 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2401 struct reg_value val[10];
2402 struct sc_service *hsvc;
2403 DWORD r = ERROR_SUCCESS;
2404 HKEY hKey;
2405 int n = 0;
2407 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2408 hService, dwServiceType, dwStartType, dwErrorControl,
2409 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2410 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2411 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2413 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2414 if (!hsvc)
2416 SetLastError( ERROR_INVALID_HANDLE );
2417 return FALSE;
2419 hKey = hsvc->hkey;
2421 if( dwServiceType != SERVICE_NO_CHANGE )
2422 service_set_dword( &val[n++], szType, &dwServiceType );
2424 if( dwStartType != SERVICE_NO_CHANGE )
2425 service_set_dword( &val[n++], szStart, &dwStartType );
2427 if( dwErrorControl != SERVICE_NO_CHANGE )
2428 service_set_dword( &val[n++], szError, &dwErrorControl );
2430 if( lpBinaryPathName )
2431 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2433 if( lpLoadOrderGroup )
2434 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2436 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2437 * There is no such key as what szDependencies refers to */
2438 if( lpDependencies )
2439 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2441 if( lpPassword )
2442 FIXME("ignoring password\n");
2444 if( lpServiceStartName )
2445 service_set_string( &val[n++], szObjectName, lpServiceStartName );
2447 r = service_write_values( hsvc->hkey, val, n );
2449 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2452 /******************************************************************************
2453 * ChangeServiceConfigA [ADVAPI32.@]
2455 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2456 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2457 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2458 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2460 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2461 LPWSTR wServiceStartName, wPassword, wDisplayName;
2462 BOOL r;
2464 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2465 hService, dwServiceType, dwStartType, dwErrorControl,
2466 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2467 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2468 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2470 wBinaryPathName = SERV_dup( lpBinaryPathName );
2471 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2472 wDependencies = SERV_dupmulti( lpDependencies );
2473 wServiceStartName = SERV_dup( lpServiceStartName );
2474 wPassword = SERV_dup( lpPassword );
2475 wDisplayName = SERV_dup( lpDisplayName );
2477 r = ChangeServiceConfigW( hService, dwServiceType,
2478 dwStartType, dwErrorControl, wBinaryPathName,
2479 wLoadOrderGroup, lpdwTagId, wDependencies,
2480 wServiceStartName, wPassword, wDisplayName);
2482 SERV_free( wBinaryPathName );
2483 SERV_free( wLoadOrderGroup );
2484 SERV_free( wDependencies );
2485 SERV_free( wServiceStartName );
2486 SERV_free( wPassword );
2487 SERV_free( wDisplayName );
2489 return r;
2492 /******************************************************************************
2493 * ChangeServiceConfig2A [ADVAPI32.@]
2495 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2496 LPVOID lpInfo)
2498 BOOL r = FALSE;
2500 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2502 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2504 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2505 SERVICE_DESCRIPTIONW sdw;
2507 sdw.lpDescription = SERV_dup( sd->lpDescription );
2509 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2511 SERV_free( sdw.lpDescription );
2513 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2515 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2516 SERVICE_FAILURE_ACTIONSW faw;
2518 faw.dwResetPeriod = fa->dwResetPeriod;
2519 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2520 faw.lpCommand = SERV_dup( fa->lpCommand );
2521 faw.cActions = fa->cActions;
2522 faw.lpsaActions = fa->lpsaActions;
2524 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2526 SERV_free( faw.lpRebootMsg );
2527 SERV_free( faw.lpCommand );
2529 else
2530 SetLastError( ERROR_INVALID_PARAMETER );
2532 return r;
2535 /******************************************************************************
2536 * ChangeServiceConfig2W [ADVAPI32.@]
2538 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2539 LPVOID lpInfo)
2541 HKEY hKey;
2542 struct sc_service *hsvc;
2544 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2545 if (!hsvc)
2547 SetLastError( ERROR_INVALID_HANDLE );
2548 return FALSE;
2550 hKey = hsvc->hkey;
2552 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2554 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2555 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2556 if (sd->lpDescription)
2558 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2559 if (sd->lpDescription[0] == 0)
2560 RegDeleteValueW(hKey,szDescription);
2561 else
2562 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2563 (LPVOID)sd->lpDescription,
2564 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2567 else
2568 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2569 return TRUE;
2572 /******************************************************************************
2573 * QueryServiceObjectSecurity [ADVAPI32.@]
2575 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2576 SECURITY_INFORMATION dwSecurityInformation,
2577 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2578 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2580 PACL pACL = NULL;
2582 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2583 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2585 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2587 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2588 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2589 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2590 return TRUE;
2593 /******************************************************************************
2594 * SetServiceObjectSecurity [ADVAPI32.@]
2596 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2597 SECURITY_INFORMATION dwSecurityInformation,
2598 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2600 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2601 return TRUE;
2604 /******************************************************************************
2605 * SetServiceBits [ADVAPI32.@]
2607 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2608 DWORD dwServiceBits,
2609 BOOL bSetBitsOn,
2610 BOOL bUpdateImmediately)
2612 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2613 bSetBitsOn, bUpdateImmediately);
2614 return TRUE;
2617 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2618 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2620 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2621 return 0;
2624 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2625 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2627 service_data *service;
2628 SERVICE_STATUS_HANDLE handle = 0;
2630 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2632 EnterCriticalSection( &service_cs );
2633 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2635 if(!strcmpW(lpServiceName, service->name))
2637 service->handler.handler_ex = lpHandlerProc;
2638 service->context = lpContext;
2639 service->extended = TRUE;
2640 handle = (SERVICE_STATUS_HANDLE)service;
2641 break;
2644 LeaveCriticalSection( &service_cs );
2646 return handle;