2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
14 #include "wine/unicode.h"
16 #include "debugtools.h"
18 DEFAULT_DEBUG_CHANNEL(advapi
);
20 static DWORD start_dwNumServiceArgs
;
21 static LPWSTR
*start_lpServiceArgVectors
;
23 /******************************************************************************
24 * EnumServicesStatusA [ADVAPI32.@]
27 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
28 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
29 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
30 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
31 { FIXME("%x type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
32 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
33 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
34 SetLastError (ERROR_ACCESS_DENIED
);
38 /******************************************************************************
39 * EnumServicesStatusW [ADVAPI32.@]
42 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
43 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
44 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
45 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
46 { FIXME("%x 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
);
53 /******************************************************************************
54 * StartServiceCtrlDispatcherA [ADVAPI32.196]
57 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
59 LPSERVICE_MAIN_FUNCTIONA fpMain
;
61 DWORD dwNumServiceArgs
;
66 TRACE("(%p)\n", servent
);
67 wait
= OpenSemaphoreA(SEMAPHORE_ALL_ACCESS
, FALSE
, "ADVAPI32_ServiceStartData");
70 ERR("Couldn't find wait semaphore\n");
71 ERR("perhaps you need to start services using StartService\n");
75 dwNumServiceArgs
= start_dwNumServiceArgs
;
76 lpArgVecW
= start_lpServiceArgVectors
;
78 ReleaseSemaphore(wait
, 1, NULL
);
80 /* Convert the Unicode arg vectors back to ASCII */
82 lpArgVecA
= (LPSTR
*) HeapAlloc( GetProcessHeap(), 0,
83 dwNumServiceArgs
*sizeof(LPSTR
) );
87 for(i
=0; i
<dwNumServiceArgs
; i
++)
88 lpArgVecA
[i
]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW
[i
]);
90 /* FIXME: should we blindly start all services? */
91 while (servent
->lpServiceName
) {
92 TRACE("%s at %p)\n", debugstr_a(servent
->lpServiceName
),servent
);
93 fpMain
= servent
->lpServiceProc
;
95 /* try to start the service */
96 fpMain( dwNumServiceArgs
, lpArgVecA
);
103 /* free arg strings */
104 for(i
=0; i
<dwNumServiceArgs
; i
++)
105 HeapFree(GetProcessHeap(), 0, lpArgVecA
[i
]);
106 HeapFree(GetProcessHeap(), 0, lpArgVecA
);
112 /******************************************************************************
113 * StartServiceCtrlDispatcherW [ADVAPI32.197]
119 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
121 LPSERVICE_MAIN_FUNCTIONW fpMain
;
123 DWORD dwNumServiceArgs
;
124 LPWSTR
*lpServiceArgVectors
;
126 TRACE("(%p)\n", servent
);
127 wait
= OpenSemaphoreA(SEMAPHORE_ALL_ACCESS
, FALSE
, "ADVAPI32_ServiceStartData");
130 ERR("Couldn't find wait semaphore\n");
131 ERR("perhaps you need to start services using StartService\n");
135 dwNumServiceArgs
= start_dwNumServiceArgs
;
136 lpServiceArgVectors
= start_lpServiceArgVectors
;
138 ReleaseSemaphore(wait
, 1, NULL
);
140 /* FIXME: should we blindly start all services? */
141 while (servent
->lpServiceName
) {
142 TRACE("%s at %p)\n", debugstr_w(servent
->lpServiceName
),servent
);
143 fpMain
= servent
->lpServiceProc
;
145 /* try to start the service */
146 fpMain( dwNumServiceArgs
, lpServiceArgVectors
);
154 /******************************************************************************
155 * RegisterServiceCtrlHandlerA [ADVAPI32.176]
157 SERVICE_STATUS_HANDLE WINAPI
158 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
,
159 LPHANDLER_FUNCTION lpfHandler
)
160 { FIXME("%s %p\n", lpServiceName
, lpfHandler
);
164 /******************************************************************************
165 * RegisterServiceCtrlHandlerW [ADVAPI32.177]
171 SERVICE_STATUS_HANDLE WINAPI
172 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
173 LPHANDLER_FUNCTION lpfHandler
)
174 { FIXME("%s %p\n", debugstr_w(lpServiceName
), lpfHandler
);
178 /******************************************************************************
179 * SetServiceStatus [ADVAPI32.192]
186 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
187 { FIXME("0x%lx %p\n",hService
, lpStatus
);
188 TRACE("\tType:%lx\n",lpStatus
->dwServiceType
);
189 TRACE("\tState:%lx\n",lpStatus
->dwCurrentState
);
190 TRACE("\tControlAccepted:%lx\n",lpStatus
->dwControlsAccepted
);
191 TRACE("\tExitCode:%lx\n",lpStatus
->dwWin32ExitCode
);
192 TRACE("\tServiceExitCode:%lx\n",lpStatus
->dwServiceSpecificExitCode
);
193 TRACE("\tCheckPoint:%lx\n",lpStatus
->dwCheckPoint
);
194 TRACE("\tWaitHint:%lx\n",lpStatus
->dwWaitHint
);
198 /******************************************************************************
199 * OpenSCManagerA [ADVAPI32.110]
202 OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
203 DWORD dwDesiredAccess
)
205 LPWSTR lpMachineNameW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpMachineName
);
206 LPWSTR lpDatabaseNameW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpDatabaseName
);
207 SC_HANDLE ret
= OpenSCManagerW(lpMachineNameW
,lpDatabaseNameW
,
209 HeapFree(GetProcessHeap(),0,lpDatabaseNameW
);
210 HeapFree(GetProcessHeap(),0,lpMachineNameW
);
214 /******************************************************************************
215 * OpenSCManagerW [ADVAPI32.111]
216 * Establishes a connection to the service control manager and opens database
219 * This should return a SC_HANDLE
222 * lpMachineName [I] Pointer to machine name string
223 * lpDatabaseName [I] Pointer to database name string
224 * dwDesiredAccess [I] Type of access
227 * Success: Handle to service control manager database
231 OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
232 DWORD dwDesiredAccess
)
237 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
238 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
241 * FIXME: what is lpDatabaseName?
242 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
243 * docs, but what if it isn't?
246 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hKey
);
247 if (r
!=ERROR_SUCCESS
)
250 TRACE("returning %x\n",hKey
);
256 /******************************************************************************
257 * AllocateLocallyUniqueId [ADVAPI32.12]
263 AllocateLocallyUniqueId( PLUID lpluid
)
265 lpluid
->s
.LowPart
= time(NULL
);
266 lpluid
->s
.HighPart
= 0;
271 /******************************************************************************
272 * ControlService [ADVAPI32.23]
273 * Sends a control code to a Win32-based service.
283 ControlService( SC_HANDLE hService
, DWORD dwControl
,
284 LPSERVICE_STATUS lpServiceStatus
)
286 FIXME("(%d,%ld,%p): stub\n",hService
,dwControl
,lpServiceStatus
);
291 /******************************************************************************
292 * CloseServiceHandle [ADVAPI32.22]
293 * Close handle to service or service control manager
296 * hSCObject [I] Handle to service or service control manager database
301 CloseServiceHandle( SC_HANDLE hSCObject
)
303 TRACE("(%x)\n", hSCObject
);
305 RegCloseKey(hSCObject
);
311 /******************************************************************************
312 * OpenServiceA [ADVAPI32.112]
315 OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
316 DWORD dwDesiredAccess
)
318 LPWSTR lpServiceNameW
= HEAP_strdupAtoW(GetProcessHeap(),0,lpServiceName
);
322 TRACE("Request for service %s\n",lpServiceName
);
325 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
326 HeapFree(GetProcessHeap(),0,lpServiceNameW
);
331 /******************************************************************************
332 * OpenServiceW [ADVAPI32.113]
333 * Opens a handle to an existing service
341 * Success: Handle to the service
345 OpenServiceW(SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
346 DWORD dwDesiredAccess
)
348 const char *str
= "System\\CurrentControlSet\\Services\\";
349 WCHAR lpServiceKey
[80]; /* FIXME: this should be dynamically allocated */
353 TRACE("(%d,%p,%ld)\n",hSCManager
, lpServiceName
,
356 MultiByteToWideChar( CP_ACP
, 0, str
, -1, lpServiceKey
, sizeof(lpServiceKey
)/sizeof(WCHAR
) );
357 strcatW(lpServiceKey
,lpServiceName
);
359 TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey
));
361 /* FIXME: dwDesiredAccess may need some processing */
362 r
= RegOpenKeyExW(hSCManager
, lpServiceKey
, 0, dwDesiredAccess
, &hKey
);
363 if (r
!=ERROR_SUCCESS
)
366 TRACE("returning %x\n",hKey
);
371 /******************************************************************************
372 * CreateServiceW [ADVAPI32.29]
375 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
376 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
377 DWORD dwServiceType
, DWORD dwStartType
,
378 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
379 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
380 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
383 FIXME("(%u,%s,%s,...)\n", hSCManager
, debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
388 /******************************************************************************
389 * CreateServiceA [ADVAPI32.28]
392 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
393 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
394 DWORD dwServiceType
, DWORD dwStartType
,
395 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
396 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
397 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
404 TRACE("(%u,%s,%s,...)\n", hSCManager
, debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
406 r
= RegCreateKeyExA(hSCManager
, lpServiceName
, 0, NULL
,
407 REG_OPTION_NON_VOLATILE
, dwDesiredAccess
, NULL
, &hKey
, &dp
);
408 if (r
!=ERROR_SUCCESS
)
410 if (dp
!= REG_CREATED_NEW_KEY
)
415 r
= RegSetValueExA(hKey
, "DisplayName", 0, REG_SZ
, lpDisplayName
, strlen(lpDisplayName
) );
416 if (r
!=ERROR_SUCCESS
)
420 r
= RegSetValueExA(hKey
, "Type", 0, REG_DWORD
, (LPVOID
)&dwServiceType
, sizeof (DWORD
) );
421 if (r
!=ERROR_SUCCESS
)
424 r
= RegSetValueExA(hKey
, "Start", 0, REG_DWORD
, (LPVOID
)&dwStartType
, sizeof (DWORD
) );
425 if (r
!=ERROR_SUCCESS
)
428 r
= RegSetValueExA(hKey
, "ErrorControl", 0, REG_DWORD
,
429 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
430 if (r
!=ERROR_SUCCESS
)
435 r
= RegSetValueExA(hKey
, "ImagePath", 0, REG_SZ
,
436 lpBinaryPathName
,strlen(lpBinaryPathName
)+1 );
437 if (r
!=ERROR_SUCCESS
)
443 r
= RegSetValueExA(hKey
, "Group", 0, REG_SZ
,
444 lpLoadOrderGroup
, strlen(lpLoadOrderGroup
)+1 );
445 if (r
!=ERROR_SUCCESS
)
449 r
= RegSetValueExA(hKey
, "ErrorControl", 0, REG_DWORD
,
450 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
451 if (r
!=ERROR_SUCCESS
)
458 /* determine the length of a double null terminated multi string */
460 len
+= (strlen(&lpDependencies
[len
])+1);
461 } while (lpDependencies
[len
++]);
463 /* fixme: this should be unicode */
464 r
= RegSetValueExA(hKey
, "Dependencies", 0, REG_MULTI_SZ
,
465 lpDependencies
, len
);
466 if (r
!=ERROR_SUCCESS
)
472 FIXME("Don't know how to add a Password for a service.\n");
475 if(lpServiceStartName
)
477 FIXME("Don't know how to add a ServiceStartName for a service.\n");
484 /******************************************************************************
485 * DeleteService [ADVAPI32.31]
488 * hService [I] Handle to service
494 DeleteService( SC_HANDLE hService
)
496 FIXME("(%d): stub\n",hService
);
501 /******************************************************************************
502 * StartServiceA [ADVAPI32.195]
506 StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
507 LPCSTR
*lpServiceArgVectors
)
512 TRACE("(%d,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
515 lpwstr
= (LPWSTR
*) HeapAlloc( GetProcessHeap(), 0,
516 dwNumServiceArgs
*sizeof(LPWSTR
) );
520 for(i
=0; i
<dwNumServiceArgs
; i
++)
521 lpwstr
[i
]=HEAP_strdupAtoW(GetProcessHeap(), 0, lpServiceArgVectors
[i
]);
523 StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
527 for(i
=0; i
<dwNumServiceArgs
; i
++)
528 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
529 HeapFree(GetProcessHeap(), 0, lpwstr
);
536 /******************************************************************************
537 * StartServiceW [ADVAPI32.198]
541 * hService [I] Handle of service
542 * dwNumServiceArgs [I] Number of arguments
543 * lpServiceArgVectors [I] Address of array of argument string pointers
547 * NT implements this function using an obscure RPC call...
549 * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
550 * to get things like %SystemRoot%\\System32\\service.exe to load.
552 * Will only work for shared address space. How should the service
553 * args be transferred when address spaces are separated?
555 * Can only start one service at a time.
557 * Has no concept of priviledge.
563 StartServiceW( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
564 LPCWSTR
*lpServiceArgVectors
)
566 CHAR path
[MAX_PATH
],str
[MAX_PATH
];
570 PROCESS_INFORMATION procinfo
;
571 STARTUPINFOA startupinfo
;
573 TRACE("(%d,%ld,%p)\n",hService
,dwNumServiceArgs
,
574 lpServiceArgVectors
);
577 r
= RegQueryValueExA(hService
, "ImagePath", NULL
, &type
, (LPVOID
)str
, &size
);
578 if (r
!=ERROR_SUCCESS
)
580 ExpandEnvironmentStringsA(str
,path
,sizeof path
);
582 TRACE("Starting service %s\n", debugstr_a(path
) );
584 data
= CreateSemaphoreA(NULL
,1,1,"ADVAPI32_ServiceStartData");
585 if(data
== ERROR_INVALID_HANDLE
)
587 data
= OpenSemaphoreA(SEMAPHORE_ALL_ACCESS
, FALSE
, "ADVAPI32_ServiceStartData");
590 ERR("Couldn't create data semaphore\n");
594 wait
= CreateSemaphoreA(NULL
,0,1,"ADVAPI32_WaitServiceStart");
596 wait
= OpenSemaphoreA(SEMAPHORE_ALL_ACCESS
, FALSE
, "ADVAPI32_ServiceStartData");
599 ERR("Couldn't create wait semaphore\n");
605 * FIXME: lpServiceArgsVectors need to be stored and returned to
606 * the service when it calls StartServiceCtrlDispatcher
608 * Chuck these in a global (yuk) so we can pass them to
609 * another process - address space separation will break this.
612 r
= WaitForSingleObject(data
,INFINITE
);
614 if( r
== WAIT_FAILED
)
617 FIXME("problematic because of address space separation.\n");
618 start_dwNumServiceArgs
= dwNumServiceArgs
;
619 start_lpServiceArgVectors
= (LPWSTR
*)lpServiceArgVectors
;
621 ZeroMemory(&startupinfo
,sizeof(STARTUPINFOA
));
622 startupinfo
.cb
= sizeof(STARTUPINFOA
);
624 r
= CreateProcessA(path
,
626 NULL
, /* process security attribs */
627 NULL
, /* thread security attribs */
628 FALSE
, /* inherit handles */
629 0, /* creation flags */
630 NULL
, /* environment */
631 NULL
, /* current directory */
632 &startupinfo
, /* startup info */
633 &procinfo
); /* process info */
637 ERR("Couldn't start process\n");
638 /* ReleaseSemaphore(data, 1, NULL);
642 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
643 r
= WaitForSingleObject(wait
,30000);
645 ReleaseSemaphore(data
, 1, NULL
);
647 if( r
== WAIT_FAILED
)
653 /******************************************************************************
654 * QueryServiceStatus [ADVAPI32.123]
662 QueryServiceStatus( SC_HANDLE hService
, LPSERVICE_STATUS lpservicestatus
)
665 DWORD type
, val
, size
;
667 FIXME("(%x,%p) partial\n",hService
,lpservicestatus
);
669 /* read the service type from the registry */
671 r
= RegQueryValueExA(hService
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
674 ERR("invalid Type\n");
677 lpservicestatus
->dwServiceType
= val
;
678 /* FIXME: how are these determined or read from the registry? */
679 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
680 lpservicestatus
->dwCurrentState
= 1;
681 lpservicestatus
->dwControlsAccepted
= 0;
682 lpservicestatus
->dwWin32ExitCode
= NO_ERROR
;
683 lpservicestatus
->dwServiceSpecificExitCode
= 0;
684 lpservicestatus
->dwCheckPoint
= 0;
685 lpservicestatus
->dwWaitHint
= 0;