advapi32/tests: Make use of skip.
[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 = 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)
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         handles[1] = pi.hProcess;
1474         ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1475         if(ret != WAIT_OBJECT_0)
1476         {
1477             SetLastError(ERROR_IO_PENDING);
1478             r = FALSE;
1479         }
1480
1481         CloseHandle( pi.hThread );
1482         CloseHandle( pi.hProcess );
1483     }
1484     CloseHandle( handles[0] );
1485     HeapFree(GetProcessHeap(),0,path);
1486     return r;
1487 }
1488
1489 static BOOL service_wait_for_startup(SC_HANDLE hService)
1490 {
1491     DWORD i;
1492     SERVICE_STATUS status;
1493     BOOL r = FALSE;
1494
1495     TRACE("%p\n", hService);
1496
1497     for (i=0; i<30; i++)
1498     {
1499         status.dwCurrentState = 0;
1500         r = QueryServiceStatus(hService, &status);
1501         if (!r)
1502             break;
1503         if (status.dwCurrentState == SERVICE_RUNNING)
1504         {
1505             TRACE("Service started successfully\n");
1506             break;
1507         }
1508         r = FALSE;
1509         Sleep(1000);
1510     }
1511     return r;
1512 }
1513
1514 /******************************************************************************
1515  * StartServiceW [ADVAPI32.@]
1516  * 
1517  * See StartServiceA.
1518  */
1519 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1520                           LPCWSTR *lpServiceArgVectors)
1521 {
1522     struct sc_service *hsvc;
1523     BOOL r = FALSE;
1524     SC_LOCK hLock;
1525     HANDLE handle = INVALID_HANDLE_VALUE;
1526
1527     TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1528
1529     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1530     if (!hsvc)
1531     {
1532         SetLastError(ERROR_INVALID_HANDLE);
1533         return r;
1534     }
1535
1536     hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1537     if (!hLock)
1538         return r;
1539
1540     handle = service_open_pipe(hsvc->name);
1541     if (handle==INVALID_HANDLE_VALUE)
1542     {
1543         /* start the service process */
1544         if (service_start_process(hsvc))
1545             handle = service_open_pipe(hsvc->name);
1546     }
1547
1548     if (handle != INVALID_HANDLE_VALUE)
1549     {
1550         service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1551         CloseHandle(handle);
1552         r = TRUE;
1553     }
1554
1555     UnlockServiceDatabase( hLock );
1556
1557     TRACE("returning %d\n", r);
1558
1559     if (r)
1560         service_wait_for_startup(hService);
1561
1562     return r;
1563 }
1564
1565 /******************************************************************************
1566  * QueryServiceStatus [ADVAPI32.@]
1567  *
1568  * PARAMS
1569  *   hService        []
1570  *   lpservicestatus []
1571  *
1572  */
1573 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1574                                LPSERVICE_STATUS lpservicestatus)
1575 {
1576     struct sc_service *hsvc;
1577     DWORD size, type, val;
1578     HANDLE pipe;
1579     LONG r;
1580
1581     TRACE("%p %p\n", hService, lpservicestatus);
1582
1583     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1584     if (!hsvc)
1585     {
1586         SetLastError( ERROR_INVALID_HANDLE );
1587         return FALSE;
1588     }
1589
1590     pipe = service_open_pipe(hsvc->name);
1591     if (pipe != INVALID_HANDLE_VALUE)
1592     {
1593         r = service_get_status(pipe, lpservicestatus);
1594         CloseHandle(pipe);
1595         if (r)
1596             return TRUE;
1597     }
1598
1599     TRACE("Failed to read service status\n");
1600
1601     /* read the service type from the registry */
1602     size = sizeof(val);
1603     r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1604     if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1605         val = 0;
1606
1607     lpservicestatus->dwServiceType = val;
1608     lpservicestatus->dwCurrentState            = SERVICE_STOPPED;  /* stopped */
1609     lpservicestatus->dwControlsAccepted        = 0;
1610     lpservicestatus->dwWin32ExitCode           = ERROR_SERVICE_NEVER_STARTED;
1611     lpservicestatus->dwServiceSpecificExitCode = 0;
1612     lpservicestatus->dwCheckPoint              = 0;
1613     lpservicestatus->dwWaitHint                = 0;
1614
1615     return TRUE;
1616 }
1617
1618 /******************************************************************************
1619  * QueryServiceStatusEx [ADVAPI32.@]
1620  *
1621  * Get information about a service.
1622  *
1623  * PARAMS
1624  *   hService       [I] Handle to service to get information about
1625  *   InfoLevel      [I] Level of information to get
1626  *   lpBuffer       [O] Destination for requested information
1627  *   cbBufSize      [I] Size of lpBuffer in bytes
1628  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1629  *
1630  * RETURNS
1631  *  Success: TRUE
1632  *  FAILURE: FALSE
1633  */
1634 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1635                         LPBYTE lpBuffer, DWORD cbBufSize,
1636                         LPDWORD pcbBytesNeeded)
1637 {
1638     FIXME("stub\n");
1639     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1640     return FALSE;
1641 }
1642
1643 /******************************************************************************
1644  * QueryServiceConfigA [ADVAPI32.@]
1645  */
1646 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1647                                  DWORD size, LPDWORD needed )
1648 {
1649     DWORD n;
1650     LPSTR p, buffer;
1651     BOOL ret;
1652     QUERY_SERVICE_CONFIGW *configW;
1653
1654     TRACE("%p %p %d %p\n", hService, config, size, needed);
1655
1656     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1657     {
1658         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1659         return FALSE;
1660     }
1661     configW = (QUERY_SERVICE_CONFIGW *)buffer;
1662     ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1663     if (!ret) goto done;
1664
1665     config->dwServiceType      = configW->dwServiceType;
1666     config->dwStartType        = configW->dwStartType;
1667     config->dwErrorControl     = configW->dwErrorControl;
1668     config->lpBinaryPathName   = NULL;
1669     config->lpLoadOrderGroup   = NULL;
1670     config->dwTagId            = configW->dwTagId;
1671     config->lpDependencies     = NULL;
1672     config->lpServiceStartName = NULL;
1673     config->lpDisplayName      = NULL;
1674
1675     p = (LPSTR)(config + 1);
1676     n = size - sizeof(*config);
1677     ret = FALSE;
1678
1679 #define MAP_STR(str) \
1680     do { \
1681         if (configW->str) \
1682         { \
1683             DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1684             if (!sz) goto done; \
1685             config->str = p; \
1686             p += sz; \
1687             n -= sz; \
1688         } \
1689     } while (0)
1690
1691     MAP_STR( lpBinaryPathName );
1692     MAP_STR( lpLoadOrderGroup );
1693     MAP_STR( lpDependencies );
1694     MAP_STR( lpServiceStartName );
1695     MAP_STR( lpDisplayName );
1696 #undef MAP_STR
1697
1698     *needed = p - buffer;
1699     ret = TRUE;
1700
1701 done:
1702     HeapFree( GetProcessHeap(), 0, buffer );
1703     return ret;
1704 }
1705
1706 /******************************************************************************
1707  * QueryServiceConfigW [ADVAPI32.@]
1708  */
1709 BOOL WINAPI 
1710 QueryServiceConfigW( SC_HANDLE hService,
1711                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1712                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1713 {
1714     WCHAR str_buffer[ MAX_PATH ];
1715     LONG r;
1716     DWORD type, val, sz, total, n;
1717     LPBYTE p;
1718     HKEY hKey;
1719     struct sc_service *hsvc;
1720
1721     TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1722            cbBufSize, pcbBytesNeeded);
1723
1724     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1725     if (!hsvc)
1726     {
1727         SetLastError( ERROR_INVALID_HANDLE );
1728         return FALSE;
1729     }
1730     hKey = hsvc->hkey;
1731
1732     /* calculate the size required first */
1733     total = sizeof (QUERY_SERVICE_CONFIGW);
1734
1735     sz = sizeof(str_buffer);
1736     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1737     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1738     {
1739         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1740         if( 0 == sz ) return FALSE;
1741
1742         total += sizeof(WCHAR) * sz;
1743     }
1744     else
1745     {
1746        /* FIXME: set last error */
1747        return FALSE;
1748     }
1749
1750     sz = 0;
1751     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1752     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1753         total += sz;
1754
1755     sz = 0;
1756     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1757     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1758         total += sz;
1759     else
1760         total += sizeof(WCHAR);
1761
1762     sz = 0;
1763     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1764     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1765         total += sz;
1766
1767     sz = 0;
1768     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1769     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1770         total += sz;
1771
1772     *pcbBytesNeeded = total;
1773
1774     /* if there's not enough memory, return an error */
1775     if( total > cbBufSize )
1776     {
1777         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1778         return FALSE;
1779     }
1780
1781     ZeroMemory( lpServiceConfig, total );
1782
1783     sz = sizeof val;
1784     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1785     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1786         lpServiceConfig->dwServiceType = val;
1787
1788     sz = sizeof val;
1789     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1790     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1791         lpServiceConfig->dwStartType = val;
1792
1793     sz = sizeof val;
1794     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1795     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1796         lpServiceConfig->dwErrorControl = val;
1797
1798     /* now do the strings */
1799     p = (LPBYTE) &lpServiceConfig[1];
1800     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1801
1802     sz = sizeof(str_buffer);
1803     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1804     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1805     {
1806         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1807         sz *= sizeof(WCHAR);
1808         if( 0 == sz || sz > n ) return FALSE;
1809
1810         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1811         p += sz;
1812         n -= sz;
1813     }
1814     else
1815     {
1816        /* FIXME: set last error */
1817        return FALSE;
1818     }
1819
1820     sz = n;
1821     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1822     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1823     {
1824         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1825         p += sz;
1826         n -= sz;
1827     }
1828
1829     sz = n;
1830     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1831     lpServiceConfig->lpDependencies = (LPWSTR) p;
1832     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1833     {
1834         p += sz;
1835         n -= sz;
1836     }
1837     else
1838     {
1839         *(WCHAR *) p = 0;
1840         p += sizeof(WCHAR);
1841         n -= sizeof(WCHAR);
1842     }
1843
1844     if( n < 0 )
1845         ERR("Buffer overflow!\n");
1846
1847     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1848     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1849
1850     return TRUE;
1851 }
1852
1853 /******************************************************************************
1854  * EnumServicesStatusA [ADVAPI32.@]
1855  */
1856 BOOL WINAPI
1857 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1858                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1859                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1860                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1861 {
1862     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1863           dwServiceType, dwServiceState, lpServices, cbBufSize,
1864           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1865     SetLastError (ERROR_ACCESS_DENIED);
1866     return FALSE;
1867 }
1868
1869 /******************************************************************************
1870  * EnumServicesStatusW [ADVAPI32.@]
1871  */
1872 BOOL WINAPI
1873 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1874                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1875                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1876                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1877 {
1878     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1879           dwServiceType, dwServiceState, lpServices, cbBufSize,
1880           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1881     SetLastError (ERROR_ACCESS_DENIED);
1882     return FALSE;
1883 }
1884
1885 /******************************************************************************
1886  * GetServiceKeyNameA [ADVAPI32.@]
1887  */
1888 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1889                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1890 {
1891     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1892     return FALSE;
1893 }
1894
1895 /******************************************************************************
1896  * GetServiceKeyNameW [ADVAPI32.@]
1897  */
1898 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1899                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1900 {
1901     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1902     return FALSE;
1903 }
1904
1905 /******************************************************************************
1906  * QueryServiceLockStatusA [ADVAPI32.@]
1907  */
1908 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1909                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1910                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1911 {
1912     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1913
1914     return FALSE;
1915 }
1916
1917 /******************************************************************************
1918  * QueryServiceLockStatusW [ADVAPI32.@]
1919  */
1920 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1921                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1922                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1923 {
1924     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1925
1926     return FALSE;
1927 }
1928
1929 /******************************************************************************
1930  * GetServiceDisplayNameA  [ADVAPI32.@]
1931  */
1932 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1933   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1934 {
1935     FIXME("%p %s %p %p\n", hSCManager,
1936           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1937     return FALSE;
1938 }
1939
1940 /******************************************************************************
1941  * GetServiceDisplayNameW  [ADVAPI32.@]
1942  */
1943 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1944   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1945 {
1946     FIXME("%p %s %p %p\n", hSCManager,
1947           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1948     return FALSE;
1949 }
1950
1951 /******************************************************************************
1952  * ChangeServiceConfigW  [ADVAPI32.@]
1953  */
1954 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1955   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1956   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1957   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1958 {
1959     struct reg_value val[10];
1960     struct sc_service *hsvc;
1961     DWORD r = ERROR_SUCCESS;
1962     HKEY hKey;
1963     int n = 0;
1964
1965     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1966           hService, dwServiceType, dwStartType, dwErrorControl, 
1967           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1968           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1969           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1970
1971     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1972     if (!hsvc)
1973     {
1974         SetLastError( ERROR_INVALID_HANDLE );
1975         return FALSE;
1976     }
1977     hKey = hsvc->hkey;
1978
1979     if( dwServiceType != SERVICE_NO_CHANGE )
1980         service_set_dword( &val[n++], szType, &dwServiceType );
1981
1982     if( dwStartType != SERVICE_NO_CHANGE )
1983         service_set_dword( &val[n++], szStart, &dwStartType );
1984
1985     if( dwErrorControl != SERVICE_NO_CHANGE )
1986         service_set_dword( &val[n++], szError, &dwErrorControl );
1987
1988     if( lpBinaryPathName )
1989         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1990
1991     if( lpLoadOrderGroup )
1992         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1993
1994     if( lpDependencies )
1995         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1996
1997     if( lpPassword )
1998         FIXME("ignoring password\n");
1999
2000     if( lpServiceStartName )
2001         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2002
2003     r = service_write_values( hsvc->hkey, val, n );
2004
2005     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2006 }
2007
2008 /******************************************************************************
2009  * ChangeServiceConfigA  [ADVAPI32.@]
2010  */
2011 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2012   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2013   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2014   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2015 {
2016     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2017     LPWSTR wServiceStartName, wPassword, wDisplayName;
2018     BOOL r;
2019
2020     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2021           hService, dwServiceType, dwStartType, dwErrorControl, 
2022           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2023           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2024           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2025
2026     wBinaryPathName = SERV_dup( lpBinaryPathName );
2027     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2028     wDependencies = SERV_dupmulti( lpDependencies );
2029     wServiceStartName = SERV_dup( lpServiceStartName );
2030     wPassword = SERV_dup( lpPassword );
2031     wDisplayName = SERV_dup( lpDisplayName );
2032
2033     r = ChangeServiceConfigW( hService, dwServiceType,
2034             dwStartType, dwErrorControl, wBinaryPathName,
2035             wLoadOrderGroup, lpdwTagId, wDependencies,
2036             wServiceStartName, wPassword, wDisplayName);
2037
2038     SERV_free( wBinaryPathName );
2039     SERV_free( wLoadOrderGroup );
2040     SERV_free( wDependencies );
2041     SERV_free( wServiceStartName );
2042     SERV_free( wPassword );
2043     SERV_free( wDisplayName );
2044
2045     return r;
2046 }
2047
2048 /******************************************************************************
2049  * ChangeServiceConfig2A  [ADVAPI32.@]
2050  */
2051 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2052     LPVOID lpInfo)
2053 {
2054     BOOL r = FALSE;
2055
2056     TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2057
2058     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2059     {
2060         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2061         SERVICE_DESCRIPTIONW sdw;
2062
2063         sdw.lpDescription = SERV_dup( sd->lpDescription );
2064
2065         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2066
2067         SERV_free( sdw.lpDescription );
2068     }
2069     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2070     {
2071         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2072         SERVICE_FAILURE_ACTIONSW faw;
2073
2074         faw.dwResetPeriod = fa->dwResetPeriod;
2075         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2076         faw.lpCommand = SERV_dup( fa->lpCommand );
2077         faw.cActions = fa->cActions;
2078         faw.lpsaActions = fa->lpsaActions;
2079
2080         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2081
2082         SERV_free( faw.lpRebootMsg );
2083         SERV_free( faw.lpCommand );
2084     }
2085     else
2086         SetLastError( ERROR_INVALID_PARAMETER );
2087
2088     return r;
2089 }
2090
2091 /******************************************************************************
2092  * ChangeServiceConfig2W  [ADVAPI32.@]
2093  */
2094 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2095     LPVOID lpInfo)
2096 {
2097     HKEY hKey;
2098     struct sc_service *hsvc;
2099
2100     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2101     if (!hsvc)
2102     {
2103         SetLastError( ERROR_INVALID_HANDLE );
2104         return FALSE;
2105     }
2106     hKey = hsvc->hkey;
2107
2108     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2109     {
2110         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2111         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2112         if (sd->lpDescription)
2113         {
2114             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2115             if (sd->lpDescription[0] == 0)
2116                 RegDeleteValueW(hKey,szDescription);
2117             else
2118                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2119                                         (LPVOID)sd->lpDescription,
2120                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2121         }
2122     }
2123     else   
2124         FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2125     return TRUE;
2126 }
2127
2128 /******************************************************************************
2129  * QueryServiceObjectSecurity [ADVAPI32.@]
2130  */
2131 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2132        SECURITY_INFORMATION dwSecurityInformation,
2133        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2134        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2135 {
2136     PACL pACL = NULL;
2137
2138     FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2139           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2140
2141     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2142
2143     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2144     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2145     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2146     return TRUE;
2147 }
2148
2149 /******************************************************************************
2150  * SetServiceObjectSecurity [ADVAPI32.@]
2151  */
2152 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2153        SECURITY_INFORMATION dwSecurityInformation,
2154        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2155 {
2156     FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2157     return TRUE;
2158 }
2159
2160 /******************************************************************************
2161  * SetServiceBits [ADVAPI32.@]
2162  */
2163 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2164         DWORD dwServiceBits,
2165         BOOL bSetBitsOn,
2166         BOOL bUpdateImmediately)
2167 {
2168     FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2169           bSetBitsOn, bUpdateImmediately);
2170     return TRUE;
2171 }
2172
2173 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2174         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2175 {
2176     FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2177     return 0;
2178 }
2179
2180 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2181         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2182 {
2183     service_data *service;
2184
2185     TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2186
2187     EnterCriticalSection( &service_cs );
2188     for(service = service_list; service; service = service->next)
2189         if(!strcmpW(lpServiceName, service->name))
2190             break;
2191     if (service)
2192     {
2193         service->handler.handler_ex = lpHandlerProc;
2194         service->context = lpContext;
2195         service->extended = TRUE;
2196     }
2197     LeaveCriticalSection( &service_cs );
2198
2199     return (SERVICE_STATUS_HANDLE)service;
2200 }