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