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