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