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