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