Branch the LSA functions from security.c to lsa.c.
[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, { 0, (DWORD)(__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("%lx %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     return NULL;
1004 }
1005
1006 /******************************************************************************
1007  * ControlService [ADVAPI32.@]
1008  *
1009  * Send a control code to a service.
1010  *
1011  * PARAMS
1012  *   hService        [I] Handle of the service control manager database
1013  *   dwControl       [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1014  *   lpServiceStatus [O] Destination for the status of the service, if available
1015  *
1016  * RETURNS
1017  *   Success: TRUE.
1018  *   Failure: FALSE.
1019  *
1020  * BUGS
1021  *   Unlike M$' implementation, control requests are not serialized and may be
1022  *   processed asynchronously.
1023  */
1024 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1025                             LPSERVICE_STATUS lpServiceStatus )
1026 {
1027     struct sc_service *hsvc;
1028     BOOL ret = FALSE;
1029     HANDLE handle;
1030
1031     TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1032
1033     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1034     if (!hsvc)
1035     {
1036         SetLastError( ERROR_INVALID_HANDLE );
1037         return FALSE;
1038     }
1039
1040     ret = QueryServiceStatus(hService, lpServiceStatus);
1041     if (!ret)
1042     {
1043         ERR("failed to query service status\n");
1044         SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1045         return FALSE;
1046     }
1047
1048     switch (lpServiceStatus->dwCurrentState)
1049     {
1050     case SERVICE_STOPPED:
1051         SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1052         return FALSE;
1053     case SERVICE_START_PENDING:
1054         if (dwControl==SERVICE_CONTROL_STOP)
1055             break;
1056         /* fall thru */
1057     case SERVICE_STOP_PENDING:
1058         SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1059         return FALSE;
1060     }
1061
1062     handle = service_open_pipe(hsvc->name);
1063     if (handle!=INVALID_HANDLE_VALUE)
1064     {
1065         DWORD result = ERROR_SUCCESS;
1066         ret = service_send_control(handle, dwControl, &result);
1067         CloseHandle(handle);
1068         if (result!=ERROR_SUCCESS)
1069         {
1070             SetLastError(result);
1071             ret = FALSE;
1072         }
1073     }
1074
1075     return ret;
1076 }
1077
1078 /******************************************************************************
1079  * CloseServiceHandle [ADVAPI32.@]
1080  * 
1081  * Close a handle to a service or the service control manager database.
1082  *
1083  * PARAMS
1084  *   hSCObject [I] Handle to service or service control manager database
1085  *
1086  * RETURNS
1087  *  Success: TRUE
1088  *  Failure: FALSE
1089  */
1090 BOOL WINAPI
1091 CloseServiceHandle( SC_HANDLE hSCObject )
1092 {
1093     TRACE("%p\n", hSCObject);
1094
1095     sc_handle_free( (struct sc_handle*) hSCObject );
1096
1097     return TRUE;
1098 }
1099
1100
1101 /******************************************************************************
1102  * OpenServiceA [ADVAPI32.@]
1103  *
1104  * Open a handle to a service.
1105  *
1106  * PARAMS
1107  *   hSCManager      [I] Handle of the service control manager database
1108  *   lpServiceName   [I] Name of the service to open
1109  *   dwDesiredAccess [I] Access required to the service
1110  *
1111  * RETURNS
1112  *    Success: Handle to the service
1113  *    Failure: NULL
1114  */
1115 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1116                                DWORD dwDesiredAccess )
1117 {
1118     LPWSTR lpServiceNameW;
1119     SC_HANDLE ret;
1120
1121     TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1122
1123     lpServiceNameW = SERV_dup(lpServiceName);
1124     ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1125     SERV_free(lpServiceNameW);
1126     return ret;
1127 }
1128
1129
1130 /******************************************************************************
1131  * OpenServiceW [ADVAPI32.@]
1132  *
1133  * See OpenServiceA.
1134  */
1135 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1136                                DWORD dwDesiredAccess)
1137 {
1138     struct sc_manager *hscm;
1139     struct sc_service *hsvc;
1140     HKEY hKey;
1141     long r;
1142     DWORD len;
1143
1144     TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1145
1146     if (!lpServiceName)
1147     {
1148         SetLastError(ERROR_INVALID_ADDRESS);
1149         return NULL;
1150     }
1151
1152     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1153     if (!hscm)
1154     {
1155         SetLastError( ERROR_INVALID_HANDLE );
1156         return FALSE;
1157     }
1158
1159     r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1160     if (r!=ERROR_SUCCESS)
1161     {
1162         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1163         return NULL;
1164     }
1165     
1166     len = strlenW(lpServiceName)+1;
1167     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1168                             sizeof (struct sc_service) + len*sizeof(WCHAR),
1169                             sc_handle_destroy_service );
1170     if (!hsvc)
1171         return NULL;
1172     strcpyW( hsvc->name, lpServiceName );
1173     hsvc->hkey = hKey;
1174
1175     /* add reference to SCM handle */
1176     hscm->hdr.ref_count++;
1177     hsvc->scm = hscm;
1178
1179     TRACE("returning %p\n",hsvc);
1180
1181     return (SC_HANDLE) &hsvc->hdr;
1182 }
1183
1184 /******************************************************************************
1185  * CreateServiceW [ADVAPI32.@]
1186  */
1187 SC_HANDLE WINAPI
1188 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1189                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1190                   DWORD dwServiceType, DWORD dwStartType,
1191                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1192                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1193                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1194                   LPCWSTR lpPassword )
1195 {
1196     struct sc_manager *hscm;
1197     struct sc_service *hsvc = NULL;
1198     HKEY hKey;
1199     LONG r;
1200     DWORD dp, len;
1201     struct reg_value val[10];
1202     int n = 0;
1203
1204     TRACE("%p %s %s\n", hSCManager, 
1205           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1206
1207     hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1208     if (!hscm)
1209     {
1210         SetLastError( ERROR_INVALID_HANDLE );
1211         return NULL;
1212     }
1213
1214     r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1215                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1216     if (r!=ERROR_SUCCESS)
1217         return NULL;
1218
1219     if (dp != REG_CREATED_NEW_KEY)
1220     {
1221         SetLastError(ERROR_SERVICE_EXISTS);
1222         goto error;
1223     }
1224
1225     if( lpDisplayName )
1226         service_set_string( &val[n++], szDisplayName, lpDisplayName );
1227
1228     service_set_dword( &val[n++], szType, &dwServiceType );
1229     service_set_dword( &val[n++], szStart, &dwStartType );
1230     service_set_dword( &val[n++], szError, &dwErrorControl );
1231
1232     if( lpBinaryPathName )
1233         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1234
1235     if( lpLoadOrderGroup )
1236         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1237
1238     if( lpDependencies )
1239         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1240
1241     if( lpPassword )
1242         FIXME("Don't know how to add a Password for a service.\n");
1243
1244     if( lpServiceStartName )
1245         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1246
1247     r = service_write_values( hKey, val, n );
1248     if( r != ERROR_SUCCESS )
1249         goto error;
1250
1251     len = strlenW(lpServiceName)+1;
1252     len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1253     hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1254     if( !hsvc )
1255         goto error;
1256     lstrcpyW( hsvc->name, lpServiceName );
1257     hsvc->hkey = hKey;
1258     hsvc->scm = hscm;
1259     hscm->hdr.ref_count++;
1260
1261     return (SC_HANDLE) &hsvc->hdr;
1262     
1263 error:
1264     RegCloseKey( hKey );
1265     return NULL;
1266 }
1267
1268
1269 /******************************************************************************
1270  * CreateServiceA [ADVAPI32.@]
1271  */
1272 SC_HANDLE WINAPI
1273 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1274                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1275                   DWORD dwServiceType, DWORD dwStartType,
1276                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1277                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1278                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1279                   LPCSTR lpPassword )
1280 {
1281     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1282         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1283     SC_HANDLE r;
1284
1285     TRACE("%p %s %s\n", hSCManager,
1286           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1287
1288     lpServiceNameW = SERV_dup( lpServiceName );
1289     lpDisplayNameW = SERV_dup( lpDisplayName );
1290     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1291     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1292     lpDependenciesW = SERV_dupmulti( lpDependencies );
1293     lpServiceStartNameW = SERV_dup( lpServiceStartName );
1294     lpPasswordW = SERV_dup( lpPassword );
1295
1296     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1297             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1298             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1299             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1300
1301     SERV_free( lpServiceNameW );
1302     SERV_free( lpDisplayNameW );
1303     SERV_free( lpBinaryPathNameW );
1304     SERV_free( lpLoadOrderGroupW );
1305     SERV_free( lpDependenciesW );
1306     SERV_free( lpServiceStartNameW );
1307     SERV_free( lpPasswordW );
1308
1309     return r;
1310 }
1311
1312
1313 /******************************************************************************
1314  * DeleteService [ADVAPI32.@]
1315  *
1316  * Delete a service from the service control manager database.
1317  *
1318  * PARAMS
1319  *    hService [I] Handle of the service to delete
1320  *
1321  * RETURNS
1322  *  Success: TRUE
1323  *  Failure: FALSE
1324  */
1325 BOOL WINAPI DeleteService( SC_HANDLE hService )
1326 {
1327     struct sc_service *hsvc;
1328     HKEY hKey;
1329     WCHAR valname[MAX_PATH+1];
1330     INT index = 0;
1331     LONG rc;
1332     DWORD size;
1333
1334     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1335     if (!hsvc)
1336     {
1337         SetLastError( ERROR_INVALID_HANDLE );
1338         return FALSE;
1339     }
1340     hKey = hsvc->hkey;
1341
1342     size = MAX_PATH+1; 
1343     /* Clean out the values */
1344     rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1345     while (rc == ERROR_SUCCESS)
1346     {
1347         RegDeleteValueW(hKey,valname);
1348         index++;
1349         size = MAX_PATH+1; 
1350         rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1351     }
1352
1353     RegCloseKey(hKey);
1354     hsvc->hkey = NULL;
1355
1356     /* delete the key */
1357     RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1358
1359     return TRUE;
1360 }
1361
1362
1363 /******************************************************************************
1364  * StartServiceA [ADVAPI32.@]
1365  *
1366  * Start a service
1367  *
1368  * PARAMS
1369  *   hService            [I] Handle of service
1370  *   dwNumServiceArgs    [I] Number of arguments
1371  *   lpServiceArgVectors [I] Address of array of argument strings
1372  *
1373  * NOTES
1374  *  - NT implements this function using an obscure RPC call.
1375  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1376  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
1377  *  - This will only work for shared address space. How should the service
1378  *    args be transferred when address spaces are separated?
1379  *  - Can only start one service at a time.
1380  *  - Has no concept of privilege.
1381  *
1382  * RETURNS
1383  *   Success: TRUE.
1384  *   Failure: FALSE
1385  */
1386 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1387                            LPCSTR *lpServiceArgVectors )
1388 {
1389     LPWSTR *lpwstr=NULL;
1390     unsigned int i;
1391     BOOL r;
1392
1393     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1394
1395     if (dwNumServiceArgs)
1396         lpwstr = HeapAlloc( GetProcessHeap(), 0,
1397                                    dwNumServiceArgs*sizeof(LPWSTR) );
1398
1399     for(i=0; i<dwNumServiceArgs; i++)
1400         lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1401
1402     r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1403
1404     if (dwNumServiceArgs)
1405     {
1406         for(i=0; i<dwNumServiceArgs; i++)
1407             SERV_free(lpwstr[i]);
1408         HeapFree(GetProcessHeap(), 0, lpwstr);
1409     }
1410
1411     return r;
1412 }
1413
1414 /******************************************************************************
1415  * service_start_process    [INTERNAL]
1416  */
1417 static DWORD service_start_process(struct sc_service *hsvc)
1418 {
1419     static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1420     PROCESS_INFORMATION pi;
1421     STARTUPINFOW si;
1422     LPWSTR path = NULL, str;
1423     DWORD type, size, ret;
1424     HANDLE handles[2];
1425     BOOL r;
1426
1427     /* read the executable path from memory */
1428     size = 0;
1429     ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1430     if (ret!=ERROR_SUCCESS)
1431         return FALSE;
1432     str = HeapAlloc(GetProcessHeap(),0,size);
1433     ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1434     if (ret==ERROR_SUCCESS)
1435     {
1436         size = ExpandEnvironmentStringsW(str,NULL,0);
1437         path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1438         ExpandEnvironmentStringsW(str,path,size);
1439     }
1440     HeapFree(GetProcessHeap(),0,str);
1441     if (!path)
1442         return FALSE;
1443
1444     /* wait for the process to start and set an event or terminate */
1445     handles[0] = service_get_event_handle( hsvc->name );
1446     ZeroMemory(&si, sizeof(STARTUPINFOW));
1447     si.cb = sizeof(STARTUPINFOW);
1448     r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1449     if (r)
1450     {
1451         handles[1] = pi.hProcess;
1452         ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1453         if(ret != WAIT_OBJECT_0)
1454         {
1455             SetLastError(ERROR_IO_PENDING);
1456             r = FALSE;
1457         }
1458
1459         CloseHandle( pi.hThread );
1460         CloseHandle( pi.hProcess );
1461     }
1462     CloseHandle( handles[0] );
1463     HeapFree(GetProcessHeap(),0,path);
1464     return r;
1465 }
1466
1467 static BOOL service_wait_for_startup(SC_HANDLE hService)
1468 {
1469     DWORD i;
1470     SERVICE_STATUS status;
1471     BOOL r = FALSE;
1472
1473     TRACE("%p\n", hService);
1474
1475     for (i=0; i<30; i++)
1476     {
1477         status.dwCurrentState = 0;
1478         r = QueryServiceStatus(hService, &status);
1479         if (!r)
1480             break;
1481         if (status.dwCurrentState == SERVICE_RUNNING)
1482         {
1483             TRACE("Service started successfully\n");
1484             break;
1485         }
1486         r = FALSE;
1487         Sleep(1000);
1488     }
1489     return r;
1490 }
1491
1492 /******************************************************************************
1493  * StartServiceW [ADVAPI32.@]
1494  * 
1495  * See StartServiceA.
1496  */
1497 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1498                           LPCWSTR *lpServiceArgVectors)
1499 {
1500     struct sc_service *hsvc;
1501     BOOL r = FALSE;
1502     SC_LOCK hLock;
1503     HANDLE handle = INVALID_HANDLE_VALUE;
1504
1505     TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1506
1507     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1508     if (!hsvc)
1509     {
1510         SetLastError(ERROR_INVALID_HANDLE);
1511         return r;
1512     }
1513
1514     hLock = LockServiceDatabase(hsvc->scm);
1515     if (!hLock)
1516         return r;
1517
1518     handle = service_open_pipe(hsvc->name);
1519     if (handle==INVALID_HANDLE_VALUE)
1520     {
1521         /* start the service process */
1522         if (service_start_process(hsvc))
1523             handle = service_open_pipe(hsvc->name);
1524     }
1525
1526     if (handle != INVALID_HANDLE_VALUE)
1527     {
1528         service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1529         CloseHandle(handle);
1530         r = TRUE;
1531     }
1532
1533     UnlockServiceDatabase( hLock );
1534
1535     TRACE("returning %d\n", r);
1536
1537     service_wait_for_startup(hService);
1538
1539     return r;
1540 }
1541
1542 /******************************************************************************
1543  * QueryServiceStatus [ADVAPI32.@]
1544  *
1545  * PARAMS
1546  *   hService        []
1547  *   lpservicestatus []
1548  *
1549  */
1550 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1551                                LPSERVICE_STATUS lpservicestatus)
1552 {
1553     struct sc_service *hsvc;
1554     DWORD size, type, val;
1555     HANDLE pipe;
1556     LONG r;
1557
1558     TRACE("%p %p\n", hService, lpservicestatus);
1559
1560     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1561     if (!hsvc)
1562     {
1563         SetLastError( ERROR_INVALID_HANDLE );
1564         return FALSE;
1565     }
1566
1567     pipe = service_open_pipe(hsvc->name);
1568     if (pipe != INVALID_HANDLE_VALUE)
1569     {
1570         r = service_get_status(pipe, lpservicestatus);
1571         CloseHandle(pipe);
1572         if (r)
1573             return TRUE;
1574     }
1575
1576     TRACE("Failed to read service status\n");
1577
1578     /* read the service type from the registry */
1579     size = sizeof(val);
1580     r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1581     if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1582         val = 0;
1583
1584     lpservicestatus->dwServiceType = val;
1585     lpservicestatus->dwCurrentState            = SERVICE_STOPPED;  /* stopped */
1586     lpservicestatus->dwControlsAccepted        = 0;
1587     lpservicestatus->dwWin32ExitCode           = ERROR_SERVICE_NEVER_STARTED;
1588     lpservicestatus->dwServiceSpecificExitCode = 0;
1589     lpservicestatus->dwCheckPoint              = 0;
1590     lpservicestatus->dwWaitHint                = 0;
1591
1592     return TRUE;
1593 }
1594
1595 /******************************************************************************
1596  * QueryServiceStatusEx [ADVAPI32.@]
1597  *
1598  * Get information about a service.
1599  *
1600  * PARAMS
1601  *   hService       [I] Handle to service to get information about
1602  *   InfoLevel      [I] Level of information to get
1603  *   lpBuffer       [O] Destination for requested information
1604  *   cbBufSize      [I] Size of lpBuffer in bytes
1605  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1606  *
1607  * RETURNS
1608  *  Success: TRUE
1609  *  FAILURE: FALSE
1610  */
1611 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1612                         LPBYTE lpBuffer, DWORD cbBufSize,
1613                         LPDWORD pcbBytesNeeded)
1614 {
1615     FIXME("stub\n");
1616     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1617     return FALSE;
1618 }
1619
1620 /******************************************************************************
1621  * QueryServiceConfigA [ADVAPI32.@]
1622  */
1623 BOOL WINAPI 
1624 QueryServiceConfigA( SC_HANDLE hService,
1625                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1626                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1627 {
1628     static const CHAR szDisplayName[] = "DisplayName";
1629     static const CHAR szType[] = "Type";
1630     static const CHAR szStart[] = "Start";
1631     static const CHAR szError[] = "ErrorControl";
1632     static const CHAR szImagePath[] = "ImagePath";
1633     static const CHAR szGroup[] = "Group";
1634     static const CHAR szDependencies[] = "Dependencies";
1635     struct sc_service *hsvc;
1636     HKEY hKey;
1637     CHAR str_buffer[ MAX_PATH ];
1638     LONG r;
1639     DWORD type, val, sz, total, n;
1640     LPBYTE p;
1641
1642     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1643            cbBufSize, pcbBytesNeeded);
1644
1645     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1646     if (!hsvc)
1647     {
1648         SetLastError( ERROR_INVALID_HANDLE );
1649         return FALSE;
1650     }
1651     hKey = hsvc->hkey;
1652
1653     /* calculate the size required first */
1654     total = sizeof (QUERY_SERVICE_CONFIGA);
1655
1656     sz = sizeof(str_buffer);
1657     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1658     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1659     {
1660         sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1661         if( 0 == sz ) return FALSE;
1662
1663         total += sz;
1664     }
1665     else
1666     {
1667         /* FIXME: set last error */
1668         return FALSE;
1669     }
1670
1671     sz = 0;
1672     r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1673     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1674         total += sz;
1675
1676     sz = 0;
1677     r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1678     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1679         total += sz;
1680
1681     sz = 0;
1682     r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1683     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1684         total += sz;
1685
1686     sz = 0;
1687     r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1688     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1689         total += sz;
1690
1691     *pcbBytesNeeded = total;
1692
1693     /* if there's not enough memory, return an error */
1694     if( total > cbBufSize )
1695     {
1696         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1697         return FALSE;
1698     }
1699
1700     ZeroMemory( lpServiceConfig, total );
1701
1702     sz = sizeof val;
1703     r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1704     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1705         lpServiceConfig->dwServiceType = val;
1706
1707     sz = sizeof val;
1708     r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1709     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1710         lpServiceConfig->dwStartType = val;
1711
1712     sz = sizeof val;
1713     r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1714     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1715         lpServiceConfig->dwErrorControl = val;
1716
1717     /* now do the strings */
1718     p = (LPBYTE) &lpServiceConfig[1];
1719     n = total - sizeof (QUERY_SERVICE_CONFIGA);
1720
1721     sz = sizeof(str_buffer);
1722     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1723     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1724     {
1725         sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1726         if( 0 == sz || sz > n ) return FALSE;
1727
1728         lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1729         p += sz;
1730         n -= sz;
1731     }
1732     else
1733     {
1734         /* FIXME: set last error */
1735         return FALSE;
1736     }
1737
1738     sz = n;
1739     r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1740     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1741     {
1742         lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1743         p += sz;
1744         n -= sz;
1745     }
1746
1747     sz = n;
1748     r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1749     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1750     {
1751         lpServiceConfig->lpDependencies = (LPSTR) p;
1752         p += sz;
1753         n -= sz;
1754     }
1755
1756     if( n < 0 )
1757         ERR("Buffer overflow!\n");
1758
1759     TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1760     TRACE("Group      = %s\n", lpServiceConfig->lpLoadOrderGroup );
1761
1762     return TRUE;
1763 }
1764
1765 /******************************************************************************
1766  * QueryServiceConfigW [ADVAPI32.@]
1767  */
1768 BOOL WINAPI 
1769 QueryServiceConfigW( SC_HANDLE hService,
1770                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1771                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1772 {
1773     WCHAR str_buffer[ MAX_PATH ];
1774     LONG r;
1775     DWORD type, val, sz, total, n;
1776     LPBYTE p;
1777     HKEY hKey;
1778     struct sc_service *hsvc;
1779
1780     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1781            cbBufSize, pcbBytesNeeded);
1782
1783     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1784     if (!hsvc)
1785     {
1786         SetLastError( ERROR_INVALID_HANDLE );
1787         return FALSE;
1788     }
1789     hKey = hsvc->hkey;
1790
1791     /* calculate the size required first */
1792     total = sizeof (QUERY_SERVICE_CONFIGW);
1793
1794     sz = sizeof(str_buffer);
1795     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1796     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1797     {
1798         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1799         if( 0 == sz ) return FALSE;
1800
1801         total += sizeof(WCHAR) * sz;
1802     }
1803     else
1804     {
1805        /* FIXME: set last error */
1806        return FALSE;
1807     }
1808
1809     sz = 0;
1810     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1811     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1812         total += sz;
1813
1814     sz = 0;
1815     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1816     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1817         total += sz;
1818     else
1819         total += sizeof(WCHAR);
1820
1821     sz = 0;
1822     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1823     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1824         total += sz;
1825
1826     sz = 0;
1827     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1828     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1829         total += sz;
1830
1831     *pcbBytesNeeded = total;
1832
1833     /* if there's not enough memory, return an error */
1834     if( total > cbBufSize )
1835     {
1836         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1837         return FALSE;
1838     }
1839
1840     ZeroMemory( lpServiceConfig, total );
1841
1842     sz = sizeof val;
1843     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1844     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1845         lpServiceConfig->dwServiceType = val;
1846
1847     sz = sizeof val;
1848     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1849     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1850         lpServiceConfig->dwStartType = val;
1851
1852     sz = sizeof val;
1853     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1854     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1855         lpServiceConfig->dwErrorControl = val;
1856
1857     /* now do the strings */
1858     p = (LPBYTE) &lpServiceConfig[1];
1859     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1860
1861     sz = sizeof(str_buffer);
1862     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1863     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1864     {
1865         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1866         sz *= sizeof(WCHAR);
1867         if( 0 == sz || sz > n ) return FALSE;
1868
1869         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1870         p += sz;
1871         n -= sz;
1872     }
1873     else
1874     {
1875        /* FIXME: set last error */
1876        return FALSE;
1877     }
1878
1879     sz = n;
1880     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1881     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1882     {
1883         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1884         p += sz;
1885         n -= sz;
1886     }
1887
1888     sz = n;
1889     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1890     lpServiceConfig->lpDependencies = (LPWSTR) p;
1891     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1892     {
1893         p += sz;
1894         n -= sz;
1895     }
1896     else
1897     {
1898         *(WCHAR *) p = 0;
1899         p += sizeof(WCHAR);
1900         n -= sizeof(WCHAR);
1901     }
1902
1903     if( n < 0 )
1904         ERR("Buffer overflow!\n");
1905
1906     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1907     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1908
1909     return TRUE;
1910 }
1911
1912 /******************************************************************************
1913  * EnumServicesStatusA [ADVAPI32.@]
1914  */
1915 BOOL WINAPI
1916 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1917                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1918                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1919                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1920 {
1921     FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1922           dwServiceType, dwServiceState, lpServices, cbBufSize,
1923           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1924     SetLastError (ERROR_ACCESS_DENIED);
1925     return FALSE;
1926 }
1927
1928 /******************************************************************************
1929  * EnumServicesStatusW [ADVAPI32.@]
1930  */
1931 BOOL WINAPI
1932 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1933                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1934                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1935                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1936 {
1937     FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1938           dwServiceType, dwServiceState, lpServices, cbBufSize,
1939           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1940     SetLastError (ERROR_ACCESS_DENIED);
1941     return FALSE;
1942 }
1943
1944 /******************************************************************************
1945  * GetServiceKeyNameA [ADVAPI32.@]
1946  */
1947 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1948                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1949 {
1950     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1951     return FALSE;
1952 }
1953
1954 /******************************************************************************
1955  * GetServiceKeyNameW [ADVAPI32.@]
1956  */
1957 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1958                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1959 {
1960     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1961     return FALSE;
1962 }
1963
1964 /******************************************************************************
1965  * QueryServiceLockStatusA [ADVAPI32.@]
1966  */
1967 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1968                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1969                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1970 {
1971     FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1972
1973     return FALSE;
1974 }
1975
1976 /******************************************************************************
1977  * QueryServiceLockStatusW [ADVAPI32.@]
1978  */
1979 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1980                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1981                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1982 {
1983     FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1984
1985     return FALSE;
1986 }
1987
1988 /******************************************************************************
1989  * GetServiceDisplayNameA  [ADVAPI32.@]
1990  */
1991 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1992   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1993 {
1994     FIXME("%p %s %p %p\n", hSCManager,
1995           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1996     return FALSE;
1997 }
1998
1999 /******************************************************************************
2000  * GetServiceDisplayNameW  [ADVAPI32.@]
2001  */
2002 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2003   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2004 {
2005     FIXME("%p %s %p %p\n", hSCManager,
2006           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2007     return FALSE;
2008 }
2009
2010 /******************************************************************************
2011  * ChangeServiceConfigW  [ADVAPI32.@]
2012  */
2013 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2014   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2015   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2016   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2017 {
2018     struct reg_value val[10];
2019     struct sc_service *hsvc;
2020     DWORD r = ERROR_SUCCESS;
2021     HKEY hKey;
2022     int n = 0;
2023
2024     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2025           hService, dwServiceType, dwStartType, dwErrorControl, 
2026           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2027           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2028           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2029
2030     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2031     if (!hsvc)
2032     {
2033         SetLastError( ERROR_INVALID_HANDLE );
2034         return FALSE;
2035     }
2036     hKey = hsvc->hkey;
2037
2038     if( dwServiceType != SERVICE_NO_CHANGE )
2039         service_set_dword( &val[n++], szType, &dwServiceType );
2040
2041     if( dwStartType != SERVICE_NO_CHANGE )
2042         service_set_dword( &val[n++], szStart, &dwStartType );
2043
2044     if( dwErrorControl != SERVICE_NO_CHANGE )
2045         service_set_dword( &val[n++], szError, &dwErrorControl );
2046
2047     if( lpBinaryPathName )
2048         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2049
2050     if( lpLoadOrderGroup )
2051         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2052
2053     if( lpDependencies )
2054         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2055
2056     if( lpPassword )
2057         FIXME("ignoring password\n");
2058
2059     if( lpServiceStartName )
2060         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2061
2062     r = service_write_values( hsvc->hkey, val, n );
2063
2064     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2065 }
2066
2067 /******************************************************************************
2068  * ChangeServiceConfigA  [ADVAPI32.@]
2069  */
2070 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2071   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2072   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2073   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2074 {
2075     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2076     LPWSTR wServiceStartName, wPassword, wDisplayName;
2077     BOOL r;
2078
2079     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2080           hService, dwServiceType, dwStartType, dwErrorControl, 
2081           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2082           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2083           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2084
2085     wBinaryPathName = SERV_dup( lpBinaryPathName );
2086     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2087     wDependencies = SERV_dupmulti( lpDependencies );
2088     wServiceStartName = SERV_dup( lpServiceStartName );
2089     wPassword = SERV_dup( lpPassword );
2090     wDisplayName = SERV_dup( lpDisplayName );
2091
2092     r = ChangeServiceConfigW( hService, dwServiceType,
2093             dwStartType, dwErrorControl, wBinaryPathName,
2094             wLoadOrderGroup, lpdwTagId, wDependencies,
2095             wServiceStartName, wPassword, wDisplayName);
2096
2097     SERV_free( wBinaryPathName );
2098     SERV_free( wLoadOrderGroup );
2099     SERV_free( wDependencies );
2100     SERV_free( wServiceStartName );
2101     SERV_free( wPassword );
2102     SERV_free( wDisplayName );
2103
2104     return r;
2105 }
2106
2107 /******************************************************************************
2108  * ChangeServiceConfig2A  [ADVAPI32.@]
2109  */
2110 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2111     LPVOID lpInfo)
2112 {
2113     BOOL r = FALSE;
2114
2115     TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2116
2117     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2118     {
2119         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2120         SERVICE_DESCRIPTIONW sdw;
2121
2122         sdw.lpDescription = SERV_dup( sd->lpDescription );
2123
2124         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2125
2126         SERV_free( sdw.lpDescription );
2127     }
2128     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2129     {
2130         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2131         SERVICE_FAILURE_ACTIONSW faw;
2132
2133         faw.dwResetPeriod = fa->dwResetPeriod;
2134         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2135         faw.lpCommand = SERV_dup( fa->lpCommand );
2136         faw.cActions = fa->cActions;
2137         faw.lpsaActions = fa->lpsaActions;
2138
2139         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2140
2141         SERV_free( faw.lpRebootMsg );
2142         SERV_free( faw.lpCommand );
2143     }
2144     else
2145         SetLastError( ERROR_INVALID_PARAMETER );
2146
2147     return r;
2148 }
2149
2150 /******************************************************************************
2151  * ChangeServiceConfig2W  [ADVAPI32.@]
2152  */
2153 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2154     LPVOID lpInfo)
2155 {
2156     HKEY hKey;
2157     struct sc_service *hsvc;
2158
2159     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2160     if (!hsvc)
2161     {
2162         SetLastError( ERROR_INVALID_HANDLE );
2163         return FALSE;
2164     }
2165     hKey = hsvc->hkey;
2166
2167     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2168     {
2169         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2170         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2171         if (sd->lpDescription)
2172         {
2173             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2174             if (sd->lpDescription[0] == 0)
2175                 RegDeleteValueW(hKey,szDescription);
2176             else
2177                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2178                                         (LPVOID)sd->lpDescription,
2179                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2180         }
2181     }
2182     else   
2183         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2184     return TRUE;
2185 }
2186
2187 /******************************************************************************
2188  * QueryServiceObjectSecurity [ADVAPI32.@]
2189  */
2190 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2191        SECURITY_INFORMATION dwSecurityInformation,
2192        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2193        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2194 {
2195     PACL pACL = NULL;
2196
2197     FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2198           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2199
2200     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2201
2202     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2203     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2204     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2205     return TRUE;
2206 }
2207
2208 /******************************************************************************
2209  * SetServiceObjectSecurity [ADVAPI32.@]
2210  */
2211 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2212        SECURITY_INFORMATION dwSecurityInformation,
2213        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2214 {
2215     FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2216     return TRUE;
2217 }
2218
2219 /******************************************************************************
2220  * SetServiceBits [ADVAPI32.@]
2221  */
2222 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2223         DWORD dwServiceBits,
2224         BOOL bSetBitsOn,
2225         BOOL bUpdateImmediately)
2226 {
2227     FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2228           bSetBitsOn, bUpdateImmediately);
2229     return TRUE;
2230 }