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