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