~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/advapi32/service.c

Version: ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

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

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.