mshtml: Fix memory leak (found by Smatch).
[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     HeapFree(GetProcessHeap(), 0, name);
690
691     /* let the process who started us know we've tried to create a pipe */
692     event = service_get_event_handle(service->name);
693     SetEvent(event);
694     CloseHandle(event);
695
696     if (pipe==INVALID_HANDLE_VALUE)
697     {
698         ERR("failed to create pipe for %s, error = %d\n",
699             debugstr_w(service->name), GetLastError());
700         return 0;
701     }
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     if( n < 0 )
2111         ERR("Buffer overflow!\n");
2112
2113     TRACE("Image path           = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2114     TRACE("Group                = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2115     TRACE("Dependencies         = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2116     TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2117     TRACE("Display name         = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2118
2119     return TRUE;
2120 }
2121
2122 /******************************************************************************
2123  * EnumServicesStatusA [ADVAPI32.@]
2124  */
2125 BOOL WINAPI
2126 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2127                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2128                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2129                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2130 {
2131     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2132           dwServiceType, dwServiceState, lpServices, cbBufSize,
2133           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
2134     SetLastError (ERROR_ACCESS_DENIED);
2135     return FALSE;
2136 }
2137
2138 /******************************************************************************
2139  * EnumServicesStatusW [ADVAPI32.@]
2140  */
2141 BOOL WINAPI
2142 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2143                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2144                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2145                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2146 {
2147     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2148           dwServiceType, dwServiceState, lpServices, cbBufSize,
2149           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
2150     SetLastError (ERROR_ACCESS_DENIED);
2151     return FALSE;
2152 }
2153
2154 /******************************************************************************
2155  * EnumServicesStatusExA [ADVAPI32.@]
2156  */
2157 BOOL WINAPI
2158 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2159                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2160                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2161 {
2162     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2163           dwServiceType, dwServiceState, lpServices, cbBufSize,
2164           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
2165     *lpServicesReturned = 0;
2166     SetLastError (ERROR_ACCESS_DENIED);
2167     return FALSE;
2168 }
2169
2170 /******************************************************************************
2171  * EnumServicesStatusExW [ADVAPI32.@]
2172  */
2173 BOOL WINAPI
2174 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2175                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2176                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2177 {
2178     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2179           dwServiceType, dwServiceState, lpServices, cbBufSize,
2180           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
2181     SetLastError (ERROR_ACCESS_DENIED);
2182     return FALSE;
2183 }
2184
2185 /******************************************************************************
2186  * GetServiceKeyNameA [ADVAPI32.@]
2187  */
2188 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2189                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2190 {
2191     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2192     return FALSE;
2193 }
2194
2195 /******************************************************************************
2196  * GetServiceKeyNameW [ADVAPI32.@]
2197  */
2198 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2199                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2200 {
2201     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2202     return FALSE;
2203 }
2204
2205 /******************************************************************************
2206  * QueryServiceLockStatusA [ADVAPI32.@]
2207  */
2208 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2209                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2210                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2211 {
2212     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2213
2214     return FALSE;
2215 }
2216
2217 /******************************************************************************
2218  * QueryServiceLockStatusW [ADVAPI32.@]
2219  */
2220 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2221                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2222                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2223 {
2224     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2225
2226     return FALSE;
2227 }
2228
2229 /******************************************************************************
2230  * GetServiceDisplayNameA  [ADVAPI32.@]
2231  */
2232 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2233   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2234 {
2235     LPWSTR lpServiceNameW, lpDisplayNameW;
2236     DWORD sizeW;
2237     BOOL ret = FALSE;
2238
2239     TRACE("%p %s %p %p\n", hSCManager,
2240           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2241
2242     lpServiceNameW = SERV_dup(lpServiceName);
2243     if (lpDisplayName)
2244         lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2245     else
2246         lpDisplayNameW = NULL;
2247
2248     sizeW = *lpcchBuffer;
2249     if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2250     {
2251         *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
2252         goto cleanup;
2253     }
2254
2255     if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2256                         *lpcchBuffer, NULL, NULL ))
2257     {
2258         *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2259         goto cleanup;
2260     }
2261
2262     /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2263      * (but if the function succeeded it means that is a good upper estimation of the size) */
2264     ret = TRUE;
2265
2266 cleanup:
2267     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2268     HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2269     return ret;
2270 }
2271
2272 /******************************************************************************
2273  * GetServiceDisplayNameW  [ADVAPI32.@]
2274  */
2275 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2276   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2277 {
2278     struct sc_manager *hscm;
2279     DWORD type, size;
2280     LONG ret;
2281
2282     TRACE("%p %s %p %p\n", hSCManager,
2283           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2284
2285     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2286     if (!hscm)
2287     {
2288         SetLastError(ERROR_INVALID_HANDLE);
2289         return FALSE;
2290     }
2291
2292     if (!lpServiceName)
2293     {
2294         SetLastError(ERROR_INVALID_ADDRESS);
2295         return FALSE;
2296     }
2297
2298     size = *lpcchBuffer * sizeof(WCHAR);
2299     ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2300     if (!ret && !lpDisplayName && size)
2301         ret = ERROR_MORE_DATA;
2302
2303     if (ret)
2304     {
2305         if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2306
2307         if (ret == ERROR_MORE_DATA)
2308         {
2309             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2310             *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2311         }
2312         else if (ret == ERROR_FILE_NOT_FOUND)
2313         {
2314             HKEY hkey;
2315
2316             if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2317             {
2318                 UINT len = lstrlenW(lpServiceName);
2319                 BOOL r = FALSE;
2320
2321                 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2322                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
2323                 else if (lpDisplayName && *lpcchBuffer)
2324                 {
2325                     /* No displayname, but the service exists and the buffer
2326                      * is big enough. We should return the servicename.
2327                      */
2328                     lstrcpyW(lpDisplayName, lpServiceName);
2329                     r = TRUE;
2330                 }
2331
2332                 *lpcchBuffer = len;
2333                 RegCloseKey(hkey);
2334                 return r;
2335             }
2336             else
2337                 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2338         }
2339         else
2340             SetLastError(ret);
2341         return FALSE;
2342     }
2343
2344     /* Always return the correct needed size on success */
2345     *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2346
2347     return TRUE;
2348 }
2349
2350 /******************************************************************************
2351  * ChangeServiceConfigW  [ADVAPI32.@]
2352  */
2353 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2354   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2355   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2356   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2357 {
2358     struct reg_value val[10];
2359     struct sc_service *hsvc;
2360     DWORD r = ERROR_SUCCESS;
2361     HKEY hKey;
2362     int n = 0;
2363
2364     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2365           hService, dwServiceType, dwStartType, dwErrorControl, 
2366           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2367           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2368           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2369
2370     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2371     if (!hsvc)
2372     {
2373         SetLastError( ERROR_INVALID_HANDLE );
2374         return FALSE;
2375     }
2376     hKey = hsvc->hkey;
2377
2378     if( dwServiceType != SERVICE_NO_CHANGE )
2379         service_set_dword( &val[n++], szType, &dwServiceType );
2380
2381     if( dwStartType != SERVICE_NO_CHANGE )
2382         service_set_dword( &val[n++], szStart, &dwStartType );
2383
2384     if( dwErrorControl != SERVICE_NO_CHANGE )
2385         service_set_dword( &val[n++], szError, &dwErrorControl );
2386
2387     if( lpBinaryPathName )
2388         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2389
2390     if( lpLoadOrderGroup )
2391         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2392
2393     /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2394      * There is no such key as what szDependencies refers to */
2395     if( lpDependencies )
2396         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2397
2398     if( lpPassword )
2399         FIXME("ignoring password\n");
2400
2401     if( lpServiceStartName )
2402         service_set_string( &val[n++], szObjectName, lpServiceStartName );
2403
2404     r = service_write_values( hsvc->hkey, val, n );
2405
2406     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2407 }
2408
2409 /******************************************************************************
2410  * ChangeServiceConfigA  [ADVAPI32.@]
2411  */
2412 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2413   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2414   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2415   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2416 {
2417     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2418     LPWSTR wServiceStartName, wPassword, wDisplayName;
2419     BOOL r;
2420
2421     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2422           hService, dwServiceType, dwStartType, dwErrorControl, 
2423           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2424           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2425           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2426
2427     wBinaryPathName = SERV_dup( lpBinaryPathName );
2428     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2429     wDependencies = SERV_dupmulti( lpDependencies );
2430     wServiceStartName = SERV_dup( lpServiceStartName );
2431     wPassword = SERV_dup( lpPassword );
2432     wDisplayName = SERV_dup( lpDisplayName );
2433
2434     r = ChangeServiceConfigW( hService, dwServiceType,
2435             dwStartType, dwErrorControl, wBinaryPathName,
2436             wLoadOrderGroup, lpdwTagId, wDependencies,
2437             wServiceStartName, wPassword, wDisplayName);
2438
2439     HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2440     HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2441     HeapFree( GetProcessHeap(), 0, wDependencies );
2442     HeapFree( GetProcessHeap(), 0, wServiceStartName );
2443     HeapFree( GetProcessHeap(), 0, wPassword );
2444     HeapFree( GetProcessHeap(), 0, wDisplayName );
2445
2446     return r;
2447 }
2448
2449 /******************************************************************************
2450  * ChangeServiceConfig2A  [ADVAPI32.@]
2451  */
2452 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2453     LPVOID lpInfo)
2454 {
2455     BOOL r = FALSE;
2456
2457     TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2458
2459     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2460     {
2461         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2462         SERVICE_DESCRIPTIONW sdw;
2463
2464         sdw.lpDescription = SERV_dup( sd->lpDescription );
2465
2466         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2467
2468         HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2469     }
2470     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2471     {
2472         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2473         SERVICE_FAILURE_ACTIONSW faw;
2474
2475         faw.dwResetPeriod = fa->dwResetPeriod;
2476         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2477         faw.lpCommand = SERV_dup( fa->lpCommand );
2478         faw.cActions = fa->cActions;
2479         faw.lpsaActions = fa->lpsaActions;
2480
2481         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2482
2483         HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2484         HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2485     }
2486     else
2487         SetLastError( ERROR_INVALID_PARAMETER );
2488
2489     return r;
2490 }
2491
2492 /******************************************************************************
2493  * ChangeServiceConfig2W  [ADVAPI32.@]
2494  */
2495 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2496     LPVOID lpInfo)
2497 {
2498     HKEY hKey;
2499     struct sc_service *hsvc;
2500
2501     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2502     if (!hsvc)
2503     {
2504         SetLastError( ERROR_INVALID_HANDLE );
2505         return FALSE;
2506     }
2507     hKey = hsvc->hkey;
2508
2509     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2510     {
2511         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2512         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2513         if (sd->lpDescription)
2514         {
2515             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2516             if (sd->lpDescription[0] == 0)
2517                 RegDeleteValueW(hKey,szDescription);
2518             else
2519                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2520                                         (LPVOID)sd->lpDescription,
2521                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2522         }
2523     }
2524     else   
2525         FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2526     return TRUE;
2527 }
2528
2529 /******************************************************************************
2530  * QueryServiceObjectSecurity [ADVAPI32.@]
2531  */
2532 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2533        SECURITY_INFORMATION dwSecurityInformation,
2534        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2535        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2536 {
2537     SECURITY_DESCRIPTOR descriptor;
2538     DWORD size;
2539     BOOL succ;
2540     ACL acl;
2541
2542     FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2543           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2544
2545     if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2546         FIXME("information %d not supported\n", dwSecurityInformation);
2547
2548     InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2549
2550     InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2551     SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2552
2553     size = cbBufSize;
2554     succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2555     *pcbBytesNeeded = size;
2556     return succ;
2557 }
2558
2559 /******************************************************************************
2560  * SetServiceObjectSecurity [ADVAPI32.@]
2561  */
2562 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2563        SECURITY_INFORMATION dwSecurityInformation,
2564        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2565 {
2566     FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2567     return TRUE;
2568 }
2569
2570 /******************************************************************************
2571  * SetServiceBits [ADVAPI32.@]
2572  */
2573 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2574         DWORD dwServiceBits,
2575         BOOL bSetBitsOn,
2576         BOOL bUpdateImmediately)
2577 {
2578     FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2579           bSetBitsOn, bUpdateImmediately);
2580     return TRUE;
2581 }
2582
2583 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2584         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2585 {
2586     FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2587     return 0;
2588 }
2589
2590 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2591         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2592 {
2593     service_data *service;
2594     SERVICE_STATUS_HANDLE handle = 0;
2595
2596     TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2597
2598     EnterCriticalSection( &service_cs );
2599     LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2600     {
2601         if(!strcmpW(lpServiceName, service->name))
2602         {
2603             service->handler.handler_ex = lpHandlerProc;
2604             service->context = lpContext;
2605             service->extended = TRUE;
2606             handle = (SERVICE_STATUS_HANDLE)service;
2607             break;
2608         }
2609     }
2610     LeaveCriticalSection( &service_cs );
2611
2612     return handle;
2613 }