msi/tests: automation: Simplify ok_exception.
[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_PROCESS 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, const 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                                          const 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(LPCWSTR 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(LPCWSTR 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(LPCWSTR 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, const 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_PROCESS 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(const 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( const SERVICE_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( const SERVICE_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 = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1014     RegCloseKey( hReg );
1015     if (r!=ERROR_SUCCESS)
1016         goto error;
1017
1018     TRACE("returning %p\n", manager);
1019
1020     return (SC_HANDLE) &manager->hdr;
1021
1022 error:
1023     sc_handle_free( &manager->hdr );
1024     SetLastError( r);
1025     return NULL;
1026 }
1027
1028 /******************************************************************************
1029  * ControlService [ADVAPI32.@]
1030  *
1031  * Send a control code to a service.
1032  *
1033  * PARAMS
1034  *   hService        [I] Handle of the service control manager database
1035  *   dwControl       [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1036  *   lpServiceStatus [O] Destination for the status of the service, if available
1037  *
1038  * RETURNS
1039  *   Success: TRUE.
1040  *   Failure: FALSE.
1041  *
1042  * BUGS
1043  *   Unlike M$' implementation, control requests are not serialized and may be
1044  *   processed asynchronously.
1045  */
1046 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1047                             LPSERVICE_STATUS lpServiceStatus )
1048 {
1049     struct sc_service *hsvc;
1050     BOOL ret = FALSE;
1051     HANDLE handle;
1052
1053     TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1054
1055     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1056     if (!hsvc)
1057     {
1058         SetLastError( ERROR_INVALID_HANDLE );
1059         return FALSE;
1060     }
1061
1062     ret = QueryServiceStatus(hService, lpServiceStatus);
1063     if (!ret)
1064     {
1065         ERR("failed to query service status\n");
1066         SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1067         return FALSE;
1068     }
1069
1070     switch (lpServiceStatus->dwCurrentState)
1071     {
1072     case SERVICE_STOPPED:
1073         SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1074         return FALSE;
1075     case SERVICE_START_PENDING:
1076         if (dwControl==SERVICE_CONTROL_STOP)
1077             break;
1078         /* fall thru */
1079     case SERVICE_STOP_PENDING:
1080         SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1081         return FALSE;
1082     }
1083
1084     handle = service_open_pipe(hsvc->name);
1085     if (handle!=INVALID_HANDLE_VALUE)
1086     {
1087         DWORD result = ERROR_SUCCESS;
1088         ret = service_send_control(handle, dwControl, &result);
1089         CloseHandle(handle);
1090         if (result!=ERROR_SUCCESS)
1091         {
1092             SetLastError(result);
1093             ret = FALSE;
1094         }
1095     }
1096
1097     return ret;
1098 }
1099
1100 /******************************************************************************
1101  * CloseServiceHandle [ADVAPI32.@]
1102  * 
1103  * Close a handle to a service or the service control manager database.
1104  *
1105  * PARAMS
1106  *   hSCObject [I] Handle to service or service control manager database
1107  *
1108  * RETURNS
1109  *  Success: TRUE
1110  *  Failure: FALSE
1111  */
1112 BOOL WINAPI
1113 CloseServiceHandle( SC_HANDLE hSCObject )
1114 {
1115     TRACE("%p\n", hSCObject);
1116
1117     sc_handle_free( (struct sc_handle*) hSCObject );
1118
1119     return TRUE;
1120 }
1121
1122
1123 /******************************************************************************
1124  * OpenServiceA [ADVAPI32.@]
1125  *
1126  * Open a handle to a service.
1127  *
1128  * PARAMS
1129  *   hSCManager      [I] Handle of the service control manager database
1130  *   lpServiceName   [I] Name of the service to open
1131  *   dwDesiredAccess [I] Access required to the service
1132  *
1133  * RETURNS
1134  *    Success: Handle to the service
1135  *    Failure: NULL
1136  */
1137 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1138                                DWORD dwDesiredAccess )
1139 {
1140     LPWSTR lpServiceNameW;
1141     SC_HANDLE ret;
1142
1143     TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1144
1145     lpServiceNameW = SERV_dup(lpServiceName);
1146     ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1147     SERV_free(lpServiceNameW);
1148     return ret;
1149 }
1150
1151
1152 /******************************************************************************
1153  * OpenServiceW [ADVAPI32.@]
1154  *
1155  * See OpenServiceA.
1156  */
1157 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1158                                DWORD dwDesiredAccess)
1159 {
1160     struct sc_manager *hscm;
1161     struct sc_service *hsvc;
1162     HKEY hKey;
1163     long r;
1164     DWORD len;
1165
1166     TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1167
1168     if (!lpServiceName)
1169     {
1170         SetLastError(ERROR_INVALID_ADDRESS);
1171         return NULL;
1172     }
1173
1174     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1175     if (!hscm)
1176     {
1177         SetLastError( ERROR_INVALID_HANDLE );
1178         return FALSE;
1179     }
1180
1181     r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1182     if (r!=ERROR_SUCCESS)
1183     {
1184         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1185         return NULL;
1186     }
1187     
1188     len = strlenW(lpServiceName)+1;
1189     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1190                             sizeof (struct sc_service) + len*sizeof(WCHAR),
1191                             sc_handle_destroy_service );
1192     if (!hsvc)
1193         return NULL;
1194     strcpyW( hsvc->name, lpServiceName );
1195     hsvc->hkey = hKey;
1196
1197     /* add reference to SCM handle */
1198     hscm->hdr.ref_count++;
1199     hsvc->scm = hscm;
1200
1201     TRACE("returning %p\n",hsvc);
1202
1203     return (SC_HANDLE) &hsvc->hdr;
1204 }
1205
1206 /******************************************************************************
1207  * CreateServiceW [ADVAPI32.@]
1208  */
1209 SC_HANDLE WINAPI
1210 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1211                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1212                   DWORD dwServiceType, DWORD dwStartType,
1213                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1214                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1215                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1216                   LPCWSTR lpPassword )
1217 {
1218     struct sc_manager *hscm;
1219     struct sc_service *hsvc = NULL;
1220     HKEY hKey;
1221     LONG r;
1222     DWORD dp, len;
1223     struct reg_value val[10];
1224     int n = 0;
1225
1226     TRACE("%p %s %s\n", hSCManager, 
1227           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1228
1229     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1230     if (!hscm)
1231     {
1232         SetLastError( ERROR_INVALID_HANDLE );
1233         return NULL;
1234     }
1235
1236     r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1237                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1238     if (r!=ERROR_SUCCESS)
1239         return NULL;
1240
1241     if (dp != REG_CREATED_NEW_KEY)
1242     {
1243         SetLastError(ERROR_SERVICE_EXISTS);
1244         goto error;
1245     }
1246
1247     if( lpDisplayName )
1248         service_set_string( &val[n++], szDisplayName, lpDisplayName );
1249
1250     service_set_dword( &val[n++], szType, &dwServiceType );
1251     service_set_dword( &val[n++], szStart, &dwStartType );
1252     service_set_dword( &val[n++], szError, &dwErrorControl );
1253
1254     if( lpBinaryPathName )
1255         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1256
1257     if( lpLoadOrderGroup )
1258         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1259
1260     if( lpDependencies )
1261         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1262
1263     if( lpPassword )
1264         FIXME("Don't know how to add a Password for a service.\n");
1265
1266     if( lpServiceStartName )
1267         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1268
1269     r = service_write_values( hKey, val, n );
1270     if( r != ERROR_SUCCESS )
1271         goto error;
1272
1273     len = strlenW(lpServiceName)+1;
1274     len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1275     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1276     if( !hsvc )
1277         goto error;
1278     lstrcpyW( hsvc->name, lpServiceName );
1279     hsvc->hkey = hKey;
1280     hsvc->scm = hscm;
1281     hscm->hdr.ref_count++;
1282
1283     return (SC_HANDLE) &hsvc->hdr;
1284     
1285 error:
1286     RegCloseKey( hKey );
1287     return NULL;
1288 }
1289
1290
1291 /******************************************************************************
1292  * CreateServiceA [ADVAPI32.@]
1293  */
1294 SC_HANDLE WINAPI
1295 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1296                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1297                   DWORD dwServiceType, DWORD dwStartType,
1298                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1299                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1300                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1301                   LPCSTR lpPassword )
1302 {
1303     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1304         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1305     SC_HANDLE r;
1306
1307     TRACE("%p %s %s\n", hSCManager,
1308           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1309
1310     lpServiceNameW = SERV_dup( lpServiceName );
1311     lpDisplayNameW = SERV_dup( lpDisplayName );
1312     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1313     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1314     lpDependenciesW = SERV_dupmulti( lpDependencies );
1315     lpServiceStartNameW = SERV_dup( lpServiceStartName );
1316     lpPasswordW = SERV_dup( lpPassword );
1317
1318     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1319             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1320             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1321             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1322
1323     SERV_free( lpServiceNameW );
1324     SERV_free( lpDisplayNameW );
1325     SERV_free( lpBinaryPathNameW );
1326     SERV_free( lpLoadOrderGroupW );
1327     SERV_free( lpDependenciesW );
1328     SERV_free( lpServiceStartNameW );
1329     SERV_free( lpPasswordW );
1330
1331     return r;
1332 }
1333
1334
1335 /******************************************************************************
1336  * DeleteService [ADVAPI32.@]
1337  *
1338  * Delete a service from the service control manager database.
1339  *
1340  * PARAMS
1341  *    hService [I] Handle of the service to delete
1342  *
1343  * RETURNS
1344  *  Success: TRUE
1345  *  Failure: FALSE
1346  */
1347 BOOL WINAPI DeleteService( SC_HANDLE hService )
1348 {
1349     struct sc_service *hsvc;
1350     HKEY hKey;
1351     WCHAR valname[MAX_PATH+1];
1352     INT index = 0;
1353     LONG rc;
1354     DWORD size;
1355
1356     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1357     if (!hsvc)
1358     {
1359         SetLastError( ERROR_INVALID_HANDLE );
1360         return FALSE;
1361     }
1362     hKey = hsvc->hkey;
1363
1364     size = MAX_PATH+1; 
1365     /* Clean out the values */
1366     rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1367     while (rc == ERROR_SUCCESS)
1368     {
1369         RegDeleteValueW(hKey,valname);
1370         index++;
1371         size = MAX_PATH+1; 
1372         rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1373     }
1374
1375     RegCloseKey(hKey);
1376     hsvc->hkey = NULL;
1377
1378     /* delete the key */
1379     RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1380
1381     return TRUE;
1382 }
1383
1384
1385 /******************************************************************************
1386  * StartServiceA [ADVAPI32.@]
1387  *
1388  * Start a service
1389  *
1390  * PARAMS
1391  *   hService            [I] Handle of service
1392  *   dwNumServiceArgs    [I] Number of arguments
1393  *   lpServiceArgVectors [I] Address of array of argument strings
1394  *
1395  * NOTES
1396  *  - NT implements this function using an obscure RPC call.
1397  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1398  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
1399  *  - This will only work for shared address space. How should the service
1400  *    args be transferred when address spaces are separated?
1401  *  - Can only start one service at a time.
1402  *  - Has no concept of privilege.
1403  *
1404  * RETURNS
1405  *   Success: TRUE.
1406  *   Failure: FALSE
1407  */
1408 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1409                            LPCSTR *lpServiceArgVectors )
1410 {
1411     LPWSTR *lpwstr=NULL;
1412     unsigned int i;
1413     BOOL r;
1414
1415     TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1416
1417     if (dwNumServiceArgs)
1418         lpwstr = HeapAlloc( GetProcessHeap(), 0,
1419                                    dwNumServiceArgs*sizeof(LPWSTR) );
1420
1421     for(i=0; i<dwNumServiceArgs; i++)
1422         lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1423
1424     r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1425
1426     if (dwNumServiceArgs)
1427     {
1428         for(i=0; i<dwNumServiceArgs; i++)
1429             SERV_free(lpwstr[i]);
1430         HeapFree(GetProcessHeap(), 0, lpwstr);
1431     }
1432
1433     return r;
1434 }
1435
1436 /******************************************************************************
1437  * service_start_process    [INTERNAL]
1438  */
1439 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1440 {
1441     static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1442     PROCESS_INFORMATION pi;
1443     STARTUPINFOW si;
1444     LPWSTR path = NULL, str;
1445     DWORD type, size, ret;
1446     HANDLE handles[2];
1447     BOOL r;
1448
1449     /* read the executable path from memory */
1450     size = 0;
1451     ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1452     if (ret!=ERROR_SUCCESS)
1453         return FALSE;
1454     str = HeapAlloc(GetProcessHeap(),0,size);
1455     ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1456     if (ret==ERROR_SUCCESS)
1457     {
1458         size = ExpandEnvironmentStringsW(str,NULL,0);
1459         path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1460         ExpandEnvironmentStringsW(str,path,size);
1461     }
1462     HeapFree(GetProcessHeap(),0,str);
1463     if (!path)
1464         return FALSE;
1465
1466     /* wait for the process to start and set an event or terminate */
1467     handles[0] = service_get_event_handle( hsvc->name );
1468     ZeroMemory(&si, sizeof(STARTUPINFOW));
1469     si.cb = sizeof(STARTUPINFOW);
1470     r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1471     if (r)
1472     {
1473         if (ppid) *ppid = pi.dwProcessId;
1474
1475         handles[1] = pi.hProcess;
1476         ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1477         if(ret != WAIT_OBJECT_0)
1478         {
1479             SetLastError(ERROR_IO_PENDING);
1480             r = FALSE;
1481         }
1482
1483         CloseHandle( pi.hThread );
1484         CloseHandle( pi.hProcess );
1485     }
1486     CloseHandle( handles[0] );
1487     HeapFree(GetProcessHeap(),0,path);
1488     return r;
1489 }
1490
1491 static BOOL service_wait_for_startup(SC_HANDLE hService)
1492 {
1493     DWORD i;
1494     SERVICE_STATUS status;
1495     BOOL r = FALSE;
1496
1497     TRACE("%p\n", hService);
1498
1499     for (i=0; i<30; i++)
1500     {
1501         status.dwCurrentState = 0;
1502         r = QueryServiceStatus(hService, &status);
1503         if (!r)
1504             break;
1505         if (status.dwCurrentState == SERVICE_RUNNING)
1506         {
1507             TRACE("Service started successfully\n");
1508             break;
1509         }
1510         r = FALSE;
1511         Sleep(1000);
1512     }
1513     return r;
1514 }
1515
1516 /******************************************************************************
1517  * StartServiceW [ADVAPI32.@]
1518  * 
1519  * See StartServiceA.
1520  */
1521 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1522                           LPCWSTR *lpServiceArgVectors)
1523 {
1524     struct sc_service *hsvc;
1525     BOOL r = FALSE;
1526     DWORD pid;
1527     SC_LOCK hLock;
1528     HANDLE handle = INVALID_HANDLE_VALUE;
1529
1530     TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1531
1532     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1533     if (!hsvc)
1534     {
1535         SetLastError(ERROR_INVALID_HANDLE);
1536         return r;
1537     }
1538
1539     hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1540     if (!hLock)
1541         return r;
1542
1543     handle = service_open_pipe(hsvc->name);
1544     if (handle==INVALID_HANDLE_VALUE)
1545     {
1546         /* start the service process */
1547         if (service_start_process(hsvc, &pid))
1548             handle = service_open_pipe(hsvc->name);
1549     }
1550
1551     if (handle != INVALID_HANDLE_VALUE)
1552     {
1553         service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1554         CloseHandle(handle);
1555         r = TRUE;
1556     }
1557
1558     UnlockServiceDatabase( hLock );
1559
1560     TRACE("returning %d\n", r);
1561
1562     if (r)
1563         service_wait_for_startup(hService);
1564
1565     return r;
1566 }
1567
1568 /******************************************************************************
1569  * QueryServiceStatus [ADVAPI32.@]
1570  *
1571  * PARAMS
1572  *   hService        [I] Handle to service to get information about
1573  *   lpservicestatus [O] buffer to receive the status information for the service
1574  *
1575  */
1576 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1577                                LPSERVICE_STATUS lpservicestatus)
1578 {
1579     SERVICE_STATUS_PROCESS SvcStatusData;
1580     BOOL ret;
1581
1582     TRACE("%p %p\n", hService, lpservicestatus);
1583
1584     ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1585                                 sizeof(SERVICE_STATUS_PROCESS), NULL);
1586     if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1587     return ret;
1588 }
1589
1590
1591 /******************************************************************************
1592  * QueryServiceStatusEx [ADVAPI32.@]
1593  *
1594  * Get information about a service.
1595  *
1596  * PARAMS
1597  *   hService       [I] Handle to service to get information about
1598  *   InfoLevel      [I] Level of information to get
1599  *   lpBuffer       [O] Destination for requested information
1600  *   cbBufSize      [I] Size of lpBuffer in bytes
1601  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1602  *
1603  * RETURNS
1604  *  Success: TRUE
1605  *  FAILURE: FALSE
1606  */
1607 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1608                         LPBYTE lpBuffer, DWORD cbBufSize,
1609                         LPDWORD pcbBytesNeeded)
1610 {
1611     struct sc_service *hsvc;
1612     DWORD size, type, val;
1613     HANDLE pipe;
1614     LONG r;
1615     LPSERVICE_STATUS_PROCESS pSvcStatusData;
1616
1617     TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1618
1619     if (InfoLevel != SC_STATUS_PROCESS_INFO)
1620     {
1621         SetLastError( ERROR_INVALID_LEVEL);
1622         return FALSE;
1623     }
1624
1625     pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1626     if (pSvcStatusData == NULL)
1627     {
1628         SetLastError( ERROR_INVALID_PARAMETER);
1629         return FALSE;
1630     }
1631
1632     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1633     {
1634         if( pcbBytesNeeded != NULL)
1635             *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1636
1637         SetLastError( ERROR_INSUFFICIENT_BUFFER);
1638         return FALSE;
1639     }
1640
1641     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1642     if (!hsvc)
1643     {
1644         SetLastError( ERROR_INVALID_HANDLE );
1645         return FALSE;
1646     }
1647
1648     pipe = service_open_pipe(hsvc->name);
1649     if (pipe != INVALID_HANDLE_VALUE)
1650     {
1651         r = service_get_status(pipe, pSvcStatusData);
1652         CloseHandle(pipe);
1653         if (r)
1654             return TRUE;
1655     }
1656
1657     TRACE("Failed to read service status\n");
1658
1659     /* read the service type from the registry */
1660     size = sizeof(val);
1661     r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1662     if (r != ERROR_SUCCESS || type != REG_DWORD)
1663         val = 0;
1664
1665     pSvcStatusData->dwServiceType = val;
1666     pSvcStatusData->dwCurrentState            = SERVICE_STOPPED;  /* stopped */
1667     pSvcStatusData->dwControlsAccepted        = 0;
1668     pSvcStatusData->dwWin32ExitCode           = ERROR_SERVICE_NEVER_STARTED;
1669     pSvcStatusData->dwServiceSpecificExitCode = 0;
1670     pSvcStatusData->dwCheckPoint              = 0;
1671     pSvcStatusData->dwWaitHint                = 0;
1672
1673     return TRUE;
1674 }
1675
1676 /******************************************************************************
1677  * QueryServiceConfigA [ADVAPI32.@]
1678  */
1679 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1680                                  DWORD size, LPDWORD needed )
1681 {
1682     DWORD n;
1683     LPSTR p, buffer;
1684     BOOL ret;
1685     QUERY_SERVICE_CONFIGW *configW;
1686
1687     TRACE("%p %p %d %p\n", hService, config, size, needed);
1688
1689     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1690     {
1691         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1692         return FALSE;
1693     }
1694     configW = (QUERY_SERVICE_CONFIGW *)buffer;
1695     ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1696     if (!ret) goto done;
1697
1698     config->dwServiceType      = configW->dwServiceType;
1699     config->dwStartType        = configW->dwStartType;
1700     config->dwErrorControl     = configW->dwErrorControl;
1701     config->lpBinaryPathName   = NULL;
1702     config->lpLoadOrderGroup   = NULL;
1703     config->dwTagId            = configW->dwTagId;
1704     config->lpDependencies     = NULL;
1705     config->lpServiceStartName = NULL;
1706     config->lpDisplayName      = NULL;
1707
1708     p = (LPSTR)(config + 1);
1709     n = size - sizeof(*config);
1710     ret = FALSE;
1711
1712 #define MAP_STR(str) \
1713     do { \
1714         if (configW->str) \
1715         { \
1716             DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1717             if (!sz) goto done; \
1718             config->str = p; \
1719             p += sz; \
1720             n -= sz; \
1721         } \
1722     } while (0)
1723
1724     MAP_STR( lpBinaryPathName );
1725     MAP_STR( lpLoadOrderGroup );
1726     MAP_STR( lpDependencies );
1727     MAP_STR( lpServiceStartName );
1728     MAP_STR( lpDisplayName );
1729 #undef MAP_STR
1730
1731     *needed = p - buffer;
1732     ret = TRUE;
1733
1734 done:
1735     HeapFree( GetProcessHeap(), 0, buffer );
1736     return ret;
1737 }
1738
1739 /******************************************************************************
1740  * QueryServiceConfigW [ADVAPI32.@]
1741  */
1742 BOOL WINAPI 
1743 QueryServiceConfigW( SC_HANDLE hService,
1744                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1745                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1746 {
1747     WCHAR str_buffer[ MAX_PATH ];
1748     LONG r;
1749     DWORD type, val, sz, total, n;
1750     LPBYTE p;
1751     HKEY hKey;
1752     struct sc_service *hsvc;
1753
1754     TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1755            cbBufSize, pcbBytesNeeded);
1756
1757     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1758     if (!hsvc)
1759     {
1760         SetLastError( ERROR_INVALID_HANDLE );
1761         return FALSE;
1762     }
1763     hKey = hsvc->hkey;
1764
1765     /* calculate the size required first */
1766     total = sizeof (QUERY_SERVICE_CONFIGW);
1767
1768     sz = sizeof(str_buffer);
1769     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1770     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1771     {
1772         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1773         if( 0 == sz ) return FALSE;
1774
1775         total += sizeof(WCHAR) * sz;
1776     }
1777     else
1778     {
1779        /* FIXME: set last error */
1780        return FALSE;
1781     }
1782
1783     sz = 0;
1784     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1785     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1786         total += sz;
1787
1788     sz = 0;
1789     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1790     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1791         total += sz;
1792     else
1793         total += sizeof(WCHAR);
1794
1795     sz = 0;
1796     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1797     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1798         total += sz;
1799
1800     sz = 0;
1801     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1802     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1803         total += sz;
1804
1805     *pcbBytesNeeded = total;
1806
1807     /* if there's not enough memory, return an error */
1808     if( total > cbBufSize )
1809     {
1810         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1811         return FALSE;
1812     }
1813
1814     ZeroMemory( lpServiceConfig, total );
1815
1816     sz = sizeof val;
1817     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1818     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1819         lpServiceConfig->dwServiceType = val;
1820
1821     sz = sizeof val;
1822     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1823     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1824         lpServiceConfig->dwStartType = val;
1825
1826     sz = sizeof val;
1827     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1828     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1829         lpServiceConfig->dwErrorControl = val;
1830
1831     /* now do the strings */
1832     p = (LPBYTE) &lpServiceConfig[1];
1833     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1834
1835     sz = sizeof(str_buffer);
1836     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1837     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1838     {
1839         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1840         sz *= sizeof(WCHAR);
1841         if( 0 == sz || sz > n ) return FALSE;
1842
1843         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1844         p += sz;
1845         n -= sz;
1846     }
1847     else
1848     {
1849        /* FIXME: set last error */
1850        return FALSE;
1851     }
1852
1853     sz = n;
1854     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1855     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1856     {
1857         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1858         p += sz;
1859         n -= sz;
1860     }
1861
1862     sz = n;
1863     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1864     lpServiceConfig->lpDependencies = (LPWSTR) p;
1865     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1866     {
1867         p += sz;
1868         n -= sz;
1869     }
1870     else
1871     {
1872         *(WCHAR *) p = 0;
1873         p += sizeof(WCHAR);
1874         n -= sizeof(WCHAR);
1875     }
1876
1877     if( n < 0 )
1878         ERR("Buffer overflow!\n");
1879
1880     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1881     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1882
1883     return TRUE;
1884 }
1885
1886 /******************************************************************************
1887  * EnumServicesStatusA [ADVAPI32.@]
1888  */
1889 BOOL WINAPI
1890 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1891                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1892                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1893                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1894 {
1895     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1896           dwServiceType, dwServiceState, lpServices, cbBufSize,
1897           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1898     SetLastError (ERROR_ACCESS_DENIED);
1899     return FALSE;
1900 }
1901
1902 /******************************************************************************
1903  * EnumServicesStatusW [ADVAPI32.@]
1904  */
1905 BOOL WINAPI
1906 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1907                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1908                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1909                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1910 {
1911     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1912           dwServiceType, dwServiceState, lpServices, cbBufSize,
1913           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1914     SetLastError (ERROR_ACCESS_DENIED);
1915     return FALSE;
1916 }
1917
1918 /******************************************************************************
1919  * EnumServicesStatusExA [ADVAPI32.@]
1920  */
1921 BOOL WINAPI
1922 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1923                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1924                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1925 {
1926     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1927           dwServiceType, dwServiceState, lpServices, cbBufSize,
1928           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
1929     SetLastError (ERROR_ACCESS_DENIED);
1930     return FALSE;
1931 }
1932
1933 /******************************************************************************
1934  * EnumServicesStatusExW [ADVAPI32.@]
1935  */
1936 BOOL WINAPI
1937 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1938                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1939                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1940 {
1941     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1942           dwServiceType, dwServiceState, lpServices, cbBufSize,
1943           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
1944     SetLastError (ERROR_ACCESS_DENIED);
1945     return FALSE;
1946 }
1947
1948 /******************************************************************************
1949  * GetServiceKeyNameA [ADVAPI32.@]
1950  */
1951 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1952                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1953 {
1954     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1955     return FALSE;
1956 }
1957
1958 /******************************************************************************
1959  * GetServiceKeyNameW [ADVAPI32.@]
1960  */
1961 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1962                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1963 {
1964     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1965     return FALSE;
1966 }
1967
1968 /******************************************************************************
1969  * QueryServiceLockStatusA [ADVAPI32.@]
1970  */
1971 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1972                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1973                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1974 {
1975     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1976
1977     return FALSE;
1978 }
1979
1980 /******************************************************************************
1981  * QueryServiceLockStatusW [ADVAPI32.@]
1982  */
1983 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1984                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1985                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1986 {
1987     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1988
1989     return FALSE;
1990 }
1991
1992 /******************************************************************************
1993  * GetServiceDisplayNameA  [ADVAPI32.@]
1994  */
1995 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1996   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1997 {
1998     FIXME("%p %s %p %p\n", hSCManager,
1999           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2000     return FALSE;
2001 }
2002
2003 /******************************************************************************
2004  * GetServiceDisplayNameW  [ADVAPI32.@]
2005  */
2006 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2007   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2008 {
2009     FIXME("%p %s %p %p\n", hSCManager,
2010           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2011     return FALSE;
2012 }
2013
2014 /******************************************************************************
2015  * ChangeServiceConfigW  [ADVAPI32.@]
2016  */
2017 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2018   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2019   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2020   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2021 {
2022     struct reg_value val[10];
2023     struct sc_service *hsvc;
2024     DWORD r = ERROR_SUCCESS;
2025     HKEY hKey;
2026     int n = 0;
2027
2028     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2029           hService, dwServiceType, dwStartType, dwErrorControl, 
2030           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2031           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2032           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2033
2034     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2035     if (!hsvc)
2036     {
2037         SetLastError( ERROR_INVALID_HANDLE );
2038         return FALSE;
2039     }
2040     hKey = hsvc->hkey;
2041
2042     if( dwServiceType != SERVICE_NO_CHANGE )
2043         service_set_dword( &val[n++], szType, &dwServiceType );
2044
2045     if( dwStartType != SERVICE_NO_CHANGE )
2046         service_set_dword( &val[n++], szStart, &dwStartType );
2047
2048     if( dwErrorControl != SERVICE_NO_CHANGE )
2049         service_set_dword( &val[n++], szError, &dwErrorControl );
2050
2051     if( lpBinaryPathName )
2052         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2053
2054     if( lpLoadOrderGroup )
2055         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2056
2057     if( lpDependencies )
2058         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2059
2060     if( lpPassword )
2061         FIXME("ignoring password\n");
2062
2063     if( lpServiceStartName )
2064         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2065
2066     r = service_write_values( hsvc->hkey, val, n );
2067
2068     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2069 }
2070
2071 /******************************************************************************
2072  * ChangeServiceConfigA  [ADVAPI32.@]
2073  */
2074 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2075   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2076   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2077   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2078 {
2079     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2080     LPWSTR wServiceStartName, wPassword, wDisplayName;
2081     BOOL r;
2082
2083     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2084           hService, dwServiceType, dwStartType, dwErrorControl, 
2085           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2086           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2087           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2088
2089     wBinaryPathName = SERV_dup( lpBinaryPathName );
2090     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2091     wDependencies = SERV_dupmulti( lpDependencies );
2092     wServiceStartName = SERV_dup( lpServiceStartName );
2093     wPassword = SERV_dup( lpPassword );
2094     wDisplayName = SERV_dup( lpDisplayName );
2095
2096     r = ChangeServiceConfigW( hService, dwServiceType,
2097             dwStartType, dwErrorControl, wBinaryPathName,
2098             wLoadOrderGroup, lpdwTagId, wDependencies,
2099             wServiceStartName, wPassword, wDisplayName);
2100
2101     SERV_free( wBinaryPathName );
2102     SERV_free( wLoadOrderGroup );
2103     SERV_free( wDependencies );
2104     SERV_free( wServiceStartName );
2105     SERV_free( wPassword );
2106     SERV_free( wDisplayName );
2107
2108     return r;
2109 }
2110
2111 /******************************************************************************
2112  * ChangeServiceConfig2A  [ADVAPI32.@]
2113  */
2114 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2115     LPVOID lpInfo)
2116 {
2117     BOOL r = FALSE;
2118
2119     TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2120
2121     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2122     {
2123         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2124         SERVICE_DESCRIPTIONW sdw;
2125
2126         sdw.lpDescription = SERV_dup( sd->lpDescription );
2127
2128         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2129
2130         SERV_free( sdw.lpDescription );
2131     }
2132     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2133     {
2134         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2135         SERVICE_FAILURE_ACTIONSW faw;
2136
2137         faw.dwResetPeriod = fa->dwResetPeriod;
2138         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2139         faw.lpCommand = SERV_dup( fa->lpCommand );
2140         faw.cActions = fa->cActions;
2141         faw.lpsaActions = fa->lpsaActions;
2142
2143         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2144
2145         SERV_free( faw.lpRebootMsg );
2146         SERV_free( faw.lpCommand );
2147     }
2148     else
2149         SetLastError( ERROR_INVALID_PARAMETER );
2150
2151     return r;
2152 }
2153
2154 /******************************************************************************
2155  * ChangeServiceConfig2W  [ADVAPI32.@]
2156  */
2157 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2158     LPVOID lpInfo)
2159 {
2160     HKEY hKey;
2161     struct sc_service *hsvc;
2162
2163     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2164     if (!hsvc)
2165     {
2166         SetLastError( ERROR_INVALID_HANDLE );
2167         return FALSE;
2168     }
2169     hKey = hsvc->hkey;
2170
2171     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2172     {
2173         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2174         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2175         if (sd->lpDescription)
2176         {
2177             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2178             if (sd->lpDescription[0] == 0)
2179                 RegDeleteValueW(hKey,szDescription);
2180             else
2181                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2182                                         (LPVOID)sd->lpDescription,
2183                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2184         }
2185     }
2186     else   
2187         FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2188     return TRUE;
2189 }
2190
2191 /******************************************************************************
2192  * QueryServiceObjectSecurity [ADVAPI32.@]
2193  */
2194 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2195        SECURITY_INFORMATION dwSecurityInformation,
2196        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2197        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2198 {
2199     PACL pACL = NULL;
2200
2201     FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2202           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2203
2204     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2205
2206     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2207     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2208     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2209     return TRUE;
2210 }
2211
2212 /******************************************************************************
2213  * SetServiceObjectSecurity [ADVAPI32.@]
2214  */
2215 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2216        SECURITY_INFORMATION dwSecurityInformation,
2217        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2218 {
2219     FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2220     return TRUE;
2221 }
2222
2223 /******************************************************************************
2224  * SetServiceBits [ADVAPI32.@]
2225  */
2226 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2227         DWORD dwServiceBits,
2228         BOOL bSetBitsOn,
2229         BOOL bUpdateImmediately)
2230 {
2231     FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2232           bSetBitsOn, bUpdateImmediately);
2233     return TRUE;
2234 }
2235
2236 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2237         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2238 {
2239     FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2240     return 0;
2241 }
2242
2243 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2244         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2245 {
2246     service_data *service;
2247
2248     TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2249
2250     EnterCriticalSection( &service_cs );
2251     for(service = service_list; service; service = service->next)
2252         if(!strcmpW(lpServiceName, service->name))
2253             break;
2254     if (service)
2255     {
2256         service->handler.handler_ex = lpHandlerProc;
2257         service->context = lpContext;
2258         service->extended = TRUE;
2259     }
2260     LeaveCriticalSection( &service_cs );
2261
2262     return (SERVICE_STATUS_HANDLE)service;
2263 }