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