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