Implement ChangeServiceConfigA using ChangeServiceConfigW.
[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 /******************************************************************************
542  * AllocateLocallyUniqueId [ADVAPI32.@]
543  *
544  * PARAMS
545  *   lpluid []
546  */
547 BOOL WINAPI
548 AllocateLocallyUniqueId( PLUID lpluid )
549 {
550         lpluid->LowPart = time(NULL);
551         lpluid->HighPart = 0;
552         return TRUE;
553 }
554
555
556 /******************************************************************************
557  * ControlService [ADVAPI32.@]
558  *
559  * Send a control code to a service.
560  *
561  * PARAMS
562  *   hService        [I] Handle of the service control manager database
563  *   dwControl       [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
564  *   lpServiceStatus [O] Destination for the status of the service, if available
565  *
566  * RETURNS
567  *   Success: TRUE.
568  *   Failure: FALSE.
569  */
570 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
571                             LPSERVICE_STATUS lpServiceStatus )
572 {
573     FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
574     return TRUE;
575 }
576
577
578 /******************************************************************************
579  * CloseServiceHandle [ADVAPI32.@]
580  * 
581  * Close a handle to a service or the service control manager database.
582  *
583  * PARAMS
584  *   hSCObject [I] Handle to service or service control manager database
585  *
586  * RETURNS
587  *  Success: TRUE
588  *  Failure: FALSE
589  */
590 BOOL WINAPI
591 CloseServiceHandle( SC_HANDLE hSCObject )
592 {
593     TRACE("(%p)\n", hSCObject);
594
595     free_sc_handle( (struct sc_handle*) hSCObject );
596
597     return TRUE;
598 }
599
600
601 /******************************************************************************
602  * OpenServiceA [ADVAPI32.@]
603  *
604  * Open a handle to a service.
605  *
606  * PARAMS
607  *   hSCManager      [I] Handle of the service control manager database
608  *   lpServiceName   [I] Name of the service to open
609  *   dwDesiredAccess [I] Access required to the service
610  *
611  * RETURNS
612  *    Success: Handle to the service
613  *    Failure: NULL
614  */
615 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
616                                DWORD dwDesiredAccess )
617 {
618     UNICODE_STRING lpServiceNameW;
619     SC_HANDLE ret;
620     RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
621     if(lpServiceName)
622         TRACE("Request for service %s\n",lpServiceName);
623     else
624         return FALSE;
625     ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
626     RtlFreeUnicodeString(&lpServiceNameW);
627     return ret;
628 }
629
630
631 /******************************************************************************
632  * OpenServiceW [ADVAPI32.@]
633  *
634  * See OpenServiceA.
635  */
636 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
637                                DWORD dwDesiredAccess)
638 {
639     struct sc_handle *hscm = hSCManager;
640     struct sc_handle *retval;
641     HKEY hKey;
642     long r;
643
644     TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
645           dwDesiredAccess);
646
647     retval = alloc_sc_handle( SC_HTYPE_SERVICE );
648     if( NULL == retval )
649         return NULL;
650
651     r = RegOpenKeyExW( hscm->u.manager.hkey_scm_db,
652                        lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
653     if (r!=ERROR_SUCCESS)
654     {
655         free_sc_handle( retval );
656         SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
657         return NULL;
658     }
659     
660     init_service_handle( retval, hscm, hKey, lpServiceName );
661
662     TRACE("returning %p\n",retval);
663
664     return (SC_HANDLE) retval;
665 }
666
667 /******************************************************************************
668  * CreateServiceW [ADVAPI32.@]
669  */
670 SC_HANDLE WINAPI
671 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
672                   LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
673                   DWORD dwServiceType, DWORD dwStartType,
674                   DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
675                   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
676                   LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
677                   LPCWSTR lpPassword )
678 {
679     struct sc_handle *hscm = hSCManager;
680     struct sc_handle *retval;
681     HKEY hKey;
682     LONG r;
683     DWORD dp;
684     static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
685     static const WCHAR szType[] = {'T','y','p','e',0};
686     static const WCHAR szStart[] = {'S','t','a','r','t',0};
687     static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
688     static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
689     static const WCHAR szGroup[] = {'G','r','o','u','p',0};
690     static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
691
692     FIXME("%p %s %s\n", hSCManager, 
693           debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
694
695     retval = alloc_sc_handle( SC_HTYPE_SERVICE );
696     if( NULL == retval )
697         return NULL;
698
699     r = RegCreateKeyExW(hscm->u.manager.hkey_scm_db, lpServiceName, 0, NULL,
700                        REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
701     if (r!=ERROR_SUCCESS)
702         goto error;
703
704     init_service_handle( retval, hscm, hKey, lpServiceName );
705
706     if (dp != REG_CREATED_NEW_KEY)
707         goto error;
708
709     if(lpDisplayName)
710     {
711         r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (LPBYTE)lpDisplayName,
712                            (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
713         if (r!=ERROR_SUCCESS)
714             goto error;
715     }
716
717     r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
718     if (r!=ERROR_SUCCESS)
719         goto error;
720
721     r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
722     if (r!=ERROR_SUCCESS)
723         goto error;
724
725     r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
726                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
727     if (r!=ERROR_SUCCESS)
728         goto error;
729
730     if(lpBinaryPathName)
731     {
732         r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (LPBYTE)lpBinaryPathName,
733                            (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
734         if (r!=ERROR_SUCCESS)
735             goto error;
736     }
737
738     if(lpLoadOrderGroup)
739     {
740         r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (LPBYTE)lpLoadOrderGroup,
741                            (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
742         if (r!=ERROR_SUCCESS)
743             goto error;
744     }
745
746     if(lpDependencies)
747     {
748         DWORD len = 0;
749
750         /* determine the length of a double null terminated multi string */
751         do {
752             len += (strlenW(&lpDependencies[len])+1);
753         } while (lpDependencies[len++]);
754
755         r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
756                            (LPBYTE)lpDependencies, len );
757         if (r!=ERROR_SUCCESS)
758             goto error;
759     }
760
761     if(lpPassword)
762     {
763         FIXME("Don't know how to add a Password for a service.\n");
764     }
765
766     if(lpServiceStartName)
767     {
768         FIXME("Don't know how to add a ServiceStartName for a service.\n");
769     }
770
771     return (SC_HANDLE) retval;
772     
773 error:
774     free_sc_handle( retval );
775     return NULL;
776 }
777
778
779 static inline LPWSTR SERV_dup( LPCSTR str )
780 {
781     UINT len;
782     LPWSTR wstr;
783
784     if( !str )
785         return NULL;
786     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
787     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
788     MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
789     return wstr;
790 }
791
792 static inline LPWSTR SERV_dupmulti( LPCSTR str )
793 {
794     UINT len = 0, n = 0;
795     LPWSTR wstr;
796
797     if( !str )
798         return NULL;
799     do {
800         len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
801         n += (strlen( &str[n] ) + 1);
802     } while (str[n]);
803     len++;
804     n++;
805     
806     wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
807     MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
808     return wstr;
809 }
810
811 static inline VOID SERV_free( LPWSTR wstr )
812 {
813     HeapFree( GetProcessHeap(), 0, wstr );
814 }
815
816 /******************************************************************************
817  * CreateServiceA [ADVAPI32.@]
818  */
819 SC_HANDLE WINAPI
820 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
821                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
822                   DWORD dwServiceType, DWORD dwStartType,
823                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
824                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
825                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
826                   LPCSTR lpPassword )
827 {
828     LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
829         lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
830     SC_HANDLE r;
831
832     TRACE("%p %s %s\n", hSCManager,
833           debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
834
835     lpServiceNameW = SERV_dup( lpServiceName );
836     lpDisplayNameW = SERV_dup( lpDisplayName );
837     lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
838     lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
839     lpDependenciesW = SERV_dupmulti( lpDependencies );
840     lpServiceStartNameW = SERV_dup( lpServiceStartName );
841     lpPasswordW = SERV_dup( lpPassword );
842
843     r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
844             dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
845             lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
846             lpDependenciesW, lpServiceStartNameW, lpPasswordW );
847
848     SERV_free( lpServiceNameW );
849     SERV_free( lpDisplayNameW );
850     SERV_free( lpBinaryPathNameW );
851     SERV_free( lpLoadOrderGroupW );
852     SERV_free( lpDependenciesW );
853     SERV_free( lpServiceStartNameW );
854     SERV_free( lpPasswordW );
855
856     return r;
857 }
858
859
860 /******************************************************************************
861  * DeleteService [ADVAPI32.@]
862  *
863  * Delete a service from the service control manager database.
864  *
865  * PARAMS
866  *    hService [I] Handle of the service to delete
867  *
868  * RETURNS
869  *  Success: TRUE
870  *  Failure: FALSE
871  */
872 BOOL WINAPI DeleteService( SC_HANDLE hService )
873 {
874     struct sc_handle *hsvc = hService;
875     HKEY hKey = hsvc->u.service.hkey;
876     WCHAR valname[MAX_PATH+1];
877     INT index = 0;
878     LONG rc;
879     DWORD size;
880
881     size = MAX_PATH+1; 
882     /* Clean out the values */
883     rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
884     while (rc == ERROR_SUCCESS)
885     {
886         RegDeleteValueW(hKey,valname);
887         index++;
888         size = MAX_PATH+1; 
889         rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
890     }
891
892     RegCloseKey(hKey);
893     hsvc->u.service.hkey = NULL;
894
895     /* delete the key */
896     RegDeleteKeyW(hsvc->u.service.sc_manager->u.manager.hkey_scm_db,
897                   hsvc->u.service.name);
898
899     return TRUE;
900 }
901
902
903 /******************************************************************************
904  * StartServiceA [ADVAPI32.@]
905  *
906  * Start a service
907  *
908  * PARAMS
909  *   hService            [I] Handle of service
910  *   dwNumServiceArgs    [I] Number of arguments
911  *   lpServiceArgVectors [I] Address of array of argument strings
912  *
913  * NOTES
914  *  - NT implements this function using an obscure RPC call.
915  *  - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
916  *    to get things like "%SystemRoot%\\System32\\service.exe" to load.
917  *  - This will only work for shared address space. How should the service
918  *    args be transferred when address spaces are separated?
919  *  - Can only start one service at a time.
920  *  - Has no concept of privilege.
921  *
922  * RETURNS
923  *   Success: TRUE.
924  *   Failure: FALSE
925  */
926 BOOL WINAPI
927 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
928                  LPCSTR *lpServiceArgVectors )
929 {
930     LPWSTR *lpwstr=NULL;
931     UNICODE_STRING usBuffer;
932     unsigned int i;
933
934     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
935
936     if(dwNumServiceArgs)
937         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
938                                    dwNumServiceArgs*sizeof(LPWSTR) );
939     else
940         lpwstr = NULL;
941
942     for(i=0; i<dwNumServiceArgs; i++)
943     {
944         RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
945         lpwstr[i]=usBuffer.Buffer;
946     }
947
948     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
949
950     if(dwNumServiceArgs)
951     {
952         for(i=0; i<dwNumServiceArgs; i++)
953             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
954         HeapFree(GetProcessHeap(), 0, lpwstr);
955     }
956
957     return TRUE;
958 }
959
960
961 /******************************************************************************
962  * StartServiceW [ADVAPI32.@]
963  * 
964  * See StartServiceA.
965  */
966 BOOL WINAPI
967 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
968                  LPCWSTR *lpServiceArgVectors )
969 {
970     static const WCHAR  _WaitServiceStartW[]  = {'A','D','V','A','P','I','_','W',
971                                                 'a','i','t','S','e','r','v','i',
972                                                 'c','e','S','t','a','r','t',0};
973     static const WCHAR  _ImagePathW[]  = {'I','m','a','g','e','P','a','t','h',0};
974                                                 
975     struct sc_handle *hsvc = hService;
976     WCHAR path[MAX_PATH],str[MAX_PATH];
977     DWORD type,size;
978     DWORD i;
979     long r;
980     HANDLE hLock;
981     HANDLE hServiceShmem = NULL;
982     HANDLE wait = NULL;
983     LPWSTR shmem_lock = NULL;
984     struct SEB *seb = NULL;
985     LPWSTR argptr;
986     PROCESS_INFORMATION procinfo;
987     STARTUPINFOW startupinfo;
988     BOOL ret = FALSE;
989
990     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
991           lpServiceArgVectors);
992
993     size = sizeof(str);
994     r = RegQueryValueExW(hsvc->u.service.hkey, _ImagePathW, NULL, &type, (LPVOID)str, &size);
995     if (r!=ERROR_SUCCESS)
996         return FALSE;
997     ExpandEnvironmentStringsW(str,path,sizeof(path));
998
999     TRACE("Starting service %s\n", debugstr_w(path) );
1000
1001     hLock = LockServiceDatabase( hsvc->u.service.sc_manager );
1002     if( NULL == hLock )
1003         return FALSE;
1004
1005     /*
1006      * FIXME: start dependent services
1007      */
1008
1009     /* pass argv[0] (service name) to the service via global SCM lock object */
1010     shmem_lock = MapViewOfFile( hLock, FILE_MAP_ALL_ACCESS,
1011                                 0, 0, MAX_SERVICE_NAME * sizeof(WCHAR) );
1012     if( NULL == shmem_lock )
1013     {
1014         ERR("Couldn't map shared memory\n");
1015         goto done;
1016     }
1017     strcpyW( shmem_lock, hsvc->u.service.name );
1018
1019     /* create service environment block */
1020     size = sizeof(struct SEB);
1021     for( i = 0; i < dwNumServiceArgs; i++ )
1022         size += sizeof(WCHAR) * (1 + strlenW( lpServiceArgVectors[ i ] ));
1023
1024     snprintfW( str, MAX_PATH, szServiceShmemNameFmtW, hsvc->u.service.name );
1025     hServiceShmem = CreateFileMappingW( INVALID_HANDLE_VALUE,
1026                                         NULL, PAGE_READWRITE, 0, size, str );
1027     if( NULL == hServiceShmem )
1028     {
1029         ERR("Couldn't create shared memory object\n");
1030         goto done;
1031     }
1032     if( GetLastError() == ERROR_ALREADY_EXISTS )
1033     {
1034         SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1035         goto done;
1036     }
1037     seb = MapViewOfFile( hServiceShmem, FILE_MAP_ALL_ACCESS, 0, 0, 0 );
1038     if( NULL == seb )
1039     {
1040         ERR("Couldn't map shared memory\n");
1041         goto done;
1042     }
1043
1044     /* copy service args to SEB */
1045     seb->argc = dwNumServiceArgs;
1046     argptr = (LPWSTR) &seb[1];
1047     for( i = 0; i < dwNumServiceArgs; i++ )
1048     {
1049         strcpyW( argptr, lpServiceArgVectors[ i ] );
1050         argptr += 1 + strlenW( argptr );
1051     }
1052
1053     wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
1054     if (!wait)
1055     {
1056         ERR("Couldn't create wait semaphore\n");
1057         goto done;
1058     }
1059
1060     ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
1061     startupinfo.cb = sizeof(STARTUPINFOW);
1062
1063     r = CreateProcessW(NULL,
1064                    path,
1065                    NULL,  /* process security attribs */
1066                    NULL,  /* thread security attribs */
1067                    FALSE, /* inherit handles */
1068                    0,     /* creation flags */
1069                    NULL,  /* environment */
1070                    NULL,  /* current directory */
1071                    &startupinfo,  /* startup info */
1072                    &procinfo); /* process info */
1073
1074     if(r == FALSE)
1075     {
1076         ERR("Couldn't start process\n");
1077         goto done;
1078     }
1079     CloseHandle( procinfo.hThread );
1080
1081     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
1082     r = WaitForSingleObject(wait,30000);
1083     if( WAIT_FAILED == r )
1084     {
1085         CloseHandle( procinfo.hProcess );
1086         goto done;
1087     }
1088
1089     /* allright */
1090     CloseHandle( procinfo.hProcess );
1091     ret = TRUE;
1092
1093 done:
1094     if( wait ) CloseHandle( wait );
1095     if( seb != NULL ) UnmapViewOfFile( seb );
1096     if( hServiceShmem != NULL ) CloseHandle( hServiceShmem );
1097     if( shmem_lock != NULL ) UnmapViewOfFile( shmem_lock );
1098     UnlockServiceDatabase( hLock );
1099     return ret;
1100 }
1101
1102 /******************************************************************************
1103  * QueryServiceStatus [ADVAPI32.@]
1104  *
1105  * PARAMS
1106  *   hService        []
1107  *   lpservicestatus []
1108  *
1109  */
1110 BOOL WINAPI
1111 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
1112 {
1113     struct sc_handle *hsvc = hService;
1114     LONG r;
1115     DWORD type, val, size;
1116
1117     FIXME("(%p,%p) partial\n",hService,lpservicestatus);
1118
1119     /* read the service type from the registry */
1120     size = sizeof(val);
1121     r = RegQueryValueExA(hsvc->u.service.hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1122     if(type!=REG_DWORD)
1123     {
1124         ERR("invalid Type\n");
1125         return FALSE;
1126     }
1127     lpservicestatus->dwServiceType = val;
1128     /* FIXME: how are these determined or read from the registry? */
1129     /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
1130     lpservicestatus->dwCurrentState            = 1;
1131     lpservicestatus->dwControlsAccepted        = 0;
1132     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
1133     lpservicestatus->dwServiceSpecificExitCode = 0;
1134     lpservicestatus->dwCheckPoint              = 0;
1135     lpservicestatus->dwWaitHint                = 0;
1136
1137     return TRUE;
1138 }
1139
1140 /******************************************************************************
1141  * QueryServiceStatusEx [ADVAPI32.@]
1142  *
1143  * Get information about a service.
1144  *
1145  * PARAMS
1146  *   hService       [I] Handle to service to get information about
1147  *   InfoLevel      [I] Level of information to get
1148  *   lpBuffer       [O] Destination for requested information
1149  *   cbBufSize      [I] Size of lpBuffer in bytes
1150  *   pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1151  *
1152  * RETURNS
1153  *  Success: TRUE
1154  *  FAILURE: FALSE
1155  */
1156 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1157                         LPBYTE lpBuffer, DWORD cbBufSize,
1158                         LPDWORD pcbBytesNeeded)
1159 {
1160     FIXME("stub\n");
1161     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1162     return FALSE;
1163 }
1164
1165 /******************************************************************************
1166  * QueryServiceConfigA [ADVAPI32.@]
1167  */
1168 BOOL WINAPI 
1169 QueryServiceConfigA( SC_HANDLE hService,
1170                      LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1171                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1172 {
1173     static const CHAR szDisplayName[] = "DisplayName";
1174     static const CHAR szType[] = "Type";
1175     static const CHAR szStart[] = "Start";
1176     static const CHAR szError[] = "ErrorControl";
1177     static const CHAR szImagePath[] = "ImagePath";
1178     static const CHAR szGroup[] = "Group";
1179     static const CHAR szDependencies[] = "Dependencies";
1180     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1181     CHAR str_buffer[ MAX_PATH ];
1182     LONG r;
1183     DWORD type, val, sz, total, n;
1184     LPBYTE p;
1185
1186     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1187            cbBufSize, pcbBytesNeeded);
1188
1189     /* calculate the size required first */
1190     total = sizeof (QUERY_SERVICE_CONFIGA);
1191
1192     sz = sizeof(str_buffer);
1193     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1194     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1195     {
1196         sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1197         if( 0 == sz ) return FALSE;
1198
1199         total += sz;
1200     }
1201     else
1202     {
1203         /* FIXME: set last error */
1204         return FALSE;
1205     }
1206
1207     sz = 0;
1208     r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1209     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1210         total += sz;
1211
1212     sz = 0;
1213     r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1214     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1215         total += sz;
1216
1217     sz = 0;
1218     r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1219     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1220         total += sz;
1221
1222     sz = 0;
1223     r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1224     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1225         total += sz;
1226
1227     /* if there's not enough memory, return an error */
1228     if( total > *pcbBytesNeeded )
1229     {
1230         *pcbBytesNeeded = total;
1231         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1232         return FALSE;
1233     }
1234
1235     *pcbBytesNeeded = total;
1236     ZeroMemory( lpServiceConfig, total );
1237
1238     sz = sizeof val;
1239     r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1240     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1241         lpServiceConfig->dwServiceType = val;
1242
1243     sz = sizeof val;
1244     r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1245     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1246         lpServiceConfig->dwStartType = val;
1247
1248     sz = sizeof val;
1249     r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1250     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1251         lpServiceConfig->dwErrorControl = val;
1252
1253     /* now do the strings */
1254     p = (LPBYTE) &lpServiceConfig[1];
1255     n = total - sizeof (QUERY_SERVICE_CONFIGA);
1256
1257     sz = sizeof(str_buffer);
1258     r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1259     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1260     {
1261         sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1262         if( 0 == sz || sz > n ) return FALSE;
1263
1264         lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1265         p += sz;
1266         n -= sz;
1267     }
1268     else
1269     {
1270         /* FIXME: set last error */
1271         return FALSE;
1272     }
1273
1274     sz = n;
1275     r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1276     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1277     {
1278         lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1279         p += sz;
1280         n -= sz;
1281     }
1282
1283     sz = n;
1284     r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1285     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1286     {
1287         lpServiceConfig->lpDependencies = (LPSTR) p;
1288         p += sz;
1289         n -= sz;
1290     }
1291
1292     if( n < 0 )
1293         ERR("Buffer overflow!\n");
1294
1295     TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1296     TRACE("Group      = %s\n", lpServiceConfig->lpLoadOrderGroup );
1297
1298     return TRUE;
1299 }
1300
1301 /******************************************************************************
1302  * QueryServiceConfigW [ADVAPI32.@]
1303  */
1304 BOOL WINAPI 
1305 QueryServiceConfigW( SC_HANDLE hService,
1306                      LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1307                      DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1308 {
1309     static const WCHAR szDisplayName[] = {
1310         'D','i','s','p','l','a','y','N','a','m','e', 0 };
1311     static const WCHAR szType[] = {'T','y','p','e',0};
1312     static const WCHAR szStart[] = {'S','t','a','r','t',0};
1313     static const WCHAR szError[] = {
1314         'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1315     static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1316     static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1317     static const WCHAR szDependencies[] = {
1318         'D','e','p','e','n','d','e','n','c','i','e','s',0};
1319     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1320     WCHAR str_buffer[ MAX_PATH ];
1321     LONG r;
1322     DWORD type, val, sz, total, n;
1323     LPBYTE p;
1324
1325     TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1326            cbBufSize, pcbBytesNeeded);
1327
1328     /* calculate the size required first */
1329     total = sizeof (QUERY_SERVICE_CONFIGW);
1330
1331     sz = sizeof(str_buffer);
1332     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1333     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1334     {
1335         sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1336         if( 0 == sz ) return FALSE;
1337
1338         total += sizeof(WCHAR) * sz;
1339     }
1340     else
1341     {
1342        /* FIXME: set last error */
1343        return FALSE;
1344     }
1345
1346     sz = 0;
1347     r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1348     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1349         total += sz;
1350
1351     sz = 0;
1352     r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1353     if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1354         total += sz;
1355
1356     sz = 0;
1357     r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1358     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1359         total += sz;
1360
1361     sz = 0;
1362     r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1363     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1364         total += sz;
1365
1366     /* if there's not enough memory, return an error */
1367     if( total > *pcbBytesNeeded )
1368     {
1369         *pcbBytesNeeded = total;
1370         SetLastError( ERROR_INSUFFICIENT_BUFFER );
1371         return FALSE;
1372     }
1373
1374     *pcbBytesNeeded = total;
1375     ZeroMemory( lpServiceConfig, total );
1376
1377     sz = sizeof val;
1378     r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1379     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1380         lpServiceConfig->dwServiceType = val;
1381
1382     sz = sizeof val;
1383     r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1384     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1385         lpServiceConfig->dwStartType = val;
1386
1387     sz = sizeof val;
1388     r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1389     if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1390         lpServiceConfig->dwErrorControl = val;
1391
1392     /* now do the strings */
1393     p = (LPBYTE) &lpServiceConfig[1];
1394     n = total - sizeof (QUERY_SERVICE_CONFIGW);
1395
1396     sz = sizeof(str_buffer);
1397     r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1398     if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1399     {
1400         sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1401         sz *= sizeof(WCHAR);
1402         if( 0 == sz || sz > n ) return FALSE;
1403
1404         lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1405         p += sz;
1406         n -= sz;
1407     }
1408     else
1409     {
1410        /* FIXME: set last error */
1411        return FALSE;
1412     }
1413
1414     sz = n;
1415     r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1416     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1417     {
1418         lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1419         p += sz;
1420         n -= sz;
1421     }
1422
1423     sz = n;
1424     r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1425     if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1426     {
1427         lpServiceConfig->lpDependencies = (LPWSTR) p;
1428         p += sz;
1429         n -= sz;
1430     }
1431
1432     if( n < 0 )
1433         ERR("Buffer overflow!\n");
1434
1435     TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1436     TRACE("Group      = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1437
1438     return TRUE;
1439 }
1440
1441 /******************************************************************************
1442  * ChangeServiceConfigW  [ADVAPI32.@]
1443  */
1444 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1445   DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1446   LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1447   LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1448 {
1449     FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1450           hService, dwServiceType, dwStartType, dwErrorControl, 
1451           debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1452           lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1453           debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1454     return TRUE;
1455 }
1456
1457 /******************************************************************************
1458  * ChangeServiceConfigA  [ADVAPI32.@]
1459  */
1460 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1461   DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1462   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1463   LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1464 {
1465     LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1466     LPWSTR wServiceStartName, wPassword, wDisplayName;
1467     BOOL r;
1468
1469     TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1470           hService, dwServiceType, dwStartType, dwErrorControl, 
1471           debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1472           lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1473           debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1474
1475     wBinaryPathName = SERV_dup( lpBinaryPathName );
1476     wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1477     wDependencies = SERV_dupmulti( lpDependencies );
1478     wServiceStartName = SERV_dup( lpServiceStartName );
1479     wPassword = SERV_dup( lpPassword );
1480     wDisplayName = SERV_dup( lpDisplayName );
1481
1482     r = ChangeServiceConfigW( hService, dwServiceType,
1483             dwStartType, dwErrorControl, wBinaryPathName,
1484             wLoadOrderGroup, lpdwTagId, wDependencies,
1485             wServiceStartName, wPassword, wDisplayName);
1486
1487     SERV_free( wBinaryPathName );
1488     SERV_free( wLoadOrderGroup );
1489     SERV_free( wDependencies );
1490     SERV_free( wServiceStartName );
1491     SERV_free( wPassword );
1492     SERV_free( wDisplayName );
1493
1494     return r;
1495 }
1496
1497 /******************************************************************************
1498  * ChangeServiceConfig2A  [ADVAPI32.@]
1499  */
1500 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel, 
1501     LPVOID lpInfo)
1502 {
1503     FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1504     return TRUE;
1505 }
1506
1507 /******************************************************************************
1508  * ChangeServiceConfig2W  [ADVAPI32.@]
1509  */
1510 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel, 
1511     LPVOID lpInfo)
1512 {
1513     HKEY hKey = ((struct sc_handle*) hService)->u.service.hkey;
1514
1515     if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1516     {
1517         static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1518         LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
1519         if (sd->lpDescription)
1520         {
1521             TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
1522             if (sd->lpDescription[0] == 0)
1523                 RegDeleteValueW(hKey,szDescription);
1524             else
1525                 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
1526                                         (LPVOID)sd->lpDescription,
1527                                  sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
1528         }
1529     }
1530     else   
1531         FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
1532     return TRUE;
1533 }
1534
1535 /******************************************************************************
1536  * QueryServiceObjectSecurity [ADVAPI32.@]
1537  */
1538 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1539        SECURITY_INFORMATION dwSecurityInformation,
1540        PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1541        DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1542 {
1543     FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
1544           lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1545     return ERROR_CALL_NOT_IMPLEMENTED;
1546 }