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

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

Version: ~ [ wine-1.5.30 ] ~ [ wine-1.5.29 ] ~ [ wine-1.5.28 ] ~ [ wine-1.5.27 ] ~ [ wine-1.5.26 ] ~ [ wine-1.5.25 ] ~ [ wine-1.5.24 ] ~ [ wine-1.5.23 ] ~ [ wine-1.5.22 ] ~ [ wine-1.5.21 ] ~ [ wine-1.5.20 ] ~ [ wine-1.5.19 ] ~ [ wine-1.5.18 ] ~ [ wine-1.5.17 ] ~ [ wine-1.5.16 ] ~ [ wine-1.5.15 ] ~ [ wine-1.5.14 ] ~ [ wine-1.5.13 ] ~ [ wine-1.5.12 ] ~ [ wine-1.5.11 ] ~ [ wine-1.5.10 ] ~ [ wine-1.5.9 ] ~ [ wine-1.5.8 ] ~ [ wine-1.5.7 ] ~ [ wine-1.4.1 ] ~ [ wine-1.5.6 ] ~ [ wine-1.5.5 ] ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ 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     TRACE("Image path           = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1603     TRACE("Group                = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1604     TRACE("Dependencies         = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1605     TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1606     TRACE("Display name         = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1607 
1608     return TRUE;
1609 }
1610 
1611 /******************************************************************************
1612  * QueryServiceConfig2A [ADVAPI32.@]
1613  *
1614  * Note
1615  *   observed under win2k:
1616  *   The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1617  *   required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1618  */
1619 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1620                                  DWORD size, LPDWORD needed)
1621 {
1622     BOOL ret;
1623     LPBYTE bufferW = NULL;
1624 
1625     if(buffer && size)
1626         bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1627 
1628     ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1629     if(!ret) goto cleanup;
1630 
1631     switch(dwLevel) {
1632         case SERVICE_CONFIG_DESCRIPTION:
1633             {   LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1634                 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1635                 if (configW->lpDescription) {
1636                     DWORD sz;
1637                     configA->lpDescription = (LPSTR)(configA + 1);
1638                     sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1639                              configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1640                     if (!sz) {
1641                         FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1642                         ret = FALSE;
1643                         configA->lpDescription = NULL;
1644                     }
1645                 }
1646                 else configA->lpDescription = NULL;
1647             }
1648         break;
1649         default:
1650             FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1651             ret = FALSE;
1652     }
1653 
1654 cleanup:
1655     HeapFree( GetProcessHeap(), 0, bufferW);
1656     return ret;
1657 }
1658 
1659 /******************************************************************************
1660  * QueryServiceConfig2W [ADVAPI32.@]
1661  */
1662 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1663                                  DWORD size, LPDWORD needed)
1664 {
1665     DWORD sz, type;
1666     HKEY hKey;
1667     LONG r;
1668     struct sc_service *hsvc;
1669 
1670     if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1671         if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
1672            (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
1673            (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
1674            (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
1675            (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
1676            (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
1677             FIXME("Level %d not implemented\n", dwLevel);
1678         SetLastError(ERROR_INVALID_LEVEL);
1679         return FALSE;
1680     }
1681     if(!needed || (!buffer && size)) {
1682         SetLastError(ERROR_INVALID_ADDRESS);
1683         return FALSE;
1684     }
1685 
1686     TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1687 
1688     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1689     if (!hsvc)
1690     {
1691         SetLastError(ERROR_INVALID_HANDLE);
1692         return FALSE;
1693     }
1694     hKey = hsvc->hkey;
1695 
1696     switch(dwLevel) {
1697         case SERVICE_CONFIG_DESCRIPTION: {
1698             static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1699             LPSERVICE_DESCRIPTIONW config = (LPSERVICE_DESCRIPTIONW) buffer;
1700             LPBYTE strbuf = NULL;
1701             *needed = sizeof (SERVICE_DESCRIPTIONW);
1702             sz = size - *needed;
1703             if(config && (*needed <= size))
1704                 strbuf = (LPBYTE) (config + 1);
1705             r = RegQueryValueExW( hKey, szDescription, 0, &type, strbuf, &sz );
1706             if((r == ERROR_SUCCESS) && ( type != REG_SZ)) {
1707                 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type);
1708                 return FALSE;
1709             }
1710             *needed += sz;
1711             if(config) {
1712                 if(r == ERROR_SUCCESS)
1713                     config->lpDescription = (LPWSTR) (config + 1);
1714                 else
1715                     config->lpDescription = NULL;
1716             }
1717         }
1718         break;
1719     }
1720     if(*needed > size)
1721         SetLastError(ERROR_INSUFFICIENT_BUFFER);
1722 
1723     return (*needed <= size);
1724 }
1725 
1726 /******************************************************************************
1727  * EnumServicesStatusA [ADVAPI32.@]
1728  */
1729 BOOL WINAPI
1730 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1731                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1732                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1733                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1734 {
1735     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1736           dwServiceType, dwServiceState, lpServices, cbBufSize,
1737           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1738     SetLastError (ERROR_ACCESS_DENIED);
1739     return FALSE;
1740 }
1741 
1742 /******************************************************************************
1743  * EnumServicesStatusW [ADVAPI32.@]
1744  */
1745 BOOL WINAPI
1746 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1747                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1748                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1749                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1750 {
1751     FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1752           dwServiceType, dwServiceState, lpServices, cbBufSize,
1753           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
1754     SetLastError (ERROR_ACCESS_DENIED);
1755     return FALSE;
1756 }
1757 
1758 /******************************************************************************
1759  * EnumServicesStatusExA [ADVAPI32.@]
1760  */
1761 BOOL WINAPI
1762 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1763                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1764                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1765 {
1766     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1767           dwServiceType, dwServiceState, lpServices, cbBufSize,
1768           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_a(pszGroupName));
1769     if (lpServicesReturned) *lpServicesReturned = 0;
1770     SetLastError (ERROR_ACCESS_DENIED);
1771     return FALSE;
1772 }
1773 
1774 /******************************************************************************
1775  * EnumServicesStatusExW [ADVAPI32.@]
1776  */
1777 BOOL WINAPI
1778 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1779                       DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1780                       LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1781 {
1782     FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1783           dwServiceType, dwServiceState, lpServices, cbBufSize,
1784           pcbBytesNeeded, lpServicesReturned,  lpResumeHandle, debugstr_w(pszGroupName));
1785     SetLastError (ERROR_ACCESS_DENIED);
1786     return FALSE;
1787 }
1788 
1789 /******************************************************************************
1790  * GetServiceKeyNameA [ADVAPI32.@]
1791  */
1792 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1793                                 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1794 {
1795     LPWSTR lpDisplayNameW, lpServiceNameW;
1796     DWORD sizeW;
1797     BOOL ret = FALSE;
1798 
1799     TRACE("%p %s %p %p\n", hSCManager,
1800           debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1801 
1802     lpDisplayNameW = SERV_dup(lpDisplayName);
1803     if (lpServiceName)
1804         lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1805     else
1806         lpServiceNameW = NULL;
1807 
1808     sizeW = *lpcchBuffer;
1809     if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1810     {
1811         if (lpServiceName && *lpcchBuffer)
1812             lpServiceName[0] = 0;
1813         *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
1814         goto cleanup;
1815     }
1816 
1817     if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1818                         *lpcchBuffer, NULL, NULL ))
1819     {
1820         if (*lpcchBuffer && lpServiceName)
1821             lpServiceName[0] = 0;
1822         *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1823         goto cleanup;
1824     }
1825 
1826     /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1827     ret = TRUE;
1828 
1829 cleanup:
1830     HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1831     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1832     return ret;
1833 }
1834 
1835 /******************************************************************************
1836  * GetServiceKeyNameW [ADVAPI32.@]
1837  */
1838 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1839                                 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1840 {
1841     struct sc_manager *hscm;
1842     DWORD err;
1843 
1844     TRACE("%p %s %p %p\n", hSCManager,
1845           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1846 
1847     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1848     if (!hscm)
1849     {
1850         SetLastError(ERROR_INVALID_HANDLE);
1851         return FALSE;
1852     }
1853 
1854     if (!lpDisplayName)
1855     {
1856         SetLastError(ERROR_INVALID_ADDRESS);
1857         return FALSE;
1858     }
1859 
1860     __TRY
1861     {
1862         err = svcctl_GetServiceKeyNameW(hscm->hdr.server_handle,
1863                 lpDisplayName, lpServiceName, lpServiceName ? *lpcchBuffer : 0, lpcchBuffer);
1864     }
1865     __EXCEPT(rpc_filter)
1866     {
1867         err = map_exception_code(GetExceptionCode());
1868     }
1869     __ENDTRY
1870 
1871     if (err)
1872         SetLastError(err);
1873     return err == ERROR_SUCCESS;
1874 }
1875 
1876 /******************************************************************************
1877  * QueryServiceLockStatusA [ADVAPI32.@]
1878  */
1879 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1880                                      LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1881                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1882 {
1883     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1884 
1885     return FALSE;
1886 }
1887 
1888 /******************************************************************************
1889  * QueryServiceLockStatusW [ADVAPI32.@]
1890  */
1891 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1892                                      LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1893                                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1894 {
1895     FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1896 
1897     return FALSE;
1898 }
1899 
1900 /******************************************************************************
1901  * GetServiceDisplayNameA  [ADVAPI32.@]
1902  */
1903 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1904   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1905 {
1906     LPWSTR lpServiceNameW, lpDisplayNameW;
1907     DWORD sizeW;
1908     BOOL ret = FALSE;
1909 
1910     TRACE("%p %s %p %p\n", hSCManager,
1911           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1912 
1913     lpServiceNameW = SERV_dup(lpServiceName);
1914     if (lpDisplayName)
1915         lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1916     else
1917         lpDisplayNameW = NULL;
1918 
1919     sizeW = *lpcchBuffer;
1920     if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1921     {
1922         if (lpDisplayName && *lpcchBuffer)
1923             lpDisplayName[0] = 0;
1924         *lpcchBuffer = sizeW*2;  /* we can only provide an upper estimation of string length */
1925         goto cleanup;
1926     }
1927 
1928     if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1929                         *lpcchBuffer, NULL, NULL ))
1930     {
1931         if (*lpcchBuffer && lpDisplayName)
1932             lpDisplayName[0] = 0;
1933         *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1934         goto cleanup;
1935     }
1936 
1937     /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1938      * (but if the function succeeded it means that is a good upper estimation of the size) */
1939     ret = TRUE;
1940 
1941 cleanup:
1942     HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1943     HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1944     return ret;
1945 }
1946 
1947 /******************************************************************************
1948  * GetServiceDisplayNameW  [ADVAPI32.@]
1949  */
1950 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1951   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1952 {
1953     struct sc_manager *hscm;
1954     DWORD err;
1955 
1956     TRACE("%p %s %p %p\n", hSCManager,
1957           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1958 
1959     hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
1960     if (!hscm)
1961     {
1962         SetLastError(ERROR_INVALID_HANDLE);
1963         return FALSE;
1964     }
1965 
1966     if (!lpServiceName)
1967     {
1968         SetLastError(ERROR_INVALID_ADDRESS);
1969         return FALSE;
1970     }
1971 
1972     __TRY
1973     {
1974         err = svcctl_GetServiceDisplayNameW(hscm->hdr.server_handle,
1975                 lpServiceName, lpDisplayName, lpDisplayName ? *lpcchBuffer : 0, lpcchBuffer);
1976     }
1977     __EXCEPT(rpc_filter)
1978     {
1979         err = map_exception_code(GetExceptionCode());
1980     }
1981     __ENDTRY
1982 
1983     if (err)
1984         SetLastError(err);
1985     return err == ERROR_SUCCESS;
1986 }
1987 
1988 /******************************************************************************
1989  * ChangeServiceConfigW  [ADVAPI32.@]
1990  */
1991 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1992   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1993   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1994   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1995 {
1996     struct sc_service *hsvc;
1997     DWORD cb_pwd;
1998     DWORD err;
1999 
2000     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2001           hService, dwServiceType, dwStartType, dwErrorControl, 
2002           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2003           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2004           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2005 
2006     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2007     if (!hsvc)
2008     {
2009         SetLastError( ERROR_INVALID_HANDLE );
2010         return FALSE;
2011     }
2012 
2013     cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2014 
2015     __TRY
2016     {
2017         err = svcctl_ChangeServiceConfigW(hsvc->hdr.server_handle, dwServiceType,
2018                 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2019                 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2020                 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2021     }
2022     __EXCEPT(rpc_filter)
2023     {
2024         err = map_exception_code(GetExceptionCode());
2025     }
2026     __ENDTRY
2027 
2028     if (err != ERROR_SUCCESS)
2029         SetLastError(err);
2030 
2031     return err == ERROR_SUCCESS;
2032 }
2033 
2034 /******************************************************************************
2035  * ChangeServiceConfigA  [ADVAPI32.@]
2036  */
2037 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2038   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2039   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2040   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2041 {
2042     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2043     LPWSTR wServiceStartName, wPassword, wDisplayName;
2044     BOOL r;
2045 
2046     TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2047           hService, dwServiceType, dwStartType, dwErrorControl, 
2048           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2049           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2050           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2051 
2052     wBinaryPathName = SERV_dup( lpBinaryPathName );
2053     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2054     wDependencies = SERV_dupmulti( lpDependencies );
2055     wServiceStartName = SERV_dup( lpServiceStartName );
2056     wPassword = SERV_dup( lpPassword );
2057     wDisplayName = SERV_dup( lpDisplayName );
2058 
2059     r = ChangeServiceConfigW( hService, dwServiceType,
2060             dwStartType, dwErrorControl, wBinaryPathName,
2061             wLoadOrderGroup, lpdwTagId, wDependencies,
2062             wServiceStartName, wPassword, wDisplayName);
2063 
2064     HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2065     HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2066     HeapFree( GetProcessHeap(), 0, wDependencies );
2067     HeapFree( GetProcessHeap(), 0, wServiceStartName );
2068     HeapFree( GetProcessHeap(), 0, wPassword );
2069     HeapFree( GetProcessHeap(), 0, wDisplayName );
2070 
2071     return r;
2072 }
2073 
2074 /******************************************************************************
2075  * ChangeServiceConfig2A  [ADVAPI32.@]
2076  */
2077 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
2078     LPVOID lpInfo)
2079 {
2080     BOOL r = FALSE;
2081 
2082     TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2083 
2084     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2085     {
2086         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2087         SERVICE_DESCRIPTIONW sdw;
2088 
2089         sdw.lpDescription = SERV_dup( sd->lpDescription );
2090 
2091         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2092 
2093         HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2094     }
2095     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2096     {
2097         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2098         SERVICE_FAILURE_ACTIONSW faw;
2099 
2100         faw.dwResetPeriod = fa->dwResetPeriod;
2101         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2102         faw.lpCommand = SERV_dup( fa->lpCommand );
2103         faw.cActions = fa->cActions;
2104         faw.lpsaActions = fa->lpsaActions;
2105 
2106         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2107 
2108         HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2109         HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2110     }
2111     else
2112         SetLastError( ERROR_INVALID_PARAMETER );
2113 
2114     return r;
2115 }
2116 
2117 /******************************************************************************
2118  * ChangeServiceConfig2W  [ADVAPI32.@]
2119  */
2120 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
2121     LPVOID lpInfo)
2122 {
2123     HKEY hKey;
2124     struct sc_service *hsvc;
2125 
2126     hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2127     if (!hsvc)
2128     {
2129         SetLastError( ERROR_INVALID_HANDLE );
2130         return FALSE;
2131     }
2132     hKey = hsvc->hkey;
2133 
2134     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2135     {
2136         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2137         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2138         if (sd->lpDescription)
2139         {
2140             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2141             if (sd->lpDescription[0] == 0)
2142                 RegDeleteValueW(hKey,szDescription);
2143             else
2144                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2145                                         (LPVOID)sd->lpDescription,
2146                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2147         }
2148     }
2149     else   
2150         FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2151     return TRUE;
2152 }
2153 
2154 /******************************************************************************
2155  * QueryServiceObjectSecurity [ADVAPI32.@]
2156  */
2157 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2158        SECURITY_INFORMATION dwSecurityInformation,
2159        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2160        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2161 {
2162     SECURITY_DESCRIPTOR descriptor;
2163     DWORD size;
2164     BOOL succ;
2165     ACL acl;
2166 
2167     FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2168           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2169 
2170     if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2171         FIXME("information %d not supported\n", dwSecurityInformation);
2172 
2173     InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2174 
2175     InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2176     SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2177 
2178     size = cbBufSize;
2179     succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2180     *pcbBytesNeeded = size;
2181     return succ;
2182 }
2183 
2184 /******************************************************************************
2185  * SetServiceObjectSecurity [ADVAPI32.@]
2186  */
2187 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2188        SECURITY_INFORMATION dwSecurityInformation,
2189        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2190 {
2191     FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2192     return TRUE;
2193 }
2194 
2195 /******************************************************************************
2196  * SetServiceBits [ADVAPI32.@]
2197  */
2198 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2199         DWORD dwServiceBits,
2200         BOOL bSetBitsOn,
2201         BOOL bUpdateImmediately)
2202 {
2203     FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2204           bSetBitsOn, bUpdateImmediately);
2205     return TRUE;
2206 }
2207 
2208 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2209 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2210 {
2211     LPHANDLER_FUNCTION func = context;
2212 
2213     func( control );
2214     return ERROR_SUCCESS;
2215 }
2216 
2217 /******************************************************************************
2218  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2219  */
2220 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2221 {
2222     return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2223 }
2224 
2225 /******************************************************************************
2226  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2227  */
2228 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2229 {
2230     return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2231 }
2232 
2233 /******************************************************************************
2234  * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2235  */
2236 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2237 {
2238     LPWSTR nameW;
2239     SERVICE_STATUS_HANDLE ret;
2240 
2241     nameW = SERV_dup(name);
2242     ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2243     HeapFree( GetProcessHeap(), 0, nameW );
2244     return ret;
2245 }
2246 
2247 /******************************************************************************
2248  * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2249  */
2250 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2251         LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2252 {
2253     service_data *service;
2254     SC_HANDLE hService = 0;
2255     BOOL found = FALSE;
2256 
2257     TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2258 
2259     EnterCriticalSection( &service_cs );
2260     if ((service = find_service_by_name( lpServiceName )))
2261     {
2262         service->handler = lpHandlerProc;
2263         service->context = lpContext;
2264         hService = service->handle;
2265         found = TRUE;
2266     }
2267     LeaveCriticalSection( &service_cs );
2268 
2269     if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2270 
2271     return (SERVICE_STATUS_HANDLE)hService;
2272 }
2273 
2274 /******************************************************************************
2275  * EnumDependentServicesA [ADVAPI32.@]
2276  */
2277 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2278                                     LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2279         LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2280 {
2281     FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2282           lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2283 
2284     *lpServicesReturned = 0;
2285     return TRUE;
2286 }
2287 
2288 /******************************************************************************
2289  * EnumDependentServicesW [ADVAPI32.@]
2290  */
2291 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2292                                     LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2293                                     LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2294 {
2295     FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2296           lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2297 
2298     *lpServicesReturned = 0;
2299     return TRUE;
2300 }
2301 

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