dbghelp: Added support for some V3 fields in structure parsing.
[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,FIELD_OFFSET(service_start_info, str[len]));
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, FIELD_OFFSET(service_start_info, str[len]), &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     if (lpServiceStatus)
1041     {
1042         ret = QueryServiceStatus(hService, lpServiceStatus);
1043         if (!ret)
1044         {
1045             ERR("failed to query service status\n");
1046             SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1047             return FALSE;
1048         }
1049
1050         switch (lpServiceStatus->dwCurrentState)
1051         {
1052         case SERVICE_STOPPED:
1053             SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1054             return FALSE;
1055         case SERVICE_START_PENDING:
1056             if (dwControl==SERVICE_CONTROL_STOP)
1057                 break;
1058             /* fall thru */
1059         case SERVICE_STOP_PENDING:
1060             SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1061             return FALSE;
1062         }
1063     }
1064
1065     handle = service_open_pipe(hsvc->name);
1066     if (handle!=INVALID_HANDLE_VALUE)
1067     {
1068         DWORD result = ERROR_SUCCESS;
1069         ret = service_send_control(handle, dwControl, &result);
1070         CloseHandle(handle);
1071         if (result!=ERROR_SUCCESS)
1072         {
1073             SetLastError(result);
1074             ret = FALSE;
1075         }
1076     }
1077
1078     return ret;
1079 }
1080
1081 /******************************************************************************
1082  * CloseServiceHandle [ADVAPI32.@]
1083  * 
1084  * Close a handle to a service or the service control manager database.
1085  *
1086  * PARAMS
1087  *   hSCObject [I] Handle to service or service control manager database
1088  *
1089  * RETURNS
1090  *  Success: TRUE
1091  *  Failure: FALSE
1092  */
1093 BOOL WINAPI
1094 CloseServiceHandle( SC_HANDLE hSCObject )
1095 {
1096     TRACE("%p\n", hSCObject);
1097
1098     sc_handle_free( (struct sc_handle*) hSCObject );
1099
1100     return TRUE;
1101 }
1102
1103
1104 /******************************************************************************
1105  * OpenServiceA [ADVAPI32.@]
1106  *
1107  * Open a handle to a service.
1108  *
1109  * PARAMS
1110  *   hSCManager      [I] Handle of the service control manager database
1111  *   lpServiceName   [I] Name of the service to open
1112  *   dwDesiredAccess [I] Access required to the service
1113  *
1114  * RETURNS
1115  *    Success: Handle to the service
1116  *    Failure: NULL
1117  */
1118 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1119                                DWORD dwDesiredAccess )
1120 {
1121     LPWSTR lpServiceNameW;
1122     SC_HANDLE ret;
1123
1124     TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1125
1126     lpServiceNameW = SERV_dup(lpServiceName);
1127     ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1128     HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1129     return ret;
1130 }
1131
1132
1133 /******************************************************************************
1134  * OpenServiceW [ADVAPI32.@]
1135  *
1136  * See OpenServiceA.
1137  */
1138 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1139                                DWORD dwDesiredAccess)
1140 {
1141     struct sc_manager *hscm;
1142     struct sc_service *hsvc;
1143     HKEY hKey;
1144     long r;
1145     DWORD len;
1146     DWORD new_mask = dwDesiredAccess;
1147
1148     TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1149
1150     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1151     if (!hscm)
1152     {
1153         SetLastError( ERROR_INVALID_HANDLE );
1154         return FALSE;
1155     }
1156
1157     if (!lpServiceName)
1158     {
1159         SetLastError(ERROR_INVALID_ADDRESS);
1160         return NULL;
1161     }
1162
1163     r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1164     if (r!=ERROR_SUCCESS)
1165     {
1166         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1167         return NULL;
1168     }
1169     
1170     len = strlenW(lpServiceName)+1;
1171     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1172                             sizeof (struct sc_service) + len*sizeof(WCHAR),
1173                             sc_handle_destroy_service );
1174     if (!hsvc)
1175     {
1176         RegCloseKey(hKey);
1177         return NULL;
1178     }
1179     strcpyW( hsvc->name, lpServiceName );
1180     hsvc->hkey = hKey;
1181
1182     RtlMapGenericMask(&new_mask, &svc_generic);
1183     hsvc->dwAccess = new_mask;
1184
1185     /* add reference to SCM handle */
1186     hscm->hdr.ref_count++;
1187     hsvc->scm = hscm;
1188
1189     TRACE("returning %p\n",hsvc);
1190
1191     return (SC_HANDLE) &hsvc->hdr;
1192 }
1193
1194 /******************************************************************************
1195  * CreateServiceW [ADVAPI32.@]
1196  */
1197 SC_HANDLE WINAPI
1198 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1199                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1200                   DWORD dwServiceType, DWORD dwStartType,
1201                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1202                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1203                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1204                   LPCWSTR lpPassword )
1205 {
1206     struct sc_manager *hscm;
1207     struct sc_service *hsvc = NULL;
1208     HKEY hKey;
1209     LONG r;
1210     DWORD dp, len;
1211     struct reg_value val[10];
1212     int n = 0;
1213     DWORD new_mask = dwDesiredAccess;
1214     DWORD index = 0;
1215     WCHAR buffer[MAX_PATH];
1216     BOOL displayname_exists = FALSE;
1217
1218     TRACE("%p %s %s\n", hSCManager, 
1219           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1220
1221     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1222     if (!hscm)
1223     {
1224         SetLastError( ERROR_INVALID_HANDLE );
1225         return NULL;
1226     }
1227
1228     if (!lpServiceName || !lpBinaryPathName)
1229     {
1230         SetLastError(ERROR_INVALID_ADDRESS);
1231         return NULL;
1232     }
1233
1234     if (!(hscm->dwAccess & SC_MANAGER_CREATE_SERVICE))
1235     {
1236         SetLastError(ERROR_ACCESS_DENIED);
1237         return NULL;
1238     }
1239
1240     if (!lpServiceName[0])
1241     {
1242         SetLastError(ERROR_INVALID_NAME);
1243         return NULL;
1244     }
1245
1246     if (!lpBinaryPathName[0])
1247     {
1248         SetLastError(ERROR_INVALID_PARAMETER);
1249         return NULL;
1250     }
1251
1252     /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1253      * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1254      * runs under the LocalSystem account)
1255      */
1256     switch (dwServiceType)
1257     {
1258     case SERVICE_KERNEL_DRIVER:
1259     case SERVICE_FILE_SYSTEM_DRIVER:
1260     case SERVICE_WIN32_OWN_PROCESS:
1261     case SERVICE_WIN32_SHARE_PROCESS:
1262         /* No problem */
1263         break;
1264     case SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1265     case SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS:
1266         /* FIXME : Do we need a more thorough check? */
1267         if (lpServiceStartName)
1268         {
1269             SetLastError(ERROR_INVALID_PARAMETER);
1270             return NULL;
1271         }
1272         break;
1273     default:
1274         SetLastError(ERROR_INVALID_PARAMETER);
1275         return NULL;
1276     }
1277
1278     if (!lpServiceStartName && (dwServiceType & SERVICE_WIN32))
1279             lpServiceStartName = szLocalSystem;
1280
1281     /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1282     if (dwStartType > SERVICE_DISABLED)
1283     {
1284         SetLastError(ERROR_INVALID_PARAMETER);
1285         return NULL;
1286     }
1287
1288     /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1289     if (((dwStartType == SERVICE_BOOT_START) || (dwStartType == SERVICE_SYSTEM_START)) &&
1290         ((dwServiceType & SERVICE_WIN32_OWN_PROCESS) || (dwServiceType & SERVICE_WIN32_SHARE_PROCESS)))
1291     {
1292         SetLastError(ERROR_INVALID_PARAMETER);
1293         return NULL;
1294     }
1295
1296     /* Loop through the registry to check if the service already exists and to
1297      * check if we can use the given displayname.
1298      * FIXME: Should we use EnumServicesStatusEx?
1299      */
1300     len = sizeof(buffer);
1301     while (RegEnumKeyExW(hscm->hkey, index, buffer, &len, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
1302     {
1303         HKEY service_key;
1304
1305         /* The service already exists, so bail out */
1306         if(!lstrcmpiW(lpServiceName, buffer))
1307         {
1308             SetLastError(ERROR_SERVICE_EXISTS);
1309             return NULL;
1310         }
1311
1312         /* The given displayname matches the found servicename. We don't bail out
1313          * as servicename is checked before a duplicate displayname
1314          */
1315         if(!lstrcmpiW(lpDisplayName, buffer))
1316             displayname_exists = TRUE;
1317
1318         if (RegOpenKeyExW(hscm->hkey, buffer, 0, KEY_READ, &service_key) == ERROR_SUCCESS)
1319         {
1320             WCHAR name[MAX_PATH];
1321             DWORD size = sizeof(name);
1322
1323             if (RegQueryValueExW(service_key, szDisplayName, NULL, NULL, (LPBYTE)name, &size) == ERROR_SUCCESS)
1324             {
1325                 /* The given displayname matches the found displayname */
1326                 if (!lstrcmpiW(lpDisplayName, name))
1327                     displayname_exists = TRUE;
1328             }
1329             RegCloseKey(service_key);
1330         }
1331         index++;
1332         len = sizeof(buffer);
1333     }
1334
1335     if (lpDisplayName && displayname_exists)
1336     {
1337         SetLastError(ERROR_DUPLICATE_SERVICE_NAME);
1338         return NULL;
1339     }
1340
1341     r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1342                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1343     if (r!=ERROR_SUCCESS)
1344     {
1345         /* FIXME: Should we set an error? */
1346         return NULL;
1347     }
1348
1349     if( lpDisplayName )
1350         service_set_string( &val[n++], szDisplayName, lpDisplayName );
1351
1352     service_set_dword( &val[n++], szType, &dwServiceType );
1353     service_set_dword( &val[n++], szStart, &dwStartType );
1354     service_set_dword( &val[n++], szError, &dwErrorControl );
1355
1356     service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1357
1358     if( lpLoadOrderGroup )
1359         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1360
1361     /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1362      * There is no such key as what szDependencies refers to */
1363     if( lpDependencies )
1364         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1365
1366     if( lpPassword )
1367         FIXME("Don't know how to add a Password for a service.\n");
1368
1369     if( lpServiceStartName )
1370         service_set_string( &val[n++], szObjectName, lpServiceStartName );
1371
1372     r = service_write_values( hKey, val, n );
1373     if( r != ERROR_SUCCESS )
1374         goto error;
1375
1376     len = strlenW(lpServiceName)+1;
1377     len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1378     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1379     if( !hsvc )
1380         goto error;
1381     lstrcpyW( hsvc->name, lpServiceName );
1382     hsvc->hkey = hKey;
1383
1384     RtlMapGenericMask(&new_mask, &svc_generic);
1385     hsvc->dwAccess = new_mask;
1386
1387     hsvc->scm = hscm;
1388     hscm->hdr.ref_count++;
1389
1390     return (SC_HANDLE) &hsvc->hdr;
1391     
1392 error:
1393     RegCloseKey( hKey );
1394     return NULL;
1395 }
1396
1397
1398 /******************************************************************************
1399  * CreateServiceA [ADVAPI32.@]
1400  */
1401 SC_HANDLE WINAPI
1402 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1403                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1404                   DWORD dwServiceType, DWORD dwStartType,
1405                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1406                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1407                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1408                   LPCSTR lpPassword )
1409 {
1410     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1411         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1412     SC_HANDLE r;
1413
1414     TRACE("%p %s %s\n", hSCManager,
1415           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1416
1417     lpServiceNameW = SERV_dup( lpServiceName );
1418     lpDisplayNameW = SERV_dup( lpDisplayName );
1419     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1420     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1421     lpDependenciesW = SERV_dupmulti( lpDependencies );
1422     lpServiceStartNameW = SERV_dup( lpServiceStartName );
1423     lpPasswordW = SERV_dup( lpPassword );
1424
1425     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1426             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1427             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1428             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1429
1430     HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1431     HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1432     HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1433     HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1434     HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1435     HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1436     HeapFree( GetProcessHeap(), 0, lpPasswordW );
1437
1438     return r;
1439 }
1440
1441
1442 /******************************************************************************
1443  * DeleteService [ADVAPI32.@]
1444  *
1445  * Delete a service from the service control manager database.
1446  *
1447  * PARAMS
1448  *    hService [I] Handle of the service to delete
1449  *
1450  * RETURNS
1451  *  Success: TRUE
1452  *  Failure: FALSE
1453  */
1454 BOOL WINAPI DeleteService( SC_HANDLE hService )
1455 {
1456     struct sc_service *hsvc;
1457
1458     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1459     if (!hsvc)
1460     {
1461         SetLastError( ERROR_INVALID_HANDLE );
1462         return FALSE;
1463     }
1464
1465     if (!(hsvc->dwAccess & DELETE))
1466     {
1467         SetLastError(ERROR_ACCESS_DENIED);
1468         return FALSE;
1469     }
1470
1471     /* Close the key to the service */
1472     RegCloseKey(hsvc->hkey);
1473
1474     /* Delete the service under the Service Control Manager key */
1475     RegDeleteTreeW(hsvc->scm->hkey, hsvc->name);
1476
1477     hsvc->hkey = NULL;
1478
1479     return TRUE;
1480 }
1481
1482
1483 /******************************************************************************
1484  * StartServiceA [ADVAPI32.@]
1485  *
1486  * Start a service
1487  *
1488  * PARAMS
1489  *   hService            [I] Handle of service
1490  *   dwNumServiceArgs    [I] Number of arguments
1491  *   lpServiceArgVectors [I] Address of array of argument strings
1492  *
1493  * NOTES
1494  *  - NT implements this function using an obscure RPC call.
1495  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1496  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
1497  *  - This will only work for shared address space. How should the service
1498  *    args be transferred when address spaces are separated?
1499  *  - Can only start one service at a time.
1500  *  - Has no concept of privilege.
1501  *
1502  * RETURNS
1503  *   Success: TRUE.
1504  *   Failure: FALSE
1505  */
1506 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1507                            LPCSTR *lpServiceArgVectors )
1508 {
1509     LPWSTR *lpwstr=NULL;
1510     unsigned int i;
1511     BOOL r;
1512
1513     TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1514
1515     if (dwNumServiceArgs)
1516         lpwstr = HeapAlloc( GetProcessHeap(), 0,
1517                                    dwNumServiceArgs*sizeof(LPWSTR) );
1518
1519     for(i=0; i<dwNumServiceArgs; i++)
1520         lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1521
1522     r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1523
1524     if (dwNumServiceArgs)
1525     {
1526         for(i=0; i<dwNumServiceArgs; i++)
1527             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1528         HeapFree(GetProcessHeap(), 0, lpwstr);
1529     }
1530
1531     return r;
1532 }
1533
1534 /******************************************************************************
1535  * service_start_process    [INTERNAL]
1536  */
1537 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1538 {
1539     static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1540     PROCESS_INFORMATION pi;
1541     STARTUPINFOW si;
1542     LPWSTR path = NULL, str;
1543     DWORD type, size, ret, svc_type;
1544     HANDLE handles[2];
1545     BOOL r;
1546
1547     size = sizeof(svc_type);
1548     if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1549         svc_type = 0;
1550
1551     if (svc_type == SERVICE_KERNEL_DRIVER)
1552     {
1553         static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1554         DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1555
1556         if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1557         GetSystemDirectoryW( path, len );
1558         lstrcatW( path, winedeviceW );
1559         lstrcatW( path, hsvc->name );
1560     }
1561     else
1562     {
1563         /* read the executable path from the registry */
1564         size = 0;
1565         ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1566         if (ret!=ERROR_SUCCESS)
1567             return FALSE;
1568         str = HeapAlloc(GetProcessHeap(),0,size);
1569         ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1570         if (ret==ERROR_SUCCESS)
1571         {
1572             size = ExpandEnvironmentStringsW(str,NULL,0);
1573             path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1574             ExpandEnvironmentStringsW(str,path,size);
1575         }
1576         HeapFree(GetProcessHeap(),0,str);
1577         if (!path)
1578             return FALSE;
1579     }
1580
1581     /* wait for the process to start and set an event or terminate */
1582     handles[0] = service_get_event_handle( hsvc->name );
1583     ZeroMemory(&si, sizeof(STARTUPINFOW));
1584     si.cb = sizeof(STARTUPINFOW);
1585     if (!(svc_type & SERVICE_INTERACTIVE_PROCESS))
1586     {
1587         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};
1588         si.lpDesktop = desktopW;
1589     }
1590
1591     r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1592     if (r)
1593     {
1594         if (ppid) *ppid = pi.dwProcessId;
1595
1596         handles[1] = pi.hProcess;
1597         ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1598         if(ret != WAIT_OBJECT_0)
1599         {
1600             SetLastError(ERROR_IO_PENDING);
1601             r = FALSE;
1602         }
1603
1604         CloseHandle( pi.hThread );
1605         CloseHandle( pi.hProcess );
1606     }
1607     CloseHandle( handles[0] );
1608     HeapFree(GetProcessHeap(),0,path);
1609     return r;
1610 }
1611
1612 static BOOL service_wait_for_startup(SC_HANDLE hService)
1613 {
1614     DWORD i;
1615     SERVICE_STATUS status;
1616     BOOL r = FALSE;
1617
1618     TRACE("%p\n", hService);
1619
1620     for (i=0; i<20; i++)
1621     {
1622         status.dwCurrentState = 0;
1623         r = QueryServiceStatus(hService, &status);
1624         if (!r)
1625             break;
1626         if (status.dwCurrentState == SERVICE_RUNNING)
1627         {
1628             TRACE("Service started successfully\n");
1629             break;
1630         }
1631         r = FALSE;
1632         if (status.dwCurrentState != SERVICE_START_PENDING) break;
1633         Sleep(100 * i);
1634     }
1635     return r;
1636 }
1637
1638 /******************************************************************************
1639  * StartServiceW [ADVAPI32.@]
1640  * 
1641  * See StartServiceA.
1642  */
1643 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1644                           LPCWSTR *lpServiceArgVectors)
1645 {
1646     struct sc_service *hsvc;
1647     BOOL r = FALSE;
1648     SC_LOCK hLock;
1649     HANDLE handle = INVALID_HANDLE_VALUE;
1650
1651     TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1652
1653     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1654     if (!hsvc)
1655     {
1656         SetLastError(ERROR_INVALID_HANDLE);
1657         return r;
1658     }
1659
1660     hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1661     if (!hLock)
1662         return r;
1663
1664     handle = service_open_pipe(hsvc->name);
1665     if (handle==INVALID_HANDLE_VALUE)
1666     {
1667         /* start the service process */
1668         if (service_start_process(hsvc, NULL))
1669             handle = service_open_pipe(hsvc->name);
1670     }
1671
1672     if (handle != INVALID_HANDLE_VALUE)
1673     {
1674         r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1675         CloseHandle(handle);
1676     }
1677
1678     UnlockServiceDatabase( hLock );
1679
1680     TRACE("returning %d\n", r);
1681
1682     if (r)
1683         service_wait_for_startup(hService);
1684
1685     return r;
1686 }
1687
1688 /******************************************************************************
1689  * QueryServiceStatus [ADVAPI32.@]
1690  *
1691  * PARAMS
1692  *   hService        [I] Handle to service to get information about
1693  *   lpservicestatus [O] buffer to receive the status information for the service
1694  *
1695  */
1696 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1697                                LPSERVICE_STATUS lpservicestatus)
1698 {
1699     SERVICE_STATUS_PROCESS SvcStatusData;
1700     BOOL ret;
1701
1702     TRACE("%p %p\n", hService, lpservicestatus);
1703
1704     ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1705                                 sizeof(SERVICE_STATUS_PROCESS), NULL);
1706     if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1707     return ret;
1708 }
1709
1710
1711 /******************************************************************************
1712  * QueryServiceStatusEx [ADVAPI32.@]
1713  *
1714  * Get information about a service.
1715  *
1716  * PARAMS
1717  *   hService       [I] Handle to service to get information about
1718  *   InfoLevel      [I] Level of information to get
1719  *   lpBuffer       [O] Destination for requested information
1720  *   cbBufSize      [I] Size of lpBuffer in bytes
1721  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1722  *
1723  * RETURNS
1724  *  Success: TRUE
1725  *  FAILURE: FALSE
1726  */
1727 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1728                         LPBYTE lpBuffer, DWORD cbBufSize,
1729                         LPDWORD pcbBytesNeeded)
1730 {
1731     struct sc_service *hsvc;
1732     DWORD size, type, val;
1733     HANDLE pipe;
1734     LONG r;
1735     LPSERVICE_STATUS_PROCESS pSvcStatusData;
1736
1737     TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1738
1739     if (InfoLevel != SC_STATUS_PROCESS_INFO)
1740     {
1741         SetLastError( ERROR_INVALID_LEVEL);
1742         return FALSE;
1743     }
1744
1745     pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1746     if (pSvcStatusData == NULL)
1747     {
1748         SetLastError( ERROR_INVALID_PARAMETER);
1749         return FALSE;
1750     }
1751
1752     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1753     {
1754         if( pcbBytesNeeded != NULL)
1755             *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1756
1757         SetLastError( ERROR_INSUFFICIENT_BUFFER);
1758         return FALSE;
1759     }
1760
1761     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1762     if (!hsvc)
1763     {
1764         SetLastError( ERROR_INVALID_HANDLE );
1765         return FALSE;
1766     }
1767
1768     pipe = service_open_pipe(hsvc->name);
1769     if (pipe != INVALID_HANDLE_VALUE)
1770     {
1771         r = service_get_status(pipe, pSvcStatusData);
1772         CloseHandle(pipe);
1773         if (r)
1774             return TRUE;
1775     }
1776
1777     TRACE("Failed to read service status\n");
1778
1779     /* read the service type from the registry */
1780     size = sizeof(val);
1781     r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1782     if (r != ERROR_SUCCESS || type != REG_DWORD)
1783         val = 0;
1784
1785     pSvcStatusData->dwServiceType = val;
1786     pSvcStatusData->dwCurrentState            = SERVICE_STOPPED;  /* stopped */
1787     pSvcStatusData->dwControlsAccepted        = 0;
1788     pSvcStatusData->dwWin32ExitCode           = ERROR_SERVICE_NEVER_STARTED;
1789     pSvcStatusData->dwServiceSpecificExitCode = 0;
1790     pSvcStatusData->dwCheckPoint              = 0;
1791     pSvcStatusData->dwWaitHint                = 0;
1792
1793     return TRUE;
1794 }
1795
1796 /******************************************************************************
1797  * QueryServiceConfigA [ADVAPI32.@]
1798  */
1799 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1800                                  DWORD size, LPDWORD needed )
1801 {
1802     DWORD n;
1803     LPSTR p, buffer;
1804     BOOL ret;
1805     QUERY_SERVICE_CONFIGW *configW;
1806
1807     TRACE("%p %p %d %p\n", hService, config, size, needed);
1808
1809     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1810     {
1811         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1812         return FALSE;
1813     }
1814     configW = (QUERY_SERVICE_CONFIGW *)buffer;
1815     ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1816     if (!ret) goto done;
1817
1818     config->dwServiceType      = configW->dwServiceType;
1819     config->dwStartType        = configW->dwStartType;
1820     config->dwErrorControl     = configW->dwErrorControl;
1821     config->lpBinaryPathName   = NULL;
1822     config->lpLoadOrderGroup   = NULL;
1823     config->dwTagId            = configW->dwTagId;
1824     config->lpDependencies     = NULL;
1825     config->lpServiceStartName = NULL;
1826     config->lpDisplayName      = NULL;
1827
1828     p = (LPSTR)(config + 1);
1829     n = size - sizeof(*config);
1830     ret = FALSE;
1831
1832 #define MAP_STR(str) \
1833     do { \
1834         if (configW->str) \
1835         { \
1836             DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1837             if (!sz) goto done; \
1838             config->str = p; \
1839             p += sz; \
1840             n -= sz; \
1841         } \
1842     } while (0)
1843
1844     MAP_STR( lpBinaryPathName );
1845     MAP_STR( lpLoadOrderGroup );
1846     MAP_STR( lpDependencies );
1847     MAP_STR( lpServiceStartName );
1848     MAP_STR( lpDisplayName );
1849 #undef MAP_STR
1850
1851     *needed = p - (LPSTR)config;
1852     ret = TRUE;
1853
1854 done:
1855     HeapFree( GetProcessHeap(), 0, buffer );
1856     return ret;
1857 }
1858
1859 /******************************************************************************
1860  * QueryServiceConfigW [ADVAPI32.@]
1861  */
1862 BOOL WINAPI 
1863 QueryServiceConfigW( SC_HANDLE hService,
1864                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1865                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1866 {
1867     WCHAR str_buffer[ MAX_PATH ];
1868     LONG r;
1869     DWORD type, val, sz, total, n;
1870     LPBYTE p;
1871     HKEY hKey;
1872     struct sc_service *hsvc;
1873
1874     TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1875            cbBufSize, pcbBytesNeeded);
1876
1877     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1878     if (!hsvc)
1879     {
1880         SetLastError( ERROR_INVALID_HANDLE );
1881         return FALSE;
1882     }
1883     hKey = hsvc->hkey;
1884
1885     /* TODO: Check which members are mandatory and what the registry types
1886      * should be. This should of course also be tested when a service is
1887      * created.
1888      */
1889
1890     /* calculate the size required first */
1891     total = sizeof (QUERY_SERVICE_CONFIGW);
1892
1893     sz = sizeof(str_buffer);
1894     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1895     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1896     {
1897         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1898         if( 0 == sz ) return FALSE;
1899
1900         total += sizeof(WCHAR) * sz;
1901     }
1902     else
1903     {
1904        /* FIXME: set last error */
1905        return FALSE;
1906     }
1907
1908     sz = 0;
1909     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1910     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1911         total += sz;
1912     else
1913         total += sizeof(WCHAR);
1914
1915     sz = 0;
1916     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1917     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1918         total += sz;
1919     else
1920         total += sizeof(WCHAR);
1921
1922     sz = 0;
1923     r = RegQueryValueExW( hKey, szObjectName, 0, &type, NULL, &sz );
1924     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1925         total += sz;
1926     else
1927         total += sizeof(WCHAR);
1928
1929     sz = 0;
1930     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1931     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1932         total += sz;
1933     else
1934         total += sizeof(WCHAR);
1935
1936     *pcbBytesNeeded = total;
1937
1938     /* if there's not enough memory, return an error */
1939     if( total > cbBufSize )
1940     {
1941         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1942         return FALSE;
1943     }
1944
1945     ZeroMemory( lpServiceConfig, total );
1946
1947     sz = sizeof val;
1948     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1949     if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1950         lpServiceConfig->dwServiceType = val;
1951
1952     sz = sizeof val;
1953     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1954     if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1955         lpServiceConfig->dwStartType = val;
1956
1957     sz = sizeof val;
1958     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1959     if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1960         lpServiceConfig->dwErrorControl = val;
1961
1962     sz = sizeof val;
1963     r = RegQueryValueExW( hKey, szTag, 0, &type, (LPBYTE)&val, &sz );
1964     if( ( r == ERROR_SUCCESS ) && ( type == REG_DWORD ) )
1965         lpServiceConfig->dwTagId = val;
1966
1967     /* now do the strings */
1968     p = (LPBYTE) &lpServiceConfig[1];
1969     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1970
1971     sz = sizeof(str_buffer);
1972     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1973     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1974     {
1975         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1976         sz *= sizeof(WCHAR);
1977         if( 0 == sz || sz > n ) return FALSE;
1978
1979         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1980         p += sz;
1981         n -= sz;
1982     }
1983     else
1984     {
1985        /* FIXME: set last error */
1986        return FALSE;
1987     }
1988
1989     sz = n;
1990     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1991     lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1992     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1993     {
1994         p += sz;
1995         n -= sz;
1996     }
1997     else
1998     {
1999         *(WCHAR *) p = 0;
2000         p += sizeof(WCHAR);
2001         n -= sizeof(WCHAR);
2002     }
2003
2004     sz = n;
2005     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
2006     lpServiceConfig->lpDependencies = (LPWSTR) p;
2007     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2008     {
2009         p += sz;
2010         n -= sz;
2011     }
2012     else
2013     {
2014         *(WCHAR *) p = 0;
2015         p += sizeof(WCHAR);
2016         n -= sizeof(WCHAR);
2017     }
2018
2019     sz = n;
2020     r = RegQueryValueExW( hKey, szObjectName, 0, &type, p, &sz );
2021     lpServiceConfig->lpServiceStartName = (LPWSTR) p;
2022     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2023     {
2024         p += sz;
2025         n -= sz;
2026     }
2027     else
2028     {
2029         *(WCHAR *) p = 0;
2030         p += sizeof(WCHAR);
2031         n -= sizeof(WCHAR);
2032     }
2033
2034     sz = n;
2035     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, p, &sz );
2036     lpServiceConfig->lpDisplayName = (LPWSTR) p;
2037     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
2038     {
2039         p += sz;
2040         n -= sz;
2041     }
2042     else
2043     {
2044         *(WCHAR *) p = 0;
2045         p += sizeof(WCHAR);
2046         n -= sizeof(WCHAR);
2047     }
2048
2049     TRACE("Image path           = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
2050     TRACE("Group                = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
2051     TRACE("Dependencies         = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
2052     TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
2053     TRACE("Display name         = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
2054
2055     return TRUE;
2056 }
2057
2058 /******************************************************************************
2059  * EnumServicesStatusA [ADVAPI32.@]
2060  */
2061 BOOL WINAPI
2062 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
2063                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
2064                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2065                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2066 {
2067     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2068           dwServiceType, dwServiceState, lpServices, cbBufSize,
2069           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
2070     SetLastError (ERROR_ACCESS_DENIED);
2071     return FALSE;
2072 }
2073
2074 /******************************************************************************
2075  * EnumServicesStatusW [ADVAPI32.@]
2076  */
2077 BOOL WINAPI
2078 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
2079                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
2080                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2081                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
2082 {
2083     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
2084           dwServiceType, dwServiceState, lpServices, cbBufSize,
2085           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
2086     SetLastError (ERROR_ACCESS_DENIED);
2087     return FALSE;
2088 }
2089
2090 /******************************************************************************
2091  * EnumServicesStatusExA [ADVAPI32.@]
2092  */
2093 BOOL WINAPI
2094 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2095                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2096                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2097 {
2098     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2099           dwServiceType, dwServiceState, lpServices, cbBufSize,
2100           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
2101     *lpServicesReturned = 0;
2102     SetLastError (ERROR_ACCESS_DENIED);
2103     return FALSE;
2104 }
2105
2106 /******************************************************************************
2107  * EnumServicesStatusExW [ADVAPI32.@]
2108  */
2109 BOOL WINAPI
2110 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2111                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2112                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2113 {
2114     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2115           dwServiceType, dwServiceState, lpServices, cbBufSize,
2116           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
2117     SetLastError (ERROR_ACCESS_DENIED);
2118     return FALSE;
2119 }
2120
2121 /******************************************************************************
2122  * GetServiceKeyNameA [ADVAPI32.@]
2123  */
2124 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2125                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2126 {
2127     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2128     return FALSE;
2129 }
2130
2131 /******************************************************************************
2132  * GetServiceKeyNameW [ADVAPI32.@]
2133  */
2134 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2135                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2136 {
2137     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2138     return FALSE;
2139 }
2140
2141 /******************************************************************************
2142  * QueryServiceLockStatusA [ADVAPI32.@]
2143  */
2144 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2145                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2146                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2147 {
2148     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2149
2150     return FALSE;
2151 }
2152
2153 /******************************************************************************
2154  * QueryServiceLockStatusW [ADVAPI32.@]
2155  */
2156 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2157                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2158                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2159 {
2160     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2161
2162     return FALSE;
2163 }
2164
2165 /******************************************************************************
2166  * GetServiceDisplayNameA  [ADVAPI32.@]
2167  */
2168 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2169   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2170 {
2171     LPWSTR lpServiceNameW, lpDisplayNameW;
2172     DWORD sizeW;
2173     BOOL ret = FALSE;
2174
2175     TRACE("%p %s %p %p\n", hSCManager,
2176           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2177
2178     lpServiceNameW = SERV_dup(lpServiceName);
2179     if (lpDisplayName)
2180         lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
2181     else
2182         lpDisplayNameW = NULL;
2183
2184     sizeW = *lpcchBuffer;
2185     if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
2186     {
2187         *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
2188         goto cleanup;
2189     }
2190
2191     if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
2192                         *lpcchBuffer, NULL, NULL ))
2193     {
2194         *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
2195         goto cleanup;
2196     }
2197
2198     /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2199      * (but if the function succeeded it means that is a good upper estimation of the size) */
2200     ret = TRUE;
2201
2202 cleanup:
2203     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
2204     HeapFree(GetProcessHeap(), 0, lpServiceNameW);
2205     return ret;
2206 }
2207
2208 /******************************************************************************
2209  * GetServiceDisplayNameW  [ADVAPI32.@]
2210  */
2211 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2212   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2213 {
2214     struct sc_manager *hscm;
2215     DWORD type, size;
2216     LONG ret;
2217
2218     TRACE("%p %s %p %p\n", hSCManager,
2219           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2220
2221     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2222     if (!hscm)
2223     {
2224         SetLastError(ERROR_INVALID_HANDLE);
2225         return FALSE;
2226     }
2227
2228     if (!lpServiceName)
2229     {
2230         SetLastError(ERROR_INVALID_ADDRESS);
2231         return FALSE;
2232     }
2233
2234     size = *lpcchBuffer * sizeof(WCHAR);
2235     ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2236     if (!ret && !lpDisplayName && size)
2237         ret = ERROR_MORE_DATA;
2238
2239     if (ret)
2240     {
2241         if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2242
2243         if (ret == ERROR_MORE_DATA)
2244         {
2245             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2246             *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2247         }
2248         else if (ret == ERROR_FILE_NOT_FOUND)
2249         {
2250             HKEY hkey;
2251
2252             if (!RegOpenKeyW(hscm->hkey, lpServiceName, &hkey))
2253             {
2254                 UINT len = lstrlenW(lpServiceName);
2255                 BOOL r = FALSE;
2256
2257                 if ((*lpcchBuffer <= len) || (!lpDisplayName && *lpcchBuffer))
2258                     SetLastError(ERROR_INSUFFICIENT_BUFFER);
2259                 else if (lpDisplayName && *lpcchBuffer)
2260                 {
2261                     /* No displayname, but the service exists and the buffer
2262                      * is big enough. We should return the servicename.
2263                      */
2264                     lstrcpyW(lpDisplayName, lpServiceName);
2265                     r = TRUE;
2266                 }
2267
2268                 *lpcchBuffer = len;
2269                 RegCloseKey(hkey);
2270                 return r;
2271             }
2272             else
2273                 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2274         }
2275         else
2276             SetLastError(ret);
2277         return FALSE;
2278     }
2279
2280     /* Always return the correct needed size on success */
2281     *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2282
2283     return TRUE;
2284 }
2285
2286 /******************************************************************************
2287  * ChangeServiceConfigW  [ADVAPI32.@]
2288  */
2289 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2290   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2291   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2292   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2293 {
2294     struct reg_value val[10];
2295     struct sc_service *hsvc;
2296     DWORD r = ERROR_SUCCESS;
2297     HKEY hKey;
2298     int n = 0;
2299
2300     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2301           hService, dwServiceType, dwStartType, dwErrorControl, 
2302           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2303           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2304           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2305
2306     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2307     if (!hsvc)
2308     {
2309         SetLastError( ERROR_INVALID_HANDLE );
2310         return FALSE;
2311     }
2312     hKey = hsvc->hkey;
2313
2314     if( dwServiceType != SERVICE_NO_CHANGE )
2315         service_set_dword( &val[n++], szType, &dwServiceType );
2316
2317     if( dwStartType != SERVICE_NO_CHANGE )
2318         service_set_dword( &val[n++], szStart, &dwStartType );
2319
2320     if( dwErrorControl != SERVICE_NO_CHANGE )
2321         service_set_dword( &val[n++], szError, &dwErrorControl );
2322
2323     if( lpBinaryPathName )
2324         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2325
2326     if( lpLoadOrderGroup )
2327         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2328
2329     /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2330      * There is no such key as what szDependencies refers to */
2331     if( lpDependencies )
2332         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2333
2334     if( lpPassword )
2335         FIXME("ignoring password\n");
2336
2337     if( lpServiceStartName )
2338         service_set_string( &val[n++], szObjectName, lpServiceStartName );
2339
2340     r = service_write_values( hsvc->hkey, val, n );
2341
2342     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2343 }
2344
2345 /******************************************************************************
2346  * ChangeServiceConfigA  [ADVAPI32.@]
2347  */
2348 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2349   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2350   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2351   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2352 {
2353     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2354     LPWSTR wServiceStartName, wPassword, wDisplayName;
2355     BOOL r;
2356
2357     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2358           hService, dwServiceType, dwStartType, dwErrorControl, 
2359           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2360           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2361           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2362
2363     wBinaryPathName = SERV_dup( lpBinaryPathName );
2364     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2365     wDependencies = SERV_dupmulti( lpDependencies );
2366     wServiceStartName = SERV_dup( lpServiceStartName );
2367     wPassword = SERV_dup( lpPassword );
2368     wDisplayName = SERV_dup( lpDisplayName );
2369
2370     r = ChangeServiceConfigW( hService, dwServiceType,
2371             dwStartType, dwErrorControl, wBinaryPathName,
2372             wLoadOrderGroup, lpdwTagId, wDependencies,
2373             wServiceStartName, wPassword, wDisplayName);
2374
2375     HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2376     HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2377     HeapFree( GetProcessHeap(), 0, wDependencies );
2378     HeapFree( GetProcessHeap(), 0, wServiceStartName );
2379     HeapFree( GetProcessHeap(), 0, wPassword );
2380     HeapFree( GetProcessHeap(), 0, wDisplayName );
2381
2382     return r;
2383 }
2384
2385 /******************************************************************************
2386  * ChangeServiceConfig2A  [ADVAPI32.@]
2387  */
2388 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2389     LPVOID lpInfo)
2390 {
2391     BOOL r = FALSE;
2392
2393     TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2394
2395     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2396     {
2397         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2398         SERVICE_DESCRIPTIONW sdw;
2399
2400         sdw.lpDescription = SERV_dup( sd->lpDescription );
2401
2402         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2403
2404         HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2405     }
2406     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2407     {
2408         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2409         SERVICE_FAILURE_ACTIONSW faw;
2410
2411         faw.dwResetPeriod = fa->dwResetPeriod;
2412         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2413         faw.lpCommand = SERV_dup( fa->lpCommand );
2414         faw.cActions = fa->cActions;
2415         faw.lpsaActions = fa->lpsaActions;
2416
2417         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2418
2419         HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2420         HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2421     }
2422     else
2423         SetLastError( ERROR_INVALID_PARAMETER );
2424
2425     return r;
2426 }
2427
2428 /******************************************************************************
2429  * ChangeServiceConfig2W  [ADVAPI32.@]
2430  */
2431 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2432     LPVOID lpInfo)
2433 {
2434     HKEY hKey;
2435     struct sc_service *hsvc;
2436
2437     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2438     if (!hsvc)
2439     {
2440         SetLastError( ERROR_INVALID_HANDLE );
2441         return FALSE;
2442     }
2443     hKey = hsvc->hkey;
2444
2445     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2446     {
2447         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2448         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2449         if (sd->lpDescription)
2450         {
2451             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2452             if (sd->lpDescription[0] == 0)
2453                 RegDeleteValueW(hKey,szDescription);
2454             else
2455                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2456                                         (LPVOID)sd->lpDescription,
2457                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2458         }
2459     }
2460     else   
2461         FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2462     return TRUE;
2463 }
2464
2465 /******************************************************************************
2466  * QueryServiceObjectSecurity [ADVAPI32.@]
2467  */
2468 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2469        SECURITY_INFORMATION dwSecurityInformation,
2470        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2471        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2472 {
2473     SECURITY_DESCRIPTOR descriptor;
2474     DWORD size;
2475     BOOL succ;
2476     ACL acl;
2477
2478     FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2479           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2480
2481     if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2482         FIXME("information %d not supported\n", dwSecurityInformation);
2483
2484     InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2485
2486     InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2487     SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2488
2489     size = cbBufSize;
2490     succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2491     *pcbBytesNeeded = size;
2492     return succ;
2493 }
2494
2495 /******************************************************************************
2496  * SetServiceObjectSecurity [ADVAPI32.@]
2497  */
2498 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2499        SECURITY_INFORMATION dwSecurityInformation,
2500        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2501 {
2502     FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2503     return TRUE;
2504 }
2505
2506 /******************************************************************************
2507  * SetServiceBits [ADVAPI32.@]
2508  */
2509 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2510         DWORD dwServiceBits,
2511         BOOL bSetBitsOn,
2512         BOOL bUpdateImmediately)
2513 {
2514     FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2515           bSetBitsOn, bUpdateImmediately);
2516     return TRUE;
2517 }
2518
2519 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2520 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2521 {
2522     LPHANDLER_FUNCTION func = context;
2523
2524     func( control );
2525     return ERROR_SUCCESS;
2526 }
2527
2528 /******************************************************************************
2529  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2530  */
2531 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2532 {
2533     return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2534 }
2535
2536 /******************************************************************************
2537  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2538  */
2539 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2540 {
2541     return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2542 }
2543
2544 /******************************************************************************
2545  * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2546  */
2547 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2548 {
2549     LPWSTR nameW;
2550     SERVICE_STATUS_HANDLE ret;
2551
2552     nameW = SERV_dup(name);
2553     ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2554     HeapFree( GetProcessHeap(), 0, nameW );
2555     return ret;
2556 }
2557
2558 /******************************************************************************
2559  * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2560  */
2561 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2562         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2563 {
2564     SERVICE_STATUS_HANDLE handle = 0;
2565     unsigned int i;
2566
2567     TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2568
2569     EnterCriticalSection( &service_cs );
2570     for (i = 0; i < nb_services; i++)
2571     {
2572         if(!strcmpW(lpServiceName, services[i]->name))
2573         {
2574             services[i]->handler = lpHandlerProc;
2575             services[i]->context = lpContext;
2576             handle = ULongToHandle( i + 1 );
2577             break;
2578         }
2579     }
2580     LeaveCriticalSection( &service_cs );
2581
2582     return handle;
2583 }
2584
2585 /******************************************************************************
2586  * EnumDependentServicesA [ADVAPI32.@]
2587  */
2588 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2589                                     LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2590         LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2591 {
2592     FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2593           lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2594
2595     *lpServicesReturned = 0;
2596     return TRUE;
2597 }
2598
2599 /******************************************************************************
2600  * EnumDependentServicesW [ADVAPI32.@]
2601  */
2602 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2603                                     LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2604                                     LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2605 {
2606     FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2607           lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2608
2609     *lpServicesReturned = 0;
2610     return TRUE;
2611 }