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