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