Fixed definitions of TTTOOLINFOA/W_V1_SIZE and
[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 /******************************************************************************
41  * EnumServicesStatusA [ADVAPI32.@]
42  */
43 BOOL WINAPI
44 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
45                      DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
46                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
47                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
48 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
49                 dwServiceType, dwServiceState, lpServices, cbBufSize,
50                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
51         SetLastError (ERROR_ACCESS_DENIED);
52         return FALSE;
53 }
54
55 /******************************************************************************
56  * EnumServicesStatusW [ADVAPI32.@]
57  */
58 BOOL WINAPI
59 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
60                      DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
61                      DWORD cbBufSize, LPDWORD pcbBytesNeeded,
62                      LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
63 {       FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
64                 dwServiceType, dwServiceState, lpServices, cbBufSize,
65                 pcbBytesNeeded, lpServicesReturned,  lpResumeHandle);
66         SetLastError (ERROR_ACCESS_DENIED);
67         return FALSE;
68 }
69
70 /******************************************************************************
71  * StartServiceCtrlDispatcherA [ADVAPI32.@]
72  */
73 BOOL WINAPI
74 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
75 {
76     LPSERVICE_MAIN_FUNCTIONA fpMain;
77     HANDLE wait;
78     DWORD  dwNumServiceArgs ;
79     LPWSTR *lpArgVecW;
80     LPSTR  *lpArgVecA;
81     int i;
82
83     TRACE("(%p)\n", servent);
84     wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData");
85     if(wait == 0)
86     {
87         ERR("Couldn't find wait semaphore\n");
88         ERR("perhaps you need to start services using StartService\n");
89         return FALSE;
90     }
91
92     dwNumServiceArgs = start_dwNumServiceArgs;
93     lpArgVecW        = start_lpServiceArgVectors;
94
95     ReleaseSemaphore(wait, 1, NULL);
96
97     /* Convert the Unicode arg vectors back to ASCII */
98     if(dwNumServiceArgs)
99         lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
100                                    dwNumServiceArgs*sizeof(LPSTR) );
101     else
102         lpArgVecA = NULL;
103
104     for(i=0; i<dwNumServiceArgs; i++)
105         lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
106
107     /* FIXME: should we blindly start all services? */
108     while (servent->lpServiceName) {
109         TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
110         fpMain = servent->lpServiceProc;
111
112         /* try to start the service */
113         fpMain( dwNumServiceArgs, lpArgVecA);
114
115         servent++;
116     }
117
118     if(dwNumServiceArgs)
119     {
120         /* free arg strings */
121         for(i=0; i<dwNumServiceArgs; i++)
122             HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
123         HeapFree(GetProcessHeap(), 0, lpArgVecA);
124     }
125
126     return TRUE;
127 }
128
129 /******************************************************************************
130  * StartServiceCtrlDispatcherW [ADVAPI32.@]
131  *
132  * PARAMS
133  *   servent []
134  */
135 BOOL WINAPI
136 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
137 {
138     static const WCHAR  _ServiceStartDataW[]  = {'A','D','V','A','P','I','_','S',
139                                                 'e','r','v','i','c','e','S','t',
140                                                 'a','r','t','D','a','t','a',0};
141     LPSERVICE_MAIN_FUNCTIONW fpMain;
142     HANDLE wait;
143     DWORD  dwNumServiceArgs ;
144     LPWSTR *lpServiceArgVectors ;
145
146     TRACE("(%p)\n", servent);
147     wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
148     if(wait == 0)
149     {
150         ERR("Couldn't find wait semaphore\n");
151         ERR("perhaps you need to start services using StartService\n");
152         return FALSE;
153     }
154
155     dwNumServiceArgs    = start_dwNumServiceArgs;
156     lpServiceArgVectors = start_lpServiceArgVectors;
157
158     ReleaseSemaphore(wait, 1, NULL);
159
160     /* FIXME: should we blindly start all services? */
161     while (servent->lpServiceName) {
162         TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
163         fpMain = servent->lpServiceProc;
164
165         /* try to start the service */
166         fpMain( dwNumServiceArgs, lpServiceArgVectors);
167
168         servent++;
169     }
170
171     return TRUE;
172 }
173
174 /******************************************************************************
175  * LockServiceDatabase  [ADVAPI32.@]
176  */
177 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
178 {
179         FIXME("%p\n",hSCManager);
180         return (SC_HANDLE)0xcacacafe;
181 }
182
183 /******************************************************************************
184  * UnlockServiceDatabase  [ADVAPI32.@]
185  */
186 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
187 {
188         FIXME(": %p\n",ScLock);
189         return TRUE;
190 }
191
192 /******************************************************************************
193  * RegisterServiceCtrlHandlerA [ADVAPI32.@]
194  */
195 SERVICE_STATUS_HANDLE WINAPI
196 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
197                              LPHANDLER_FUNCTION lpfHandler )
198 {       FIXME("%s %p\n", lpServiceName, lpfHandler);
199         return 0xcacacafe;
200 }
201
202 /******************************************************************************
203  * RegisterServiceCtrlHandlerW [ADVAPI32.@]
204  *
205  * PARAMS
206  *   lpServiceName []
207  *   lpfHandler    []
208  */
209 SERVICE_STATUS_HANDLE WINAPI
210 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
211                              LPHANDLER_FUNCTION lpfHandler )
212 {       FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
213         return 0xcacacafe;
214 }
215
216 /******************************************************************************
217  * SetServiceStatus [ADVAPI32.@]
218  *
219  * PARAMS
220  *   hService []
221  *   lpStatus []
222  */
223 BOOL WINAPI
224 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
225 {       FIXME("0x%lx %p\n",hService, lpStatus);
226         TRACE("\tType:%lx\n",lpStatus->dwServiceType);
227         TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
228         TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
229         TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
230         TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
231         TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
232         TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
233         return TRUE;
234 }
235
236 /******************************************************************************
237  * OpenSCManagerA [ADVAPI32.@]
238  */
239 SC_HANDLE WINAPI
240 OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
241                   DWORD dwDesiredAccess )
242 {
243     UNICODE_STRING lpMachineNameW;
244     UNICODE_STRING lpDatabaseNameW;
245     SC_HANDLE ret;
246
247     RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
248     RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
249     ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
250     RtlFreeUnicodeString(&lpDatabaseNameW);
251     RtlFreeUnicodeString(&lpMachineNameW);
252     return ret;
253 }
254
255 /******************************************************************************
256  * OpenSCManagerW [ADVAPI32.@]
257  * Establishes a connection to the service control manager and opens database
258  *
259  * NOTES
260  *   This should return a SC_HANDLE
261  *
262  * PARAMS
263  *   lpMachineName   [I] Pointer to machine name string
264  *   lpDatabaseName  [I] Pointer to database name string
265  *   dwDesiredAccess [I] Type of access
266  *
267  * RETURNS
268  *   Success: Handle to service control manager database
269  *   Failure: NULL
270  */
271 SC_HANDLE WINAPI
272 OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
273                   DWORD dwDesiredAccess )
274 {
275     HKEY hKey;
276     LONG r;
277
278     TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
279           debugstr_w(lpDatabaseName), dwDesiredAccess);
280
281     /*
282      * FIXME: what is lpDatabaseName?
283      * It should be set to "SERVICES_ACTIVE_DATABASE" according to
284      * docs, but what if it isn't?
285      */
286
287     r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hKey);
288     if (r!=ERROR_SUCCESS)
289         return 0;
290
291     TRACE("returning %p\n",hKey);
292
293     return hKey;
294 }
295
296
297 /******************************************************************************
298  * AllocateLocallyUniqueId [ADVAPI32.@]
299  *
300  * PARAMS
301  *   lpluid []
302  */
303 BOOL WINAPI
304 AllocateLocallyUniqueId( PLUID lpluid )
305 {
306         lpluid->LowPart = time(NULL);
307         lpluid->HighPart = 0;
308         return TRUE;
309 }
310
311
312 /******************************************************************************
313  * ControlService [ADVAPI32.@]
314  * Sends a control code to a Win32-based service.
315  *
316  * PARAMS
317  *   hService        []
318  *   dwControl       []
319  *   lpServiceStatus []
320  *
321  * RETURNS STD
322  */
323 BOOL WINAPI
324 ControlService( SC_HANDLE hService, DWORD dwControl,
325                 LPSERVICE_STATUS lpServiceStatus )
326 {
327     FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
328     return TRUE;
329 }
330
331
332 /******************************************************************************
333  * CloseServiceHandle [ADVAPI32.@]
334  * Close handle to service or service control manager
335  *
336  * PARAMS
337  *   hSCObject [I] Handle to service or service control manager database
338  *
339  * RETURNS STD
340  */
341 BOOL WINAPI
342 CloseServiceHandle( SC_HANDLE hSCObject )
343 {
344     TRACE("(%p)\n", hSCObject);
345
346     RegCloseKey(hSCObject);
347
348     return TRUE;
349 }
350
351
352 /******************************************************************************
353  * OpenServiceA [ADVAPI32.@]
354  */
355 SC_HANDLE WINAPI
356 OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
357                 DWORD dwDesiredAccess )
358 {
359     UNICODE_STRING lpServiceNameW;
360     SC_HANDLE ret;
361     RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
362     if(lpServiceName)
363         TRACE("Request for service %s\n",lpServiceName);
364     else
365         return FALSE;
366     ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
367     RtlFreeUnicodeString(&lpServiceNameW);
368     return ret;
369 }
370
371
372 /******************************************************************************
373  * OpenServiceW [ADVAPI32.@]
374  * Opens a handle to an existing service
375  *
376  * PARAMS
377  *   hSCManager      []
378  *   lpServiceName   []
379  *   dwDesiredAccess []
380  *
381  * RETURNS
382  *    Success: Handle to the service
383  *    Failure: NULL
384  */
385 SC_HANDLE WINAPI
386 OpenServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName,
387                DWORD dwDesiredAccess)
388 {
389     const char *str = "System\\CurrentControlSet\\Services\\";
390     WCHAR lpServiceKey[80]; /* FIXME: this should be dynamically allocated */
391     HKEY hKey;
392     long r;
393
394     TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
395           dwDesiredAccess);
396
397     MultiByteToWideChar( CP_ACP, 0, str, -1, lpServiceKey, sizeof(lpServiceKey)/sizeof(WCHAR) );
398     strcatW(lpServiceKey,lpServiceName);
399
400     TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey));
401
402     /* FIXME: dwDesiredAccess may need some processing */
403     r = RegOpenKeyExW(hSCManager, lpServiceKey, 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     FIXME("(%p,%s,%s,...)\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
425     return 0;
426 }
427
428
429 /******************************************************************************
430  * CreateServiceA [ADVAPI32.@]
431  */
432 SC_HANDLE WINAPI
433 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
434                   LPCSTR lpDisplayName, DWORD dwDesiredAccess,
435                   DWORD dwServiceType, DWORD dwStartType,
436                   DWORD dwErrorControl, LPCSTR lpBinaryPathName,
437                   LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
438                   LPCSTR lpDependencies, LPCSTR lpServiceStartName,
439                   LPCSTR lpPassword )
440 {
441     HKEY hKey;
442     LONG r;
443     DWORD dp;
444
445     TRACE("(%p,%s,%s,...)\n", hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
446
447     r = RegCreateKeyExA(hSCManager, lpServiceName, 0, NULL,
448                        REG_OPTION_NON_VOLATILE, dwDesiredAccess, NULL, &hKey, &dp);
449     if (r!=ERROR_SUCCESS)
450         return 0;
451     if (dp != REG_CREATED_NEW_KEY)
452         return 0;
453
454     if(lpDisplayName)
455     {
456         r = RegSetValueExA(hKey, "DisplayName", 0, REG_SZ, lpDisplayName, strlen(lpDisplayName) );
457         if (r!=ERROR_SUCCESS)
458             return 0;
459     }
460
461     r = RegSetValueExA(hKey, "Type", 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
462     if (r!=ERROR_SUCCESS)
463         return 0;
464
465     r = RegSetValueExA(hKey, "Start", 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
466     if (r!=ERROR_SUCCESS)
467         return 0;
468
469     r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
470                            (LPVOID)&dwErrorControl, sizeof (DWORD) );
471     if (r!=ERROR_SUCCESS)
472         return 0;
473
474     if(lpBinaryPathName)
475     {
476         r = RegSetValueExA(hKey, "ImagePath", 0, REG_SZ,
477                            lpBinaryPathName,strlen(lpBinaryPathName)+1 );
478         if (r!=ERROR_SUCCESS)
479             return 0;
480     }
481
482     if(lpLoadOrderGroup)
483     {
484         r = RegSetValueExA(hKey, "Group", 0, REG_SZ,
485                            lpLoadOrderGroup, strlen(lpLoadOrderGroup)+1 );
486         if (r!=ERROR_SUCCESS)
487             return 0;
488     }
489
490     r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
491                        (LPVOID)&dwErrorControl, sizeof (DWORD) );
492     if (r!=ERROR_SUCCESS)
493         return 0;
494
495     if(lpDependencies)
496     {
497         DWORD len = 0;
498
499         /* determine the length of a double null terminated multi string */
500         do {
501             len += (strlen(&lpDependencies[len])+1);
502         } while (lpDependencies[len++]);
503
504         /* FIXME: this should be unicode */
505         r = RegSetValueExA(hKey, "Dependencies", 0, REG_MULTI_SZ,
506                            lpDependencies, len );
507         if (r!=ERROR_SUCCESS)
508             return 0;
509     }
510
511     if(lpPassword)
512     {
513         FIXME("Don't know how to add a Password for a service.\n");
514     }
515
516     if(lpServiceStartName)
517     {
518         FIXME("Don't know how to add a ServiceStartName for a service.\n");
519     }
520
521     return hKey;
522 }
523
524
525 /******************************************************************************
526  * DeleteService [ADVAPI32.@]
527  *
528  * PARAMS
529  *    hService [I] Handle to service
530  *
531  * RETURNS STD
532  *
533  */
534 BOOL WINAPI
535 DeleteService( SC_HANDLE hService )
536 {
537     FIXME("(%p): stub\n",hService);
538     return TRUE;
539 }
540
541
542 /******************************************************************************
543  * StartServiceA [ADVAPI32.@]
544  *
545  */
546 BOOL WINAPI
547 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
548                  LPCSTR *lpServiceArgVectors )
549 {
550     LPWSTR *lpwstr=NULL;
551     UNICODE_STRING usBuffer;
552     int i;
553
554     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
555
556     if(dwNumServiceArgs)
557         lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
558                                    dwNumServiceArgs*sizeof(LPWSTR) );
559     else
560         lpwstr = NULL;
561
562     for(i=0; i<dwNumServiceArgs; i++)
563     {
564         RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
565         lpwstr[i]=usBuffer.Buffer;
566     }
567
568     StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
569
570     if(dwNumServiceArgs)
571     {
572         for(i=0; i<dwNumServiceArgs; i++)
573             HeapFree(GetProcessHeap(), 0, lpwstr[i]);
574         HeapFree(GetProcessHeap(), 0, lpwstr);
575     }
576
577     return TRUE;
578 }
579
580
581 /******************************************************************************
582  * StartServiceW [ADVAPI32.@]
583  * Starts a service
584  *
585  * PARAMS
586  *   hService            [I] Handle of service
587  *   dwNumServiceArgs    [I] Number of arguments
588  *   lpServiceArgVectors [I] Address of array of argument string pointers
589  *
590  * NOTES
591  *
592  * NT implements this function using an obscure RPC call...
593  *
594  * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
595  *   to get things like %SystemRoot%\\System32\\service.exe to load.
596  *
597  * Will only work for shared address space. How should the service
598  *  args be transferred when address spaces are separated?
599  *
600  * Can only start one service at a time.
601  *
602  * Has no concept of privilege.
603  *
604  * RETURNS STD
605  *
606  */
607 BOOL WINAPI
608 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
609                  LPCWSTR *lpServiceArgVectors )
610 {
611     static const WCHAR  _ServiceStartDataW[]  = {'A','D','V','A','P','I','_','S',
612                                                 'e','r','v','i','c','e','S','t',
613                                                 'a','r','t','D','a','t','a',0};
614                                                 
615     static const WCHAR  _WaitServiceStartW[]  = {'A','D','V','A','P','I','_','W',
616                                                 'a','i','t','S','e','r','v','i',
617                                                 'c','e','S','t','a','r','t',0};
618     static const WCHAR  _ImagePathW[]  = {'I','m','a','g','e','P','a','t','h',0};
619                                                 
620     WCHAR path[MAX_PATH],str[MAX_PATH];
621     DWORD type,size;
622     long r;
623     HANDLE data,wait;
624     PROCESS_INFORMATION procinfo;
625     STARTUPINFOW startupinfo;
626     TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
627           lpServiceArgVectors);
628
629     size = sizeof(str);
630     r = RegQueryValueExW(hService, _ImagePathW, NULL, &type, (LPVOID)str, &size);
631     if (r!=ERROR_SUCCESS)
632         return FALSE;
633     ExpandEnvironmentStringsW(str,path,sizeof(path));
634
635     TRACE("Starting service %s\n", debugstr_w(path) );
636
637     data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
638     if (!data)
639     {
640         data = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
641         if(data == 0)
642         {
643             ERR("Couldn't create data semaphore\n");
644             return FALSE;
645         }
646     }
647     wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
648     {
649         wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
650         if(wait == 0)
651         {
652             ERR("Couldn't create wait semaphore\n");
653             return FALSE;
654         }
655     }
656
657     /*
658      * FIXME: lpServiceArgsVectors need to be stored and returned to
659      *        the service when it calls StartServiceCtrlDispatcher
660      *
661      * Chuck these in a global (yuk) so we can pass them to
662      * another process - address space separation will break this.
663      */
664
665     r = WaitForSingleObject(data,INFINITE);
666
667     if( r == WAIT_FAILED)
668         return FALSE;
669
670     FIXME("problematic because of address space separation.\n");
671     start_dwNumServiceArgs    = dwNumServiceArgs;
672     start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
673
674     ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
675     startupinfo.cb = sizeof(STARTUPINFOW);
676
677     r = CreateProcessW(path,
678                    NULL,
679                    NULL,  /* process security attribs */
680                    NULL,  /* thread security attribs */
681                    FALSE, /* inherit handles */
682                    0,     /* creation flags */
683                    NULL,  /* environment */
684                    NULL,  /* current directory */
685                    &startupinfo,  /* startup info */
686                    &procinfo); /* process info */
687
688     if(r == FALSE)
689     {
690         ERR("Couldn't start process\n");
691         /* ReleaseSemaphore(data, 1, NULL);
692         return FALSE; */
693     }
694
695     /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
696     r = WaitForSingleObject(wait,30000);
697
698     ReleaseSemaphore(data, 1, NULL);
699
700     if( r == WAIT_FAILED)
701         return FALSE;
702
703     return TRUE;
704 }
705
706 /******************************************************************************
707  * QueryServiceStatus [ADVAPI32.@]
708  *
709  * PARAMS
710  *   hService        []
711  *   lpservicestatus []
712  *
713  */
714 BOOL WINAPI
715 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
716 {
717     LONG r;
718     DWORD type, val, size;
719
720     FIXME("(%p,%p) partial\n",hService,lpservicestatus);
721
722     /* read the service type from the registry */
723     size = sizeof(val);
724     r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
725     if(type!=REG_DWORD)
726     {
727         ERR("invalid Type\n");
728         return FALSE;
729     }
730     lpservicestatus->dwServiceType = val;
731     /* FIXME: how are these determined or read from the registry? */
732     /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
733     lpservicestatus->dwCurrentState            = 1;
734     lpservicestatus->dwControlsAccepted        = 0;
735     lpservicestatus->dwWin32ExitCode           = NO_ERROR;
736     lpservicestatus->dwServiceSpecificExitCode = 0;
737     lpservicestatus->dwCheckPoint              = 0;
738     lpservicestatus->dwWaitHint                = 0;
739
740     return TRUE;
741 }
742
743 /******************************************************************************
744  * QueryServiceStatusEx [ADVAPI32.@]
745  *
746  * PARAMS
747  *   hService       [handle to service]
748  *   InfoLevel      [information level]
749  *   lpBuffer       [buffer]
750  *   cbBufSize      [size of buffer]
751  *   pcbBytesNeeded [bytes needed]
752 */
753 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
754                         LPBYTE lpBuffer, DWORD cbBufSize,
755                         LPDWORD pcbBytesNeeded)
756 {
757     FIXME("stub\n");
758     SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
759     return FALSE;
760 }