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