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