advapi/service: Check servicetype and starttype.
[wine] / dlls / advapi32 / service.c
1 /*
2  * Win32 advapi functions
3  *
4  * Copyright 1995 Sven Verdoolaege
5  * Copyright 2005 Mike McCormack
6  * Copyright 2007 Rolf Kalbermatter
7  *
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.
12  *
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.
17  *
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
21  */
22
23 #include <stdarg.h>
24 #include <string.h>
25 #include <time.h>
26 #include <assert.h>
27
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"
39
40 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
41
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};
47
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
53 };
54
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
60 };
61
62 typedef struct service_start_info_t
63 {
64     DWORD cmd;
65     DWORD size;
66     WCHAR str[1];
67 } service_start_info;
68
69 #define WINESERV_STARTINFO   1
70 #define WINESERV_GETSTATUS   2
71 #define WINESERV_SENDCONTROL 3
72 #define WINESERV_SETPID      4
73
74 typedef struct service_data_t
75 {
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;
93
94 static CRITICAL_SECTION service_cs;
95 static CRITICAL_SECTION_DEBUG service_cs_debug =
96 {
97     0, 0, &service_cs,
98     { &service_cs_debug.ProcessLocksList, 
99       &service_cs_debug.ProcessLocksList },
100       0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
101 };
102 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
103
104 static struct list service_list = LIST_INIT(service_list);
105
106 extern HANDLE __wine_make_process_system(void);
107
108 /******************************************************************************
109  * SC_HANDLEs
110  */
111
112 #define MAX_SERVICE_NAME 256
113
114 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
115
116 struct sc_handle;
117 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
118
119 struct sc_handle
120 {
121     SC_HANDLE_TYPE htype;
122     DWORD ref_count;
123     sc_handle_destructor destroy;
124 };
125
126 struct sc_manager       /* service control manager handle */
127 {
128     struct sc_handle hdr;
129     HKEY   hkey;   /* handle to services database in the registry */
130     DWORD  dwAccess;
131 };
132
133 struct sc_service       /* service handle */
134 {
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];
140 };
141
142 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
143                              sc_handle_destructor destroy)
144 {
145     struct sc_handle *hdr;
146
147     hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
148     if (hdr)
149     {
150         hdr->htype = htype;
151         hdr->ref_count = 1;
152         hdr->destroy = destroy;
153     }
154     TRACE("sc_handle type=%d -> %p\n", htype, hdr);
155     return hdr;
156 }
157
158 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
159 {
160     struct sc_handle *hdr = (struct sc_handle *) handle;
161
162     if (!hdr)
163         return NULL;
164     if (hdr->htype != htype)
165         return NULL;
166     return hdr;
167 }
168
169 static void sc_handle_free(struct sc_handle* hdr)
170 {
171     if (!hdr)
172         return;
173     if (--hdr->ref_count)
174         return;
175     hdr->destroy(hdr);
176     HeapFree(GetProcessHeap(), 0, hdr);
177 }
178
179 static void sc_handle_destroy_manager(struct sc_handle *handle)
180 {
181     struct sc_manager *mgr = (struct sc_manager*) handle;
182
183     TRACE("destroying SC Manager %p\n", mgr);
184     if (mgr->hkey)
185         RegCloseKey(mgr->hkey);
186 }
187
188 static void sc_handle_destroy_service(struct sc_handle *handle)
189 {
190     struct sc_service *svc = (struct sc_service*) handle;
191     
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;
198 }
199
200 /******************************************************************************
201  * String management functions
202  */
203 static inline LPWSTR SERV_dup( LPCSTR str )
204 {
205     UINT len;
206     LPWSTR wstr;
207
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;
214 }
215
216 static inline LPWSTR SERV_dupmulti(LPCSTR str)
217 {
218     UINT len = 0, n = 0;
219     LPWSTR wstr;
220
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++;
229
230     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
231     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
232     return wstr;
233 }
234
235 static inline VOID SERV_free( LPWSTR wstr )
236 {
237     HeapFree( GetProcessHeap(), 0, wstr );
238 }
239
240 /******************************************************************************
241  * registry access functions and data
242  */
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};
259
260 struct reg_value {
261     DWORD type;
262     DWORD size;
263     LPCWSTR name;
264     LPCVOID data;
265 };
266
267 static inline void service_set_value( struct reg_value *val,
268                         DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
269 {
270     val->name = name;
271     val->type = type;
272     val->data = data;
273     val->size = size;
274 }
275
276 static inline void service_set_dword( struct reg_value *val, 
277                                       LPCWSTR name, const DWORD *data )
278 {
279     service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
280 }
281
282 static inline void service_set_string( struct reg_value *val,
283                                        LPCWSTR name, LPCWSTR string )
284 {
285     DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
286     service_set_value( val, REG_SZ, name, string, len );
287 }
288
289 static inline void service_set_multi_string( struct reg_value *val,
290                                              LPCWSTR name, LPCWSTR string )
291 {
292     DWORD len = 0;
293
294     /* determine the length of a double null terminated multi string */
295     do {
296         len += (lstrlenW( &string[ len ] )+1);
297     } while ( string[ len++ ] );
298
299     len *= sizeof (WCHAR);
300     service_set_value( val, REG_MULTI_SZ, name, string, len );
301 }
302
303 static inline LONG service_write_values( HKEY hKey,
304                                          const struct reg_value *val, int n )
305 {
306     LONG r = ERROR_SUCCESS;
307     int i;
308
309     for( i=0; i<n; i++ )
310     {
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;
315     }
316     return r;
317 }
318
319 /******************************************************************************
320  * Service IPC functions
321  */
322 static LPWSTR service_get_pipe_name(LPCWSTR service)
323 {
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;
328
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;
334 }
335
336 static HANDLE service_open_pipe(LPCWSTR service)
337 {
338     LPWSTR szPipe = service_get_pipe_name( service );
339     HANDLE handle = INVALID_HANDLE_VALUE;
340
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);
350
351     return handle;
352 }
353
354 /******************************************************************************
355  * service_get_event_handle
356  */
357 static HANDLE service_get_event_handle(LPCWSTR service)
358 {
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;
364
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;
372 }
373
374 /******************************************************************************
375  * service_thread
376  *
377  * Call into the main service routine provided by StartServiceCtrlDispatcher.
378  */
379 static DWORD WINAPI service_thread(LPVOID arg)
380 {
381     service_data *info = arg;
382     LPWSTR str = info->args;
383     DWORD argc = 0, len = 0;
384
385     TRACE("%p\n", arg);
386
387     while (str[len])
388     {
389         len += strlenW(&str[len]) + 1;
390         argc++;
391     }
392
393     if (!argc)
394     {
395         if (info->unicode)
396             info->proc.w(0, NULL);
397         else
398             info->proc.a(0, NULL);
399         return 0;
400     }
401     
402     if (info->unicode)
403     {
404         LPWSTR *argv, p;
405
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;
410
411         info->proc.w(argc, argv);
412         HeapFree(GetProcessHeap(), 0, argv);
413     }
414     else
415     {
416         LPSTR strA, *argv, p;
417         DWORD lenA;
418         
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);
422
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;
427
428         info->proc.a(argc, argv);
429         HeapFree(GetProcessHeap(), 0, argv);
430         HeapFree(GetProcessHeap(), 0, strA);
431     }
432     return 0;
433 }
434
435 /******************************************************************************
436  * service_handle_start
437  */
438 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
439 {
440     DWORD read = 0, result = 0;
441     LPWSTR args;
442     BOOL r;
443
444     TRACE("%p %p %d\n", pipe, service, count);
445
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])
449     {
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;
453     }
454
455     if (service->thread)
456     {
457         ERR("service is not stopped\n");
458         goto end;
459     }
460
461     SERV_free(service->args);
462     service->args = args;
463     args = NULL;
464     service->thread = CreateThread( NULL, 0, service_thread,
465                                     service, 0, NULL );
466
467 end:
468     HeapFree(GetProcessHeap(), 0, args);
469     WriteFile( pipe, &result, sizeof result, &read, NULL );
470
471     return TRUE;
472 }
473
474 /******************************************************************************
475  * service_send_start_message
476  */
477 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
478 {
479     DWORD i, len, count, result;
480     service_start_info *ssi;
481     LPWSTR p;
482     BOOL r;
483
484     TRACE("%p %p %d\n", pipe, argv, argc);
485
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;
490
491     ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
492     ssi->cmd = WINESERV_STARTINFO;
493     ssi->size = len;
494
495     /* copy service args into a single buffer*/
496     p = &ssi->str[0];
497     for (i=0; i<argc; i++)
498     {
499         strcpyW(p, argv[i]);
500         p += strlenW(p) + 1;
501     }
502     *p=0;
503
504     r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
505     if (r)
506         r = ReadFile(pipe, &result, sizeof result, &count, NULL);
507
508     HeapFree(GetProcessHeap(),0,ssi);
509
510     return r;
511 }
512
513 /******************************************************************************
514  * service_handle_get_status
515  */
516 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
517 {
518     DWORD count = 0;
519     TRACE("\n");
520     return WriteFile(pipe, &service->status, 
521                      sizeof service->status, &count, NULL);
522 }
523
524 /******************************************************************************
525  * service_get_status
526  */
527 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
528 {
529     DWORD cmd[2], count = 0;
530     BOOL r;
531     
532     cmd[0] = WINESERV_GETSTATUS;
533     cmd[1] = 0;
534     r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
535     if (!r || count != sizeof cmd)
536     {
537         ERR("service protocol error - failed to write pipe!\n");
538         return r;
539     }
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;
545 }
546
547 /******************************************************************************
548  * service_handle_set_processID
549  */
550 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
551 {
552     DWORD count, ret = ERROR_SUCCESS;
553
554     TRACE("received control %d\n", dwProcessId);
555         service->status.dwProcessId = dwProcessId;
556     return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
557 }
558
559 /******************************************************************************
560  * service_set_processID
561  */
562 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
563 {
564     DWORD cmd[2], count = 0;
565     BOOL r;
566
567     cmd[0] = WINESERV_SETPID;
568     cmd[1] = dwprocessId;
569     r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
570     if (!r || count != sizeof cmd)
571     {
572         ERR("service protocol error - failed to write pipe!\n");
573         return r;
574     }
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;
580 }
581
582 /******************************************************************************
583  * service_send_control
584  */
585 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
586 {
587     DWORD cmd[2], count = 0;
588     BOOL r;
589     
590     cmd[0] = WINESERV_SENDCONTROL;
591     cmd[1] = dwControl;
592     r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
593     if (!r || count != sizeof cmd)
594     {
595         ERR("service protocol error - failed to write pipe!\n");
596         return r;
597     }
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;
603 }
604
605 /******************************************************************************
606  * service_accepts_control
607  */
608 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
609 {
610     DWORD a = service->status.dwControlsAccepted;
611
612     switch (dwControl)
613     {
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;
639     }
640     if (!service->extended)
641         return FALSE;
642     switch (dwControl)
643     {
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;
656     }
657     return FALSE;
658 }
659
660 /******************************************************************************
661  * service_handle_control
662  */
663 static BOOL service_handle_control(HANDLE pipe, service_data *service,
664                                    DWORD dwControl)
665 {
666     DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
667
668     TRACE("received control %d\n", dwControl);
669     
670     if (service_accepts_control(service, dwControl))
671     {
672         if (service->extended && service->handler.handler_ex)
673         {
674             service->handler.handler_ex(dwControl, 0, NULL, service->context);
675             ret = ERROR_SUCCESS;
676         }
677         else if (service->handler.handler)
678         {
679             service->handler.handler(dwControl);
680             ret = ERROR_SUCCESS;
681         }
682     }
683     return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
684 }
685
686 /******************************************************************************
687  * service_reap_thread
688  */
689 static DWORD service_reap_thread(service_data *service)
690 {
691     DWORD exitcode = 0;
692
693     if (!service->thread)
694         return 0;
695     GetExitCodeThread(service->thread, &exitcode);
696     if (exitcode!=STILL_ACTIVE)
697     {
698         CloseHandle(service->thread);
699         service->thread = 0;
700     }
701     return exitcode;
702 }
703
704 /******************************************************************************
705  * service_control_dispatcher
706  */
707 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
708 {
709     service_data *service = arg;
710     LPWSTR name;
711     HANDLE pipe, event;
712
713     TRACE("%p %s\n", service, debugstr_w(service->name));
714
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);
720
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);
725
726     if (pipe==INVALID_HANDLE_VALUE)
727     {
728         ERR("failed to create pipe for %s, error = %d\n",
729             debugstr_w(service->name), GetLastError());
730         return 0;
731     }
732
733     /* dispatcher loop */
734     while (1)
735     {
736         BOOL r;
737         DWORD count, req[2] = {0,0};
738
739         r = ConnectNamedPipe(pipe, NULL);
740         if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
741         {
742             ERR("pipe connect failed\n");
743             break;
744         }
745
746         r = ReadFile( pipe, &req, sizeof req, &count, NULL );
747         if (!r || count!=sizeof req)
748         {
749             ERR("pipe read failed\n");
750             break;
751         }
752
753         service_reap_thread(service);
754
755         /* handle the request */
756         switch (req[0])
757         {
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]);
772         }
773
774         FlushFileBuffers(pipe);
775         DisconnectNamedPipe(pipe);
776     }
777
778     CloseHandle(pipe);
779     return 1;
780 }
781
782 /******************************************************************************
783  * service_run_threads
784  */
785 static BOOL service_run_threads(void)
786 {
787     service_data *service;
788     DWORD count, n = 0;
789     HANDLE *handles;
790
791     EnterCriticalSection( &service_cs );
792
793     count = list_count( &service_list );
794
795     TRACE("starting %d pipe listener threads\n", count);
796
797     handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
798
799     handles[n++] = __wine_make_process_system();
800
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);
805
806     LeaveCriticalSection( &service_cs );
807
808     /* wait for all the threads to pack up and exit */
809     while (n > 1)
810     {
811         DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
812         if (!ret)  /* system process event */
813         {
814             TRACE( "last user process exited, shutting down\n" );
815             /* FIXME: we should maybe send a shutdown control to running services */
816             ExitProcess(0);
817         }
818         if (ret < MAXIMUM_WAIT_OBJECTS)
819         {
820             CloseHandle( handles[ret] );
821             memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
822             n--;
823         }
824         else break;
825     }
826
827     while (n) CloseHandle( handles[--n] );
828     HeapFree(GetProcessHeap(), 0, handles);
829
830     return TRUE;
831 }
832
833 /******************************************************************************
834  * StartServiceCtrlDispatcherA [ADVAPI32.@]
835  *
836  * See StartServiceCtrlDispatcherW.
837  */
838 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
839 {
840     service_data *info;
841     DWORD sz, len;
842     BOOL ret = TRUE;
843
844     TRACE("%p\n", servent);
845
846     EnterCriticalSection( &service_cs );
847     while (servent->lpServiceName)
848     {
849         LPSTR name = servent->lpServiceName;
850
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++;
859     }
860     LeaveCriticalSection( &service_cs );
861
862     service_run_threads();
863
864     return ret;
865 }
866
867 /******************************************************************************
868  * StartServiceCtrlDispatcherW [ADVAPI32.@]
869  *
870  *  Connects a process containing one or more services to the service control
871  * manager.
872  *
873  * PARAMS
874  *   servent [I]  A list of the service names and service procedures
875  *
876  * RETURNS
877  *  Success: TRUE.
878  *  Failure: FALSE.
879  */
880 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
881 {
882     service_data *info;
883     DWORD sz, len;
884     BOOL ret = TRUE;
885
886     TRACE("%p\n", servent);
887
888     EnterCriticalSection( &service_cs );
889     while (servent->lpServiceName)
890     {
891         LPWSTR name = servent->lpServiceName;
892
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++;
901     }
902     LeaveCriticalSection( &service_cs );
903
904     service_run_threads();
905
906     return ret;
907 }
908
909 /******************************************************************************
910  * LockServiceDatabase  [ADVAPI32.@]
911  */
912 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
913 {
914     HANDLE ret;
915
916     TRACE("%p\n",hSCManager);
917
918     ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
919     if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
920     {
921         CloseHandle( ret );
922         ret = NULL;
923         SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
924     }
925
926     TRACE("returning %p\n", ret);
927
928     return ret;
929 }
930
931 /******************************************************************************
932  * UnlockServiceDatabase  [ADVAPI32.@]
933  */
934 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
935 {
936     TRACE("%p\n",ScLock);
937
938     return CloseHandle( ScLock );
939 }
940
941 /******************************************************************************
942  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
943  */
944 SERVICE_STATUS_HANDLE WINAPI
945 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
946 {
947     LPWSTR lpServiceNameW;
948     SERVICE_STATUS_HANDLE ret;
949
950     lpServiceNameW = SERV_dup(lpServiceName);
951     ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
952     SERV_free(lpServiceNameW);
953     return ret;
954 }
955
956 /******************************************************************************
957  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
958  *
959  * PARAMS
960  *   lpServiceName []
961  *   lpfHandler    []
962  */
963 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
964                              LPHANDLER_FUNCTION lpfHandler )
965 {
966     service_data *service;
967     SERVICE_STATUS_HANDLE handle = 0;
968
969     EnterCriticalSection( &service_cs );
970     LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
971     {
972         if(!strcmpW(lpServiceName, service->name))
973         {
974             service->handler.handler = lpfHandler;
975             handle = (SERVICE_STATUS_HANDLE)service;
976             break;
977         }
978     }
979     LeaveCriticalSection( &service_cs );
980     return handle;
981 }
982
983 /******************************************************************************
984  * SetServiceStatus [ADVAPI32.@]
985  *
986  * PARAMS
987  *   hService []
988  *   lpStatus []
989  */
990 BOOL WINAPI
991 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
992 {
993     service_data *service;
994     BOOL r = FALSE;
995
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);
1001
1002     EnterCriticalSection( &service_cs );
1003     LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
1004     {
1005         if(service == (service_data*)hService)
1006         {
1007             memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
1008             TRACE("Set service status to %d\n",service->status.dwCurrentState);
1009             r = TRUE;
1010             break;
1011         }
1012     }
1013     LeaveCriticalSection( &service_cs );
1014
1015     return r;
1016 }
1017
1018
1019 /******************************************************************************
1020  * OpenSCManagerA [ADVAPI32.@]
1021  *
1022  * Establish a connection to the service control manager and open its database.
1023  *
1024  * PARAMS
1025  *   lpMachineName   [I] Pointer to machine name string
1026  *   lpDatabaseName  [I] Pointer to database name string
1027  *   dwDesiredAccess [I] Type of access
1028  *
1029  * RETURNS
1030  *   Success: A Handle to the service control manager database
1031  *   Failure: NULL
1032  */
1033 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1034                                  DWORD dwDesiredAccess )
1035 {
1036     LPWSTR lpMachineNameW, lpDatabaseNameW;
1037     SC_HANDLE ret;
1038
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;
1045 }
1046
1047 /******************************************************************************
1048  * OpenSCManagerW [ADVAPI32.@]
1049  *
1050  * See OpenSCManagerA.
1051  */
1052 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1053                                  DWORD dwDesiredAccess )
1054 {
1055     struct sc_manager *manager;
1056     HKEY hReg;
1057     LONG r;
1058     DWORD new_mask = dwDesiredAccess;
1059
1060     TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1061           debugstr_w(lpDatabaseName), dwDesiredAccess);
1062
1063     if( lpDatabaseName && lpDatabaseName[0] )
1064     {
1065         if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1066         {
1067             /* noop, all right */
1068         }
1069         else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1070         {
1071             SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1072             return NULL;
1073         }
1074         else
1075         {
1076             SetLastError( ERROR_INVALID_NAME );
1077             return NULL;
1078         }
1079     }
1080
1081     manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1082                                sc_handle_destroy_manager );
1083     if (!manager)
1084          return NULL;
1085
1086     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1087     if (r!=ERROR_SUCCESS)
1088         goto error;
1089
1090     r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1091     RegCloseKey( hReg );
1092     if (r!=ERROR_SUCCESS)
1093         goto error;
1094
1095     RtlMapGenericMask(&new_mask, &scm_generic);
1096     manager->dwAccess = new_mask;
1097     TRACE("returning %p (access : 0x%08x)\n", manager, manager->dwAccess);
1098
1099     return (SC_HANDLE) &manager->hdr;
1100
1101 error:
1102     sc_handle_free( &manager->hdr );
1103     SetLastError( r);
1104     return NULL;
1105 }
1106
1107 /******************************************************************************
1108  * ControlService [ADVAPI32.@]
1109  *
1110  * Send a control code to a service.
1111  *
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
1116  *
1117  * RETURNS
1118  *   Success: TRUE.
1119  *   Failure: FALSE.
1120  *
1121  * BUGS
1122  *   Unlike M$' implementation, control requests are not serialized and may be
1123  *   processed asynchronously.
1124  */
1125 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1126                             LPSERVICE_STATUS lpServiceStatus )
1127 {
1128     struct sc_service *hsvc;
1129     BOOL ret = FALSE;
1130     HANDLE handle;
1131
1132     TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1133
1134     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1135     if (!hsvc)
1136     {
1137         SetLastError( ERROR_INVALID_HANDLE );
1138         return FALSE;
1139     }
1140
1141     ret = QueryServiceStatus(hService, lpServiceStatus);
1142     if (!ret)
1143     {
1144         ERR("failed to query service status\n");
1145         SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1146         return FALSE;
1147     }
1148
1149     switch (lpServiceStatus->dwCurrentState)
1150     {
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;
1161     }
1162
1163     handle = service_open_pipe(hsvc->name);
1164     if (handle!=INVALID_HANDLE_VALUE)
1165     {
1166         DWORD result = ERROR_SUCCESS;
1167         ret = service_send_control(handle, dwControl, &result);
1168         CloseHandle(handle);
1169         if (result!=ERROR_SUCCESS)
1170         {
1171             SetLastError(result);
1172             ret = FALSE;
1173         }
1174     }
1175
1176     return ret;
1177 }
1178
1179 /******************************************************************************
1180  * CloseServiceHandle [ADVAPI32.@]
1181  * 
1182  * Close a handle to a service or the service control manager database.
1183  *
1184  * PARAMS
1185  *   hSCObject [I] Handle to service or service control manager database
1186  *
1187  * RETURNS
1188  *  Success: TRUE
1189  *  Failure: FALSE
1190  */
1191 BOOL WINAPI
1192 CloseServiceHandle( SC_HANDLE hSCObject )
1193 {
1194     TRACE("%p\n", hSCObject);
1195
1196     sc_handle_free( (struct sc_handle*) hSCObject );
1197
1198     return TRUE;
1199 }
1200
1201
1202 /******************************************************************************
1203  * OpenServiceA [ADVAPI32.@]
1204  *
1205  * Open a handle to a service.
1206  *
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
1211  *
1212  * RETURNS
1213  *    Success: Handle to the service
1214  *    Failure: NULL
1215  */
1216 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1217                                DWORD dwDesiredAccess )
1218 {
1219     LPWSTR lpServiceNameW;
1220     SC_HANDLE ret;
1221
1222     TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1223
1224     lpServiceNameW = SERV_dup(lpServiceName);
1225     ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1226     SERV_free(lpServiceNameW);
1227     return ret;
1228 }
1229
1230
1231 /******************************************************************************
1232  * OpenServiceW [ADVAPI32.@]
1233  *
1234  * See OpenServiceA.
1235  */
1236 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1237                                DWORD dwDesiredAccess)
1238 {
1239     struct sc_manager *hscm;
1240     struct sc_service *hsvc;
1241     HKEY hKey;
1242     long r;
1243     DWORD len;
1244     DWORD new_mask = dwDesiredAccess;
1245
1246     TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1247
1248     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1249     if (!hscm)
1250     {
1251         SetLastError( ERROR_INVALID_HANDLE );
1252         return FALSE;
1253     }
1254
1255     if (!lpServiceName)
1256     {
1257         SetLastError(ERROR_INVALID_ADDRESS);
1258         return NULL;
1259     }
1260
1261     r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1262     if (r!=ERROR_SUCCESS)
1263     {
1264         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1265         return NULL;
1266     }
1267     
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)
1273     {
1274         RegCloseKey(hKey);
1275         return NULL;
1276     }
1277     strcpyW( hsvc->name, lpServiceName );
1278     hsvc->hkey = hKey;
1279
1280     RtlMapGenericMask(&new_mask, &svc_generic);
1281     hsvc->dwAccess = new_mask;
1282
1283     /* add reference to SCM handle */
1284     hscm->hdr.ref_count++;
1285     hsvc->scm = hscm;
1286
1287     TRACE("returning %p\n",hsvc);
1288
1289     return (SC_HANDLE) &hsvc->hdr;
1290 }
1291
1292 /******************************************************************************
1293  * CreateServiceW [ADVAPI32.@]
1294  */
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 )
1303 {
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
1313     TRACE("%p %s %s\n", hSCManager, 
1314           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1315
1316     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1317     if (!hscm)
1318     {
1319         SetLastError( ERROR_INVALID_HANDLE );
1320         return NULL;
1321     }
1322
1323     if (!lpServiceName || !lpBinaryPathName)
1324     {
1325         SetLastError(ERROR_INVALID_ADDRESS);
1326         return NULL;
1327     }
1328
1329     if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1330     {
1331         SetLastError(ERROR_ACCESS_DENIED);
1332         return NULL;
1333     }
1334
1335     if (!lpServiceName[0])
1336     {
1337         SetLastError(ERROR_INVALID_NAME);
1338         return NULL;
1339     }
1340
1341     if (!lpBinaryPathName[0])
1342     {
1343         SetLastError(ERROR_INVALID_PARAMETER);
1344         return NULL;
1345     }
1346
1347     /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1348      * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1349      * runs under the LocalSystem account)
1350      */
1351     switch (dwServiceType)
1352     {
1353     case SERVICE_KERNEL_DRIVER:
1354     case SERVICE_FILE_SYSTEM_DRIVER:
1355     case SERVICE_WIN32_OWN_PROCESS:
1356     case SERVICE_WIN32_SHARE_PROCESS:
1357         /* No problem */
1358         break;
1359     case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1360     case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1361         /* FIXME : Do we need a more thorough check? */
1362         if (lpServiceStartName)
1363         {
1364             SetLastError(ERROR_INVALID_PARAMETER);
1365             return NULL;
1366         }
1367         break;
1368     default:
1369         SetLastError(ERROR_INVALID_PARAMETER);
1370         return NULL;
1371     }
1372
1373     /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1374     if (dwStartType > SERVICE_DISABLED)
1375     {
1376         SetLastError(ERROR_INVALID_PARAMETER);
1377         return NULL;
1378     }
1379
1380     r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1381                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1382     if (r!=ERROR_SUCCESS)
1383         return NULL;
1384
1385     if (dp != REG_CREATED_NEW_KEY)
1386     {
1387         SetLastError(ERROR_SERVICE_EXISTS);
1388         goto error;
1389     }
1390
1391     if( lpDisplayName )
1392         service_set_string( &val[n++], szDisplayName, lpDisplayName );
1393
1394     service_set_dword( &val[n++], szType, &dwServiceType );
1395     service_set_dword( &val[n++], szStart, &dwStartType );
1396     service_set_dword( &val[n++], szError, &dwErrorControl );
1397
1398     if( lpBinaryPathName )
1399         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1400
1401     if( lpLoadOrderGroup )
1402         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1403
1404     /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1405      * There is no such key as what szDependencies refers to */
1406     if( lpDependencies )
1407         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1408
1409     if( lpPassword )
1410         FIXME("Don't know how to add a Password for a service.\n");
1411
1412     if( lpServiceStartName )
1413         service_set_string( &val[n++], szObjectName, lpServiceStartName );
1414
1415     r = service_write_values( hKey, val, n );
1416     if( r != ERROR_SUCCESS )
1417         goto error;
1418
1419     len = strlenW(lpServiceName)+1;
1420     len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1421     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1422     if( !hsvc )
1423         goto error;
1424     lstrcpyW( hsvc->name, lpServiceName );
1425     hsvc->hkey = hKey;
1426
1427     RtlMapGenericMask(&new_mask, &svc_generic);
1428     hsvc->dwAccess = new_mask;
1429
1430     hsvc->scm = hscm;
1431     hscm->hdr.ref_count++;
1432
1433     return (SC_HANDLE) &hsvc->hdr;
1434     
1435 error:
1436     RegCloseKey( hKey );
1437     return NULL;
1438 }
1439
1440
1441 /******************************************************************************
1442  * CreateServiceA [ADVAPI32.@]
1443  */
1444 SC_HANDLE WINAPI
1445 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1446                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1447                   DWORD dwServiceType, DWORD dwStartType,
1448                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1449                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1450                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1451                   LPCSTR lpPassword )
1452 {
1453     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1454         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1455     SC_HANDLE r;
1456
1457     TRACE("%p %s %s\n", hSCManager,
1458           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1459
1460     lpServiceNameW = SERV_dup( lpServiceName );
1461     lpDisplayNameW = SERV_dup( lpDisplayName );
1462     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1463     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1464     lpDependenciesW = SERV_dupmulti( lpDependencies );
1465     lpServiceStartNameW = SERV_dup( lpServiceStartName );
1466     lpPasswordW = SERV_dup( lpPassword );
1467
1468     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1469             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1470             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1471             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1472
1473     SERV_free( lpServiceNameW );
1474     SERV_free( lpDisplayNameW );
1475     SERV_free( lpBinaryPathNameW );
1476     SERV_free( lpLoadOrderGroupW );
1477     SERV_free( lpDependenciesW );
1478     SERV_free( lpServiceStartNameW );
1479     SERV_free( lpPasswordW );
1480
1481     return r;
1482 }
1483
1484
1485 /******************************************************************************
1486  * DeleteService [ADVAPI32.@]
1487  *
1488  * Delete a service from the service control manager database.
1489  *
1490  * PARAMS
1491  *    hService [I] Handle of the service to delete
1492  *
1493  * RETURNS
1494  *  Success: TRUE
1495  *  Failure: FALSE
1496  */
1497 BOOL WINAPI DeleteService( SC_HANDLE hService )
1498 {
1499     struct sc_service *hsvc;
1500
1501     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1502     if (!hsvc)
1503     {
1504         SetLastError( ERROR_INVALID_HANDLE );
1505         return FALSE;
1506     }
1507
1508     /* Close the key to the service */
1509     RegCloseKey(hsvc->hkey);
1510
1511     /* Delete the service under the Service Control Manager key */
1512     RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1513
1514     hsvc->hkey = NULL;
1515
1516     return TRUE;
1517 }
1518
1519
1520 /******************************************************************************
1521  * StartServiceA [ADVAPI32.@]
1522  *
1523  * Start a service
1524  *
1525  * PARAMS
1526  *   hService            [I] Handle of service
1527  *   dwNumServiceArgs    [I] Number of arguments
1528  *   lpServiceArgVectors [I] Address of array of argument strings
1529  *
1530  * NOTES
1531  *  - NT implements this function using an obscure RPC call.
1532  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1533  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
1534  *  - This will only work for shared address space. How should the service
1535  *    args be transferred when address spaces are separated?
1536  *  - Can only start one service at a time.
1537  *  - Has no concept of privilege.
1538  *
1539  * RETURNS
1540  *   Success: TRUE.
1541  *   Failure: FALSE
1542  */
1543 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1544                            LPCSTR *lpServiceArgVectors )
1545 {
1546     LPWSTR *lpwstr=NULL;
1547     unsigned int i;
1548     BOOL r;
1549
1550     TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1551
1552     if (dwNumServiceArgs)
1553         lpwstr = HeapAlloc( GetProcessHeap(), 0,
1554                                    dwNumServiceArgs*sizeof(LPWSTR) );
1555
1556     for(i=0; i<dwNumServiceArgs; i++)
1557         lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1558
1559     r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1560
1561     if (dwNumServiceArgs)
1562     {
1563         for(i=0; i<dwNumServiceArgs; i++)
1564             SERV_free(lpwstr[i]);
1565         HeapFree(GetProcessHeap(), 0, lpwstr);
1566     }
1567
1568     return r;
1569 }
1570
1571 /******************************************************************************
1572  * service_start_process    [INTERNAL]
1573  */
1574 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1575 {
1576     static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1577     PROCESS_INFORMATION pi;
1578     STARTUPINFOW si;
1579     LPWSTR path = NULL, str;
1580     DWORD type, size, ret, svc_type;
1581     HANDLE handles[2];
1582     BOOL r;
1583
1584     size = sizeof(svc_type);
1585     if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1586         svc_type = 0;
1587
1588     if (svc_type == SERVICE_KERNEL_DRIVER)
1589     {
1590         static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1591         DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1592
1593         if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1594         GetSystemDirectoryW( path, len );
1595         lstrcatW( path, winedeviceW );
1596         lstrcatW( path, hsvc->name );
1597     }
1598     else
1599     {
1600         /* read the executable path from the registry */
1601         size = 0;
1602         ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1603         if (ret!=ERROR_SUCCESS)
1604             return FALSE;
1605         str = HeapAlloc(GetProcessHeap(),0,size);
1606         ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1607         if (ret==ERROR_SUCCESS)
1608         {
1609             size = ExpandEnvironmentStringsW(str,NULL,0);
1610             path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1611             ExpandEnvironmentStringsW(str,path,size);
1612         }
1613         HeapFree(GetProcessHeap(),0,str);
1614         if (!path)
1615             return FALSE;
1616     }
1617
1618     /* wait for the process to start and set an event or terminate */
1619     handles[0] = service_get_event_handle( hsvc->name );
1620     ZeroMemory(&si, sizeof(STARTUPINFOW));
1621     si.cb = sizeof(STARTUPINFOW);
1622     r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1623     if (r)
1624     {
1625         if (ppid) *ppid = pi.dwProcessId;
1626
1627         handles[1] = pi.hProcess;
1628         ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1629         if(ret != WAIT_OBJECT_0)
1630         {
1631             SetLastError(ERROR_IO_PENDING);
1632             r = FALSE;
1633         }
1634
1635         CloseHandle( pi.hThread );
1636         CloseHandle( pi.hProcess );
1637     }
1638     CloseHandle( handles[0] );
1639     HeapFree(GetProcessHeap(),0,path);
1640     return r;
1641 }
1642
1643 static BOOL service_wait_for_startup(SC_HANDLE hService)
1644 {
1645     DWORD i;
1646     SERVICE_STATUS status;
1647     BOOL r = FALSE;
1648
1649     TRACE("%p\n", hService);
1650
1651     for (i=0; i<30; i++)
1652     {
1653         status.dwCurrentState = 0;
1654         r = QueryServiceStatus(hService, &status);
1655         if (!r)
1656             break;
1657         if (status.dwCurrentState == SERVICE_RUNNING)
1658         {
1659             TRACE("Service started successfully\n");
1660             break;
1661         }
1662         r = FALSE;
1663         Sleep(1000);
1664     }
1665     return r;
1666 }
1667
1668 /******************************************************************************
1669  * StartServiceW [ADVAPI32.@]
1670  * 
1671  * See StartServiceA.
1672  */
1673 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1674                           LPCWSTR *lpServiceArgVectors)
1675 {
1676     struct sc_service *hsvc;
1677     BOOL r = FALSE;
1678     DWORD dwResult, dwProcessId = 0;
1679     SC_LOCK hLock;
1680     HANDLE handle = INVALID_HANDLE_VALUE;
1681
1682     TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1683
1684     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1685     if (!hsvc)
1686     {
1687         SetLastError(ERROR_INVALID_HANDLE);
1688         return r;
1689     }
1690
1691     hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1692     if (!hLock)
1693         return r;
1694
1695     handle = service_open_pipe(hsvc->name);
1696     if (handle==INVALID_HANDLE_VALUE)
1697     {
1698         /* start the service process */
1699         if (service_start_process(hsvc, &dwProcessId))
1700             handle = service_open_pipe(hsvc->name);
1701     }
1702
1703     if (handle != INVALID_HANDLE_VALUE)
1704     {
1705         r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1706         CloseHandle(handle);
1707     }
1708
1709     handle = service_open_pipe(hsvc->name);
1710     if (handle != INVALID_HANDLE_VALUE)
1711     {
1712         service_set_processID(handle, dwProcessId, &dwResult);
1713         CloseHandle(handle);
1714     }
1715
1716     UnlockServiceDatabase( hLock );
1717
1718     TRACE("returning %d\n", r);
1719
1720     if (r)
1721         service_wait_for_startup(hService);
1722
1723     return r;
1724 }
1725
1726 /******************************************************************************
1727  * QueryServiceStatus [ADVAPI32.@]
1728  *
1729  * PARAMS
1730  *   hService        [I] Handle to service to get information about
1731  *   lpservicestatus [O] buffer to receive the status information for the service
1732  *
1733  */
1734 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1735                                LPSERVICE_STATUS lpservicestatus)
1736 {
1737     SERVICE_STATUS_PROCESS SvcStatusData;
1738     BOOL ret;
1739
1740     TRACE("%p %p\n", hService, lpservicestatus);
1741
1742     ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1743                                 sizeof(SERVICE_STATUS_PROCESS), NULL);
1744     if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1745     return ret;
1746 }
1747
1748
1749 /******************************************************************************
1750  * QueryServiceStatusEx [ADVAPI32.@]
1751  *
1752  * Get information about a service.
1753  *
1754  * PARAMS
1755  *   hService       [I] Handle to service to get information about
1756  *   InfoLevel      [I] Level of information to get
1757  *   lpBuffer       [O] Destination for requested information
1758  *   cbBufSize      [I] Size of lpBuffer in bytes
1759  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1760  *
1761  * RETURNS
1762  *  Success: TRUE
1763  *  FAILURE: FALSE
1764  */
1765 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1766                         LPBYTE lpBuffer, DWORD cbBufSize,
1767                         LPDWORD pcbBytesNeeded)
1768 {
1769     struct sc_service *hsvc;
1770     DWORD size, type, val;
1771     HANDLE pipe;
1772     LONG r;
1773     LPSERVICE_STATUS_PROCESS pSvcStatusData;
1774
1775     TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1776
1777     if (InfoLevel != SC_STATUS_PROCESS_INFO)
1778     {
1779         SetLastError( ERROR_INVALID_LEVEL);
1780         return FALSE;
1781     }
1782
1783     pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1784     if (pSvcStatusData == NULL)
1785     {
1786         SetLastError( ERROR_INVALID_PARAMETER);
1787         return FALSE;
1788     }
1789
1790     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1791     {
1792         if( pcbBytesNeeded != NULL)
1793             *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1794
1795         SetLastError( ERROR_INSUFFICIENT_BUFFER);
1796         return FALSE;
1797     }
1798
1799     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1800     if (!hsvc)
1801     {
1802         SetLastError( ERROR_INVALID_HANDLE );
1803         return FALSE;
1804     }
1805
1806     pipe = service_open_pipe(hsvc->name);
1807     if (pipe != INVALID_HANDLE_VALUE)
1808     {
1809         r = service_get_status(pipe, pSvcStatusData);
1810         CloseHandle(pipe);
1811         if (r)
1812             return TRUE;
1813     }
1814
1815     TRACE("Failed to read service status\n");
1816
1817     /* read the service type from the registry */
1818     size = sizeof(val);
1819     r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1820     if (r != ERROR_SUCCESS || type != REG_DWORD)
1821         val = 0;
1822
1823     pSvcStatusData->dwServiceType = val;
1824     pSvcStatusData->dwCurrentState            = SERVICE_STOPPED;  /* stopped */
1825     pSvcStatusData->dwControlsAccepted        = 0;
1826     pSvcStatusData->dwWin32ExitCode           = ERROR_SERVICE_NEVER_STARTED;
1827     pSvcStatusData->dwServiceSpecificExitCode = 0;
1828     pSvcStatusData->dwCheckPoint              = 0;
1829     pSvcStatusData->dwWaitHint                = 0;
1830
1831     return TRUE;
1832 }
1833
1834 /******************************************************************************
1835  * QueryServiceConfigA [ADVAPI32.@]
1836  */
1837 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1838                                  DWORD size, LPDWORD needed )
1839 {
1840     DWORD n;
1841     LPSTR p, buffer;
1842     BOOL ret;
1843     QUERY_SERVICE_CONFIGW *configW;
1844
1845     TRACE("%p %p %d %p\n", hService, config, size, needed);
1846
1847     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1848     {
1849         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1850         return FALSE;
1851     }
1852     configW = (QUERY_SERVICE_CONFIGW *)buffer;
1853     ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1854     if (!ret) goto done;
1855
1856     config->dwServiceType      = configW->dwServiceType;
1857     config->dwStartType        = configW->dwStartType;
1858     config->dwErrorControl     = configW->dwErrorControl;
1859     config->lpBinaryPathName   = NULL;
1860     config->lpLoadOrderGroup   = NULL;
1861     config->dwTagId            = configW->dwTagId;
1862     config->lpDependencies     = NULL;
1863     config->lpServiceStartName = NULL;
1864     config->lpDisplayName      = NULL;
1865
1866     p = (LPSTR)(config + 1);
1867     n = size - sizeof(*config);
1868     ret = FALSE;
1869
1870 #define MAP_STR(str) \
1871     do { \
1872         if (configW->str) \
1873         { \
1874             DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1875             if (!sz) goto done; \
1876             config->str = p; \
1877             p += sz; \
1878             n -= sz; \
1879         } \
1880     } while (0)
1881
1882     MAP_STR( lpBinaryPathName );
1883     MAP_STR( lpLoadOrderGroup );
1884     MAP_STR( lpDependencies );
1885     MAP_STR( lpServiceStartName );
1886     MAP_STR( lpDisplayName );
1887 #undef MAP_STR
1888
1889     *needed = p - (LPSTR)config;
1890     ret = TRUE;
1891
1892 done:
1893     HeapFree( GetProcessHeap(), 0, buffer );
1894     return ret;
1895 }
1896
1897 /******************************************************************************
1898  * QueryServiceConfigW [ADVAPI32.@]
1899  */
1900 BOOL WINAPI 
1901 QueryServiceConfigW( SC_HANDLE hService,
1902                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1903                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1904 {
1905     WCHAR str_buffer[ MAX_PATH ];
1906     LONG r;
1907     DWORD type, val, sz, total, n;
1908     LPBYTE p;
1909     HKEY hKey;
1910     struct sc_service *hsvc;
1911
1912     TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1913            cbBufSize, pcbBytesNeeded);
1914
1915     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1916     if (!hsvc)
1917     {
1918         SetLastError( ERROR_INVALID_HANDLE );
1919         return FALSE;
1920     }
1921     hKey = hsvc->hkey;
1922
1923     /* TODO: Check which members are mandatory and what the registry types
1924      * should be. This should of course also be tested when a service is
1925      * created.
1926      */
1927
1928     /* calculate the size required first */
1929     total = sizeof (QUERY_SERVICE_CONFIGW);
1930
1931     sz = sizeof(str_buffer);
1932     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1933     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1934     {
1935         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1936         if( 0 == sz ) return FALSE;
1937
1938         total += sizeof(WCHAR) * sz;
1939     }
1940     else
1941     {
1942        /* FIXME: set last error */
1943        return FALSE;
1944     }
1945
1946     sz = 0;
1947     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1948     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1949         total += sz;
1950     else
1951         total += sizeof(WCHAR);
1952
1953     sz = 0;
1954     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1955     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1956         total += sz;
1957     else
1958         total += sizeof(WCHAR);
1959
1960     sz = 0;
1961     r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1962     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1963         total += sz;
1964     else
1965         total += sizeof(WCHAR);
1966
1967     sz = 0;
1968     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1969     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1970         total += sz;
1971     else
1972         total += sizeof(WCHAR);
1973
1974     *pcbBytesNeeded = total;
1975
1976     /* if there's not enough memory, return an error */
1977     if( total > cbBufSize )
1978     {
1979         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1980         return FALSE;
1981     }
1982
1983     ZeroMemory( lpServiceConfig, total );
1984
1985     sz = sizeof val;
1986     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1987     if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1988         lpServiceConfig->dwServiceType = val;
1989
1990     sz = sizeof val;
1991     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1992     if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1993         lpServiceConfig->dwStartType = val;
1994
1995     sz = sizeof val;
1996     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1997     if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1998         lpServiceConfig->dwErrorControl = val;
1999
2000     sz = sizeof val;
2001     r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
2002     if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
2003         lpServiceConfig->dwTagId = val;
2004
2005     /* now do the strings */
2006     p = (LPBYTE) &lpServiceConfig[1];
2007     n = total - sizeof (QUERY_SERVICE_CONFIGW);
2008
2009     sz = sizeof(str_buffer);
2010     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
2011     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
2012     {
2013         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
2014         sz *= sizeof(WCHAR);
2015         if( 0 == sz || sz > n ) return FALSE;
2016
2017         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
2018         p += sz;
2019         n -= sz;
2020     }
2021     else
2022     {
2023        /* FIXME: set last error */
2024        return FALSE;
2025     }
2026
2027     sz = n;
2028     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
2029     lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
2030     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2031     {
2032         p += sz;
2033         n -= sz;
2034     }
2035     else
2036     {
2037         *(WCHAR *) p = 0;
2038         p += sizeof(WCHAR);
2039         n -= sizeof(WCHAR);
2040     }
2041
2042     sz = n;
2043     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2044     lpServiceConfig->lpDependencies = (LPWSTR) p;
2045     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2046     {
2047         p += sz;
2048         n -= sz;
2049     }
2050     else
2051     {
2052         *(WCHAR *) p = 0;
2053         p += sizeof(WCHAR);
2054         n -= sizeof(WCHAR);
2055     }
2056
2057     sz = n;
2058     r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2059     lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2060     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2061     {
2062         p += sz;
2063         n -= sz;
2064     }
2065     else
2066     {
2067         *(WCHAR *) p = 0;
2068         p += sizeof(WCHAR);
2069         n -= sizeof(WCHAR);
2070     }
2071
2072     sz = n;
2073     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2074     lpServiceConfig->lpDisplayName = (LPWSTR) p;
2075     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2076     {
2077         p += sz;
2078         n -= sz;
2079     }
2080     else
2081     {
2082         *(WCHAR *) p = 0;
2083         p += sizeof(WCHAR);
2084         n -= sizeof(WCHAR);
2085     }
2086
2087     if( n < 0 )
2088         ERR("Buffer overflow!\n");
2089
2090     TRACE("Image path           = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2091     TRACE("Group                = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2092     TRACE("Dependencies         = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2093     TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2094     TRACE("Display name         = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2095
2096     return TRUE;
2097 }
2098
2099 /******************************************************************************
2100  * EnumServicesStatusA [ADVAPI32.@]
2101  */
2102 BOOL WINAPI
2103 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2104                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2105                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2106                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2107 {
2108     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2109           dwServiceType, dwServiceState, lpServices, cbBufSize,
2110           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
2111     SetLastError (ERROR_ACCESS_DENIED);
2112     return FALSE;
2113 }
2114
2115 /******************************************************************************
2116  * EnumServicesStatusW [ADVAPI32.@]
2117  */
2118 BOOL WINAPI
2119 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2120                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2121                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2122                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2123 {
2124     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2125           dwServiceType, dwServiceState, lpServices, cbBufSize,
2126           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
2127     SetLastError (ERROR_ACCESS_DENIED);
2128     return FALSE;
2129 }
2130
2131 /******************************************************************************
2132  * EnumServicesStatusExA [ADVAPI32.@]
2133  */
2134 BOOL WINAPI
2135 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2136                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2137                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2138 {
2139     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2140           dwServiceType, dwServiceState, lpServices, cbBufSize,
2141           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
2142     SetLastError (ERROR_ACCESS_DENIED);
2143     return FALSE;
2144 }
2145
2146 /******************************************************************************
2147  * EnumServicesStatusExW [ADVAPI32.@]
2148  */
2149 BOOL WINAPI
2150 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2151                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2152                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2153 {
2154     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2155           dwServiceType, dwServiceState, lpServices, cbBufSize,
2156           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
2157     SetLastError (ERROR_ACCESS_DENIED);
2158     return FALSE;
2159 }
2160
2161 /******************************************************************************
2162  * GetServiceKeyNameA [ADVAPI32.@]
2163  */
2164 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2165                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2166 {
2167     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2168     return FALSE;
2169 }
2170
2171 /******************************************************************************
2172  * GetServiceKeyNameW [ADVAPI32.@]
2173  */
2174 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2175                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2176 {
2177     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2178     return FALSE;
2179 }
2180
2181 /******************************************************************************
2182  * QueryServiceLockStatusA [ADVAPI32.@]
2183  */
2184 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2185                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2186                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2187 {
2188     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2189
2190     return FALSE;
2191 }
2192
2193 /******************************************************************************
2194  * QueryServiceLockStatusW [ADVAPI32.@]
2195  */
2196 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2197                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2198                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2199 {
2200     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2201
2202     return FALSE;
2203 }
2204
2205 /******************************************************************************
2206  * GetServiceDisplayNameA  [ADVAPI32.@]
2207  */
2208 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2209   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2210 {
2211     struct sc_manager *hscm;
2212     DWORD type, size;
2213     LONG ret;
2214
2215     TRACE("%p %s %p %p\n", hSCManager,
2216           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2217
2218     if (!lpServiceName)
2219     {
2220         SetLastError(ERROR_INVALID_PARAMETER);
2221         return FALSE;
2222     }
2223
2224     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2225     if (!hscm)
2226     {
2227         SetLastError(ERROR_INVALID_HANDLE);
2228         return FALSE;
2229     }
2230
2231     size = *lpcchBuffer;
2232     ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2233     if (!ret && !lpDisplayName && size)
2234         ret = ERROR_MORE_DATA;
2235
2236     if (ret)
2237     {
2238         if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2239
2240         if (ret == ERROR_MORE_DATA)
2241         {
2242             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2243             *lpcchBuffer = size - 1;
2244         }
2245         else
2246             SetLastError(ret);
2247         return FALSE;
2248     }
2249     return TRUE;
2250 }
2251
2252 /******************************************************************************
2253  * GetServiceDisplayNameW  [ADVAPI32.@]
2254  */
2255 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2256   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2257 {
2258     struct sc_manager *hscm;
2259     DWORD type, size;
2260     LONG ret;
2261
2262     TRACE("%p %s %p %p\n", hSCManager,
2263           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2264
2265     if (!lpServiceName)
2266     {
2267         SetLastError(ERROR_INVALID_PARAMETER);
2268         return FALSE;
2269     }
2270
2271     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2272     if (!hscm)
2273     {
2274         SetLastError(ERROR_INVALID_HANDLE);
2275         return FALSE;
2276     }
2277
2278     size = *lpcchBuffer * sizeof(WCHAR);
2279     ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2280     if (!ret && !lpDisplayName && size)
2281         ret = ERROR_MORE_DATA;
2282
2283     if (ret)
2284     {
2285         if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2286
2287         if (ret == ERROR_MORE_DATA)
2288         {
2289             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2290             *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2291         }
2292         else
2293             SetLastError(ret);
2294         return FALSE;
2295     }
2296     return TRUE;
2297 }
2298
2299 /******************************************************************************
2300  * ChangeServiceConfigW  [ADVAPI32.@]
2301  */
2302 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2303   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2304   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2305   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2306 {
2307     struct reg_value val[10];
2308     struct sc_service *hsvc;
2309     DWORD r = ERROR_SUCCESS;
2310     HKEY hKey;
2311     int n = 0;
2312
2313     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2314           hService, dwServiceType, dwStartType, dwErrorControl, 
2315           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2316           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2317           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2318
2319     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2320     if (!hsvc)
2321     {
2322         SetLastError( ERROR_INVALID_HANDLE );
2323         return FALSE;
2324     }
2325     hKey = hsvc->hkey;
2326
2327     if( dwServiceType != SERVICE_NO_CHANGE )
2328         service_set_dword( &val[n++], szType, &dwServiceType );
2329
2330     if( dwStartType != SERVICE_NO_CHANGE )
2331         service_set_dword( &val[n++], szStart, &dwStartType );
2332
2333     if( dwErrorControl != SERVICE_NO_CHANGE )
2334         service_set_dword( &val[n++], szError, &dwErrorControl );
2335
2336     if( lpBinaryPathName )
2337         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2338
2339     if( lpLoadOrderGroup )
2340         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2341
2342     /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2343      * There is no such key as what szDependencies refers to */
2344     if( lpDependencies )
2345         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2346
2347     if( lpPassword )
2348         FIXME("ignoring password\n");
2349
2350     if( lpServiceStartName )
2351         service_set_string( &val[n++], szObjectName, lpServiceStartName );
2352
2353     r = service_write_values( hsvc->hkey, val, n );
2354
2355     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2356 }
2357
2358 /******************************************************************************
2359  * ChangeServiceConfigA  [ADVAPI32.@]
2360  */
2361 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2362   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2363   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2364   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2365 {
2366     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2367     LPWSTR wServiceStartName, wPassword, wDisplayName;
2368     BOOL r;
2369
2370     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2371           hService, dwServiceType, dwStartType, dwErrorControl, 
2372           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2373           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2374           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2375
2376     wBinaryPathName = SERV_dup( lpBinaryPathName );
2377     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2378     wDependencies = SERV_dupmulti( lpDependencies );
2379     wServiceStartName = SERV_dup( lpServiceStartName );
2380     wPassword = SERV_dup( lpPassword );
2381     wDisplayName = SERV_dup( lpDisplayName );
2382
2383     r = ChangeServiceConfigW( hService, dwServiceType,
2384             dwStartType, dwErrorControl, wBinaryPathName,
2385             wLoadOrderGroup, lpdwTagId, wDependencies,
2386             wServiceStartName, wPassword, wDisplayName);
2387
2388     SERV_free( wBinaryPathName );
2389     SERV_free( wLoadOrderGroup );
2390     SERV_free( wDependencies );
2391     SERV_free( wServiceStartName );
2392     SERV_free( wPassword );
2393     SERV_free( wDisplayName );
2394
2395     return r;
2396 }
2397
2398 /******************************************************************************
2399  * ChangeServiceConfig2A  [ADVAPI32.@]
2400  */
2401 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2402     LPVOID lpInfo)
2403 {
2404     BOOL r = FALSE;
2405
2406     TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2407
2408     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2409     {
2410         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2411         SERVICE_DESCRIPTIONW sdw;
2412
2413         sdw.lpDescription = SERV_dup( sd->lpDescription );
2414
2415         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2416
2417         SERV_free( sdw.lpDescription );
2418     }
2419     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2420     {
2421         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2422         SERVICE_FAILURE_ACTIONSW faw;
2423
2424         faw.dwResetPeriod = fa->dwResetPeriod;
2425         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2426         faw.lpCommand = SERV_dup( fa->lpCommand );
2427         faw.cActions = fa->cActions;
2428         faw.lpsaActions = fa->lpsaActions;
2429
2430         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2431
2432         SERV_free( faw.lpRebootMsg );
2433         SERV_free( faw.lpCommand );
2434     }
2435     else
2436         SetLastError( ERROR_INVALID_PARAMETER );
2437
2438     return r;
2439 }
2440
2441 /******************************************************************************
2442  * ChangeServiceConfig2W  [ADVAPI32.@]
2443  */
2444 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2445     LPVOID lpInfo)
2446 {
2447     HKEY hKey;
2448     struct sc_service *hsvc;
2449
2450     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2451     if (!hsvc)
2452     {
2453         SetLastError( ERROR_INVALID_HANDLE );
2454         return FALSE;
2455     }
2456     hKey = hsvc->hkey;
2457
2458     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2459     {
2460         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2461         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2462         if (sd->lpDescription)
2463         {
2464             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2465             if (sd->lpDescription[0] == 0)
2466                 RegDeleteValueW(hKey,szDescription);
2467             else
2468                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2469                                         (LPVOID)sd->lpDescription,
2470                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2471         }
2472     }
2473     else   
2474         FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2475     return TRUE;
2476 }
2477
2478 /******************************************************************************
2479  * QueryServiceObjectSecurity [ADVAPI32.@]
2480  */
2481 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2482        SECURITY_INFORMATION dwSecurityInformation,
2483        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2484        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2485 {
2486     PACL pACL = NULL;
2487
2488     FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2489           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2490
2491     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2492
2493     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2494     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2495     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2496     return TRUE;
2497 }
2498
2499 /******************************************************************************
2500  * SetServiceObjectSecurity [ADVAPI32.@]
2501  */
2502 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2503        SECURITY_INFORMATION dwSecurityInformation,
2504        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2505 {
2506     FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2507     return TRUE;
2508 }
2509
2510 /******************************************************************************
2511  * SetServiceBits [ADVAPI32.@]
2512  */
2513 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2514         DWORD dwServiceBits,
2515         BOOL bSetBitsOn,
2516         BOOL bUpdateImmediately)
2517 {
2518     FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2519           bSetBitsOn, bUpdateImmediately);
2520     return TRUE;
2521 }
2522
2523 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2524         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2525 {
2526     FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2527     return 0;
2528 }
2529
2530 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2531         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2532 {
2533     service_data *service;
2534     SERVICE_STATUS_HANDLE handle = 0;
2535
2536     TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2537
2538     EnterCriticalSection( &service_cs );
2539     LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2540     {
2541         if(!strcmpW(lpServiceName, service->name))
2542         {
2543             service->handler.handler_ex = lpHandlerProc;
2544             service->context = lpContext;
2545             service->extended = TRUE;
2546             handle = (SERVICE_STATUS_HANDLE)service;
2547             break;
2548         }
2549     }
2550     LeaveCriticalSection( &service_cs );
2551
2552     return handle;
2553 }