Check service database name in OpenSCManager().
[wine] / dlls / advapi32 / service.c
1 /*
2  * Win32 advapi functions
3  *
4  * Copyright 1995 Sven Verdoolaege
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <stdarg.h>
22 #include <string.h>
23 #include <time.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winsvc.h"
28 #include "winerror.h"
29 #include "winreg.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32 #include "winternl.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
35
36 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
37       'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
38       'S','e','r','v','i','c','e','s','\\',0 };
39 static const WCHAR  szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
40                                    'L','O','C','K',0};
41 static const WCHAR  szServiceShmemNameFmtW[] = {'A','D','V','A','P','I','_',
42                                                 'S','E','B','_','%','s',0};
43 static const WCHAR  szServiceDispEventNameFmtW[] = {'A','D','V','A','P','I','_',
44                                                     'D','I','S','P','_','%','s',0};
45 static const WCHAR  szServiceMutexNameFmtW[] = {'A','D','V','A','P','I','_',
46                                                 'M','U','X','_','%','s',0};
47 static const WCHAR  szServiceAckEventNameFmtW[] = {'A','D','V','A','P','I','_',
48                                                    'A','C','K','_','%','s',0};
49 static const WCHAR  szWaitServiceStartW[]  = {'A','D','V','A','P','I','_','W',
50                                               'a','i','t','S','e','r','v','i',
51                                               'c','e','S','t','a','r','t',0};
52
53 struct SEB              /* service environment block */
54 {                       /*   resides in service's shared memory object */
55     DWORD control_code;      /* service control code */
56     DWORD dispatcher_error;  /* set by dispatcher if it fails to invoke control handler */
57     SERVICE_STATUS status;
58     DWORD argc;
59     /* variable part of SEB contains service arguments */
60 };
61
62 static HANDLE dispatcher_event;  /* this is used by service thread to wakeup
63                                   * service control dispatcher when thread terminates */
64
65 static struct service_thread_data *service;  /* FIXME: this should be a list */
66
67 /******************************************************************************
68  * SC_HANDLEs
69  */
70
71 #define MAX_SERVICE_NAME 256
72
73 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
74
75 struct sc_handle;
76
77 struct sc_manager       /* SCM handle */
78 {
79     HKEY hkey_scm_db;   /* handle to services database in the registry */
80     LONG ref_count;     /* handle must remain alive until any related service */
81                         /* handle exists because DeleteService requires it */
82 };
83
84 struct sc_service       /* service handle */
85 {
86     HKEY hkey;          /* handle to service entry in the registry (under hkey_scm_db) */
87     struct sc_handle *sc_manager;  /* pointer to SCM handle */
88     WCHAR name[ MAX_SERVICE_NAME ];
89 };
90
91 struct sc_handle
92 {
93     SC_HANDLE_TYPE htype;
94     union
95     {
96         struct sc_manager manager;
97         struct sc_service service;
98     } u;
99 };
100
101 static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
102 {
103     struct sc_handle *retval;
104
105     retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
106     if( retval != NULL )
107     {
108         retval->htype = htype;
109     }
110     TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
111     return retval;
112 }
113
114 static void free_sc_handle( struct sc_handle* handle )
115 {
116     if( NULL == handle )
117         return;
118
119     switch( handle->htype )
120     {
121         case SC_HTYPE_MANAGER:
122         {
123             if( InterlockedDecrement( &handle->u.manager.ref_count ) )
124                 /* there are references to this handle */
125                 return;
126
127             if( handle->u.manager.hkey_scm_db )
128                 RegCloseKey( handle->u.manager.hkey_scm_db );
129             break;
130         }
131
132         case SC_HTYPE_SERVICE:
133         {
134             struct sc_handle *h = handle->u.service.sc_manager;
135
136             if( h )
137             {
138                 /* release SCM handle */
139                 if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
140                 {
141                     /* it's time to destroy SCM handle */
142                     if( h->u.manager.hkey_scm_db )
143                         RegCloseKey( h->u.manager.hkey_scm_db );
144                     
145                     TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
146                     
147                     HeapFree( GetProcessHeap(), 0, h );
148                 }
149             }
150             if( handle->u.service.hkey )
151                 RegCloseKey( handle->u.service.hkey );
152             break;
153         }
154     }
155
156     TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
157
158     HeapFree( GetProcessHeap(), 0, handle );
159 }
160
161 static void init_service_handle( struct sc_handle* handle,
162                                  struct sc_handle* sc_manager,
163                                  HKEY hKey, LPCWSTR lpServiceName )
164 {
165     /* init sc_service structure */
166     handle->u.service.hkey = hKey;
167     lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
168
169     /* add reference to SCM handle */
170     InterlockedIncrement( &sc_manager->u.manager.ref_count );
171     handle->u.service.sc_manager = sc_manager;
172 }
173
174 static inline LPWSTR SERV_dup( LPCSTR str )
175 {
176     UINT len;
177     LPWSTR wstr;
178
179     if( !str )
180         return NULL;
181     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
182     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
183     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
184     return wstr;
185 }
186
187 static inline LPWSTR SERV_dupmulti( LPCSTR str )
188 {
189     UINT len = 0, n = 0;
190     LPWSTR wstr;
191
192     if( !str )
193         return NULL;
194     do {
195         len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
196         n += (strlen( &str[n] ) + 1);
197     } while (str[n]);
198     len++;
199     n++;
200
201     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
202     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
203     return wstr;
204 }
205
206 static inline VOID SERV_free( LPWSTR wstr )
207 {
208     HeapFree( GetProcessHeap(), 0, wstr );
209 }
210
211 /******************************************************************************
212  * EnumServicesStatusA [ADVAPI32.@]
213  */
214 BOOL WINAPI
215 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
216                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
217                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
218                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
219 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
220                 dwServiceType, dwServiceState, lpServices, cbBufSize,
221                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
222         SetLastError (ERROR_ACCESS_DENIED);
223         return FALSE;
224 }
225
226 /******************************************************************************
227  * EnumServicesStatusW [ADVAPI32.@]
228  */
229 BOOL WINAPI
230 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
231                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
232                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
233                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
234 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
235                 dwServiceType, dwServiceState, lpServices, cbBufSize,
236                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
237         SetLastError (ERROR_ACCESS_DENIED);
238         return FALSE;
239 }
240
241 /******************************************************************************
242  * read_scm_lock_data
243  *
244  * helper function for service control dispatcher
245  *
246  * SCM database is locked by StartService;
247  * open global SCM lock object and read service name
248  */
249 static BOOL read_scm_lock_data( LPWSTR buffer )
250 {
251     HANDLE hLock;
252     LPWSTR argptr;
253
254     hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
255     if( NULL == hLock )
256     {
257         SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
258         return FALSE;
259     }
260     argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
261                             0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
262     if( NULL == argptr )
263     {
264         CloseHandle( hLock );
265         return FALSE;
266     }
267     strcpyW( buffer, argptr );
268     UnmapViewOfFile( argptr );
269     CloseHandle( hLock );
270     return TRUE;
271 }
272
273 /******************************************************************************
274  * open_seb_shmem
275  *
276  * helper function for service control dispatcher
277  */
278 static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
279 {
280     WCHAR object_name[ MAX_PATH ];
281     HANDLE hmem;
282     struct SEB *ret;
283
284     snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
285     hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
286     if( NULL == hmem )
287         return NULL;
288
289     ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
290     if( NULL == ret )
291         CloseHandle( hmem );
292     else
293         *hServiceShmem = hmem;
294     return ret;
295 }
296
297 /******************************************************************************
298  * build_arg_vectors
299  *
300  * helper function for start_new_service
301  *
302  * Allocate and initialize array of LPWSTRs to arguments in variable part
303  * of service environment block.
304  * First entry in the array is reserved for service name and not initialized.
305  */
306 static LPWSTR* build_arg_vectors( struct SEB* seb )
307 {
308     LPWSTR *ret;
309     LPWSTR argptr;
310     DWORD i;
311
312     ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
313     if( NULL == ret )
314         return NULL;
315
316     argptr = (LPWSTR) &seb[1];
317     for( i = 0; i < seb->argc; i++ )
318     {
319         ret[ 1 + i ] = argptr;
320         argptr += 1 + strlenW( argptr );
321     }
322     return ret;
323 }
324
325 /******************************************************************************
326  * service thread
327  */
328 struct service_thread_data
329 {
330     WCHAR service_name[ MAX_SERVICE_NAME ];
331     CHAR service_nameA[ MAX_SERVICE_NAME ];
332     LPSERVICE_MAIN_FUNCTIONW service_main;
333     DWORD argc;
334     LPWSTR *argv;
335     HANDLE hServiceShmem;
336     struct SEB *seb;
337     HANDLE thread_handle;
338     HANDLE mutex;            /* provides serialization of control request */
339     HANDLE ack_event;        /* control handler completion acknowledgement */
340     LPHANDLER_FUNCTION ctrl_handler;
341 };
342
343 static DWORD WINAPI service_thread( LPVOID arg )
344 {
345     struct service_thread_data *data = arg;
346
347     data->service_main( data->argc, data->argv );
348     SetEvent( dispatcher_event );
349     return 0;
350 }
351
352 /******************************************************************************
353  * dispose_service_thread_data
354  *
355  * helper function for service control dispatcher
356  */
357 static void dispose_service_thread_data( struct service_thread_data* thread_data )
358 {
359     if( thread_data->mutex ) CloseHandle( thread_data->mutex );
360     if( thread_data->ack_event ) CloseHandle( thread_data->ack_event );
361     if( thread_data->argv ) HeapFree( GetProcessHeap(), 0, thread_data->argv );
362     if( thread_data->seb ) UnmapViewOfFile( thread_data->seb );
363     if( thread_data->hServiceShmem ) CloseHandle( thread_data->hServiceShmem );
364     HeapFree( GetProcessHeap(), 0, thread_data );
365 }
366
367 /******************************************************************************
368  * start_new_service
369  *
370  * helper function for service control dispatcher
371  */
372 static struct service_thread_data*
373 start_new_service( LPSERVICE_MAIN_FUNCTIONW service_main, BOOL ascii )
374 {
375     struct service_thread_data *thread_data;
376     unsigned int i;
377     WCHAR object_name[ MAX_PATH ];
378
379     thread_data = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct service_thread_data) );
380     if( NULL == thread_data )
381         return NULL;
382
383     if( ! read_scm_lock_data( thread_data->service_name ) )
384     {
385         /* FIXME: Instead of exiting we allow
386            service to be executed as ordinary program.
387            This behaviour was specially introduced in the patch
388            submitted against revision 1.45 and so preserved here.
389          */
390         FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
391         service_main( 0, NULL );
392         HeapFree( GetProcessHeap(), 0, thread_data );
393         return NULL;
394     }
395
396     thread_data->seb = open_seb_shmem( thread_data->service_name, &thread_data->hServiceShmem );
397     if( NULL == thread_data->seb )
398         goto error;
399
400     thread_data->argv = build_arg_vectors( thread_data->seb );
401     if( NULL == thread_data->argv )
402         goto error;
403
404     thread_data->argv[0] = thread_data->service_name;
405     thread_data->argc = thread_data->seb->argc + 1;
406
407     if( ascii )
408     {
409         /* Convert the Unicode arg vectors back to ASCII;
410          * but we'll need unicode service name (argv[0]) for object names */
411         WideCharToMultiByte( CP_ACP, 0, thread_data->argv[0], -1,
412                              thread_data->service_nameA, MAX_SERVICE_NAME, NULL, NULL );
413         thread_data->argv[0] = (LPWSTR) thread_data->service_nameA;
414
415         for(i=1; i<thread_data->argc; i++)
416         {
417             LPWSTR src = thread_data->argv[i];
418             int len = WideCharToMultiByte( CP_ACP, 0, src, -1, NULL, 0, NULL, NULL );
419             LPSTR dest = HeapAlloc( GetProcessHeap(), 0, len );
420             if( NULL == dest )
421                 goto error;
422             WideCharToMultiByte( CP_ACP, 0, src, -1, dest, len, NULL, NULL );
423             /* copy converted string back  */
424             memcpy( src, dest, len );
425             HeapFree( GetProcessHeap(), 0, dest );
426         }
427     }
428
429     /* init status according to docs for StartService */
430     thread_data->seb->status.dwCurrentState = SERVICE_START_PENDING;
431     thread_data->seb->status.dwControlsAccepted = 0;
432     thread_data->seb->status.dwCheckPoint = 0;
433     thread_data->seb->status.dwWaitHint = 2000;
434
435     /* create service mutex; mutex is initially owned */
436     snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, thread_data->service_name );
437     thread_data->mutex = CreateMutexW( NULL, TRUE, object_name );
438     if( NULL == thread_data->mutex )
439         goto error;
440
441     if( ERROR_ALREADY_EXISTS == GetLastError() )
442     {
443         SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
444         goto error;
445     }
446
447     /* create service event */
448     snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, thread_data->service_name );
449     thread_data->ack_event = CreateEventW( NULL, FALSE, FALSE, object_name );
450     if( NULL == thread_data->ack_event )
451         goto error;
452
453     if( ERROR_ALREADY_EXISTS == GetLastError() )
454     {
455         SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
456         goto error;
457     }
458
459     /* create service thread in suspended state
460      * to avoid race while caller handles return value */
461     thread_data->service_main = service_main;
462     thread_data->thread_handle = CreateThread( NULL, 0, service_thread,
463                                                thread_data, CREATE_SUSPENDED, NULL );
464     if( thread_data->thread_handle )
465         return thread_data;
466
467 error:
468     dispose_service_thread_data( thread_data );
469     return FALSE;
470 }
471
472 /******************************************************************************
473  * service_ctrl_dispatcher
474  */
475 static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii )
476 {
477     WCHAR object_name[ MAX_PATH ];
478     HANDLE wait;
479
480     /* FIXME: if shared service, find entry by service name */
481
482     /* FIXME: move this into dispatcher loop */
483     service = start_new_service( servent->lpServiceProc, ascii );
484     if( NULL == service )
485         return FALSE;
486
487     ResumeThread( service->thread_handle );
488
489     /* create dispatcher event object */
490     /* FIXME: object_name should be based on executable image path because
491      * this object is common for all services in the process */
492     /* But what if own and shared services have the same executable? */
493     snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, service->service_name );
494     dispatcher_event = CreateEventW( NULL, FALSE, FALSE, object_name );
495     if( NULL == dispatcher_event )
496     {
497         dispose_service_thread_data( service );
498         return FALSE;
499     }
500
501     if( ERROR_ALREADY_EXISTS == GetLastError() )
502     {
503         SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
504         CloseHandle( dispatcher_event );
505         return FALSE;
506     }
507
508     /* ready to accept control requests */
509     ReleaseMutex( service->mutex );
510
511     /* signal for StartService */
512     wait = OpenSemaphoreW( SEMAPHORE_MODIFY_STATE, FALSE, szWaitServiceStartW );
513     if( wait )
514     {
515         ReleaseSemaphore( wait, 1, NULL );
516         CloseHandle( wait );
517     }
518
519     /* dispatcher loop */
520     for(;;)
521     {
522         DWORD ret;
523
524         WaitForSingleObject( dispatcher_event, INFINITE );
525
526         /* at first, look for terminated service thread
527          * FIXME: threads, if shared service */
528         if( !GetExitCodeThread( service->thread_handle, &ret ) )
529             ERR("Couldn't get thread exit code\n");
530         else if( ret != STILL_ACTIVE )
531         {
532             CloseHandle( service->thread_handle );
533             dispose_service_thread_data( service );
534             break;
535         }
536
537         /* look for control requests */
538         if( service->seb->control_code )
539         {
540             if( NULL == service->ctrl_handler )
541                 service->seb->dispatcher_error = ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
542             else
543             {
544                 service->ctrl_handler( service->seb->control_code );
545                 service->seb->dispatcher_error = 0;
546             }
547             service->seb->control_code = 0;
548             SetEvent( service->ack_event );
549         }
550
551         /* FIXME: if shared service, check SCM lock object;
552          * if exists, a new service should be started */
553     }
554
555     CloseHandle( dispatcher_event );
556     return TRUE;
557 }
558
559 /******************************************************************************
560  * StartServiceCtrlDispatcherA [ADVAPI32.@]
561  */
562 BOOL WINAPI
563 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
564 {
565     int count, i;
566     LPSERVICE_TABLE_ENTRYW ServiceTableW;
567     BOOL ret;
568
569     TRACE("(%p)\n", servent);
570
571     /* convert service table to unicode */
572     for( count = 0; servent[ count ].lpServiceName; )
573         count++;
574     ServiceTableW = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(SERVICE_TABLE_ENTRYW) );
575     if( NULL == ServiceTableW )
576         return FALSE;
577
578     for( i = 0; i < count; i++ )
579     {
580         ServiceTableW[ i ].lpServiceName = SERV_dup( servent[ i ].lpServiceName );
581         ServiceTableW[ i ].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONW) servent[ i ].lpServiceProc;
582     }
583     ServiceTableW[ count ].lpServiceName = NULL;
584     ServiceTableW[ count ].lpServiceProc = NULL;
585
586     /* start dispatcher */
587     ret = service_ctrl_dispatcher( ServiceTableW, TRUE );
588
589     /* free service table */
590     for( i = 0; i < count; i++ )
591         SERV_free( ServiceTableW[ i ].lpServiceName );
592     HeapFree( GetProcessHeap(), 0, ServiceTableW );
593     return ret;
594 }
595
596 /******************************************************************************
597  * StartServiceCtrlDispatcherW [ADVAPI32.@]
598  *
599  * PARAMS
600  *   servent []
601  */
602 BOOL WINAPI
603 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
604 {
605     TRACE("(%p)\n", servent);
606     return service_ctrl_dispatcher( servent, FALSE );
607 }
608
609 /******************************************************************************
610  * LockServiceDatabase  [ADVAPI32.@]
611  */
612 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
613 {
614     HANDLE ret;
615
616     TRACE("%p\n",hSCManager);
617
618     ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
619                               0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
620     if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
621     {
622         CloseHandle( ret );
623         ret = NULL;
624         SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
625     }
626
627     TRACE("returning %p\n", ret);
628
629     return ret;
630 }
631
632 /******************************************************************************
633  * UnlockServiceDatabase  [ADVAPI32.@]
634  */
635 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
636 {
637     TRACE("%p\n",ScLock);
638
639     return CloseHandle( (HANDLE) ScLock );
640 }
641
642 /******************************************************************************
643  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
644  */
645 SERVICE_STATUS_HANDLE WINAPI
646 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
647                              LPHANDLER_FUNCTION lpfHandler )
648 {
649     UNICODE_STRING lpServiceNameW;
650     SERVICE_STATUS_HANDLE ret;
651
652     RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
653     ret = RegisterServiceCtrlHandlerW( lpServiceNameW.Buffer, lpfHandler );
654     RtlFreeUnicodeString(&lpServiceNameW);
655     return ret;
656 }
657
658 /******************************************************************************
659  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
660  *
661  * PARAMS
662  *   lpServiceName []
663  *   lpfHandler    []
664  */
665 SERVICE_STATUS_HANDLE WINAPI
666 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
667                              LPHANDLER_FUNCTION lpfHandler )
668 {
669     /* FIXME: find service thread data by service name */
670
671     service->ctrl_handler = lpfHandler;
672     return 0xcacacafe;
673 }
674
675 /******************************************************************************
676  * SetServiceStatus [ADVAPI32.@]
677  *
678  * PARAMS
679  *   hService []
680  *   lpStatus []
681  */
682 BOOL WINAPI
683 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
684 {
685     DWORD r;
686
687     TRACE("\tType:%lx\n",lpStatus->dwServiceType);
688     TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
689     TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
690     TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
691     TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
692     TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
693     TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
694
695     /* FIXME: find service thread data by status handle */
696
697     /* acquire mutex; note that mutex may already be owned
698      * when service handles control request
699      */
700     r = WaitForSingleObject( service->mutex, 0 );
701     memcpy( &service->seb->status, lpStatus, sizeof(SERVICE_STATUS) );
702     if( WAIT_OBJECT_0 == r || WAIT_ABANDONED == r )
703         ReleaseMutex( service->mutex );
704     return TRUE;
705 }
706
707 /******************************************************************************
708  * OpenSCManagerA [ADVAPI32.@]
709  *
710  * Establish a connection to the service control manager and open its database.
711  *
712  * PARAMS
713  *   lpMachineName   [I] Pointer to machine name string
714  *   lpDatabaseName  [I] Pointer to database name string
715  *   dwDesiredAccess [I] Type of access
716  *
717  * RETURNS
718  *   Success: A Handle to the service control manager database
719  *   Failure: NULL
720  */
721 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
722                                  DWORD dwDesiredAccess )
723 {
724     UNICODE_STRING lpMachineNameW;
725     UNICODE_STRING lpDatabaseNameW;
726     SC_HANDLE ret;
727
728     RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
729     RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
730     ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
731     RtlFreeUnicodeString(&lpDatabaseNameW);
732     RtlFreeUnicodeString(&lpMachineNameW);
733     return ret;
734 }
735
736 /******************************************************************************
737  * OpenSCManagerW [ADVAPI32.@]
738  *
739  * See OpenSCManagerA.
740  */
741 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
742                                  DWORD dwDesiredAccess )
743 {
744     struct sc_handle *retval;
745     HKEY hReg;
746     LONG r;
747
748     TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
749           debugstr_w(lpDatabaseName), dwDesiredAccess);
750
751     if( lpDatabaseName )
752     {
753         if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
754         {
755             /* noop, all right */
756         }
757         else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
758         {
759             SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
760             return NULL;
761         }
762         else
763         {
764             SetLastError( ERROR_INVALID_NAME );
765             return NULL;
766         }
767     }
768
769     retval = alloc_sc_handle( SC_HTYPE_MANAGER );
770     if( NULL == retval ) return NULL;
771
772     retval->u.manager.ref_count = 1;
773
774     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
775     if (r!=ERROR_SUCCESS)
776         goto error;
777
778     r = RegOpenKeyExW(hReg, szServiceManagerKey,
779                       0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
780     RegCloseKey( hReg );
781     if (r!=ERROR_SUCCESS)
782         goto error;
783
784     TRACE("returning %p\n", retval);
785
786     return (SC_HANDLE) retval;
787
788 error:
789     free_sc_handle( retval );
790     return NULL;
791 }
792
793 /******************************************************************************
794  * ControlService [ADVAPI32.@]
795  *
796  * Send a control code to a service.
797  *
798  * PARAMS
799  *   hService        [I] Handle of the service control manager database
800  *   dwControl       [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
801  *   lpServiceStatus [O] Destination for the status of the service, if available
802  *
803  * RETURNS
804  *   Success: TRUE.
805  *   Failure: FALSE.
806  *
807  * BUGS
808  *   Unlike M$' implementation, control requests are not serialized and may be
809  *   processed asynchronously.
810  */
811 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
812                             LPSERVICE_STATUS lpServiceStatus )
813 {
814     struct sc_handle *hsvc = hService;
815     WCHAR object_name[ MAX_PATH ];
816     HANDLE mutex = NULL, shmem = NULL;
817     HANDLE disp_event = NULL, ack_event = NULL;
818     struct SEB *seb = NULL;
819     DWORD  r;
820     BOOL ret = FALSE, mutex_owned = FALSE;
821
822     /* open and hold mutex */
823     snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->u.service.name );
824     mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
825     if( NULL == mutex )
826     {
827         SetLastError( ERROR_SERVICE_NOT_ACTIVE );
828         return FALSE;
829     }
830
831     r = WaitForSingleObject( mutex, 30000 );
832     if( WAIT_FAILED == r )
833         goto done;
834
835     if( WAIT_TIMEOUT == r )
836     {
837         SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
838         goto done;
839     }
840     mutex_owned = TRUE;
841
842     /* open event objects */
843     snprintfW( object_name, MAX_PATH, szServiceDispEventNameFmtW, hsvc->u.service.name );
844     disp_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
845     if( NULL == disp_event )
846         goto done;
847
848     snprintfW( object_name, MAX_PATH, szServiceAckEventNameFmtW, hsvc->u.service.name );
849     ack_event = OpenEventW( EVENT_ALL_ACCESS, FALSE, object_name );
850     if( NULL == ack_event )
851         goto done;
852
853     /* get service environment block */
854     seb = open_seb_shmem( hsvc->u.service.name, &shmem );
855     if( NULL == seb )
856         goto done;
857
858     /* send request */
859     /* FIXME: check dwControl against controls accepted */
860     seb->control_code = dwControl;
861     SetEvent( disp_event );
862
863     /* wait for acknowledgement */
864     r = WaitForSingleObject( ack_event, 30000 );
865     if( WAIT_FAILED == r )
866         goto done;
867
868     if( WAIT_TIMEOUT == r )
869     {
870         SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
871         goto done;
872     }
873
874     if( seb->dispatcher_error )
875     {
876         SetLastError( seb->dispatcher_error );
877         goto done;
878     }
879
880     /* get status */
881     if( lpServiceStatus )
882         memcpy( lpServiceStatus, &seb->status, sizeof(SERVICE_STATUS) );
883     ret = TRUE;
884
885 done:
886     if( seb ) UnmapViewOfFile( seb );
887     if( shmem ) CloseHandle( shmem );
888     if( ack_event ) CloseHandle( ack_event );
889     if( disp_event ) CloseHandle( disp_event );
890     if( mutex_owned ) ReleaseMutex( mutex );
891     if( mutex ) CloseHandle( mutex );
892     return ret;
893 }
894
895 /******************************************************************************
896  * CloseServiceHandle [ADVAPI32.@]
897  * 
898  * Close a handle to a service or the service control manager database.
899  *
900  * PARAMS
901  *   hSCObject [I] Handle to service or service control manager database
902  *
903  * RETURNS
904  *  Success: TRUE
905  *  Failure: FALSE
906  */
907 BOOL WINAPI
908 CloseServiceHandle( SC_HANDLE hSCObject )
909 {
910     TRACE("(%p)\n", hSCObject);
911
912     free_sc_handle( (struct sc_handle*) hSCObject );
913
914     return TRUE;
915 }
916
917
918 /******************************************************************************
919  * OpenServiceA [ADVAPI32.@]
920  *
921  * Open a handle to a service.
922  *
923  * PARAMS
924  *   hSCManager      [I] Handle of the service control manager database
925  *   lpServiceName   [I] Name of the service to open
926  *   dwDesiredAccess [I] Access required to the service
927  *
928  * RETURNS
929  *    Success: Handle to the service
930  *    Failure: NULL
931  */
932 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
933                                DWORD dwDesiredAccess )
934 {
935     UNICODE_STRING lpServiceNameW;
936     SC_HANDLE ret;
937     RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
938     if(lpServiceName)
939         TRACE("Request for service %s\n",lpServiceName);
940     else
941         return FALSE;
942     ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
943     RtlFreeUnicodeString(&lpServiceNameW);
944     return ret;
945 }
946
947
948 /******************************************************************************
949  * OpenServiceW [ADVAPI32.@]
950  *
951  * See OpenServiceA.
952  */
953 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
954                                DWORD dwDesiredAccess)
955 {
956     struct sc_handle *hscm = hSCManager;
957     struct sc_handle *retval;
958     HKEY hKey;
959     long r;
960
961     TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
962           dwDesiredAccess);
963
964     retval = alloc_sc_handle( SC_HTYPE_SERVICE );
965     if( NULL == retval )
966         return NULL;
967
968     r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
969                        lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
970     if (r!=ERROR_SUCCESS)
971     {
972         free_sc_handle( retval );
973         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
974         return NULL;
975     }
976     
977     init_service_handle( retval, hscm, hKey, lpServiceName );
978
979     TRACE("returning %p\n",retval);
980
981     return (SC_HANDLE) retval;
982 }
983
984 /******************************************************************************
985  * CreateServiceW [ADVAPI32.@]
986  */
987 SC_HANDLE WINAPI
988 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
989                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
990                   DWORD dwServiceType, DWORD dwStartType,
991                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
992                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
993                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
994                   LPCWSTR lpPassword )
995 {
996     struct sc_handle *hscm = hSCManager;
997     struct sc_handle *retval;
998     HKEY hKey;
999     LONG r;
1000     DWORD dp;
1001     static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1002     static const WCHAR szType[] = {'T','y','p','e',0};
1003     static const WCHAR szStart[] = {'S','t','a','r','t',0};
1004     static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1005     static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1006     static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1007     static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1008
1009     FIXME("%p %s %s\n", hSCManager, 
1010           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1011
1012     retval = alloc_sc_handle( SC_HTYPE_SERVICE );
1013     if( NULL == retval )
1014         return NULL;
1015
1016     r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
1017                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1018     if (r!=ERROR_SUCCESS)
1019         goto error;
1020
1021     init_service_handle( retval, hscm, hKey, lpServiceName );
1022
1023     if (dp != REG_CREATED_NEW_KEY)
1024         goto error;
1025
1026     if(lpDisplayName)
1027     {
1028         r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (const BYTE*)lpDisplayName,
1029                            (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
1030         if (r!=ERROR_SUCCESS)
1031             goto error;
1032     }
1033
1034     r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
1035     if (r!=ERROR_SUCCESS)
1036         goto error;
1037
1038     r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
1039     if (r!=ERROR_SUCCESS)
1040         goto error;
1041
1042     r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
1043                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
1044     if (r!=ERROR_SUCCESS)
1045         goto error;
1046
1047     if(lpBinaryPathName)
1048     {
1049         r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (const BYTE*)lpBinaryPathName,
1050                            (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
1051         if (r!=ERROR_SUCCESS)
1052             goto error;
1053     }
1054
1055     if(lpLoadOrderGroup)
1056     {
1057         r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (const BYTE*)lpLoadOrderGroup,
1058                            (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
1059         if (r!=ERROR_SUCCESS)
1060             goto error;
1061     }
1062
1063     if(lpDependencies)
1064     {
1065         DWORD len = 0;
1066
1067         /* determine the length of a double null terminated multi string */
1068         do {
1069             len += (strlenW(&lpDependencies[len])+1);
1070         } while (lpDependencies[len++]);
1071
1072         r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
1073                            (const BYTE*)lpDependencies, len );
1074         if (r!=ERROR_SUCCESS)
1075             goto error;
1076     }
1077
1078     if(lpPassword)
1079     {
1080         FIXME("Don't know how to add a Password for a service.\n");
1081     }
1082
1083     if(lpServiceStartName)
1084     {
1085         FIXME("Don't know how to add a ServiceStartName for a service.\n");
1086     }
1087
1088     return (SC_HANDLE) retval;
1089     
1090 error:
1091     free_sc_handle( retval );
1092     return NULL;
1093 }
1094
1095
1096 /******************************************************************************
1097  * CreateServiceA [ADVAPI32.@]
1098  */
1099 SC_HANDLE WINAPI
1100 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1101                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1102                   DWORD dwServiceType, DWORD dwStartType,
1103                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1104                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1105                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1106                   LPCSTR lpPassword )
1107 {
1108     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1109         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1110     SC_HANDLE r;
1111
1112     TRACE("%p %s %s\n", hSCManager,
1113           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1114
1115     lpServiceNameW = SERV_dup( lpServiceName );
1116     lpDisplayNameW = SERV_dup( lpDisplayName );
1117     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1118     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1119     lpDependenciesW = SERV_dupmulti( lpDependencies );
1120     lpServiceStartNameW = SERV_dup( lpServiceStartName );
1121     lpPasswordW = SERV_dup( lpPassword );
1122
1123     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1124             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1125             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1126             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1127
1128     SERV_free( lpServiceNameW );
1129     SERV_free( lpDisplayNameW );
1130     SERV_free( lpBinaryPathNameW );
1131     SERV_free( lpLoadOrderGroupW );
1132     SERV_free( lpDependenciesW );
1133     SERV_free( lpServiceStartNameW );
1134     SERV_free( lpPasswordW );
1135
1136     return r;
1137 }
1138
1139
1140 /******************************************************************************
1141  * DeleteService [ADVAPI32.@]
1142  *
1143  * Delete a service from the service control manager database.
1144  *
1145  * PARAMS
1146  *    hService [I] Handle of the service to delete
1147  *
1148  * RETURNS
1149  *  Success: TRUE
1150  *  Failure: FALSE
1151  */
1152 BOOL WINAPI DeleteService( SC_HANDLE hService )
1153 {
1154     struct sc_handle *hsvc = hService;
1155     HKEY hKey = hsvc->u.service.hkey;
1156     WCHAR valname[MAX_PATH+1];
1157     INT index = 0;
1158     LONG rc;
1159     DWORD size;
1160
1161     size = MAX_PATH+1; 
1162     /* Clean out the values */
1163     rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1164     while (rc == ERROR_SUCCESS)
1165     {
1166         RegDeleteValueW(hKey,valname);
1167         index++;
1168         size = MAX_PATH+1; 
1169         rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1170     }
1171
1172     RegCloseKey(hKey);
1173     hsvc->u.service.hkey = NULL;
1174
1175     /* delete the key */
1176     RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
1177                   hsvc->u.service.name);
1178
1179     return TRUE;
1180 }
1181
1182
1183 /******************************************************************************
1184  * StartServiceA [ADVAPI32.@]
1185  *
1186  * Start a service
1187  *
1188  * PARAMS
1189  *   hService            [I] Handle of service
1190  *   dwNumServiceArgs    [I] Number of arguments
1191  *   lpServiceArgVectors [I] Address of array of argument strings
1192  *
1193  * NOTES
1194  *  - NT implements this function using an obscure RPC call.
1195  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1196  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
1197  *  - This will only work for shared address space. How should the service
1198  *    args be transferred when address spaces are separated?
1199  *  - Can only start one service at a time.
1200  *  - Has no concept of privilege.
1201  *
1202  * RETURNS
1203  *   Success: TRUE.
1204  *   Failure: FALSE
1205  */
1206 BOOL WINAPI
1207 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1208                  LPCSTR *lpServiceArgVectors )
1209 {
1210     LPWSTR *lpwstr=NULL;
1211     UNICODE_STRING usBuffer;
1212     unsigned int i;
1213
1214     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1215
1216     if(dwNumServiceArgs)
1217         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
1218                                    dwNumServiceArgs*sizeof(LPWSTR) );
1219     else
1220         lpwstr = NULL;
1221
1222     for(i=0; i<dwNumServiceArgs; i++)
1223     {
1224         RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
1225         lpwstr[i]=usBuffer.Buffer;
1226     }
1227
1228     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1229
1230     if(dwNumServiceArgs)
1231     {
1232         for(i=0; i<dwNumServiceArgs; i++)
1233             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1234         HeapFree(GetProcessHeap(), 0, lpwstr);
1235     }
1236
1237     return TRUE;
1238 }
1239
1240
1241 /******************************************************************************
1242  * StartServiceW [ADVAPI32.@]
1243  * 
1244  * See StartServiceA.
1245  */
1246 BOOL WINAPI
1247 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
1248                  LPCWSTR *lpServiceArgVectors )
1249 {
1250     static const WCHAR  _ImagePathW[]  = {'I','m','a','g','e','P','a','t','h',0};
1251                                                 
1252     struct sc_handle *hsvc = hService;
1253     WCHAR path[MAX_PATH],str[MAX_PATH];
1254     DWORD type,size;
1255     DWORD i;
1256     long r;
1257     HANDLE hLock;
1258     HANDLE hServiceShmem = NULL;
1259     HANDLE wait = NULL;
1260     LPWSTR shmem_lock = NULL;
1261     struct SEB *seb = NULL;
1262     LPWSTR argptr;
1263     PROCESS_INFORMATION procinfo;
1264     STARTUPINFOW startupinfo;
1265     BOOL ret = FALSE;
1266
1267     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
1268           lpServiceArgVectors);
1269
1270     size = sizeof(str);
1271     r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
1272     if (r!=ERROR_SUCCESS)
1273         return FALSE;
1274     ExpandEnvironmentStringsW(str,path,sizeof(path));
1275
1276     TRACE("Starting service %s\n", debugstr_w(path) );
1277
1278     hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
1279     if( NULL == hLock )
1280         return FALSE;
1281
1282     /*
1283      * FIXME: start dependent services
1284      */
1285
1286     /* pass argv[0] (service name) to the service via global SCM lock object */
1287     shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
1288                                 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
1289     if( NULL == shmem_lock )
1290     {
1291         ERR("Couldn't map shared memory\n");
1292         goto done;
1293     }
1294     strcpyW( shmem_lock, hsvc->u.service.name );
1295
1296     /* create service environment block */
1297     size = sizeof(struct SEB);
1298     for( i = 0; i < dwNumServiceArgs; i++ )
1299         size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] ));
1300
1301     snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1302     hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1303                                         NULL, PAGE_READWRITE, 0, size, str );
1304     if( NULL == hServiceShmem )
1305     {
1306         ERR("Couldn't create shared memory object\n");
1307         goto done;
1308     }
1309     if( GetLastError() == ERROR_ALREADY_EXISTS )
1310     {
1311         SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1312         goto done;
1313     }
1314     seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1315     if( NULL == seb )
1316     {
1317         ERR("Couldn't map shared memory\n");
1318         goto done;
1319     }
1320
1321     /* copy service args to SEB */
1322     seb->argc = dwNumServiceArgs;
1323     argptr = (LPWSTR) &seb[1];
1324     for( i = 0; i < dwNumServiceArgs; i++ )
1325     {
1326         strcpyW( argptr, lpServiceArgVectors[ i ] );
1327         argptr += 1 + strlenW( argptr );
1328     }
1329
1330     wait = CreateSemaphoreW(NULL,0,1,szWaitServiceStartW);
1331     if (!wait)
1332     {
1333         ERR("Couldn't create wait semaphore\n");
1334         goto done;
1335     }
1336
1337     ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1338     startupinfo.cb = sizeof(STARTUPINFOW);
1339
1340     r = CreateProcessW(NULL,
1341                    path,
1342                    NULL,  /* process security attribs */
1343                    NULL,  /* thread security attribs */
1344                    FALSE, /* inherit handles */
1345                    0,     /* creation flags */
1346                    NULL,  /* environment */
1347                    NULL,  /* current directory */
1348                    &startupinfo,  /* startup info */
1349                    &procinfo); /* process info */
1350
1351     if(r == FALSE)
1352     {
1353         ERR("Couldn't start process\n");
1354         goto done;
1355     }
1356     CloseHandle( procinfo.hThread );
1357
1358     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1359     r = WaitForSingleObject(wait,30000);
1360     if( WAIT_FAILED == r )
1361     {
1362         CloseHandle( procinfo.hProcess );
1363         goto done;
1364     }
1365     if( WAIT_TIMEOUT == r )
1366     {
1367         TerminateProcess( procinfo.hProcess, 1 );
1368         CloseHandle( procinfo.hProcess );
1369         SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
1370         goto done;
1371     }
1372
1373     /* allright */
1374     CloseHandle( procinfo.hProcess );
1375     ret = TRUE;
1376
1377 done:
1378     if( wait ) CloseHandle( wait );
1379     if( seb != NULL ) UnmapViewOfFile( seb );
1380     if( hServiceShmem != NULL ) CloseHandle( hServiceShmem );
1381     if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock );
1382     UnlockServiceDatabase( hLock );
1383     return ret;
1384 }
1385
1386 /******************************************************************************
1387  * QueryServiceStatus [ADVAPI32.@]
1388  *
1389  * PARAMS
1390  *   hService        []
1391  *   lpservicestatus []
1392  *
1393  */
1394 BOOL WINAPI
1395 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1396 {
1397     struct sc_handle *hsvc = hService;
1398     LONG r;
1399     DWORD type, val, size;
1400     WCHAR object_name[ MAX_PATH ];
1401     HANDLE mutex, shmem = NULL;
1402     struct SEB *seb = NULL;
1403     BOOL ret = FALSE, mutex_owned = FALSE;
1404
1405     /* try to open service mutex */
1406     snprintfW( object_name, MAX_PATH, szServiceMutexNameFmtW, hsvc->u.service.name );
1407     mutex = OpenMutexW( MUTEX_ALL_ACCESS, FALSE, object_name );
1408     if( NULL == mutex )
1409         goto stopped;
1410
1411     /* hold mutex */
1412     r = WaitForSingleObject( mutex, 30000 );
1413     if( WAIT_FAILED == r )
1414         goto done;
1415
1416     if( WAIT_TIMEOUT == r )
1417     {
1418         SetLastError( ERROR_SERVICE_REQUEST_TIMEOUT );
1419         goto done;
1420     }
1421     mutex_owned = TRUE;
1422
1423     /* get service environment block */
1424     seb = open_seb_shmem( hsvc->u.service.name, &shmem );
1425     if( NULL == seb )
1426         goto done;
1427  
1428     /* get status */
1429     memcpy( lpservicestatus, &seb->status, sizeof(SERVICE_STATUS) );
1430     ret = TRUE;
1431
1432 done:
1433     if( seb ) UnmapViewOfFile( seb );
1434     if( shmem ) CloseHandle( shmem );
1435     if( mutex_owned ) ReleaseMutex( mutex );
1436     CloseHandle( mutex );
1437     return ret;
1438  
1439 stopped:
1440     /* service stopped */
1441     /* read the service type from the registry */
1442     size = sizeof(val);
1443     r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1444     if(type!=REG_DWORD)
1445     {
1446         ERR("invalid Type\n");
1447         return FALSE;
1448     }
1449     lpservicestatus->dwServiceType = val;
1450     lpservicestatus->dwCurrentState            = 1;  /* stopped */
1451     lpservicestatus->dwControlsAccepted        = 0;
1452     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
1453     lpservicestatus->dwServiceSpecificExitCode = 0;
1454     lpservicestatus->dwCheckPoint              = 0;
1455     lpservicestatus->dwWaitHint                = 0;
1456
1457     return TRUE;
1458 }
1459
1460 /******************************************************************************
1461  * QueryServiceStatusEx [ADVAPI32.@]
1462  *
1463  * Get information about a service.
1464  *
1465  * PARAMS
1466  *   hService       [I] Handle to service to get information about
1467  *   InfoLevel      [I] Level of information to get
1468  *   lpBuffer       [O] Destination for requested information
1469  *   cbBufSize      [I] Size of lpBuffer in bytes
1470  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1471  *
1472  * RETURNS
1473  *  Success: TRUE
1474  *  FAILURE: FALSE
1475  */
1476 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1477                         LPBYTE lpBuffer, DWORD cbBufSize,
1478                         LPDWORD pcbBytesNeeded)
1479 {
1480     FIXME("stub\n");
1481     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1482     return FALSE;
1483 }
1484
1485 /******************************************************************************
1486  * QueryServiceConfigA [ADVAPI32.@]
1487  */
1488 BOOL WINAPI 
1489 QueryServiceConfigA( SC_HANDLE hService,
1490                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1491                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1492 {
1493     static const CHAR szDisplayName[] = "DisplayName";
1494     static const CHAR szType[] = "Type";
1495     static const CHAR szStart[] = "Start";
1496     static const CHAR szError[] = "ErrorControl";
1497     static const CHAR szImagePath[] = "ImagePath";
1498     static const CHAR szGroup[] = "Group";
1499     static const CHAR szDependencies[] = "Dependencies";
1500     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1501     CHAR str_buffer[ MAX_PATH ];
1502     LONG r;
1503     DWORD type, val, sz, total, n;
1504     LPBYTE p;
1505
1506     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1507            cbBufSize, pcbBytesNeeded);
1508
1509     /* calculate the size required first */
1510     total = sizeof (QUERY_SERVICE_CONFIGA);
1511
1512     sz = sizeof(str_buffer);
1513     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1514     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1515     {
1516         sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1517         if( 0 == sz ) return FALSE;
1518
1519         total += sz;
1520     }
1521     else
1522     {
1523         /* FIXME: set last error */
1524         return FALSE;
1525     }
1526
1527     sz = 0;
1528     r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1529     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1530         total += sz;
1531
1532     sz = 0;
1533     r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1534     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1535         total += sz;
1536
1537     sz = 0;
1538     r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1539     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1540         total += sz;
1541
1542     sz = 0;
1543     r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1544     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1545         total += sz;
1546
1547     /* if there's not enough memory, return an error */
1548     if( total > *pcbBytesNeeded )
1549     {
1550         *pcbBytesNeeded = total;
1551         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1552         return FALSE;
1553     }
1554
1555     *pcbBytesNeeded = total;
1556     ZeroMemory( lpServiceConfig, total );
1557
1558     sz = sizeof val;
1559     r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1560     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1561         lpServiceConfig->dwServiceType = val;
1562
1563     sz = sizeof val;
1564     r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1565     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1566         lpServiceConfig->dwStartType = val;
1567
1568     sz = sizeof val;
1569     r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1570     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1571         lpServiceConfig->dwErrorControl = val;
1572
1573     /* now do the strings */
1574     p = (LPBYTE) &lpServiceConfig[1];
1575     n = total - sizeof (QUERY_SERVICE_CONFIGA);
1576
1577     sz = sizeof(str_buffer);
1578     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1579     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1580     {
1581         sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1582         if( 0 == sz || sz > n ) return FALSE;
1583
1584         lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1585         p += sz;
1586         n -= sz;
1587     }
1588     else
1589     {
1590         /* FIXME: set last error */
1591         return FALSE;
1592     }
1593
1594     sz = n;
1595     r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1596     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1597     {
1598         lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1599         p += sz;
1600         n -= sz;
1601     }
1602
1603     sz = n;
1604     r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1605     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1606     {
1607         lpServiceConfig->lpDependencies = (LPSTR) p;
1608         p += sz;
1609         n -= sz;
1610     }
1611
1612     if( n < 0 )
1613         ERR("Buffer overflow!\n");
1614
1615     TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1616     TRACE("Group      = %s\n", lpServiceConfig->lpLoadOrderGroup );
1617
1618     return TRUE;
1619 }
1620
1621 /******************************************************************************
1622  * QueryServiceConfigW [ADVAPI32.@]
1623  */
1624 BOOL WINAPI 
1625 QueryServiceConfigW( SC_HANDLE hService,
1626                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1627                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1628 {
1629     static const WCHAR szDisplayName[] = {
1630         'D','i','s','p','l','a','y','N','a','m','e', 0 };
1631     static const WCHAR szType[] = {'T','y','p','e',0};
1632     static const WCHAR szStart[] = {'S','t','a','r','t',0};
1633     static const WCHAR szError[] = {
1634         'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1635     static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1636     static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1637     static const WCHAR szDependencies[] = {
1638         'D','e','p','e','n','d','e','n','c','i','e','s',0};
1639     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1640     WCHAR str_buffer[ MAX_PATH ];
1641     LONG r;
1642     DWORD type, val, sz, total, n;
1643     LPBYTE p;
1644
1645     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1646            cbBufSize, pcbBytesNeeded);
1647
1648     /* calculate the size required first */
1649     total = sizeof (QUERY_SERVICE_CONFIGW);
1650
1651     sz = sizeof(str_buffer);
1652     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1653     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1654     {
1655         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1656         if( 0 == sz ) return FALSE;
1657
1658         total += sizeof(WCHAR) * sz;
1659     }
1660     else
1661     {
1662        /* FIXME: set last error */
1663        return FALSE;
1664     }
1665
1666     sz = 0;
1667     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1668     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1669         total += sz;
1670
1671     sz = 0;
1672     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1673     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1674         total += sz;
1675
1676     sz = 0;
1677     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1678     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1679         total += sz;
1680
1681     sz = 0;
1682     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1683     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1684         total += sz;
1685
1686     /* if there's not enough memory, return an error */
1687     if( total > *pcbBytesNeeded )
1688     {
1689         *pcbBytesNeeded = total;
1690         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1691         return FALSE;
1692     }
1693
1694     *pcbBytesNeeded = total;
1695     ZeroMemory( lpServiceConfig, total );
1696
1697     sz = sizeof val;
1698     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1699     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1700         lpServiceConfig->dwServiceType = val;
1701
1702     sz = sizeof val;
1703     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1704     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1705         lpServiceConfig->dwStartType = val;
1706
1707     sz = sizeof val;
1708     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1709     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1710         lpServiceConfig->dwErrorControl = val;
1711
1712     /* now do the strings */
1713     p = (LPBYTE) &lpServiceConfig[1];
1714     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1715
1716     sz = sizeof(str_buffer);
1717     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1718     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1719     {
1720         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1721         sz *= sizeof(WCHAR);
1722         if( 0 == sz || sz > n ) return FALSE;
1723
1724         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1725         p += sz;
1726         n -= sz;
1727     }
1728     else
1729     {
1730        /* FIXME: set last error */
1731        return FALSE;
1732     }
1733
1734     sz = n;
1735     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1736     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1737     {
1738         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1739         p += sz;
1740         n -= sz;
1741     }
1742
1743     sz = n;
1744     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1745     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1746     {
1747         lpServiceConfig->lpDependencies = (LPWSTR) p;
1748         p += sz;
1749         n -= sz;
1750     }
1751
1752     if( n < 0 )
1753         ERR("Buffer overflow!\n");
1754
1755     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1756     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1757
1758     return TRUE;
1759 }
1760
1761
1762 /******************************************************************************
1763  * GetServiceDisplayNameA  [ADVAPI32.@]
1764  */
1765 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1766   LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1767 {
1768     FIXME("%p %s %p %p\n", hSCManager,
1769           debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1770     return FALSE;
1771 }
1772
1773
1774 /******************************************************************************
1775  * GetServiceDisplayNameW  [ADVAPI32.@]
1776  */
1777 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1778   LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1779 {
1780     FIXME("%p %s %p %p\n", hSCManager,
1781           debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1782     return FALSE;
1783 }
1784
1785
1786 /******************************************************************************
1787  * ChangeServiceConfigW  [ADVAPI32.@]
1788  */
1789 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1790   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1791   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1792   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1793 {
1794     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1795           hService, dwServiceType, dwStartType, dwErrorControl, 
1796           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1797           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1798           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1799     return TRUE;
1800 }
1801
1802 /******************************************************************************
1803  * ChangeServiceConfigA  [ADVAPI32.@]
1804  */
1805 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1806   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1807   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1808   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1809 {
1810     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1811     LPWSTR wServiceStartName, wPassword, wDisplayName;
1812     BOOL r;
1813
1814     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1815           hService, dwServiceType, dwStartType, dwErrorControl, 
1816           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1817           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1818           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1819
1820     wBinaryPathName = SERV_dup( lpBinaryPathName );
1821     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1822     wDependencies = SERV_dupmulti( lpDependencies );
1823     wServiceStartName = SERV_dup( lpServiceStartName );
1824     wPassword = SERV_dup( lpPassword );
1825     wDisplayName = SERV_dup( lpDisplayName );
1826
1827     r = ChangeServiceConfigW( hService, dwServiceType,
1828             dwStartType, dwErrorControl, wBinaryPathName,
1829             wLoadOrderGroup, lpdwTagId, wDependencies,
1830             wServiceStartName, wPassword, wDisplayName);
1831
1832     SERV_free( wBinaryPathName );
1833     SERV_free( wLoadOrderGroup );
1834     SERV_free( wDependencies );
1835     SERV_free( wServiceStartName );
1836     SERV_free( wPassword );
1837     SERV_free( wDisplayName );
1838
1839     return r;
1840 }
1841
1842 /******************************************************************************
1843  * ChangeServiceConfig2A  [ADVAPI32.@]
1844  */
1845 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
1846     LPVOID lpInfo)
1847 {
1848     BOOL r = FALSE;
1849
1850     TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
1851
1852     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1853     {
1854         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
1855         SERVICE_DESCRIPTIONW sdw;
1856
1857         sdw.lpDescription = SERV_dup( sd->lpDescription );
1858
1859         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
1860
1861         SERV_free( sdw.lpDescription );
1862     }
1863     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
1864     {
1865         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
1866         SERVICE_FAILURE_ACTIONSW faw;
1867
1868         faw.dwResetPeriod = fa->dwResetPeriod;
1869         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
1870         faw.lpCommand = SERV_dup( fa->lpCommand );
1871         faw.cActions = fa->cActions;
1872         faw.lpsaActions = fa->lpsaActions;
1873
1874         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
1875
1876         SERV_free( faw.lpRebootMsg );
1877         SERV_free( faw.lpCommand );
1878     }
1879     else
1880         SetLastError( ERROR_INVALID_PARAMETER );
1881
1882     return r;
1883 }
1884
1885 /******************************************************************************
1886  * ChangeServiceConfig2W  [ADVAPI32.@]
1887  */
1888 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
1889     LPVOID lpInfo)
1890 {
1891     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1892
1893     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1894     {
1895         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1896         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1897         if (sd->lpDescription)
1898         {
1899             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1900             if (sd->lpDescription[0] == 0)
1901                 RegDeleteValueW(hKey,szDescription);
1902             else
1903                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1904                                         (LPVOID)sd->lpDescription,
1905                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1906         }
1907     }
1908     else   
1909         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1910     return TRUE;
1911 }
1912
1913 /******************************************************************************
1914  * QueryServiceObjectSecurity [ADVAPI32.@]
1915  */
1916 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1917        SECURITY_INFORMATION dwSecurityInformation,
1918        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1919        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1920 {
1921     PACL pACL = NULL;
1922     FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1923           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1924
1925
1926     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
1927
1928     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
1929     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
1930     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
1931     return TRUE;
1932 }
1933
1934 /******************************************************************************
1935  * SetServiceObjectSecurity [ADVAPI32.@]
1936  */
1937 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1938        SECURITY_INFORMATION dwSecurityInformation,
1939        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1940 {
1941     FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1942     return TRUE;
1943 }