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

~ [ 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.