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