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