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