wordpad: Removed spaces between dots in ellipses for english menu text.
[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     if (bufpos - (LPBYTE)lpServiceConfig > cbBufSize)
1603         ERR("Buffer overflow!\n");
1604
1605     TRACE("Image path           = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1606     TRACE("Group                = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1607     TRACE("Dependencies         = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1608     TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1609     TRACE("Display name         = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1610
1611     return TRUE;
1612 }
1613
1614 /******************************************************************************
1615  * QueryServiceConfig2A [ADVAPI32.@]
1616  *
1617  * Note
1618  *   observed under win2k:
1619  *   The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1620  *   required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1621  */
1622 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1623                                  DWORD size, LPDWORD needed)
1624 {
1625     BOOL ret;
1626     LPBYTE bufferW = NULL;
1627
1628     if(buffer && size)
1629         bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1630
1631     ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1632     if(!ret) goto cleanup;
1633
1634     switch(dwLevel) {
1635         case SERVICE_CONFIG_DESCRIPTION:
1636             {   LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1637                 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1638                 if (configW->lpDescription) {
1639                     DWORD sz;
1640                     configA->lpDescription = (LPSTR)(configA + 1);
1641                     sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1642                              configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1643                     if (!sz) {
1644                         FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1645                         ret = FALSE;
1646                         configA->lpDescription = NULL;
1647                     }
1648                 }
1649                 else configA->lpDescription = NULL;
1650             }
1651         break;
1652         default:
1653             FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1654             ret = FALSE;
1655     }
1656
1657 cleanup:
1658     HeapFree( GetProcessHeap(), 0, bufferW);
1659     return ret;
1660 }
1661
1662 /******************************************************************************
1663  * QueryServiceConfig2W [ADVAPI32.@]
1664  */
1665 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1666                                  DWORD size, LPDWORD needed)
1667 {
1668     DWORD sz, type;
1669     HKEY hKey;
1670     LONG r;
1671     struct sc_service *hsvc;
1672
1673     if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1674         if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
1675            (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
1676            (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
1677            (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
1678            (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
1679            (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
1680             FIXME("Level %d not implemented\n", dwLevel);
1681         SetLastError(ERROR_INVALID_LEVEL);
1682         return FALSE;
1683     }
1684     if(!needed || (!buffer && size)) {
1685         SetLastError(ERROR_INVALID_ADDRESS);
1686         return FALSE;
1687     }
1688
1689     TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1690
1691     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1692     if (!hsvc)
1693     {
1694         SetLastError(ERROR_INVALID_HANDLE);
1695         return FALSE;
1696     }
1697     hKey = hsvc->hkey;
1698
1699     switch(dwLevel) {
1700         case SERVICE_CONFIG_DESCRIPTION: {
1701             static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1702             LPSERVICE_DESCRIPTIONW config = (LPSERVICE_DESCRIPTIONW) buffer;
1703             LPBYTE strbuf = NULL;
1704             *needed = sizeof (SERVICE_DESCRIPTIONW);
1705             sz = size - *needed;
1706             if(config && (*needed <= size))
1707                 strbuf = (LPBYTE) (config + 1);
1708             r = RegQueryValueExW( hKey, szDescription, 0, &type, strbuf, &sz );
1709             if((r == ERROR_SUCCESS) && ( type != REG_SZ)) {
1710                 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type);
1711                 return FALSE;
1712             }
1713             *needed += sz;
1714             if(config) {
1715                 if(r == ERROR_SUCCESS)
1716                     config->lpDescription = (LPWSTR) (config + 1);
1717                 else
1718                     config->lpDescription = NULL;
1719             }
1720         }
1721         break;
1722     }
1723     if(*needed > size)
1724         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1725
1726     return (*needed <= size);
1727 }
1728
1729 /******************************************************************************
1730  * EnumServicesStatusA [ADVAPI32.@]
1731  */
1732 BOOL WINAPI
1733 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1734                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1735                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1736                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1737 {
1738     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1739           dwServiceType, dwServiceState, lpServices, cbBufSize,
1740           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1741     SetLastError (ERROR_ACCESS_DENIED);
1742     return FALSE;
1743 }
1744
1745 /******************************************************************************
1746  * EnumServicesStatusW [ADVAPI32.@]
1747  */
1748 BOOL WINAPI
1749 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1750                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1751                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1752                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1753 {
1754     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1755           dwServiceType, dwServiceState, lpServices, cbBufSize,
1756           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1757     SetLastError (ERROR_ACCESS_DENIED);
1758     return FALSE;
1759 }
1760
1761 /******************************************************************************
1762  * EnumServicesStatusExA [ADVAPI32.@]
1763  */
1764 BOOL WINAPI
1765 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1766                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1767                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1768 {
1769     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1770           dwServiceType, dwServiceState, lpServices, cbBufSize,
1771           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
1772     *lpServicesReturned = 0;
1773     SetLastError (ERROR_ACCESS_DENIED);
1774     return FALSE;
1775 }
1776
1777 /******************************************************************************
1778  * EnumServicesStatusExW [ADVAPI32.@]
1779  */
1780 BOOL WINAPI
1781 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1782                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1783                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1784 {
1785     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1786           dwServiceType, dwServiceState, lpServices, cbBufSize,
1787           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
1788     SetLastError (ERROR_ACCESS_DENIED);
1789     return FALSE;
1790 }
1791
1792 /******************************************************************************
1793  * GetServiceKeyNameA [ADVAPI32.@]
1794  */
1795 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1796                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1797 {
1798     LPWSTR lpDisplayNameW, lpServiceNameW;
1799     DWORD sizeW;
1800     BOOL ret = FALSE;
1801
1802     TRACE("%p %s %p %p\n", hSCManager,
1803           debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1804
1805     lpDisplayNameW = SERV_dup(lpDisplayName);
1806     if (lpServiceName)
1807         lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1808     else
1809         lpServiceNameW = NULL;
1810
1811     sizeW = *lpcchBuffer;
1812     if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1813     {
1814         if (lpServiceName && *lpcchBuffer)
1815             lpServiceName[0] = 0;
1816         *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
1817         goto cleanup;
1818     }
1819
1820     if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1821                         *lpcchBuffer, NULL, NULL ))
1822     {
1823         if (*lpcchBuffer && lpServiceName)
1824             lpServiceName[0] = 0;
1825         *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1826         goto cleanup;
1827     }
1828
1829     /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1830     ret = TRUE;
1831
1832 cleanup:
1833     HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1834     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1835     return ret;
1836 }
1837
1838 /******************************************************************************
1839  * GetServiceKeyNameW [ADVAPI32.@]
1840  */
1841 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1842                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1843 {
1844     struct sc_manager *hscm;
1845     DWORD err;
1846
1847     TRACE("%p %s %p %p\n", hSCManager,
1848           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1849
1850     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1851     if (!hscm)
1852     {
1853         SetLastError(ERROR_INVALID_HANDLE);
1854         return FALSE;
1855     }
1856
1857     if (!lpDisplayName)
1858     {
1859         SetLastError(ERROR_INVALID_ADDRESS);
1860         return FALSE;
1861     }
1862
1863     __TRY
1864     {
1865         err = svcctl_GetServiceKeyNameW(hscm->hdr.server_handle,
1866                 lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
1867     }
1868     __EXCEPT(rpc_filter)
1869     {
1870         err = map_exception_code(GetExceptionCode());
1871     }
1872     __ENDTRY
1873
1874     if (err)
1875         SetLastError(err);
1876     return err == ERROR_SUCCESS;
1877 }
1878
1879 /******************************************************************************
1880  * QueryServiceLockStatusA [ADVAPI32.@]
1881  */
1882 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1883                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1884                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1885 {
1886     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1887
1888     return FALSE;
1889 }
1890
1891 /******************************************************************************
1892  * QueryServiceLockStatusW [ADVAPI32.@]
1893  */
1894 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1895                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1896                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1897 {
1898     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1899
1900     return FALSE;
1901 }
1902
1903 /******************************************************************************
1904  * GetServiceDisplayNameA  [ADVAPI32.@]
1905  */
1906 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1907   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1908 {
1909     LPWSTR lpServiceNameW, lpDisplayNameW;
1910     DWORD sizeW;
1911     BOOL ret = FALSE;
1912
1913     TRACE("%p %s %p %p\n", hSCManager,
1914           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1915
1916     lpServiceNameW = SERV_dup(lpServiceName);
1917     if (lpDisplayName)
1918         lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1919     else
1920         lpDisplayNameW = NULL;
1921
1922     sizeW = *lpcchBuffer;
1923     if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1924     {
1925         if (lpDisplayName && *lpcchBuffer)
1926             lpDisplayName[0] = 0;
1927         *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
1928         goto cleanup;
1929     }
1930
1931     if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1932                         *lpcchBuffer, NULL, NULL ))
1933     {
1934         if (*lpcchBuffer && lpDisplayName)
1935             lpDisplayName[0] = 0;
1936         *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1937         goto cleanup;
1938     }
1939
1940     /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1941      * (but if the function succeeded it means that is a good upper estimation of the size) */
1942     ret = TRUE;
1943
1944 cleanup:
1945     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1946     HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1947     return ret;
1948 }
1949
1950 /******************************************************************************
1951  * GetServiceDisplayNameW  [ADVAPI32.@]
1952  */
1953 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1954   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1955 {
1956     struct sc_manager *hscm;
1957     DWORD err;
1958
1959     TRACE("%p %s %p %p\n", hSCManager,
1960           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1961
1962     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1963     if (!hscm)
1964     {
1965         SetLastError(ERROR_INVALID_HANDLE);
1966         return FALSE;
1967     }
1968
1969     if (!lpServiceName)
1970     {
1971         SetLastError(ERROR_INVALID_ADDRESS);
1972         return FALSE;
1973     }
1974
1975     __TRY
1976     {
1977         err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
1978                 lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
1979     }
1980     __EXCEPT(rpc_filter)
1981     {
1982         err = map_exception_code(GetExceptionCode());
1983     }
1984     __ENDTRY
1985
1986     if (err)
1987         SetLastError(err);
1988     return err == ERROR_SUCCESS;
1989 }
1990
1991 /******************************************************************************
1992  * ChangeServiceConfigW  [ADVAPI32.@]
1993  */
1994 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1995   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1996   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1997   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1998 {
1999     struct sc_service *hsvc;
2000     DWORD cb_pwd;
2001     DWORD err;
2002
2003     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2004           hService, dwServiceType, dwStartType, dwErrorControl, 
2005           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2006           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2007           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2008
2009     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2010     if (!hsvc)
2011     {
2012         SetLastError( ERROR_INVALID_HANDLE );
2013         return FALSE;
2014     }
2015
2016     cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2017
2018     __TRY
2019     {
2020         err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
2021                 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2022                 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2023                 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2024     }
2025     __EXCEPT(rpc_filter)
2026     {
2027         err = map_exception_code(GetExceptionCode());
2028     }
2029     __ENDTRY
2030
2031     if (err != ERROR_SUCCESS)
2032         SetLastError(err);
2033
2034     return err == ERROR_SUCCESS;
2035 }
2036
2037 /******************************************************************************
2038  * ChangeServiceConfigA  [ADVAPI32.@]
2039  */
2040 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2041   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2042   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2043   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2044 {
2045     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2046     LPWSTR wServiceStartName, wPassword, wDisplayName;
2047     BOOL r;
2048
2049     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2050           hService, dwServiceType, dwStartType, dwErrorControl, 
2051           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2052           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2053           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2054
2055     wBinaryPathName = SERV_dup( lpBinaryPathName );
2056     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2057     wDependencies = SERV_dupmulti( lpDependencies );
2058     wServiceStartName = SERV_dup( lpServiceStartName );
2059     wPassword = SERV_dup( lpPassword );
2060     wDisplayName = SERV_dup( lpDisplayName );
2061
2062     r = ChangeServiceConfigW( hService, dwServiceType,
2063             dwStartType, dwErrorControl, wBinaryPathName,
2064             wLoadOrderGroup, lpdwTagId, wDependencies,
2065             wServiceStartName, wPassword, wDisplayName);
2066
2067     HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2068     HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2069     HeapFree( GetProcessHeap(), 0, wDependencies );
2070     HeapFree( GetProcessHeap(), 0, wServiceStartName );
2071     HeapFree( GetProcessHeap(), 0, wPassword );
2072     HeapFree( GetProcessHeap(), 0, wDisplayName );
2073
2074     return r;
2075 }
2076
2077 /******************************************************************************
2078  * ChangeServiceConfig2A  [ADVAPI32.@]
2079  */
2080 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2081     LPVOID lpInfo)
2082 {
2083     BOOL r = FALSE;
2084
2085     TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2086
2087     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2088     {
2089         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2090         SERVICE_DESCRIPTIONW sdw;
2091
2092         sdw.lpDescription = SERV_dup( sd->lpDescription );
2093
2094         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2095
2096         HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2097     }
2098     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2099     {
2100         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2101         SERVICE_FAILURE_ACTIONSW faw;
2102
2103         faw.dwResetPeriod = fa->dwResetPeriod;
2104         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2105         faw.lpCommand = SERV_dup( fa->lpCommand );
2106         faw.cActions = fa->cActions;
2107         faw.lpsaActions = fa->lpsaActions;
2108
2109         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2110
2111         HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2112         HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2113     }
2114     else
2115         SetLastError( ERROR_INVALID_PARAMETER );
2116
2117     return r;
2118 }
2119
2120 /******************************************************************************
2121  * ChangeServiceConfig2W  [ADVAPI32.@]
2122  */
2123 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2124     LPVOID lpInfo)
2125 {
2126     HKEY hKey;
2127     struct sc_service *hsvc;
2128
2129     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2130     if (!hsvc)
2131     {
2132         SetLastError( ERROR_INVALID_HANDLE );
2133         return FALSE;
2134     }
2135     hKey = hsvc->hkey;
2136
2137     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2138     {
2139         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2140         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2141         if (sd->lpDescription)
2142         {
2143             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2144             if (sd->lpDescription[0] == 0)
2145                 RegDeleteValueW(hKey,szDescription);
2146             else
2147                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2148                                         (LPVOID)sd->lpDescription,
2149                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2150         }
2151     }
2152     else   
2153         FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2154     return TRUE;
2155 }
2156
2157 /******************************************************************************
2158  * QueryServiceObjectSecurity [ADVAPI32.@]
2159  */
2160 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2161        SECURITY_INFORMATION dwSecurityInformation,
2162        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2163        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2164 {
2165     SECURITY_DESCRIPTOR descriptor;
2166     DWORD size;
2167     BOOL succ;
2168     ACL acl;
2169
2170     FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2171           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2172
2173     if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2174         FIXME("information %d not supported\n", dwSecurityInformation);
2175
2176     InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2177
2178     InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2179     SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2180
2181     size = cbBufSize;
2182     succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2183     *pcbBytesNeeded = size;
2184     return succ;
2185 }
2186
2187 /******************************************************************************
2188  * SetServiceObjectSecurity [ADVAPI32.@]
2189  */
2190 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2191        SECURITY_INFORMATION dwSecurityInformation,
2192        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2193 {
2194     FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2195     return TRUE;
2196 }
2197
2198 /******************************************************************************
2199  * SetServiceBits [ADVAPI32.@]
2200  */
2201 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2202         DWORD dwServiceBits,
2203         BOOL bSetBitsOn,
2204         BOOL bUpdateImmediately)
2205 {
2206     FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2207           bSetBitsOn, bUpdateImmediately);
2208     return TRUE;
2209 }
2210
2211 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2212 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2213 {
2214     LPHANDLER_FUNCTION func = context;
2215
2216     func( control );
2217     return ERROR_SUCCESS;
2218 }
2219
2220 /******************************************************************************
2221  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2222  */
2223 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2224 {
2225     return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2226 }
2227
2228 /******************************************************************************
2229  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2230  */
2231 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2232 {
2233     return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2234 }
2235
2236 /******************************************************************************
2237  * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2238  */
2239 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2240 {
2241     LPWSTR nameW;
2242     SERVICE_STATUS_HANDLE ret;
2243
2244     nameW = SERV_dup(name);
2245     ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2246     HeapFree( GetProcessHeap(), 0, nameW );
2247     return ret;
2248 }
2249
2250 /******************************************************************************
2251  * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2252  */
2253 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2254         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2255 {
2256     service_data *service;
2257     SC_HANDLE hService = 0;
2258     BOOL found = FALSE;
2259
2260     TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2261
2262     EnterCriticalSection( &service_cs );
2263     if ((service = find_service_by_name( lpServiceName )))
2264     {
2265         service->handler = lpHandlerProc;
2266         service->context = lpContext;
2267         hService = service->handle;
2268         found = TRUE;
2269     }
2270     LeaveCriticalSection( &service_cs );
2271
2272     if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2273
2274     return (SERVICE_STATUS_HANDLE)hService;
2275 }
2276
2277 /******************************************************************************
2278  * EnumDependentServicesA [ADVAPI32.@]
2279  */
2280 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2281                                     LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2282         LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2283 {
2284     FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2285           lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2286
2287     *lpServicesReturned = 0;
2288     return TRUE;
2289 }
2290
2291 /******************************************************************************
2292  * EnumDependentServicesW [ADVAPI32.@]
2293  */
2294 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2295                                     LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2296                                     LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2297 {
2298     FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2299           lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2300
2301     *lpServicesReturned = 0;
2302     return TRUE;
2303 }