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