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
30 #include "wine/unicode.h"
32 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
37 static DWORD start_dwNumServiceArgs;
38 static LPWSTR *start_lpServiceArgVectors;
40 /******************************************************************************
41 * EnumServicesStatusA [ADVAPI32.@]
44 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
45 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
46 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
47 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
48 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
49 dwServiceType, dwServiceState, lpServices, cbBufSize,
50 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
51 SetLastError (ERROR_ACCESS_DENIED);
55 /******************************************************************************
56 * EnumServicesStatusW [ADVAPI32.@]
59 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
60 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
61 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
62 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
63 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
64 dwServiceType, dwServiceState, lpServices, cbBufSize,
65 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
66 SetLastError (ERROR_ACCESS_DENIED);
70 /******************************************************************************
71 * StartServiceCtrlDispatcherA [ADVAPI32.@]
74 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
76 LPSERVICE_MAIN_FUNCTIONA fpMain;
78 DWORD dwNumServiceArgs ;
83 TRACE("(%p)\n", servent);
84 wait = OpenSemaphoreA(SEMAPHORE_ALL_ACCESS, FALSE, "ADVAPI32_ServiceStartData");
87 ERR("Couldn't find wait semaphore\n");
88 ERR("perhaps you need to start services using StartService\n");
92 dwNumServiceArgs = start_dwNumServiceArgs;
93 lpArgVecW = start_lpServiceArgVectors;
95 ReleaseSemaphore(wait, 1, NULL);
97 /* Convert the Unicode arg vectors back to ASCII */
99 lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
100 dwNumServiceArgs*sizeof(LPSTR) );
104 for(i=0; i<dwNumServiceArgs; i++)
105 lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
107 /* FIXME: should we blindly start all services? */
108 while (servent->lpServiceName) {
109 TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
110 fpMain = servent->lpServiceProc;
112 /* try to start the service */
113 fpMain( dwNumServiceArgs, lpArgVecA);
120 /* free arg strings */
121 for(i=0; i<dwNumServiceArgs; i++)
122 HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
123 HeapFree(GetProcessHeap(), 0, lpArgVecA);
129 /******************************************************************************
130 * StartServiceCtrlDispatcherW [ADVAPI32.@]
136 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
138 static const WCHAR _ServiceStartDataW[] = {'A','D','V','A','P','I','_','S',
139 'e','r','v','i','c','e','S','t',
140 'a','r','t','D','a','t','a',0};
141 LPSERVICE_MAIN_FUNCTIONW fpMain;
143 DWORD dwNumServiceArgs ;
144 LPWSTR *lpServiceArgVectors ;
146 TRACE("(%p)\n", servent);
147 wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
150 ERR("Couldn't find wait semaphore\n");
151 ERR("perhaps you need to start services using StartService\n");
155 dwNumServiceArgs = start_dwNumServiceArgs;
156 lpServiceArgVectors = start_lpServiceArgVectors;
158 ReleaseSemaphore(wait, 1, NULL);
160 /* FIXME: should we blindly start all services? */
161 while (servent->lpServiceName) {
162 TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
163 fpMain = servent->lpServiceProc;
165 /* try to start the service */
166 fpMain( dwNumServiceArgs, lpServiceArgVectors);
174 /******************************************************************************
175 * LockServiceDatabase [ADVAPI32.@]
177 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
179 FIXME("%p\n",hSCManager);
180 return (SC_HANDLE)0xcacacafe;
183 /******************************************************************************
184 * UnlockServiceDatabase [ADVAPI32.@]
186 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
188 FIXME(": %p\n",ScLock);
192 /******************************************************************************
193 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
195 SERVICE_STATUS_HANDLE WINAPI
196 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
197 LPHANDLER_FUNCTION lpfHandler )
198 { FIXME("%s %p\n", lpServiceName, lpfHandler);
202 /******************************************************************************
203 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
209 SERVICE_STATUS_HANDLE WINAPI
210 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
211 LPHANDLER_FUNCTION lpfHandler )
212 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
216 /******************************************************************************
217 * SetServiceStatus [ADVAPI32.@]
224 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
225 { FIXME("0x%lx %p\n",hService, lpStatus);
226 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
227 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
228 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
229 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
230 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
231 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
232 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
236 /******************************************************************************
237 * OpenSCManagerA [ADVAPI32.@]
240 OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
241 DWORD dwDesiredAccess )
243 UNICODE_STRING lpMachineNameW;
244 UNICODE_STRING lpDatabaseNameW;
247 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
248 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
249 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
250 RtlFreeUnicodeString(&lpDatabaseNameW);
251 RtlFreeUnicodeString(&lpMachineNameW);
255 /******************************************************************************
256 * OpenSCManagerW [ADVAPI32.@]
257 * Establishes a connection to the service control manager and opens database
260 * This should return a SC_HANDLE
263 * lpMachineName [I] Pointer to machine name string
264 * lpDatabaseName [I] Pointer to database name string
265 * dwDesiredAccess [I] Type of access
268 * Success: Handle to service control manager database
272 OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
273 DWORD dwDesiredAccess )
278 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
279 debugstr_w(lpDatabaseName), dwDesiredAccess);
282 * FIXME: what is lpDatabaseName?
283 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
284 * docs, but what if it isn't?
287 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hKey);
288 if (r!=ERROR_SUCCESS)
291 TRACE("returning %p\n",hKey);
297 /******************************************************************************
298 * AllocateLocallyUniqueId [ADVAPI32.@]
304 AllocateLocallyUniqueId( PLUID lpluid )
306 lpluid->LowPart = time(NULL);
307 lpluid->HighPart = 0;
312 /******************************************************************************
313 * ControlService [ADVAPI32.@]
314 * Sends a control code to a Win32-based service.
324 ControlService( SC_HANDLE hService, DWORD dwControl,
325 LPSERVICE_STATUS lpServiceStatus )
327 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
332 /******************************************************************************
333 * CloseServiceHandle [ADVAPI32.@]
334 * Close handle to service or service control manager
337 * hSCObject [I] Handle to service or service control manager database
342 CloseServiceHandle( SC_HANDLE hSCObject )
344 TRACE("(%p)\n", hSCObject);
346 RegCloseKey(hSCObject);
352 /******************************************************************************
353 * OpenServiceA [ADVAPI32.@]
356 OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
357 DWORD dwDesiredAccess )
359 UNICODE_STRING lpServiceNameW;
361 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
363 TRACE("Request for service %s\n",lpServiceName);
366 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
367 RtlFreeUnicodeString(&lpServiceNameW);
372 /******************************************************************************
373 * OpenServiceW [ADVAPI32.@]
374 * Opens a handle to an existing service
382 * Success: Handle to the service
386 OpenServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName,
387 DWORD dwDesiredAccess)
389 const char *str = "System\\CurrentControlSet\\Services\\";
390 WCHAR lpServiceKey[80]; /* FIXME: this should be dynamically allocated */
394 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
397 MultiByteToWideChar( CP_ACP, 0, str, -1, lpServiceKey, sizeof(lpServiceKey)/sizeof(WCHAR) );
398 strcatW(lpServiceKey,lpServiceName);
400 TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey));
402 /* FIXME: dwDesiredAccess may need some processing */
403 r = RegOpenKeyExW(hSCManager, lpServiceKey, 0, dwDesiredAccess, &hKey );
404 if (r!=ERROR_SUCCESS)
407 TRACE("returning %p\n",hKey);
412 /******************************************************************************
413 * CreateServiceW [ADVAPI32.@]
416 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
417 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
418 DWORD dwServiceType, DWORD dwStartType,
419 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
420 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
421 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
424 FIXME("(%p,%s,%s,...)\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
429 /******************************************************************************
430 * CreateServiceA [ADVAPI32.@]
433 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
434 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
435 DWORD dwServiceType, DWORD dwStartType,
436 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
437 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
438 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
445 TRACE("(%p,%s,%s,...)\n", hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
447 r = RegCreateKeyExA(hSCManager, lpServiceName, 0, NULL,
448 REG_OPTION_NON_VOLATILE, dwDesiredAccess, NULL, &hKey, &dp);
449 if (r!=ERROR_SUCCESS)
451 if (dp != REG_CREATED_NEW_KEY)
456 r = RegSetValueExA(hKey, "DisplayName", 0, REG_SZ, lpDisplayName, strlen(lpDisplayName) );
457 if (r!=ERROR_SUCCESS)
461 r = RegSetValueExA(hKey, "Type", 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
462 if (r!=ERROR_SUCCESS)
465 r = RegSetValueExA(hKey, "Start", 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
466 if (r!=ERROR_SUCCESS)
469 r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
470 (LPVOID)&dwErrorControl, sizeof (DWORD) );
471 if (r!=ERROR_SUCCESS)
476 r = RegSetValueExA(hKey, "ImagePath", 0, REG_SZ,
477 lpBinaryPathName,strlen(lpBinaryPathName)+1 );
478 if (r!=ERROR_SUCCESS)
484 r = RegSetValueExA(hKey, "Group", 0, REG_SZ,
485 lpLoadOrderGroup, strlen(lpLoadOrderGroup)+1 );
486 if (r!=ERROR_SUCCESS)
490 r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
491 (LPVOID)&dwErrorControl, sizeof (DWORD) );
492 if (r!=ERROR_SUCCESS)
499 /* determine the length of a double null terminated multi string */
501 len += (strlen(&lpDependencies[len])+1);
502 } while (lpDependencies[len++]);
504 /* FIXME: this should be unicode */
505 r = RegSetValueExA(hKey, "Dependencies", 0, REG_MULTI_SZ,
506 lpDependencies, len );
507 if (r!=ERROR_SUCCESS)
513 FIXME("Don't know how to add a Password for a service.\n");
516 if(lpServiceStartName)
518 FIXME("Don't know how to add a ServiceStartName for a service.\n");
525 /******************************************************************************
526 * DeleteService [ADVAPI32.@]
529 * hService [I] Handle to service
535 DeleteService( SC_HANDLE hService )
537 FIXME("(%p): stub\n",hService);
542 /******************************************************************************
543 * StartServiceA [ADVAPI32.@]
547 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
548 LPCSTR *lpServiceArgVectors )
551 UNICODE_STRING usBuffer;
554 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
557 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
558 dwNumServiceArgs*sizeof(LPWSTR) );
562 for(i=0; i<dwNumServiceArgs; i++)
564 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
565 lpwstr[i]=usBuffer.Buffer;
568 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
572 for(i=0; i<dwNumServiceArgs; i++)
573 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
574 HeapFree(GetProcessHeap(), 0, lpwstr);
581 /******************************************************************************
582 * StartServiceW [ADVAPI32.@]
586 * hService [I] Handle of service
587 * dwNumServiceArgs [I] Number of arguments
588 * lpServiceArgVectors [I] Address of array of argument string pointers
592 * NT implements this function using an obscure RPC call...
594 * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
595 * to get things like %SystemRoot%\\System32\\service.exe to load.
597 * Will only work for shared address space. How should the service
598 * args be transferred when address spaces are separated?
600 * Can only start one service at a time.
602 * Has no concept of privilege.
608 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
609 LPCWSTR *lpServiceArgVectors )
611 static const WCHAR _ServiceStartDataW[] = {'A','D','V','A','P','I','_','S',
612 'e','r','v','i','c','e','S','t',
613 'a','r','t','D','a','t','a',0};
615 static const WCHAR _WaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
616 'a','i','t','S','e','r','v','i',
617 'c','e','S','t','a','r','t',0};
618 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
620 WCHAR path[MAX_PATH],str[MAX_PATH];
624 PROCESS_INFORMATION procinfo;
625 STARTUPINFOW startupinfo;
626 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
627 lpServiceArgVectors);
630 r = RegQueryValueExW(hService, _ImagePathW, NULL, &type, (LPVOID)str, &size);
631 if (r!=ERROR_SUCCESS)
633 ExpandEnvironmentStringsW(str,path,sizeof(path));
635 TRACE("Starting service %s\n", debugstr_w(path) );
637 data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
640 data = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
643 ERR("Couldn't create data semaphore\n");
647 wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
649 wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
652 ERR("Couldn't create wait semaphore\n");
658 * FIXME: lpServiceArgsVectors need to be stored and returned to
659 * the service when it calls StartServiceCtrlDispatcher
661 * Chuck these in a global (yuk) so we can pass them to
662 * another process - address space separation will break this.
665 r = WaitForSingleObject(data,INFINITE);
667 if( r == WAIT_FAILED)
670 FIXME("problematic because of address space separation.\n");
671 start_dwNumServiceArgs = dwNumServiceArgs;
672 start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
674 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
675 startupinfo.cb = sizeof(STARTUPINFOW);
677 r = CreateProcessW(path,
679 NULL, /* process security attribs */
680 NULL, /* thread security attribs */
681 FALSE, /* inherit handles */
682 0, /* creation flags */
683 NULL, /* environment */
684 NULL, /* current directory */
685 &startupinfo, /* startup info */
686 &procinfo); /* process info */
690 ERR("Couldn't start process\n");
691 /* ReleaseSemaphore(data, 1, NULL);
695 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
696 r = WaitForSingleObject(wait,30000);
698 ReleaseSemaphore(data, 1, NULL);
700 if( r == WAIT_FAILED)
706 /******************************************************************************
707 * QueryServiceStatus [ADVAPI32.@]
715 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
718 DWORD type, val, size;
720 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
722 /* read the service type from the registry */
724 r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
727 ERR("invalid Type\n");
730 lpservicestatus->dwServiceType = val;
731 /* FIXME: how are these determined or read from the registry? */
732 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
733 lpservicestatus->dwCurrentState = 1;
734 lpservicestatus->dwControlsAccepted = 0;
735 lpservicestatus->dwWin32ExitCode = NO_ERROR;
736 lpservicestatus->dwServiceSpecificExitCode = 0;
737 lpservicestatus->dwCheckPoint = 0;
738 lpservicestatus->dwWaitHint = 0;
743 /******************************************************************************
744 * QueryServiceStatusEx [ADVAPI32.@]
747 * hService [handle to service]
748 * InfoLevel [information level]
750 * cbBufSize [size of buffer]
751 * pcbBytesNeeded [bytes needed]
753 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
754 LPBYTE lpBuffer, DWORD cbBufSize,
755 LPDWORD pcbBytesNeeded)
758 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);