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