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