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