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