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