Const correctness fixes.
[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
44 struct SEB              /* service environment block */
45 {                       /*   resides in service's shared memory object */
46     DWORD argc;
47     /* variable part of SEB contains service arguments */
48 };
49
50 /******************************************************************************
51  * SC_HANDLEs
52  */
53
54 #define MAX_SERVICE_NAME 256
55
56 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
57
58 struct sc_handle;
59
60 struct sc_manager       /* SCM handle */
61 {
62     HKEY hkey_scm_db;   /* handle to services database in the registry */
63     LONG ref_count;     /* handle must remain alive until any related service */
64                         /* handle exists because DeleteService requires it */
65 };
66
67 struct sc_service       /* service handle */
68 {
69     HKEY hkey;          /* handle to service entry in the registry (under hkey_scm_db) */
70     struct sc_handle *sc_manager;  /* pointer to SCM handle */
71     WCHAR name[ MAX_SERVICE_NAME ];
72 };
73
74 struct sc_handle
75 {
76     SC_HANDLE_TYPE htype;
77     union
78     {
79         struct sc_manager manager;
80         struct sc_service service;
81     } u;
82 };
83
84 static struct sc_handle* alloc_sc_handle( SC_HANDLE_TYPE htype )
85 {
86     struct sc_handle *retval;
87
88     retval = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct sc_handle) );
89     if( retval != NULL )
90     {
91         retval->htype = htype;
92     }
93     TRACE("SC_HANDLE type=%d -> %p\n",htype,retval);
94     return retval;
95 }
96
97 static void free_sc_handle( struct sc_handle* handle )
98 {
99     if( NULL == handle )
100         return;
101
102     switch( handle->htype )
103     {
104         case SC_HTYPE_MANAGER:
105         {
106             if( InterlockedDecrement( &handle->u.manager.ref_count ) )
107                 /* there are references to this handle */
108                 return;
109
110             if( handle->u.manager.hkey_scm_db )
111                 RegCloseKey( handle->u.manager.hkey_scm_db );
112             break;
113         }
114
115         case SC_HTYPE_SERVICE:
116         {
117             struct sc_handle *h = handle->u.service.sc_manager;
118
119             if( h )
120             {
121                 /* release SCM handle */
122                 if( 0 == InterlockedDecrement( &h->u.manager.ref_count ) )
123                 {
124                     /* it's time to destroy SCM handle */
125                     if( h->u.manager.hkey_scm_db )
126                         RegCloseKey( h->u.manager.hkey_scm_db );
127                     
128                     TRACE("SC_HANDLE (SCM) %p type=%d\n",h,h->htype);
129                     
130                     HeapFree( GetProcessHeap(), 0, h );
131                 }
132             }
133             if( handle->u.service.hkey )
134                 RegCloseKey( handle->u.service.hkey );
135             break;
136         }
137     }
138
139     TRACE("SC_HANDLE %p type=%d\n",handle,handle->htype);
140
141     HeapFree( GetProcessHeap(), 0, handle );
142 }
143
144 static void init_service_handle( struct sc_handle* handle,
145                                  struct sc_handle* sc_manager,
146                                  HKEY hKey, LPCWSTR lpServiceName )
147 {
148     /* init sc_service structure */
149     handle->u.service.hkey = hKey;
150     lstrcpynW( handle->u.service.name, lpServiceName, MAX_SERVICE_NAME );
151
152     /* add reference to SCM handle */
153     InterlockedIncrement( &sc_manager->u.manager.ref_count );
154     handle->u.service.sc_manager = sc_manager;
155 }
156
157 static inline LPWSTR SERV_dup( LPCSTR str )
158 {
159     UINT len;
160     LPWSTR wstr;
161
162     if( !str )
163         return NULL;
164     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
165     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
166     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
167     return wstr;
168 }
169
170 static inline LPWSTR SERV_dupmulti( LPCSTR str )
171 {
172     UINT len = 0, n = 0;
173     LPWSTR wstr;
174
175     if( !str )
176         return NULL;
177     do {
178         len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
179         n += (strlen( &str[n] ) + 1);
180     } while (str[n]);
181     len++;
182     n++;
183
184     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
185     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
186     return wstr;
187 }
188
189 static inline VOID SERV_free( LPWSTR wstr )
190 {
191     HeapFree( GetProcessHeap(), 0, wstr );
192 }
193
194 /******************************************************************************
195  * EnumServicesStatusA [ADVAPI32.@]
196  */
197 BOOL WINAPI
198 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
199                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
200                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
201                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
202 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
203                 dwServiceType, dwServiceState, lpServices, cbBufSize,
204                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
205         SetLastError (ERROR_ACCESS_DENIED);
206         return FALSE;
207 }
208
209 /******************************************************************************
210  * EnumServicesStatusW [ADVAPI32.@]
211  */
212 BOOL WINAPI
213 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
214                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
215                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
216                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
217 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
218                 dwServiceType, dwServiceState, lpServices, cbBufSize,
219                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
220         SetLastError (ERROR_ACCESS_DENIED);
221         return FALSE;
222 }
223
224 /******************************************************************************
225  * read_scm_lock_data
226  *
227  * helper function for service control dispatcher
228  *
229  * SCM database is locked by StartService;
230  * open global SCM lock object and read service name
231  */
232 static BOOL read_scm_lock_data( LPWSTR buffer )
233 {
234     HANDLE hLock;
235     LPWSTR argptr;
236
237     hLock = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, szSCMLock );
238     if( NULL == hLock )
239     {
240         SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
241         return FALSE;
242     }
243     argptr = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
244                             0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
245     if( NULL == argptr )
246     {
247         CloseHandle( hLock );
248         return FALSE;
249     }
250     strcpyW( buffer, argptr );
251     UnmapViewOfFile( argptr );
252     CloseHandle( hLock );
253     return TRUE;
254 }
255
256 /******************************************************************************
257  * open_seb_shmem
258  *
259  * helper function for service control dispatcher
260  */
261 static struct SEB* open_seb_shmem( LPWSTR service_name, HANDLE* hServiceShmem )
262 {
263     WCHAR object_name[ MAX_PATH ];
264     HANDLE hmem;
265     struct SEB *ret;
266
267     snprintfW( object_name, MAX_PATH, szServiceShmemNameFmtW, service_name );
268     hmem = OpenFileMappingW( FILE_MAP_ALL_ACCESS, FALSE, object_name );
269     if( NULL == hmem )
270         return NULL;
271
272     ret = MapViewOfFile( hmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
273     if( NULL == ret )
274         CloseHandle( hmem );
275     else
276         *hServiceShmem = hmem;
277     return ret;
278 }
279
280 /******************************************************************************
281  * build_arg_vectors
282  *
283  * helper function for service control dispatcher
284  *
285  * Allocate and initialize array of LPWSTRs to arguments in variable part
286  * of service environment block.
287  * First entry in the array is reserved for service name and not initialized.
288  */
289 static LPWSTR* build_arg_vectors( struct SEB* seb )
290 {
291     LPWSTR *ret;
292     LPWSTR argptr;
293     DWORD i;
294
295     ret = HeapAlloc( GetProcessHeap(), 0, (1 + seb->argc) * sizeof(LPWSTR) );
296     if( NULL == ret )
297         return NULL;
298
299     argptr = (LPWSTR) &seb[1];
300     for( i = 0; i < seb->argc; i++ )
301     {
302         ret[ 1 + i ] = argptr;
303         argptr += 1 + strlenW( argptr );
304     }
305     return ret;
306 }
307
308 /******************************************************************************
309  * service_ctrl_dispatcher
310  *
311  * helper function for StartServiceCtrlDispatcherA/W
312  */
313 static BOOL service_ctrl_dispatcher( LPSERVICE_TABLE_ENTRYW servent, BOOL ascii )
314 {
315     WCHAR service_name[ MAX_SERVICE_NAME ];
316     HANDLE hServiceShmem = NULL;
317     struct SEB *seb = NULL;
318     DWORD  dwNumServiceArgs;
319     LPWSTR *lpArgVecW = NULL;
320     unsigned int i;
321     BOOL ret = FALSE;
322
323     if( ! read_scm_lock_data( service_name ) )
324     {
325         /* FIXME: Instead of exiting we allow
326            service to be executed as ordinary program.
327            This behaviour was specially introduced in the patch
328            submitted against revision 1.45 and so preserved here.
329          */
330         FIXME("should fail with ERROR_FAILED_SERVICE_CONTROLLER_CONNECT\n");
331         servent->lpServiceProc( 0, NULL );
332         return TRUE;
333     }
334
335     seb = open_seb_shmem( service_name, &hServiceShmem );
336     if( NULL == seb )
337         return FALSE;
338
339     lpArgVecW = build_arg_vectors( seb );
340     if( NULL == lpArgVecW )
341         goto done;
342
343     lpArgVecW[0] = service_name;
344     dwNumServiceArgs = seb->argc + 1;
345
346     if( ascii )
347         /* Convert the Unicode arg vectors back to ASCII */
348         for(i=0; i<dwNumServiceArgs; i++)
349         {
350             LPWSTR src = lpArgVecW[i];
351             int len = WideCharToMultiByte( CP_ACP, 0, src, -1, NULL, 0, NULL, NULL );
352             LPSTR dest = HeapAlloc( GetProcessHeap(), 0, len );
353             if( NULL == dest )
354                 goto done;
355             WideCharToMultiByte( CP_ACP, 0, src, -1, dest, len, NULL, NULL );
356             /* copy converted string back  */
357             memcpy( src, dest, len );
358             HeapFree( GetProcessHeap(), 0, dest );
359         }
360
361     /* try to start the service */
362     servent->lpServiceProc( dwNumServiceArgs, lpArgVecW);
363     ret = TRUE;
364
365 done:
366     if( lpArgVecW ) HeapFree( GetProcessHeap(), 0, lpArgVecW );
367     if( seb ) UnmapViewOfFile( seb );
368     if( hServiceShmem ) CloseHandle( hServiceShmem );
369     return ret;
370 }
371
372 /******************************************************************************
373  * StartServiceCtrlDispatcherA [ADVAPI32.@]
374  */
375 BOOL WINAPI
376 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
377 {
378     int count, i;
379     LPSERVICE_TABLE_ENTRYW ServiceTableW;
380     BOOL ret;
381
382     TRACE("(%p)\n", servent);
383
384     /* convert service table to unicode */
385     for( count = 0; servent[ count ].lpServiceName; )
386         count++;
387     ServiceTableW = HeapAlloc( GetProcessHeap(), 0, (count + 1) * sizeof(SERVICE_TABLE_ENTRYW) );
388     if( NULL == ServiceTableW )
389         return FALSE;
390
391     for( i = 0; i < count; i++ )
392     {
393         ServiceTableW[ i ].lpServiceName = SERV_dup( servent[ i ].lpServiceName );
394         ServiceTableW[ i ].lpServiceProc = (LPSERVICE_MAIN_FUNCTIONW) servent[ i ].lpServiceProc;
395     }
396     ServiceTableW[ count ].lpServiceName = NULL;
397     ServiceTableW[ count ].lpServiceProc = NULL;
398
399     /* start dispatcher */
400     ret = service_ctrl_dispatcher( ServiceTableW, TRUE );
401
402     /* free service table */
403     for( i = 0; i < count; i++ )
404         SERV_free( ServiceTableW[ i ].lpServiceName );
405     HeapFree( GetProcessHeap(), 0, ServiceTableW );
406     return ret;
407 }
408
409 /******************************************************************************
410  * StartServiceCtrlDispatcherW [ADVAPI32.@]
411  *
412  * PARAMS
413  *   servent []
414  */
415 BOOL WINAPI
416 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
417 {
418     TRACE("(%p)\n", servent);
419     return service_ctrl_dispatcher( servent, FALSE );
420 }
421
422 /******************************************************************************
423  * LockServiceDatabase  [ADVAPI32.@]
424  */
425 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
426 {
427     HANDLE ret;
428
429     TRACE("%p\n",hSCManager);
430
431     ret = CreateFileMappingW( INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE,
432                               0, MAX_SERVICE_NAME * sizeof(WCHAR), szSCMLock );
433     if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
434     {
435         CloseHandle( ret );
436         ret = NULL;
437         SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
438     }
439
440     TRACE("returning %p\n", ret);
441
442     return ret;
443 }
444
445 /******************************************************************************
446  * UnlockServiceDatabase  [ADVAPI32.@]
447  */
448 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
449 {
450     TRACE("%p\n",ScLock);
451
452     return CloseHandle( (HANDLE) ScLock );
453 }
454
455 /******************************************************************************
456  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
457  */
458 SERVICE_STATUS_HANDLE WINAPI
459 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
460                              LPHANDLER_FUNCTION lpfHandler )
461 {       FIXME("%s %p\n", lpServiceName, lpfHandler);
462         return 0xcacacafe;
463 }
464
465 /******************************************************************************
466  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
467  *
468  * PARAMS
469  *   lpServiceName []
470  *   lpfHandler    []
471  */
472 SERVICE_STATUS_HANDLE WINAPI
473 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
474                              LPHANDLER_FUNCTION lpfHandler )
475 {       FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
476         return 0xcacacafe;
477 }
478
479 /******************************************************************************
480  * SetServiceStatus [ADVAPI32.@]
481  *
482  * PARAMS
483  *   hService []
484  *   lpStatus []
485  */
486 BOOL WINAPI
487 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
488 {       FIXME("0x%lx %p\n",hService, lpStatus);
489         TRACE("\tType:%lx\n",lpStatus->dwServiceType);
490         TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
491         TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
492         TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
493         TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
494         TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
495         TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
496         return TRUE;
497 }
498
499 /******************************************************************************
500  * OpenSCManagerA [ADVAPI32.@]
501  *
502  * Establish a connection to the service control manager and open its database.
503  *
504  * PARAMS
505  *   lpMachineName   [I] Pointer to machine name string
506  *   lpDatabaseName  [I] Pointer to database name string
507  *   dwDesiredAccess [I] Type of access
508  *
509  * RETURNS
510  *   Success: A Handle to the service control manager database
511  *   Failure: NULL
512  */
513 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
514                                  DWORD dwDesiredAccess )
515 {
516     UNICODE_STRING lpMachineNameW;
517     UNICODE_STRING lpDatabaseNameW;
518     SC_HANDLE ret;
519
520     RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
521     RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
522     ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
523     RtlFreeUnicodeString(&lpDatabaseNameW);
524     RtlFreeUnicodeString(&lpMachineNameW);
525     return ret;
526 }
527
528 /******************************************************************************
529  * OpenSCManagerW [ADVAPI32.@]
530  *
531  * See OpenSCManagerA.
532  */
533 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
534                                  DWORD dwDesiredAccess )
535 {
536     struct sc_handle *retval;
537     HKEY hReg;
538     LONG r;
539
540     TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
541           debugstr_w(lpDatabaseName), dwDesiredAccess);
542
543     /*
544      * FIXME: what is lpDatabaseName?
545      * It should be set to "SERVICES_ACTIVE_DATABASE" according to
546      * docs, but what if it isn't?
547      */
548
549     retval = alloc_sc_handle( SC_HTYPE_MANAGER );
550     if( NULL == retval ) return NULL;
551
552     retval->u.manager.ref_count = 1;
553
554     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
555     if (r!=ERROR_SUCCESS)
556         goto error;
557
558     r = RegOpenKeyExW(hReg, szServiceManagerKey,
559                       0, KEY_ALL_ACCESS, &retval->u.manager.hkey_scm_db);
560     RegCloseKey( hReg );
561     if (r!=ERROR_SUCCESS)
562         goto error;
563
564     TRACE("returning %p\n", retval);
565
566     return (SC_HANDLE) retval;
567
568 error:
569     free_sc_handle( retval );
570     return NULL;
571 }
572
573 /******************************************************************************
574  * ControlService [ADVAPI32.@]
575  *
576  * Send a control code to a service.
577  *
578  * PARAMS
579  *   hService        [I] Handle of the service control manager database
580  *   dwControl       [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
581  *   lpServiceStatus [O] Destination for the status of the service, if available
582  *
583  * RETURNS
584  *   Success: TRUE.
585  *   Failure: FALSE.
586  */
587 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
588                             LPSERVICE_STATUS lpServiceStatus )
589 {
590     FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
591     return TRUE;
592 }
593
594
595 /******************************************************************************
596  * CloseServiceHandle [ADVAPI32.@]
597  * 
598  * Close a handle to a service or the service control manager database.
599  *
600  * PARAMS
601  *   hSCObject [I] Handle to service or service control manager database
602  *
603  * RETURNS
604  *  Success: TRUE
605  *  Failure: FALSE
606  */
607 BOOL WINAPI
608 CloseServiceHandle( SC_HANDLE hSCObject )
609 {
610     TRACE("(%p)\n", hSCObject);
611
612     free_sc_handle( (struct sc_handle*) hSCObject );
613
614     return TRUE;
615 }
616
617
618 /******************************************************************************
619  * OpenServiceA [ADVAPI32.@]
620  *
621  * Open a handle to a service.
622  *
623  * PARAMS
624  *   hSCManager      [I] Handle of the service control manager database
625  *   lpServiceName   [I] Name of the service to open
626  *   dwDesiredAccess [I] Access required to the service
627  *
628  * RETURNS
629  *    Success: Handle to the service
630  *    Failure: NULL
631  */
632 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
633                                DWORD dwDesiredAccess )
634 {
635     UNICODE_STRING lpServiceNameW;
636     SC_HANDLE ret;
637     RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
638     if(lpServiceName)
639         TRACE("Request for service %s\n",lpServiceName);
640     else
641         return FALSE;
642     ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
643     RtlFreeUnicodeString(&lpServiceNameW);
644     return ret;
645 }
646
647
648 /******************************************************************************
649  * OpenServiceW [ADVAPI32.@]
650  *
651  * See OpenServiceA.
652  */
653 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
654                                DWORD dwDesiredAccess)
655 {
656     struct sc_handle *hscm = hSCManager;
657     struct sc_handle *retval;
658     HKEY hKey;
659     long r;
660
661     TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
662           dwDesiredAccess);
663
664     retval = alloc_sc_handle( SC_HTYPE_SERVICE );
665     if( NULL == retval )
666         return NULL;
667
668     r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
669                        lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
670     if (r!=ERROR_SUCCESS)
671     {
672         free_sc_handle( retval );
673         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
674         return NULL;
675     }
676     
677     init_service_handle( retval, hscm, hKey, lpServiceName );
678
679     TRACE("returning %p\n",retval);
680
681     return (SC_HANDLE) retval;
682 }
683
684 /******************************************************************************
685  * CreateServiceW [ADVAPI32.@]
686  */
687 SC_HANDLE WINAPI
688 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
689                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
690                   DWORD dwServiceType, DWORD dwStartType,
691                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
692                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
693                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
694                   LPCWSTR lpPassword )
695 {
696     struct sc_handle *hscm = hSCManager;
697     struct sc_handle *retval;
698     HKEY hKey;
699     LONG r;
700     DWORD dp;
701     static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
702     static const WCHAR szType[] = {'T','y','p','e',0};
703     static const WCHAR szStart[] = {'S','t','a','r','t',0};
704     static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
705     static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
706     static const WCHAR szGroup[] = {'G','r','o','u','p',0};
707     static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
708
709     FIXME("%p %s %s\n", hSCManager, 
710           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
711
712     retval = alloc_sc_handle( SC_HTYPE_SERVICE );
713     if( NULL == retval )
714         return NULL;
715
716     r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
717                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
718     if (r!=ERROR_SUCCESS)
719         goto error;
720
721     init_service_handle( retval, hscm, hKey, lpServiceName );
722
723     if (dp != REG_CREATED_NEW_KEY)
724         goto error;
725
726     if(lpDisplayName)
727     {
728         r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (const BYTE*)lpDisplayName,
729                            (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
730         if (r!=ERROR_SUCCESS)
731             goto error;
732     }
733
734     r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
735     if (r!=ERROR_SUCCESS)
736         goto error;
737
738     r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
739     if (r!=ERROR_SUCCESS)
740         goto error;
741
742     r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
743                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
744     if (r!=ERROR_SUCCESS)
745         goto error;
746
747     if(lpBinaryPathName)
748     {
749         r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (const BYTE*)lpBinaryPathName,
750                            (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
751         if (r!=ERROR_SUCCESS)
752             goto error;
753     }
754
755     if(lpLoadOrderGroup)
756     {
757         r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (const BYTE*)lpLoadOrderGroup,
758                            (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
759         if (r!=ERROR_SUCCESS)
760             goto error;
761     }
762
763     if(lpDependencies)
764     {
765         DWORD len = 0;
766
767         /* determine the length of a double null terminated multi string */
768         do {
769             len += (strlenW(&lpDependencies[len])+1);
770         } while (lpDependencies[len++]);
771
772         r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
773                            (const BYTE*)lpDependencies, len );
774         if (r!=ERROR_SUCCESS)
775             goto error;
776     }
777
778     if(lpPassword)
779     {
780         FIXME("Don't know how to add a Password for a service.\n");
781     }
782
783     if(lpServiceStartName)
784     {
785         FIXME("Don't know how to add a ServiceStartName for a service.\n");
786     }
787
788     return (SC_HANDLE) retval;
789     
790 error:
791     free_sc_handle( retval );
792     return NULL;
793 }
794
795
796 /******************************************************************************
797  * CreateServiceA [ADVAPI32.@]
798  */
799 SC_HANDLE WINAPI
800 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
801                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
802                   DWORD dwServiceType, DWORD dwStartType,
803                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
804                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
805                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
806                   LPCSTR lpPassword )
807 {
808     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
809         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
810     SC_HANDLE r;
811
812     TRACE("%p %s %s\n", hSCManager,
813           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
814
815     lpServiceNameW = SERV_dup( lpServiceName );
816     lpDisplayNameW = SERV_dup( lpDisplayName );
817     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
818     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
819     lpDependenciesW = SERV_dupmulti( lpDependencies );
820     lpServiceStartNameW = SERV_dup( lpServiceStartName );
821     lpPasswordW = SERV_dup( lpPassword );
822
823     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
824             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
825             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
826             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
827
828     SERV_free( lpServiceNameW );
829     SERV_free( lpDisplayNameW );
830     SERV_free( lpBinaryPathNameW );
831     SERV_free( lpLoadOrderGroupW );
832     SERV_free( lpDependenciesW );
833     SERV_free( lpServiceStartNameW );
834     SERV_free( lpPasswordW );
835
836     return r;
837 }
838
839
840 /******************************************************************************
841  * DeleteService [ADVAPI32.@]
842  *
843  * Delete a service from the service control manager database.
844  *
845  * PARAMS
846  *    hService [I] Handle of the service to delete
847  *
848  * RETURNS
849  *  Success: TRUE
850  *  Failure: FALSE
851  */
852 BOOL WINAPI DeleteService( SC_HANDLE hService )
853 {
854     struct sc_handle *hsvc = hService;
855     HKEY hKey = hsvc->u.service.hkey;
856     WCHAR valname[MAX_PATH+1];
857     INT index = 0;
858     LONG rc;
859     DWORD size;
860
861     size = MAX_PATH+1; 
862     /* Clean out the values */
863     rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
864     while (rc == ERROR_SUCCESS)
865     {
866         RegDeleteValueW(hKey,valname);
867         index++;
868         size = MAX_PATH+1; 
869         rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
870     }
871
872     RegCloseKey(hKey);
873     hsvc->u.service.hkey = NULL;
874
875     /* delete the key */
876     RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
877                   hsvc->u.service.name);
878
879     return TRUE;
880 }
881
882
883 /******************************************************************************
884  * StartServiceA [ADVAPI32.@]
885  *
886  * Start a service
887  *
888  * PARAMS
889  *   hService            [I] Handle of service
890  *   dwNumServiceArgs    [I] Number of arguments
891  *   lpServiceArgVectors [I] Address of array of argument strings
892  *
893  * NOTES
894  *  - NT implements this function using an obscure RPC call.
895  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
896  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
897  *  - This will only work for shared address space. How should the service
898  *    args be transferred when address spaces are separated?
899  *  - Can only start one service at a time.
900  *  - Has no concept of privilege.
901  *
902  * RETURNS
903  *   Success: TRUE.
904  *   Failure: FALSE
905  */
906 BOOL WINAPI
907 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
908                  LPCSTR *lpServiceArgVectors )
909 {
910     LPWSTR *lpwstr=NULL;
911     UNICODE_STRING usBuffer;
912     unsigned int i;
913
914     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
915
916     if(dwNumServiceArgs)
917         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
918                                    dwNumServiceArgs*sizeof(LPWSTR) );
919     else
920         lpwstr = NULL;
921
922     for(i=0; i<dwNumServiceArgs; i++)
923     {
924         RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
925         lpwstr[i]=usBuffer.Buffer;
926     }
927
928     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
929
930     if(dwNumServiceArgs)
931     {
932         for(i=0; i<dwNumServiceArgs; i++)
933             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
934         HeapFree(GetProcessHeap(), 0, lpwstr);
935     }
936
937     return TRUE;
938 }
939
940
941 /******************************************************************************
942  * StartServiceW [ADVAPI32.@]
943  * 
944  * See StartServiceA.
945  */
946 BOOL WINAPI
947 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
948                  LPCWSTR *lpServiceArgVectors )
949 {
950     static const WCHAR  _WaitServiceStartW[]  = {'A','D','V','A','P','I','_','W',
951                                                 'a','i','t','S','e','r','v','i',
952                                                 'c','e','S','t','a','r','t',0};
953     static const WCHAR  _ImagePathW[]  = {'I','m','a','g','e','P','a','t','h',0};
954                                                 
955     struct sc_handle *hsvc = hService;
956     WCHAR path[MAX_PATH],str[MAX_PATH];
957     DWORD type,size;
958     DWORD i;
959     long r;
960     HANDLE hLock;
961     HANDLE hServiceShmem = NULL;
962     HANDLE wait = NULL;
963     LPWSTR shmem_lock = NULL;
964     struct SEB *seb = NULL;
965     LPWSTR argptr;
966     PROCESS_INFORMATION procinfo;
967     STARTUPINFOW startupinfo;
968     BOOL ret = FALSE;
969
970     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
971           lpServiceArgVectors);
972
973     size = sizeof(str);
974     r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
975     if (r!=ERROR_SUCCESS)
976         return FALSE;
977     ExpandEnvironmentStringsW(str,path,sizeof(path));
978
979     TRACE("Starting service %s\n", debugstr_w(path) );
980
981     hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
982     if( NULL == hLock )
983         return FALSE;
984
985     /*
986      * FIXME: start dependent services
987      */
988
989     /* pass argv[0] (service name) to the service via global SCM lock object */
990     shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
991                                 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
992     if( NULL == shmem_lock )
993     {
994         ERR("Couldn't map shared memory\n");
995         goto done;
996     }
997     strcpyW( shmem_lock, hsvc->u.service.name );
998
999     /* create service environment block */
1000     size = sizeof(struct SEB);
1001     for( i = 0; i < dwNumServiceArgs; i++ )
1002         size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] ));
1003
1004     snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1005     hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1006                                         NULL, PAGE_READWRITE, 0, size, str );
1007     if( NULL == hServiceShmem )
1008     {
1009         ERR("Couldn't create shared memory object\n");
1010         goto done;
1011     }
1012     if( GetLastError() == ERROR_ALREADY_EXISTS )
1013     {
1014         SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1015         goto done;
1016     }
1017     seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1018     if( NULL == seb )
1019     {
1020         ERR("Couldn't map shared memory\n");
1021         goto done;
1022     }
1023
1024     /* copy service args to SEB */
1025     seb->argc = dwNumServiceArgs;
1026     argptr = (LPWSTR) &seb[1];
1027     for( i = 0; i < dwNumServiceArgs; i++ )
1028     {
1029         strcpyW( argptr, lpServiceArgVectors[ i ] );
1030         argptr += 1 + strlenW( argptr );
1031     }
1032
1033     wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
1034     if (!wait)
1035     {
1036         ERR("Couldn't create wait semaphore\n");
1037         goto done;
1038     }
1039
1040     ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1041     startupinfo.cb = sizeof(STARTUPINFOW);
1042
1043     r = CreateProcessW(NULL,
1044                    path,
1045                    NULL,  /* process security attribs */
1046                    NULL,  /* thread security attribs */
1047                    FALSE, /* inherit handles */
1048                    0,     /* creation flags */
1049                    NULL,  /* environment */
1050                    NULL,  /* current directory */
1051                    &startupinfo,  /* startup info */
1052                    &procinfo); /* process info */
1053
1054     if(r == FALSE)
1055     {
1056         ERR("Couldn't start process\n");
1057         goto done;
1058     }
1059     CloseHandle( procinfo.hThread );
1060
1061     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1062     r = WaitForSingleObject(wait,30000);
1063     if( WAIT_FAILED == r )
1064     {
1065         CloseHandle( procinfo.hProcess );
1066         goto done;
1067     }
1068
1069     /* allright */
1070     CloseHandle( procinfo.hProcess );
1071     ret = TRUE;
1072
1073 done:
1074     if( wait ) CloseHandle( wait );
1075     if( seb != NULL ) UnmapViewOfFile( seb );
1076     if( hServiceShmem != NULL ) CloseHandle( hServiceShmem );
1077     if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock );
1078     UnlockServiceDatabase( hLock );
1079     return ret;
1080 }
1081
1082 /******************************************************************************
1083  * QueryServiceStatus [ADVAPI32.@]
1084  *
1085  * PARAMS
1086  *   hService        []
1087  *   lpservicestatus []
1088  *
1089  */
1090 BOOL WINAPI
1091 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1092 {
1093     struct sc_handle *hsvc = hService;
1094     LONG r;
1095     DWORD type, val, size;
1096     WCHAR str[MAX_PATH];
1097     HANDLE hServiceShmem = NULL;
1098
1099     FIXME("(%p,%p) partial\n",hService,lpservicestatus);
1100
1101     /* read the service type from the registry */
1102     size = sizeof(val);
1103     r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1104     if(type!=REG_DWORD)
1105     {
1106         ERR("invalid Type\n");
1107         return FALSE;
1108     }
1109     lpservicestatus->dwServiceType = val;
1110     /* FIXME: how are these determined or read from the registry? */
1111     /* SERVICE: unavailable=0, stopped=1, starting=2, running=3?  */
1112
1113     /* Determine if currently running via named shared memory     */
1114     snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1115     hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1116                                         NULL, PAGE_READWRITE, 0, size, str );
1117     if( NULL == hServiceShmem )
1118     {
1119         lpservicestatus->dwCurrentState = 1;
1120     } else {
1121         if( GetLastError() == ERROR_ALREADY_EXISTS )
1122         {
1123             lpservicestatus->dwCurrentState = 3;
1124         } else {
1125             lpservicestatus->dwCurrentState = 1;
1126         }
1127         CloseHandle( hServiceShmem );
1128     }
1129
1130     lpservicestatus->dwControlsAccepted        = 0;
1131     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
1132     lpservicestatus->dwServiceSpecificExitCode = 0;
1133     lpservicestatus->dwCheckPoint              = 0;
1134     lpservicestatus->dwWaitHint                = 0;
1135
1136     return TRUE;
1137 }
1138
1139 /******************************************************************************
1140  * QueryServiceStatusEx [ADVAPI32.@]
1141  *
1142  * Get information about a service.
1143  *
1144  * PARAMS
1145  *   hService       [I] Handle to service to get information about
1146  *   InfoLevel      [I] Level of information to get
1147  *   lpBuffer       [O] Destination for requested information
1148  *   cbBufSize      [I] Size of lpBuffer in bytes
1149  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1150  *
1151  * RETURNS
1152  *  Success: TRUE
1153  *  FAILURE: FALSE
1154  */
1155 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1156                         LPBYTE lpBuffer, DWORD cbBufSize,
1157                         LPDWORD pcbBytesNeeded)
1158 {
1159     FIXME("stub\n");
1160     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1161     return FALSE;
1162 }
1163
1164 /******************************************************************************
1165  * QueryServiceConfigA [ADVAPI32.@]
1166  */
1167 BOOL WINAPI 
1168 QueryServiceConfigA( SC_HANDLE hService,
1169                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1170                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1171 {
1172     static const CHAR szDisplayName[] = "DisplayName";
1173     static const CHAR szType[] = "Type";
1174     static const CHAR szStart[] = "Start";
1175     static const CHAR szError[] = "ErrorControl";
1176     static const CHAR szImagePath[] = "ImagePath";
1177     static const CHAR szGroup[] = "Group";
1178     static const CHAR szDependencies[] = "Dependencies";
1179     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1180     CHAR str_buffer[ MAX_PATH ];
1181     LONG r;
1182     DWORD type, val, sz, total, n;
1183     LPBYTE p;
1184
1185     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1186            cbBufSize, pcbBytesNeeded);
1187
1188     /* calculate the size required first */
1189     total = sizeof (QUERY_SERVICE_CONFIGA);
1190
1191     sz = sizeof(str_buffer);
1192     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1193     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1194     {
1195         sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1196         if( 0 == sz ) return FALSE;
1197
1198         total += sz;
1199     }
1200     else
1201     {
1202         /* FIXME: set last error */
1203         return FALSE;
1204     }
1205
1206     sz = 0;
1207     r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1208     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1209         total += sz;
1210
1211     sz = 0;
1212     r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1213     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1214         total += sz;
1215
1216     sz = 0;
1217     r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1218     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1219         total += sz;
1220
1221     sz = 0;
1222     r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1223     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1224         total += sz;
1225
1226     /* if there's not enough memory, return an error */
1227     if( total > *pcbBytesNeeded )
1228     {
1229         *pcbBytesNeeded = total;
1230         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1231         return FALSE;
1232     }
1233
1234     *pcbBytesNeeded = total;
1235     ZeroMemory( lpServiceConfig, total );
1236
1237     sz = sizeof val;
1238     r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1239     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1240         lpServiceConfig->dwServiceType = val;
1241
1242     sz = sizeof val;
1243     r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1244     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1245         lpServiceConfig->dwStartType = val;
1246
1247     sz = sizeof val;
1248     r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1249     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1250         lpServiceConfig->dwErrorControl = val;
1251
1252     /* now do the strings */
1253     p = (LPBYTE) &lpServiceConfig[1];
1254     n = total - sizeof (QUERY_SERVICE_CONFIGA);
1255
1256     sz = sizeof(str_buffer);
1257     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1258     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1259     {
1260         sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1261         if( 0 == sz || sz > n ) return FALSE;
1262
1263         lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1264         p += sz;
1265         n -= sz;
1266     }
1267     else
1268     {
1269         /* FIXME: set last error */
1270         return FALSE;
1271     }
1272
1273     sz = n;
1274     r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1275     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1276     {
1277         lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1278         p += sz;
1279         n -= sz;
1280     }
1281
1282     sz = n;
1283     r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1284     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1285     {
1286         lpServiceConfig->lpDependencies = (LPSTR) p;
1287         p += sz;
1288         n -= sz;
1289     }
1290
1291     if( n < 0 )
1292         ERR("Buffer overflow!\n");
1293
1294     TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1295     TRACE("Group      = %s\n", lpServiceConfig->lpLoadOrderGroup );
1296
1297     return TRUE;
1298 }
1299
1300 /******************************************************************************
1301  * QueryServiceConfigW [ADVAPI32.@]
1302  */
1303 BOOL WINAPI 
1304 QueryServiceConfigW( SC_HANDLE hService,
1305                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1306                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1307 {
1308     static const WCHAR szDisplayName[] = {
1309         'D','i','s','p','l','a','y','N','a','m','e', 0 };
1310     static const WCHAR szType[] = {'T','y','p','e',0};
1311     static const WCHAR szStart[] = {'S','t','a','r','t',0};
1312     static const WCHAR szError[] = {
1313         'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1314     static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1315     static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1316     static const WCHAR szDependencies[] = {
1317         'D','e','p','e','n','d','e','n','c','i','e','s',0};
1318     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1319     WCHAR str_buffer[ MAX_PATH ];
1320     LONG r;
1321     DWORD type, val, sz, total, n;
1322     LPBYTE p;
1323
1324     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1325            cbBufSize, pcbBytesNeeded);
1326
1327     /* calculate the size required first */
1328     total = sizeof (QUERY_SERVICE_CONFIGW);
1329
1330     sz = sizeof(str_buffer);
1331     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1332     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1333     {
1334         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1335         if( 0 == sz ) return FALSE;
1336
1337         total += sizeof(WCHAR) * sz;
1338     }
1339     else
1340     {
1341        /* FIXME: set last error */
1342        return FALSE;
1343     }
1344
1345     sz = 0;
1346     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1347     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1348         total += sz;
1349
1350     sz = 0;
1351     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1352     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1353         total += sz;
1354
1355     sz = 0;
1356     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1357     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1358         total += sz;
1359
1360     sz = 0;
1361     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1362     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1363         total += sz;
1364
1365     /* if there's not enough memory, return an error */
1366     if( total > *pcbBytesNeeded )
1367     {
1368         *pcbBytesNeeded = total;
1369         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1370         return FALSE;
1371     }
1372
1373     *pcbBytesNeeded = total;
1374     ZeroMemory( lpServiceConfig, total );
1375
1376     sz = sizeof val;
1377     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1378     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1379         lpServiceConfig->dwServiceType = val;
1380
1381     sz = sizeof val;
1382     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1383     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1384         lpServiceConfig->dwStartType = val;
1385
1386     sz = sizeof val;
1387     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1388     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1389         lpServiceConfig->dwErrorControl = val;
1390
1391     /* now do the strings */
1392     p = (LPBYTE) &lpServiceConfig[1];
1393     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1394
1395     sz = sizeof(str_buffer);
1396     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1397     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1398     {
1399         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1400         sz *= sizeof(WCHAR);
1401         if( 0 == sz || sz > n ) return FALSE;
1402
1403         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1404         p += sz;
1405         n -= sz;
1406     }
1407     else
1408     {
1409        /* FIXME: set last error */
1410        return FALSE;
1411     }
1412
1413     sz = n;
1414     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1415     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1416     {
1417         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1418         p += sz;
1419         n -= sz;
1420     }
1421
1422     sz = n;
1423     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1424     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1425     {
1426         lpServiceConfig->lpDependencies = (LPWSTR) p;
1427         p += sz;
1428         n -= sz;
1429     }
1430
1431     if( n < 0 )
1432         ERR("Buffer overflow!\n");
1433
1434     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1435     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1436
1437     return TRUE;
1438 }
1439
1440 /******************************************************************************
1441  * ChangeServiceConfigW  [ADVAPI32.@]
1442  */
1443 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1444   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1445   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1446   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1447 {
1448     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1449           hService, dwServiceType, dwStartType, dwErrorControl, 
1450           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1451           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1452           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1453     return TRUE;
1454 }
1455
1456 /******************************************************************************
1457  * ChangeServiceConfigA  [ADVAPI32.@]
1458  */
1459 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1460   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1461   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1462   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1463 {
1464     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1465     LPWSTR wServiceStartName, wPassword, wDisplayName;
1466     BOOL r;
1467
1468     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1469           hService, dwServiceType, dwStartType, dwErrorControl, 
1470           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1471           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1472           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1473
1474     wBinaryPathName = SERV_dup( lpBinaryPathName );
1475     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1476     wDependencies = SERV_dupmulti( lpDependencies );
1477     wServiceStartName = SERV_dup( lpServiceStartName );
1478     wPassword = SERV_dup( lpPassword );
1479     wDisplayName = SERV_dup( lpDisplayName );
1480
1481     r = ChangeServiceConfigW( hService, dwServiceType,
1482             dwStartType, dwErrorControl, wBinaryPathName,
1483             wLoadOrderGroup, lpdwTagId, wDependencies,
1484             wServiceStartName, wPassword, wDisplayName);
1485
1486     SERV_free( wBinaryPathName );
1487     SERV_free( wLoadOrderGroup );
1488     SERV_free( wDependencies );
1489     SERV_free( wServiceStartName );
1490     SERV_free( wPassword );
1491     SERV_free( wDisplayName );
1492
1493     return r;
1494 }
1495
1496 /******************************************************************************
1497  * ChangeServiceConfig2A  [ADVAPI32.@]
1498  */
1499 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
1500     LPVOID lpInfo)
1501 {
1502     BOOL r = FALSE;
1503
1504     TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
1505
1506     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1507     {
1508         LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
1509         SERVICE_DESCRIPTIONW sdw;
1510
1511         sdw.lpDescription = SERV_dup( sd->lpDescription );
1512
1513         r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
1514
1515         SERV_free( sdw.lpDescription );
1516     }
1517     else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
1518     {
1519         LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
1520         SERVICE_FAILURE_ACTIONSW faw;
1521
1522         faw.dwResetPeriod = fa->dwResetPeriod;
1523         faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
1524         faw.lpCommand = SERV_dup( fa->lpCommand );
1525         faw.cActions = fa->cActions;
1526         faw.lpsaActions = fa->lpsaActions;
1527
1528         r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
1529
1530         SERV_free( faw.lpRebootMsg );
1531         SERV_free( faw.lpCommand );
1532     }
1533     else
1534         SetLastError( ERROR_INVALID_PARAMETER );
1535
1536     return r;
1537 }
1538
1539 /******************************************************************************
1540  * ChangeServiceConfig2W  [ADVAPI32.@]
1541  */
1542 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
1543     LPVOID lpInfo)
1544 {
1545     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1546
1547     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1548     {
1549         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1550         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1551         if (sd->lpDescription)
1552         {
1553             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1554             if (sd->lpDescription[0] == 0)
1555                 RegDeleteValueW(hKey,szDescription);
1556             else
1557                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1558                                         (LPVOID)sd->lpDescription,
1559                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1560         }
1561     }
1562     else   
1563         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1564     return TRUE;
1565 }
1566
1567 /******************************************************************************
1568  * QueryServiceObjectSecurity [ADVAPI32.@]
1569  */
1570 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1571        SECURITY_INFORMATION dwSecurityInformation,
1572        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1573        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1574 {
1575     PACL pACL = NULL;
1576     FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1577           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1578
1579
1580     InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
1581
1582     pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
1583     InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
1584     SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
1585     return TRUE;
1586 }
1587
1588 /******************************************************************************
1589  * SetServiceObjectSecurity [ADVAPI32.@]
1590  */
1591 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1592        SECURITY_INFORMATION dwSecurityInformation,
1593        PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1594 {
1595     FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1596     return TRUE;
1597 }