Added CSIDL_MYVIDEO|MYPICTURES|MYMUSIC to _SHRegisterUserShellFolders.
[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  * See StartServiceCtrlDispatcherW.
735  */
736 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
737 {
738     service_data *info;
739     DWORD sz, len;
740     BOOL ret = TRUE;
741
742     TRACE("%p\n", servent);
743
744     EnterCriticalSection( &service_cs );
745     while (servent->lpServiceName)
746     {
747         LPSTR name = servent->lpServiceName;
748
749         len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
750         sz = len*sizeof(WCHAR) + sizeof *info;
751         info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
752         MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
753         info->proc.a = servent->lpServiceProc;
754         info->unicode = FALSE;
755         
756         /* insert into the list */
757         info->next = service_list;
758         service_list = info;
759
760         servent++;
761     }
762     LeaveCriticalSection( &service_cs );
763
764     service_run_threads();
765
766     return ret;
767 }
768
769 /******************************************************************************
770  * StartServiceCtrlDispatcherW [ADVAPI32.@]
771  *
772  *  Connects a process containing one or more services to the service control
773  * manager.
774  *
775  * PARAMS
776  *   servent [I]  A list of the service names and service procedures
777  *
778  * RETURNS
779  *  Success: TRUE.
780  *  Failure: FALSE.
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     if (r)
1539         service_wait_for_startup(hService);
1540
1541     return r;
1542 }
1543
1544 /******************************************************************************
1545  * QueryServiceStatus [ADVAPI32.@]
1546  *
1547  * PARAMS
1548  *   hService        []
1549  *   lpservicestatus []
1550  *
1551  */
1552 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1553                                LPSERVICE_STATUS lpservicestatus)
1554 {
1555     struct sc_service *hsvc;
1556     DWORD size, type, val;
1557     HANDLE pipe;
1558     LONG r;
1559
1560     TRACE("%p %p\n", hService, lpservicestatus);
1561
1562     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1563     if (!hsvc)
1564     {
1565         SetLastError( ERROR_INVALID_HANDLE );
1566         return FALSE;
1567     }
1568
1569     pipe = service_open_pipe(hsvc->name);
1570     if (pipe != INVALID_HANDLE_VALUE)
1571     {
1572         r = service_get_status(pipe, lpservicestatus);
1573         CloseHandle(pipe);
1574         if (r)
1575             return TRUE;
1576     }
1577
1578     TRACE("Failed to read service status\n");
1579
1580     /* read the service type from the registry */
1581     size = sizeof(val);
1582     r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1583     if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1584         val = 0;
1585
1586     lpservicestatus->dwServiceType = val;
1587     lpservicestatus->dwCurrentState            = SERVICE_STOPPED;  /* stopped */
1588     lpservicestatus->dwControlsAccepted        = 0;
1589     lpservicestatus->dwWin32ExitCode           = ERROR_SERVICE_NEVER_STARTED;
1590     lpservicestatus->dwServiceSpecificExitCode = 0;
1591     lpservicestatus->dwCheckPoint              = 0;
1592     lpservicestatus->dwWaitHint                = 0;
1593
1594     return TRUE;
1595 }
1596
1597 /******************************************************************************
1598  * QueryServiceStatusEx [ADVAPI32.@]
1599  *
1600  * Get information about a service.
1601  *
1602  * PARAMS
1603  *   hService       [I] Handle to service to get information about
1604  *   InfoLevel      [I] Level of information to get
1605  *   lpBuffer       [O] Destination for requested information
1606  *   cbBufSize      [I] Size of lpBuffer in bytes
1607  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1608  *
1609  * RETURNS
1610  *  Success: TRUE
1611  *  FAILURE: FALSE
1612  */
1613 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1614                         LPBYTE lpBuffer, DWORD cbBufSize,
1615                         LPDWORD pcbBytesNeeded)
1616 {
1617     FIXME("stub\n");
1618     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1619     return FALSE;
1620 }
1621
1622 /******************************************************************************
1623  * QueryServiceConfigA [ADVAPI32.@]
1624  */
1625 BOOL WINAPI 
1626 QueryServiceConfigA( SC_HANDLE hService,
1627                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1628                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1629 {
1630     static const CHAR szDisplayName[] = "DisplayName";
1631     static const CHAR szType[] = "Type";
1632     static const CHAR szStart[] = "Start";
1633     static const CHAR szError[] = "ErrorControl";
1634     static const CHAR szImagePath[] = "ImagePath";
1635     static const CHAR szGroup[] = "Group";
1636     static const CHAR szDependencies[] = "Dependencies";
1637     struct sc_service *hsvc;
1638     HKEY hKey;
1639     CHAR str_buffer[ MAX_PATH ];
1640     LONG r;
1641     DWORD type, val, sz, total, n;
1642     LPSTR p;
1643
1644     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1645            cbBufSize, pcbBytesNeeded);
1646
1647     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1648     if (!hsvc)
1649     {
1650         SetLastError( ERROR_INVALID_HANDLE );
1651         return FALSE;
1652     }
1653     hKey = hsvc->hkey;
1654
1655     /* calculate the size required first */
1656     total = sizeof (QUERY_SERVICE_CONFIGA);
1657
1658     sz = sizeof(str_buffer);
1659     r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1660     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1661     {
1662         sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1663         if( 0 == sz ) return FALSE;
1664
1665         total += sz;
1666     }
1667     else
1668     {
1669         /* FIXME: set last error */
1670         return FALSE;
1671     }
1672
1673     sz = 0;
1674     r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1675     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1676         total += sz;
1677
1678     sz = 0;
1679     r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1680     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1681         total += sz;
1682
1683     sz = 0;
1684     r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1685     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1686         total += sz;
1687
1688     sz = 0;
1689     r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1690     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1691         total += sz;
1692
1693     *pcbBytesNeeded = total;
1694
1695     /* if there's not enough memory, return an error */
1696     if( total > cbBufSize )
1697     {
1698         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1699         return FALSE;
1700     }
1701
1702     ZeroMemory( lpServiceConfig, total );
1703
1704     sz = sizeof val;
1705     r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1706     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1707         lpServiceConfig->dwServiceType = val;
1708
1709     sz = sizeof val;
1710     r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1711     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1712         lpServiceConfig->dwStartType = val;
1713
1714     sz = sizeof val;
1715     r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1716     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1717         lpServiceConfig->dwErrorControl = val;
1718
1719     /* now do the strings */
1720     p = (LPSTR) &lpServiceConfig[1];
1721     n = total - sizeof (QUERY_SERVICE_CONFIGA);
1722
1723     sz = sizeof(str_buffer);
1724     r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1725     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1726     {
1727         sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1728         if( 0 == sz || sz > n ) return FALSE;
1729
1730         lpServiceConfig->lpBinaryPathName = p;
1731         p += sz;
1732         n -= sz;
1733     }
1734     else
1735     {
1736         /* FIXME: set last error */
1737         return FALSE;
1738     }
1739
1740     sz = n;
1741     r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1742     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1743     {
1744         lpServiceConfig->lpLoadOrderGroup = p;
1745         p += sz;
1746         n -= sz;
1747     }
1748
1749     sz = n;
1750     r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1751     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1752     {
1753         lpServiceConfig->lpDependencies = p;
1754         p += sz;
1755         n -= sz;
1756     }
1757
1758     if( n < 0 )
1759         ERR("Buffer overflow!\n");
1760
1761     TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1762     TRACE("Group      = %s\n", lpServiceConfig->lpLoadOrderGroup );
1763
1764     return TRUE;
1765 }
1766
1767 /******************************************************************************
1768  * QueryServiceConfigW [ADVAPI32.@]
1769  */
1770 BOOL WINAPI 
1771 QueryServiceConfigW( SC_HANDLE hService,
1772                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1773                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1774 {
1775     WCHAR str_buffer[ MAX_PATH ];
1776     LONG r;
1777     DWORD type, val, sz, total, n;
1778     LPBYTE p;
1779     HKEY hKey;
1780     struct sc_service *hsvc;
1781
1782     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1783            cbBufSize, pcbBytesNeeded);
1784
1785     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1786     if (!hsvc)
1787     {
1788         SetLastError( ERROR_INVALID_HANDLE );
1789         return FALSE;
1790     }
1791     hKey = hsvc->hkey;
1792
1793     /* calculate the size required first */
1794     total = sizeof (QUERY_SERVICE_CONFIGW);
1795
1796     sz = sizeof(str_buffer);
1797     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1798     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1799     {
1800         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1801         if( 0 == sz ) return FALSE;
1802
1803         total += sizeof(WCHAR) * sz;
1804     }
1805     else
1806     {
1807        /* FIXME: set last error */
1808        return FALSE;
1809     }
1810
1811     sz = 0;
1812     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1813     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1814         total += sz;
1815
1816     sz = 0;
1817     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1818     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1819         total += sz;
1820     else
1821         total += sizeof(WCHAR);
1822
1823     sz = 0;
1824     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1825     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1826         total += sz;
1827
1828     sz = 0;
1829     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1830     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1831         total += sz;
1832
1833     *pcbBytesNeeded = total;
1834
1835     /* if there's not enough memory, return an error */
1836     if( total > cbBufSize )
1837     {
1838         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1839         return FALSE;
1840     }
1841
1842     ZeroMemory( lpServiceConfig, total );
1843
1844     sz = sizeof val;
1845     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1846     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1847         lpServiceConfig->dwServiceType = val;
1848
1849     sz = sizeof val;
1850     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1851     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1852         lpServiceConfig->dwStartType = val;
1853
1854     sz = sizeof val;
1855     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1856     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1857         lpServiceConfig->dwErrorControl = val;
1858
1859     /* now do the strings */
1860     p = (LPBYTE) &lpServiceConfig[1];
1861     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1862
1863     sz = sizeof(str_buffer);
1864     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1865     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1866     {
1867         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1868         sz *= sizeof(WCHAR);
1869         if( 0 == sz || sz > n ) return FALSE;
1870
1871         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1872         p += sz;
1873         n -= sz;
1874     }
1875     else
1876     {
1877        /* FIXME: set last error */
1878        return FALSE;
1879     }
1880
1881     sz = n;
1882     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1883     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1884     {
1885         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1886         p += sz;
1887         n -= sz;
1888     }
1889
1890     sz = n;
1891     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1892     lpServiceConfig->lpDependencies = (LPWSTR) p;
1893     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1894     {
1895         p += sz;
1896         n -= sz;
1897     }
1898     else
1899     {
1900         *(WCHAR *) p = 0;
1901         p += sizeof(WCHAR);
1902         n -= sizeof(WCHAR);
1903     }
1904
1905     if( n < 0 )
1906         ERR("Buffer overflow!\n");
1907
1908     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1909     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1910
1911     return TRUE;
1912 }
1913
1914 /******************************************************************************
1915  * EnumServicesStatusA [ADVAPI32.@]
1916  */
1917 BOOL WINAPI
1918 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1919                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1920                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1921                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1922 {
1923     FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1924           dwServiceType, dwServiceState, lpServices, cbBufSize,
1925           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1926     SetLastError (ERROR_ACCESS_DENIED);
1927     return FALSE;
1928 }
1929
1930 /******************************************************************************
1931  * EnumServicesStatusW [ADVAPI32.@]
1932  */
1933 BOOL WINAPI
1934 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1935                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1936                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1937                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1938 {
1939     FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1940           dwServiceType, dwServiceState, lpServices, cbBufSize,
1941           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1942     SetLastError (ERROR_ACCESS_DENIED);
1943     return FALSE;
1944 }
1945
1946 /******************************************************************************
1947  * GetServiceKeyNameA [ADVAPI32.@]
1948  */
1949 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1950                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1951 {
1952     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1953     return FALSE;
1954 }
1955
1956 /******************************************************************************
1957  * GetServiceKeyNameW [ADVAPI32.@]
1958  */
1959 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1960                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1961 {
1962     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1963     return FALSE;
1964 }
1965
1966 /******************************************************************************
1967  * QueryServiceLockStatusA [ADVAPI32.@]
1968  */
1969 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1970                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1971                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1972 {
1973     FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1974
1975     return FALSE;
1976 }
1977
1978 /******************************************************************************
1979  * QueryServiceLockStatusW [ADVAPI32.@]
1980  */
1981 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1982                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1983                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1984 {
1985     FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1986
1987     return FALSE;
1988 }
1989
1990 /******************************************************************************
1991  * GetServiceDisplayNameA  [ADVAPI32.@]
1992  */
1993 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1994   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1995 {
1996     FIXME("%p %s %p %p\n", hSCManager,
1997           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1998     return FALSE;
1999 }
2000
2001 /******************************************************************************
2002  * GetServiceDisplayNameW  [ADVAPI32.@]
2003  */
2004 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2005   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2006 {
2007     FIXME("%p %s %p %p\n", hSCManager,
2008           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2009     return FALSE;
2010 }
2011
2012 /******************************************************************************
2013  * ChangeServiceConfigW  [ADVAPI32.@]
2014  */
2015 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2016   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2017   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2018   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2019 {
2020     struct reg_value val[10];
2021     struct sc_service *hsvc;
2022     DWORD r = ERROR_SUCCESS;
2023     HKEY hKey;
2024     int n = 0;
2025
2026     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2027           hService, dwServiceType, dwStartType, dwErrorControl, 
2028           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2029           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2030           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2031
2032     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2033     if (!hsvc)
2034     {
2035         SetLastError( ERROR_INVALID_HANDLE );
2036         return FALSE;
2037     }
2038     hKey = hsvc->hkey;
2039
2040     if( dwServiceType != SERVICE_NO_CHANGE )
2041         service_set_dword( &val[n++], szType, &dwServiceType );
2042
2043     if( dwStartType != SERVICE_NO_CHANGE )
2044         service_set_dword( &val[n++], szStart, &dwStartType );
2045
2046     if( dwErrorControl != SERVICE_NO_CHANGE )
2047         service_set_dword( &val[n++], szError, &dwErrorControl );
2048
2049     if( lpBinaryPathName )
2050         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2051
2052     if( lpLoadOrderGroup )
2053         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2054
2055     if( lpDependencies )
2056         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2057
2058     if( lpPassword )
2059         FIXME("ignoring password\n");
2060
2061     if( lpServiceStartName )
2062         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2063
2064     r = service_write_values( hsvc->hkey, val, n );
2065
2066     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2067 }
2068
2069 /******************************************************************************
2070  * ChangeServiceConfigA  [ADVAPI32.@]
2071  */
2072 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2073   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2074   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2075   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2076 {
2077     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2078     LPWSTR wServiceStartName, wPassword, wDisplayName;
2079     BOOL r;
2080
2081     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2082           hService, dwServiceType, dwStartType, dwErrorControl, 
2083           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2084           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2085           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2086
2087     wBinaryPathName = SERV_dup( lpBinaryPathName );
2088     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2089     wDependencies = SERV_dupmulti( lpDependencies );
2090     wServiceStartName = SERV_dup( lpServiceStartName );
2091     wPassword = SERV_dup( lpPassword );
2092     wDisplayName = SERV_dup( lpDisplayName );
2093
2094     r = ChangeServiceConfigW( hService, dwServiceType,
2095             dwStartType, dwErrorControl, wBinaryPathName,
2096             wLoadOrderGroup, lpdwTagId, wDependencies,
2097             wServiceStartName, wPassword, wDisplayName);
2098
2099     SERV_free( wBinaryPathName );
2100     SERV_free( wLoadOrderGroup );
2101     SERV_free( wDependencies );
2102     SERV_free( wServiceStartName );
2103     SERV_free( wPassword );
2104     SERV_free( wDisplayName );
2105
2106     return r;
2107 }
2108
2109 /******************************************************************************
2110  * ChangeServiceConfig2A  [ADVAPI32.@]
2111  */
2112 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2113     LPVOID lpInfo)
2114 {
2115     BOOL r = FALSE;
2116
2117     TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2118
2119     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2120     {
2121         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2122         SERVICE_DESCRIPTIONW sdw;
2123
2124         sdw.lpDescription = SERV_dup( sd->lpDescription );
2125
2126         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2127
2128         SERV_free( sdw.lpDescription );
2129     }
2130     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2131     {
2132         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2133         SERVICE_FAILURE_ACTIONSW faw;
2134
2135         faw.dwResetPeriod = fa->dwResetPeriod;
2136         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2137         faw.lpCommand = SERV_dup( fa->lpCommand );
2138         faw.cActions = fa->cActions;
2139         faw.lpsaActions = fa->lpsaActions;
2140
2141         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2142
2143         SERV_free( faw.lpRebootMsg );
2144         SERV_free( faw.lpCommand );
2145     }
2146     else
2147         SetLastError( ERROR_INVALID_PARAMETER );
2148
2149     return r;
2150 }
2151
2152 /******************************************************************************
2153  * ChangeServiceConfig2W  [ADVAPI32.@]
2154  */
2155 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2156     LPVOID lpInfo)
2157 {
2158     HKEY hKey;
2159     struct sc_service *hsvc;
2160
2161     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2162     if (!hsvc)
2163     {
2164         SetLastError( ERROR_INVALID_HANDLE );
2165         return FALSE;
2166     }
2167     hKey = hsvc->hkey;
2168
2169     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2170     {
2171         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2172         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2173         if (sd->lpDescription)
2174         {
2175             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2176             if (sd->lpDescription[0] == 0)
2177                 RegDeleteValueW(hKey,szDescription);
2178             else
2179                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2180                                         (LPVOID)sd->lpDescription,
2181                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2182         }
2183     }
2184     else   
2185         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2186     return TRUE;
2187 }
2188
2189 /******************************************************************************
2190  * QueryServiceObjectSecurity [ADVAPI32.@]
2191  */
2192 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2193        SECURITY_INFORMATION dwSecurityInformation,
2194        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2195        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2196 {
2197     PACL pACL = NULL;
2198
2199     FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2200           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2201
2202     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2203
2204     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2205     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2206     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2207     return TRUE;
2208 }
2209
2210 /******************************************************************************
2211  * SetServiceObjectSecurity [ADVAPI32.@]
2212  */
2213 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2214        SECURITY_INFORMATION dwSecurityInformation,
2215        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2216 {
2217     FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2218     return TRUE;
2219 }
2220
2221 /******************************************************************************
2222  * SetServiceBits [ADVAPI32.@]
2223  */
2224 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2225         DWORD dwServiceBits,
2226         BOOL bSetBitsOn,
2227         BOOL bUpdateImmediately)
2228 {
2229     FIXME("%p %08lx %x %x\n", hServiceStatus, dwServiceBits,
2230           bSetBitsOn, bUpdateImmediately);
2231     return TRUE;
2232 }
2233
2234 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2235         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2236 {
2237     FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2238     return 0;
2239 }
2240
2241 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2242         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2243 {
2244     FIXME("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2245     return 0;
2246 }