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