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