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