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