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