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