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