d3drm: Implement D3DRMCreateColorRGB.
[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, svc_type;
1490     HANDLE handles[2];
1491     BOOL r;
1492
1493     size = sizeof(svc_type);
1494     if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1495         svc_type = 0;
1496
1497     if (svc_type == SERVICE_KERNEL_DRIVER)
1498     {
1499         static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1500         DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1501
1502         if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1503         GetSystemDirectoryW( path, len );
1504         lstrcatW( path, winedeviceW );
1505         lstrcatW( path, hsvc->name );
1506     }
1507     else
1508     {
1509         /* read the executable path from the registry */
1510         size = 0;
1511         ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1512         if (ret!=ERROR_SUCCESS)
1513             return FALSE;
1514         str = HeapAlloc(GetProcessHeap(),0,size);
1515         ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1516         if (ret==ERROR_SUCCESS)
1517         {
1518             size = ExpandEnvironmentStringsW(str,NULL,0);
1519             path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1520             ExpandEnvironmentStringsW(str,path,size);
1521         }
1522         HeapFree(GetProcessHeap(),0,str);
1523         if (!path)
1524             return FALSE;
1525     }
1526
1527     /* wait for the process to start and set an event or terminate */
1528     handles[0] = service_get_event_handle( hsvc->name );
1529     ZeroMemory(&si, sizeof(STARTUPINFOW));
1530     si.cb = sizeof(STARTUPINFOW);
1531     r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1532     if (r)
1533     {
1534         if (ppid) *ppid = pi.dwProcessId;
1535
1536         handles[1] = pi.hProcess;
1537         ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1538         if(ret != WAIT_OBJECT_0)
1539         {
1540             SetLastError(ERROR_IO_PENDING);
1541             r = FALSE;
1542         }
1543
1544         CloseHandle( pi.hThread );
1545         CloseHandle( pi.hProcess );
1546     }
1547     CloseHandle( handles[0] );
1548     HeapFree(GetProcessHeap(),0,path);
1549     return r;
1550 }
1551
1552 static BOOL service_wait_for_startup(SC_HANDLE hService)
1553 {
1554     DWORD i;
1555     SERVICE_STATUS status;
1556     BOOL r = FALSE;
1557
1558     TRACE("%p\n", hService);
1559
1560     for (i=0; i<30; i++)
1561     {
1562         status.dwCurrentState = 0;
1563         r = QueryServiceStatus(hService, &status);
1564         if (!r)
1565             break;
1566         if (status.dwCurrentState == SERVICE_RUNNING)
1567         {
1568             TRACE("Service started successfully\n");
1569             break;
1570         }
1571         r = FALSE;
1572         Sleep(1000);
1573     }
1574     return r;
1575 }
1576
1577 /******************************************************************************
1578  * StartServiceW [ADVAPI32.@]
1579  * 
1580  * See StartServiceA.
1581  */
1582 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1583                           LPCWSTR *lpServiceArgVectors)
1584 {
1585     struct sc_service *hsvc;
1586     BOOL r = FALSE;
1587     DWORD dwResult, dwProcessId = 0;
1588     SC_LOCK hLock;
1589     HANDLE handle = INVALID_HANDLE_VALUE;
1590
1591     TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1592
1593     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1594     if (!hsvc)
1595     {
1596         SetLastError(ERROR_INVALID_HANDLE);
1597         return r;
1598     }
1599
1600     hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1601     if (!hLock)
1602         return r;
1603
1604     handle = service_open_pipe(hsvc->name);
1605     if (handle==INVALID_HANDLE_VALUE)
1606     {
1607         /* start the service process */
1608         if (service_start_process(hsvc, &dwProcessId))
1609             handle = service_open_pipe(hsvc->name);
1610     }
1611
1612     if (handle != INVALID_HANDLE_VALUE)
1613     {
1614         r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1615         CloseHandle(handle);
1616     }
1617
1618     handle = service_open_pipe(hsvc->name);
1619     if (handle != INVALID_HANDLE_VALUE)
1620     {
1621         service_set_processID(handle, dwProcessId, &dwResult);
1622         CloseHandle(handle);
1623     }
1624
1625     UnlockServiceDatabase( hLock );
1626
1627     TRACE("returning %d\n", r);
1628
1629     if (r)
1630         service_wait_for_startup(hService);
1631
1632     return r;
1633 }
1634
1635 /******************************************************************************
1636  * QueryServiceStatus [ADVAPI32.@]
1637  *
1638  * PARAMS
1639  *   hService        [I] Handle to service to get information about
1640  *   lpservicestatus [O] buffer to receive the status information for the service
1641  *
1642  */
1643 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1644                                LPSERVICE_STATUS lpservicestatus)
1645 {
1646     SERVICE_STATUS_PROCESS SvcStatusData;
1647     BOOL ret;
1648
1649     TRACE("%p %p\n", hService, lpservicestatus);
1650
1651     ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1652                                 sizeof(SERVICE_STATUS_PROCESS), NULL);
1653     if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1654     return ret;
1655 }
1656
1657
1658 /******************************************************************************
1659  * QueryServiceStatusEx [ADVAPI32.@]
1660  *
1661  * Get information about a service.
1662  *
1663  * PARAMS
1664  *   hService       [I] Handle to service to get information about
1665  *   InfoLevel      [I] Level of information to get
1666  *   lpBuffer       [O] Destination for requested information
1667  *   cbBufSize      [I] Size of lpBuffer in bytes
1668  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1669  *
1670  * RETURNS
1671  *  Success: TRUE
1672  *  FAILURE: FALSE
1673  */
1674 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1675                         LPBYTE lpBuffer, DWORD cbBufSize,
1676                         LPDWORD pcbBytesNeeded)
1677 {
1678     struct sc_service *hsvc;
1679     DWORD size, type, val;
1680     HANDLE pipe;
1681     LONG r;
1682     LPSERVICE_STATUS_PROCESS pSvcStatusData;
1683
1684     TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1685
1686     if (InfoLevel != SC_STATUS_PROCESS_INFO)
1687     {
1688         SetLastError( ERROR_INVALID_LEVEL);
1689         return FALSE;
1690     }
1691
1692     pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1693     if (pSvcStatusData == NULL)
1694     {
1695         SetLastError( ERROR_INVALID_PARAMETER);
1696         return FALSE;
1697     }
1698
1699     if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1700     {
1701         if( pcbBytesNeeded != NULL)
1702             *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1703
1704         SetLastError( ERROR_INSUFFICIENT_BUFFER);
1705         return FALSE;
1706     }
1707
1708     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1709     if (!hsvc)
1710     {
1711         SetLastError( ERROR_INVALID_HANDLE );
1712         return FALSE;
1713     }
1714
1715     pipe = service_open_pipe(hsvc->name);
1716     if (pipe != INVALID_HANDLE_VALUE)
1717     {
1718         r = service_get_status(pipe, pSvcStatusData);
1719         CloseHandle(pipe);
1720         if (r)
1721             return TRUE;
1722     }
1723
1724     TRACE("Failed to read service status\n");
1725
1726     /* read the service type from the registry */
1727     size = sizeof(val);
1728     r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1729     if (r != ERROR_SUCCESS || type != REG_DWORD)
1730         val = 0;
1731
1732     pSvcStatusData->dwServiceType = val;
1733     pSvcStatusData->dwCurrentState            = SERVICE_STOPPED;  /* stopped */
1734     pSvcStatusData->dwControlsAccepted        = 0;
1735     pSvcStatusData->dwWin32ExitCode           = ERROR_SERVICE_NEVER_STARTED;
1736     pSvcStatusData->dwServiceSpecificExitCode = 0;
1737     pSvcStatusData->dwCheckPoint              = 0;
1738     pSvcStatusData->dwWaitHint                = 0;
1739
1740     return TRUE;
1741 }
1742
1743 /******************************************************************************
1744  * QueryServiceConfigA [ADVAPI32.@]
1745  */
1746 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1747                                  DWORD size, LPDWORD needed )
1748 {
1749     DWORD n;
1750     LPSTR p, buffer;
1751     BOOL ret;
1752     QUERY_SERVICE_CONFIGW *configW;
1753
1754     TRACE("%p %p %d %p\n", hService, config, size, needed);
1755
1756     if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1757     {
1758         SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1759         return FALSE;
1760     }
1761     configW = (QUERY_SERVICE_CONFIGW *)buffer;
1762     ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1763     if (!ret) goto done;
1764
1765     config->dwServiceType      = configW->dwServiceType;
1766     config->dwStartType        = configW->dwStartType;
1767     config->dwErrorControl     = configW->dwErrorControl;
1768     config->lpBinaryPathName   = NULL;
1769     config->lpLoadOrderGroup   = NULL;
1770     config->dwTagId            = configW->dwTagId;
1771     config->lpDependencies     = NULL;
1772     config->lpServiceStartName = NULL;
1773     config->lpDisplayName      = NULL;
1774
1775     p = (LPSTR)(config + 1);
1776     n = size - sizeof(*config);
1777     ret = FALSE;
1778
1779 #define MAP_STR(str) \
1780     do { \
1781         if (configW->str) \
1782         { \
1783             DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1784             if (!sz) goto done; \
1785             config->str = p; \
1786             p += sz; \
1787             n -= sz; \
1788         } \
1789     } while (0)
1790
1791     MAP_STR( lpBinaryPathName );
1792     MAP_STR( lpLoadOrderGroup );
1793     MAP_STR( lpDependencies );
1794     MAP_STR( lpServiceStartName );
1795     MAP_STR( lpDisplayName );
1796 #undef MAP_STR
1797
1798     *needed = p - buffer;
1799     ret = TRUE;
1800
1801 done:
1802     HeapFree( GetProcessHeap(), 0, buffer );
1803     return ret;
1804 }
1805
1806 /******************************************************************************
1807  * QueryServiceConfigW [ADVAPI32.@]
1808  */
1809 BOOL WINAPI 
1810 QueryServiceConfigW( SC_HANDLE hService,
1811                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1812                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1813 {
1814     WCHAR str_buffer[ MAX_PATH ];
1815     LONG r;
1816     DWORD type, val, sz, total, n;
1817     LPBYTE p;
1818     HKEY hKey;
1819     struct sc_service *hsvc;
1820
1821     TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1822            cbBufSize, pcbBytesNeeded);
1823
1824     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1825     if (!hsvc)
1826     {
1827         SetLastError( ERROR_INVALID_HANDLE );
1828         return FALSE;
1829     }
1830     hKey = hsvc->hkey;
1831
1832     /* calculate the size required first */
1833     total = sizeof (QUERY_SERVICE_CONFIGW);
1834
1835     sz = sizeof(str_buffer);
1836     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1837     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1838     {
1839         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1840         if( 0 == sz ) return FALSE;
1841
1842         total += sizeof(WCHAR) * sz;
1843     }
1844     else
1845     {
1846        /* FIXME: set last error */
1847        return FALSE;
1848     }
1849
1850     sz = 0;
1851     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1852     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1853         total += sz;
1854
1855     sz = 0;
1856     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1857     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1858         total += sz;
1859     else
1860         total += sizeof(WCHAR);
1861
1862     sz = 0;
1863     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1864     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1865         total += sz;
1866
1867     sz = 0;
1868     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1869     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1870         total += sz;
1871
1872     *pcbBytesNeeded = total;
1873
1874     /* if there's not enough memory, return an error */
1875     if( total > cbBufSize )
1876     {
1877         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1878         return FALSE;
1879     }
1880
1881     ZeroMemory( lpServiceConfig, total );
1882
1883     sz = sizeof val;
1884     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1885     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1886         lpServiceConfig->dwServiceType = val;
1887
1888     sz = sizeof val;
1889     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1890     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1891         lpServiceConfig->dwStartType = val;
1892
1893     sz = sizeof val;
1894     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1895     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1896         lpServiceConfig->dwErrorControl = val;
1897
1898     /* now do the strings */
1899     p = (LPBYTE) &lpServiceConfig[1];
1900     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1901
1902     sz = sizeof(str_buffer);
1903     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1904     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1905     {
1906         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1907         sz *= sizeof(WCHAR);
1908         if( 0 == sz || sz > n ) return FALSE;
1909
1910         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1911         p += sz;
1912         n -= sz;
1913     }
1914     else
1915     {
1916        /* FIXME: set last error */
1917        return FALSE;
1918     }
1919
1920     sz = n;
1921     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1922     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1923     {
1924         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1925         p += sz;
1926         n -= sz;
1927     }
1928
1929     sz = n;
1930     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1931     lpServiceConfig->lpDependencies = (LPWSTR) p;
1932     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1933     {
1934         p += sz;
1935         n -= sz;
1936     }
1937     else
1938     {
1939         *(WCHAR *) p = 0;
1940         p += sizeof(WCHAR);
1941         n -= sizeof(WCHAR);
1942     }
1943
1944     if( n < 0 )
1945         ERR("Buffer overflow!\n");
1946
1947     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1948     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1949
1950     return TRUE;
1951 }
1952
1953 /******************************************************************************
1954  * EnumServicesStatusA [ADVAPI32.@]
1955  */
1956 BOOL WINAPI
1957 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1958                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1959                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1960                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1961 {
1962     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1963           dwServiceType, dwServiceState, lpServices, cbBufSize,
1964           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1965     SetLastError (ERROR_ACCESS_DENIED);
1966     return FALSE;
1967 }
1968
1969 /******************************************************************************
1970  * EnumServicesStatusW [ADVAPI32.@]
1971  */
1972 BOOL WINAPI
1973 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1974                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1975                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1976                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1977 {
1978     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1979           dwServiceType, dwServiceState, lpServices, cbBufSize,
1980           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1981     SetLastError (ERROR_ACCESS_DENIED);
1982     return FALSE;
1983 }
1984
1985 /******************************************************************************
1986  * EnumServicesStatusExA [ADVAPI32.@]
1987  */
1988 BOOL WINAPI
1989 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1990                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1991                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1992 {
1993     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1994           dwServiceType, dwServiceState, lpServices, cbBufSize,
1995           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
1996     SetLastError (ERROR_ACCESS_DENIED);
1997     return FALSE;
1998 }
1999
2000 /******************************************************************************
2001  * EnumServicesStatusExW [ADVAPI32.@]
2002  */
2003 BOOL WINAPI
2004 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2005                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2006                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2007 {
2008     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2009           dwServiceType, dwServiceState, lpServices, cbBufSize,
2010           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
2011     SetLastError (ERROR_ACCESS_DENIED);
2012     return FALSE;
2013 }
2014
2015 /******************************************************************************
2016  * GetServiceKeyNameA [ADVAPI32.@]
2017  */
2018 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2019                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2020 {
2021     FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2022     return FALSE;
2023 }
2024
2025 /******************************************************************************
2026  * GetServiceKeyNameW [ADVAPI32.@]
2027  */
2028 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2029                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2030 {
2031     FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2032     return FALSE;
2033 }
2034
2035 /******************************************************************************
2036  * QueryServiceLockStatusA [ADVAPI32.@]
2037  */
2038 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2039                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2040                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2041 {
2042     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2043
2044     return FALSE;
2045 }
2046
2047 /******************************************************************************
2048  * QueryServiceLockStatusW [ADVAPI32.@]
2049  */
2050 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2051                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2052                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2053 {
2054     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2055
2056     return FALSE;
2057 }
2058
2059 /******************************************************************************
2060  * GetServiceDisplayNameA  [ADVAPI32.@]
2061  */
2062 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2063   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2064 {
2065     struct sc_manager *hscm;
2066     DWORD type, size;
2067     LONG ret;
2068
2069     TRACE("%p %s %p %p\n", hSCManager,
2070           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2071
2072     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2073     if (!hscm)
2074     {
2075         SetLastError(ERROR_INVALID_HANDLE);
2076         return FALSE;
2077     }
2078
2079     size = *lpcchBuffer;
2080     ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2081     if (!ret && !lpDisplayName && size)
2082         ret = ERROR_MORE_DATA;
2083
2084     if (ret)
2085     {
2086         if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2087
2088         if (ret == ERROR_MORE_DATA)
2089         {
2090             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2091             *lpcchBuffer = size - 1;
2092         }
2093         else
2094             SetLastError(ret);
2095         return FALSE;
2096     }
2097     return TRUE;
2098 }
2099
2100 /******************************************************************************
2101  * GetServiceDisplayNameW  [ADVAPI32.@]
2102  */
2103 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2104   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2105 {
2106     struct sc_manager *hscm;
2107     DWORD type, size;
2108     LONG ret;
2109
2110     TRACE("%p %s %p %p\n", hSCManager,
2111           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2112
2113     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2114     if (!hscm)
2115     {
2116         SetLastError(ERROR_INVALID_HANDLE);
2117         return FALSE;
2118     }
2119
2120     size = *lpcchBuffer * sizeof(WCHAR);
2121     ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2122     if (!ret && !lpDisplayName && size)
2123         ret = ERROR_MORE_DATA;
2124
2125     if (ret)
2126     {
2127         if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2128
2129         if (ret == ERROR_MORE_DATA)
2130         {
2131             SetLastError(ERROR_INSUFFICIENT_BUFFER);
2132             *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2133         }
2134         else
2135             SetLastError(ret);
2136         return FALSE;
2137     }
2138     return TRUE;
2139 }
2140
2141 /******************************************************************************
2142  * ChangeServiceConfigW  [ADVAPI32.@]
2143  */
2144 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2145   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2146   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2147   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2148 {
2149     struct reg_value val[10];
2150     struct sc_service *hsvc;
2151     DWORD r = ERROR_SUCCESS;
2152     HKEY hKey;
2153     int n = 0;
2154
2155     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2156           hService, dwServiceType, dwStartType, dwErrorControl, 
2157           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2158           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2159           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2160
2161     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2162     if (!hsvc)
2163     {
2164         SetLastError( ERROR_INVALID_HANDLE );
2165         return FALSE;
2166     }
2167     hKey = hsvc->hkey;
2168
2169     if( dwServiceType != SERVICE_NO_CHANGE )
2170         service_set_dword( &val[n++], szType, &dwServiceType );
2171
2172     if( dwStartType != SERVICE_NO_CHANGE )
2173         service_set_dword( &val[n++], szStart, &dwStartType );
2174
2175     if( dwErrorControl != SERVICE_NO_CHANGE )
2176         service_set_dword( &val[n++], szError, &dwErrorControl );
2177
2178     if( lpBinaryPathName )
2179         service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2180
2181     if( lpLoadOrderGroup )
2182         service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2183
2184     if( lpDependencies )
2185         service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2186
2187     if( lpPassword )
2188         FIXME("ignoring password\n");
2189
2190     if( lpServiceStartName )
2191         service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2192
2193     r = service_write_values( hsvc->hkey, val, n );
2194
2195     return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2196 }
2197
2198 /******************************************************************************
2199  * ChangeServiceConfigA  [ADVAPI32.@]
2200  */
2201 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2202   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2203   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2204   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2205 {
2206     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2207     LPWSTR wServiceStartName, wPassword, wDisplayName;
2208     BOOL r;
2209
2210     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2211           hService, dwServiceType, dwStartType, dwErrorControl, 
2212           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2213           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2214           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2215
2216     wBinaryPathName = SERV_dup( lpBinaryPathName );
2217     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2218     wDependencies = SERV_dupmulti( lpDependencies );
2219     wServiceStartName = SERV_dup( lpServiceStartName );
2220     wPassword = SERV_dup( lpPassword );
2221     wDisplayName = SERV_dup( lpDisplayName );
2222
2223     r = ChangeServiceConfigW( hService, dwServiceType,
2224             dwStartType, dwErrorControl, wBinaryPathName,
2225             wLoadOrderGroup, lpdwTagId, wDependencies,
2226             wServiceStartName, wPassword, wDisplayName);
2227
2228     SERV_free( wBinaryPathName );
2229     SERV_free( wLoadOrderGroup );
2230     SERV_free( wDependencies );
2231     SERV_free( wServiceStartName );
2232     SERV_free( wPassword );
2233     SERV_free( wDisplayName );
2234
2235     return r;
2236 }
2237
2238 /******************************************************************************
2239  * ChangeServiceConfig2A  [ADVAPI32.@]
2240  */
2241 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2242     LPVOID lpInfo)
2243 {
2244     BOOL r = FALSE;
2245
2246     TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2247
2248     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2249     {
2250         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2251         SERVICE_DESCRIPTIONW sdw;
2252
2253         sdw.lpDescription = SERV_dup( sd->lpDescription );
2254
2255         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2256
2257         SERV_free( sdw.lpDescription );
2258     }
2259     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2260     {
2261         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2262         SERVICE_FAILURE_ACTIONSW faw;
2263
2264         faw.dwResetPeriod = fa->dwResetPeriod;
2265         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2266         faw.lpCommand = SERV_dup( fa->lpCommand );
2267         faw.cActions = fa->cActions;
2268         faw.lpsaActions = fa->lpsaActions;
2269
2270         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2271
2272         SERV_free( faw.lpRebootMsg );
2273         SERV_free( faw.lpCommand );
2274     }
2275     else
2276         SetLastError( ERROR_INVALID_PARAMETER );
2277
2278     return r;
2279 }
2280
2281 /******************************************************************************
2282  * ChangeServiceConfig2W  [ADVAPI32.@]
2283  */
2284 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2285     LPVOID lpInfo)
2286 {
2287     HKEY hKey;
2288     struct sc_service *hsvc;
2289
2290     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2291     if (!hsvc)
2292     {
2293         SetLastError( ERROR_INVALID_HANDLE );
2294         return FALSE;
2295     }
2296     hKey = hsvc->hkey;
2297
2298     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2299     {
2300         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2301         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2302         if (sd->lpDescription)
2303         {
2304             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2305             if (sd->lpDescription[0] == 0)
2306                 RegDeleteValueW(hKey,szDescription);
2307             else
2308                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2309                                         (LPVOID)sd->lpDescription,
2310                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2311         }
2312     }
2313     else   
2314         FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2315     return TRUE;
2316 }
2317
2318 /******************************************************************************
2319  * QueryServiceObjectSecurity [ADVAPI32.@]
2320  */
2321 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2322        SECURITY_INFORMATION dwSecurityInformation,
2323        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2324        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2325 {
2326     PACL pACL = NULL;
2327
2328     FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2329           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2330
2331     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2332
2333     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2334     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2335     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2336     return TRUE;
2337 }
2338
2339 /******************************************************************************
2340  * SetServiceObjectSecurity [ADVAPI32.@]
2341  */
2342 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2343        SECURITY_INFORMATION dwSecurityInformation,
2344        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2345 {
2346     FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2347     return TRUE;
2348 }
2349
2350 /******************************************************************************
2351  * SetServiceBits [ADVAPI32.@]
2352  */
2353 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2354         DWORD dwServiceBits,
2355         BOOL bSetBitsOn,
2356         BOOL bUpdateImmediately)
2357 {
2358     FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2359           bSetBitsOn, bUpdateImmediately);
2360     return TRUE;
2361 }
2362
2363 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2364         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2365 {
2366     FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2367     return 0;
2368 }
2369
2370 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2371         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2372 {
2373     service_data *service;
2374
2375     TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2376
2377     EnterCriticalSection( &service_cs );
2378     for(service = service_list; service; service = service->next)
2379         if(!strcmpW(lpServiceName, service->name))
2380             break;
2381     if (service)
2382     {
2383         service->handler.handler_ex = lpHandlerProc;
2384         service->context = lpContext;
2385         service->extended = TRUE;
2386     }
2387     LeaveCriticalSection( &service_cs );
2388
2389     return (SERVICE_STATUS_HANDLE)service;
2390 }