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