2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
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.
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.
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
28 #include "wine/unicode.h"
30 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
35 static DWORD start_dwNumServiceArgs;
36 static LPWSTR *start_lpServiceArgVectors;
38 /******************************************************************************
39 * EnumServicesStatusA [ADVAPI32.@]
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);
53 /******************************************************************************
54 * EnumServicesStatusW [ADVAPI32.@]
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);
68 /******************************************************************************
69 * StartServiceCtrlDispatcherA [ADVAPI32.@]
72 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
74 LPSERVICE_MAIN_FUNCTIONA fpMain;
76 DWORD dwNumServiceArgs ;
81 TRACE("(%p)\n", servent);
82 wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData");
85 ERR("Couldn't find wait semaphore\n");
86 ERR("perhaps you need to start services using StartService\n");
90 dwNumServiceArgs = start_dwNumServiceArgs;
91 lpArgVecW = start_lpServiceArgVectors;
93 ReleaseSemaphore(wait, 1, NULL);
95 /* Convert the Unicode arg vectors back to ASCII */
97 lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
98 dwNumServiceArgs*sizeof(LPSTR) );
102 for(i=0; i<dwNumServiceArgs; i++)
103 lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
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;
110 /* try to start the service */
111 fpMain( dwNumServiceArgs, lpArgVecA);
118 /* free arg strings */
119 for(i=0; i<dwNumServiceArgs; i++)
120 HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
121 HeapFree(GetProcessHeap(), 0, lpArgVecA);
127 /******************************************************************************
128 * StartServiceCtrlDispatcherW [ADVAPI32.@]
134 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
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;
141 DWORD dwNumServiceArgs ;
142 LPWSTR *lpServiceArgVectors ;
144 TRACE("(%p)\n", servent);
145 wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
148 ERR("Couldn't find wait semaphore\n");
149 ERR("perhaps you need to start services using StartService\n");
153 dwNumServiceArgs = start_dwNumServiceArgs;
154 lpServiceArgVectors = start_lpServiceArgVectors;
156 ReleaseSemaphore(wait, 1, NULL);
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;
163 /* try to start the service */
164 fpMain( dwNumServiceArgs, lpServiceArgVectors);
172 /******************************************************************************
173 * LockServiceDatabase [ADVAPI32.@]
175 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
177 FIXME("%p\n",hSCManager);
178 return (SC_HANDLE)0xcacacafe;
181 /******************************************************************************
182 * UnlockServiceDatabase [ADVAPI32.@]
184 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
186 FIXME(": %p\n",ScLock);
190 /******************************************************************************
191 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
193 SERVICE_STATUS_HANDLE WINAPI
194 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
195 LPHANDLER_FUNCTION lpfHandler )
196 { FIXME("%s %p\n", lpServiceName, lpfHandler);
200 /******************************************************************************
201 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
207 SERVICE_STATUS_HANDLE WINAPI
208 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
209 LPHANDLER_FUNCTION lpfHandler )
210 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
214 /******************************************************************************
215 * SetServiceStatus [ADVAPI32.@]
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);
234 /******************************************************************************
235 * OpenSCManagerA [ADVAPI32.@]
238 OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
239 DWORD dwDesiredAccess )
241 UNICODE_STRING lpMachineNameW;
242 UNICODE_STRING lpDatabaseNameW;
245 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
246 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
247 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
248 RtlFreeUnicodeString(&lpDatabaseNameW);
249 RtlFreeUnicodeString(&lpMachineNameW);
253 /******************************************************************************
254 * OpenSCManagerW [ADVAPI32.@]
255 * Establishes a connection to the service control manager and opens database
258 * This should return a SC_HANDLE
261 * lpMachineName [I] Pointer to machine name string
262 * lpDatabaseName [I] Pointer to database name string
263 * dwDesiredAccess [I] Type of access
266 * Success: Handle to service control manager database
270 OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
271 DWORD dwDesiredAccess )
276 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
277 debugstr_w(lpDatabaseName), dwDesiredAccess);
280 * FIXME: what is lpDatabaseName?
281 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
282 * docs, but what if it isn't?
285 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hKey);
286 if (r!=ERROR_SUCCESS)
289 TRACE("returning %p\n",hKey);
295 /******************************************************************************
296 * AllocateLocallyUniqueId [ADVAPI32.@]
302 AllocateLocallyUniqueId( PLUID lpluid )
304 lpluid->LowPart = time(NULL);
305 lpluid->HighPart = 0;
310 /******************************************************************************
311 * ControlService [ADVAPI32.@]
312 * Sends a control code to a Win32-based service.
322 ControlService( SC_HANDLE hService, DWORD dwControl,
323 LPSERVICE_STATUS lpServiceStatus )
325 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
330 /******************************************************************************
331 * CloseServiceHandle [ADVAPI32.@]
332 * Close handle to service or service control manager
335 * hSCObject [I] Handle to service or service control manager database
340 CloseServiceHandle( SC_HANDLE hSCObject )
342 TRACE("(%p)\n", hSCObject);
344 RegCloseKey(hSCObject);
350 /******************************************************************************
351 * OpenServiceA [ADVAPI32.@]
354 OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
355 DWORD dwDesiredAccess )
357 UNICODE_STRING lpServiceNameW;
359 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
361 TRACE("Request for service %s\n",lpServiceName);
364 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
365 RtlFreeUnicodeString(&lpServiceNameW);
370 /******************************************************************************
371 * OpenServiceW [ADVAPI32.@]
372 * Opens a handle to an existing service
380 * Success: Handle to the service
384 OpenServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName,
385 DWORD dwDesiredAccess)
387 const char *str = "System\\CurrentControlSet\\Services\\";
388 WCHAR lpServiceKey[80]; /* FIXME: this should be dynamically allocated */
392 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
395 MultiByteToWideChar( CP_ACP, 0, str, -1, lpServiceKey, sizeof(lpServiceKey)/sizeof(WCHAR) );
396 strcatW(lpServiceKey,lpServiceName);
398 TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey));
400 /* FIXME: dwDesiredAccess may need some processing */
401 r = RegOpenKeyExW(hSCManager, lpServiceKey, 0, dwDesiredAccess, &hKey );
402 if (r!=ERROR_SUCCESS)
405 TRACE("returning %p\n",hKey);
410 /******************************************************************************
411 * CreateServiceW [ADVAPI32.@]
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,
422 FIXME("(%p,%s,%s,...)\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
427 /******************************************************************************
428 * CreateServiceA [ADVAPI32.@]
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,
443 TRACE("(%p,%s,%s,...)\n", hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
445 r = RegCreateKeyExA(hSCManager, lpServiceName, 0, NULL,
446 REG_OPTION_NON_VOLATILE, dwDesiredAccess, NULL, &hKey, &dp);
447 if (r!=ERROR_SUCCESS)
449 if (dp != REG_CREATED_NEW_KEY)
454 r = RegSetValueExA(hKey, "DisplayName", 0, REG_SZ, lpDisplayName, strlen(lpDisplayName) );
455 if (r!=ERROR_SUCCESS)
459 r = RegSetValueExA(hKey, "Type", 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
460 if (r!=ERROR_SUCCESS)
463 r = RegSetValueExA(hKey, "Start", 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
464 if (r!=ERROR_SUCCESS)
467 r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
468 (LPVOID)&dwErrorControl, sizeof (DWORD) );
469 if (r!=ERROR_SUCCESS)
474 r = RegSetValueExA(hKey, "ImagePath", 0, REG_SZ,
475 lpBinaryPathName,strlen(lpBinaryPathName)+1 );
476 if (r!=ERROR_SUCCESS)
482 r = RegSetValueExA(hKey, "Group", 0, REG_SZ,
483 lpLoadOrderGroup, strlen(lpLoadOrderGroup)+1 );
484 if (r!=ERROR_SUCCESS)
488 r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
489 (LPVOID)&dwErrorControl, sizeof (DWORD) );
490 if (r!=ERROR_SUCCESS)
497 /* determine the length of a double null terminated multi string */
499 len += (strlen(&lpDependencies[len])+1);
500 } while (lpDependencies[len++]);
502 /* FIXME: this should be unicode */
503 r = RegSetValueExA(hKey, "Dependencies", 0, REG_MULTI_SZ,
504 lpDependencies, len );
505 if (r!=ERROR_SUCCESS)
511 FIXME("Don't know how to add a Password for a service.\n");
514 if(lpServiceStartName)
516 FIXME("Don't know how to add a ServiceStartName for a service.\n");
523 /******************************************************************************
524 * DeleteService [ADVAPI32.@]
527 * hService [I] Handle to service
533 DeleteService( SC_HANDLE hService )
535 FIXME("(%p): stub\n",hService);
540 /******************************************************************************
541 * StartServiceA [ADVAPI32.@]
545 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
546 LPCSTR *lpServiceArgVectors )
549 UNICODE_STRING usBuffer;
552 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
555 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
556 dwNumServiceArgs*sizeof(LPWSTR) );
560 for(i=0; i<dwNumServiceArgs; i++)
562 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
563 lpwstr[i]=usBuffer.Buffer;
566 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
570 for(i=0; i<dwNumServiceArgs; i++)
571 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
572 HeapFree(GetProcessHeap(), 0, lpwstr);
579 /******************************************************************************
580 * StartServiceW [ADVAPI32.@]
584 * hService [I] Handle of service
585 * dwNumServiceArgs [I] Number of arguments
586 * lpServiceArgVectors [I] Address of array of argument string pointers
590 * NT implements this function using an obscure RPC call...
592 * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
593 * to get things like %SystemRoot%\\System32\\service.exe to load.
595 * Will only work for shared address space. How should the service
596 * args be transferred when address spaces are separated?
598 * Can only start one service at a time.
600 * Has no concept of privilege.
606 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
607 LPCWSTR *lpServiceArgVectors )
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};
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};
618 WCHAR path[MAX_PATH],str[MAX_PATH];
622 PROCESS_INFORMATION procinfo;
623 STARTUPINFOW startupinfo;
624 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
625 lpServiceArgVectors);
628 r = RegQueryValueExW(hService, _ImagePathW, NULL, &type, (LPVOID)str, &size);
629 if (r!=ERROR_SUCCESS)
631 ExpandEnvironmentStringsW(str,path,sizeof path);
633 TRACE("Starting service %s\n", debugstr_w(path) );
635 data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
638 data = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
641 ERR("Couldn't create data semaphore\n");
645 wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
647 wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
650 ERR("Couldn't create wait semaphore\n");
656 * FIXME: lpServiceArgsVectors need to be stored and returned to
657 * the service when it calls StartServiceCtrlDispatcher
659 * Chuck these in a global (yuk) so we can pass them to
660 * another process - address space separation will break this.
663 r = WaitForSingleObject(data,INFINITE);
665 if( r == WAIT_FAILED)
668 FIXME("problematic because of address space separation.\n");
669 start_dwNumServiceArgs = dwNumServiceArgs;
670 start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
672 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
673 startupinfo.cb = sizeof(STARTUPINFOW);
675 r = CreateProcessW(path,
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 */
688 ERR("Couldn't start process\n");
689 /* ReleaseSemaphore(data, 1, NULL);
693 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
694 r = WaitForSingleObject(wait,30000);
696 ReleaseSemaphore(data, 1, NULL);
698 if( r == WAIT_FAILED)
704 /******************************************************************************
705 * QueryServiceStatus [ADVAPI32.@]
713 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
716 DWORD type, val, size;
718 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
720 /* read the service type from the registry */
722 r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
725 ERR("invalid Type\n");
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;
741 /******************************************************************************
742 * QueryServiceStatusEx [ADVAPI32.@]
745 * hService [handle to service]
746 * InfoLevel [information level]
748 * cbBufSize [size of buffer]
749 * pcbBytesNeeded [bytes needed]
751 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
752 LPBYTE lpBuffer, DWORD cbBufSize,
753 LPDWORD pcbBytesNeeded)
756 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);