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