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