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