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