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