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