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