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