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 static const WCHAR _ServiceStartDataW[] = {'A','D','V','A','P','I','_','S',
41 'e','r','v','i','c','e','S','t',
42 'a','r','t','D','a','t','a',0};
44 /******************************************************************************
45 * EnumServicesStatusA [ADVAPI32.@]
48 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
49 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
50 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
51 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
52 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
53 dwServiceType, dwServiceState, lpServices, cbBufSize,
54 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
55 SetLastError (ERROR_ACCESS_DENIED);
59 /******************************************************************************
60 * EnumServicesStatusW [ADVAPI32.@]
63 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
64 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
65 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
66 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
67 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
68 dwServiceType, dwServiceState, lpServices, cbBufSize,
69 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
70 SetLastError (ERROR_ACCESS_DENIED);
74 /******************************************************************************
75 * StartServiceCtrlDispatcherA [ADVAPI32.@]
78 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
80 LPSERVICE_MAIN_FUNCTIONA fpMain;
82 DWORD dwNumServiceArgs ;
87 TRACE("(%p)\n", servent);
88 wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
91 ERR("Couldn't find wait semaphore\n");
92 ERR("perhaps you need to start services using StartService\n");
96 dwNumServiceArgs = start_dwNumServiceArgs;
97 lpArgVecW = start_lpServiceArgVectors;
99 ReleaseSemaphore(wait, 1, NULL);
101 /* Convert the Unicode arg vectors back to ASCII */
103 lpArgVecA = (LPSTR*) HeapAlloc( GetProcessHeap(), 0,
104 dwNumServiceArgs*sizeof(LPSTR) );
108 for(i=0; i<dwNumServiceArgs; i++)
109 lpArgVecA[i]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW[i]);
111 /* FIXME: should we blindly start all services? */
112 while (servent->lpServiceName) {
113 TRACE("%s at %p)\n", debugstr_a(servent->lpServiceName),servent);
114 fpMain = servent->lpServiceProc;
116 /* try to start the service */
117 fpMain( dwNumServiceArgs, lpArgVecA);
124 /* free arg strings */
125 for(i=0; i<dwNumServiceArgs; i++)
126 HeapFree(GetProcessHeap(), 0, lpArgVecA[i]);
127 HeapFree(GetProcessHeap(), 0, lpArgVecA);
133 /******************************************************************************
134 * StartServiceCtrlDispatcherW [ADVAPI32.@]
140 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
142 LPSERVICE_MAIN_FUNCTIONW fpMain;
144 DWORD dwNumServiceArgs ;
145 LPWSTR *lpServiceArgVectors ;
147 TRACE("(%p)\n", servent);
148 wait = OpenSemaphoreW(SEMAPHORE_ALL_ACCESS, FALSE, _ServiceStartDataW);
151 ERR("Couldn't find wait semaphore\n");
152 ERR("perhaps you need to start services using StartService\n");
156 dwNumServiceArgs = start_dwNumServiceArgs;
157 lpServiceArgVectors = start_lpServiceArgVectors;
159 ReleaseSemaphore(wait, 1, NULL);
161 /* FIXME: should we blindly start all services? */
162 while (servent->lpServiceName) {
163 TRACE("%s at %p)\n", debugstr_w(servent->lpServiceName),servent);
164 fpMain = servent->lpServiceProc;
166 /* try to start the service */
167 fpMain( dwNumServiceArgs, lpServiceArgVectors);
175 /******************************************************************************
176 * LockServiceDatabase [ADVAPI32.@]
178 LPVOID WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
180 FIXME("%p\n",hSCManager);
181 return (SC_HANDLE)0xcacacafe;
184 /******************************************************************************
185 * UnlockServiceDatabase [ADVAPI32.@]
187 BOOL WINAPI UnlockServiceDatabase (LPVOID ScLock)
189 FIXME(": %p\n",ScLock);
193 /******************************************************************************
194 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
196 SERVICE_STATUS_HANDLE WINAPI
197 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName,
198 LPHANDLER_FUNCTION lpfHandler )
199 { FIXME("%s %p\n", lpServiceName, lpfHandler);
203 /******************************************************************************
204 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
210 SERVICE_STATUS_HANDLE WINAPI
211 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
212 LPHANDLER_FUNCTION lpfHandler )
213 { FIXME("%s %p\n", debugstr_w(lpServiceName), lpfHandler);
217 /******************************************************************************
218 * SetServiceStatus [ADVAPI32.@]
225 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
226 { FIXME("0x%lx %p\n",hService, lpStatus);
227 TRACE("\tType:%lx\n",lpStatus->dwServiceType);
228 TRACE("\tState:%lx\n",lpStatus->dwCurrentState);
229 TRACE("\tControlAccepted:%lx\n",lpStatus->dwControlsAccepted);
230 TRACE("\tExitCode:%lx\n",lpStatus->dwWin32ExitCode);
231 TRACE("\tServiceExitCode:%lx\n",lpStatus->dwServiceSpecificExitCode);
232 TRACE("\tCheckPoint:%lx\n",lpStatus->dwCheckPoint);
233 TRACE("\tWaitHint:%lx\n",lpStatus->dwWaitHint);
237 /******************************************************************************
238 * OpenSCManagerA [ADVAPI32.@]
241 OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
242 DWORD dwDesiredAccess )
244 UNICODE_STRING lpMachineNameW;
245 UNICODE_STRING lpDatabaseNameW;
248 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW,lpMachineName);
249 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW,lpDatabaseName);
250 ret = OpenSCManagerW(lpMachineNameW.Buffer,lpDatabaseNameW.Buffer, dwDesiredAccess);
251 RtlFreeUnicodeString(&lpDatabaseNameW);
252 RtlFreeUnicodeString(&lpMachineNameW);
256 /******************************************************************************
257 * OpenSCManagerW [ADVAPI32.@]
258 * Establishes a connection to the service control manager and opens database
261 * This should return a SC_HANDLE
264 * lpMachineName [I] Pointer to machine name string
265 * lpDatabaseName [I] Pointer to database name string
266 * dwDesiredAccess [I] Type of access
269 * Success: Handle to service control manager database
273 OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
274 DWORD dwDesiredAccess )
279 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
280 debugstr_w(lpDatabaseName), dwDesiredAccess);
283 * FIXME: what is lpDatabaseName?
284 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
285 * docs, but what if it isn't?
288 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hKey);
289 if (r!=ERROR_SUCCESS)
292 TRACE("returning %p\n",hKey);
298 /******************************************************************************
299 * AllocateLocallyUniqueId [ADVAPI32.@]
305 AllocateLocallyUniqueId( PLUID lpluid )
307 lpluid->LowPart = time(NULL);
308 lpluid->HighPart = 0;
313 /******************************************************************************
314 * ControlService [ADVAPI32.@]
315 * Sends a control code to a Win32-based service.
325 ControlService( SC_HANDLE hService, DWORD dwControl,
326 LPSERVICE_STATUS lpServiceStatus )
328 FIXME("(%p,%ld,%p): stub\n",hService,dwControl,lpServiceStatus);
333 /******************************************************************************
334 * CloseServiceHandle [ADVAPI32.@]
335 * Close handle to service or service control manager
338 * hSCObject [I] Handle to service or service control manager database
343 CloseServiceHandle( SC_HANDLE hSCObject )
345 TRACE("(%p)\n", hSCObject);
347 RegCloseKey(hSCObject);
353 /******************************************************************************
354 * OpenServiceA [ADVAPI32.@]
357 OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
358 DWORD dwDesiredAccess )
360 UNICODE_STRING lpServiceNameW;
362 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW,lpServiceName);
364 TRACE("Request for service %s\n",lpServiceName);
367 ret = OpenServiceW( hSCManager, lpServiceNameW.Buffer, dwDesiredAccess);
368 RtlFreeUnicodeString(&lpServiceNameW);
373 /******************************************************************************
374 * OpenServiceW [ADVAPI32.@]
375 * Opens a handle to an existing service
383 * Success: Handle to the service
387 OpenServiceW(SC_HANDLE hSCManager, LPCWSTR lpServiceName,
388 DWORD dwDesiredAccess)
390 const char *str = "System\\CurrentControlSet\\Services\\";
391 WCHAR lpServiceKey[80]; /* FIXME: this should be dynamically allocated */
395 TRACE("(%p,%p,%ld)\n",hSCManager, lpServiceName,
398 MultiByteToWideChar( CP_ACP, 0, str, -1, lpServiceKey, sizeof(lpServiceKey)/sizeof(WCHAR) );
399 strcatW(lpServiceKey,lpServiceName);
401 TRACE("Opening reg key %s\n", debugstr_w(lpServiceKey));
403 /* FIXME: dwDesiredAccess may need some processing */
404 r = RegOpenKeyExW(hSCManager, lpServiceKey, 0, dwDesiredAccess, &hKey );
405 if (r!=ERROR_SUCCESS)
408 TRACE("returning %p\n",hKey);
413 /******************************************************************************
414 * CreateServiceW [ADVAPI32.@]
417 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
418 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
419 DWORD dwServiceType, DWORD dwStartType,
420 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
421 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
422 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
425 FIXME("(%p,%s,%s,...)\n", hSCManager, debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
430 /******************************************************************************
431 * CreateServiceA [ADVAPI32.@]
434 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
435 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
436 DWORD dwServiceType, DWORD dwStartType,
437 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
438 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
439 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
446 TRACE("(%p,%s,%s,...)\n", hSCManager, debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
448 r = RegCreateKeyExA(hSCManager, lpServiceName, 0, NULL,
449 REG_OPTION_NON_VOLATILE, dwDesiredAccess, NULL, &hKey, &dp);
450 if (r!=ERROR_SUCCESS)
452 if (dp != REG_CREATED_NEW_KEY)
457 r = RegSetValueExA(hKey, "DisplayName", 0, REG_SZ, lpDisplayName, strlen(lpDisplayName) );
458 if (r!=ERROR_SUCCESS)
462 r = RegSetValueExA(hKey, "Type", 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
463 if (r!=ERROR_SUCCESS)
466 r = RegSetValueExA(hKey, "Start", 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
467 if (r!=ERROR_SUCCESS)
470 r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
471 (LPVOID)&dwErrorControl, sizeof (DWORD) );
472 if (r!=ERROR_SUCCESS)
477 r = RegSetValueExA(hKey, "ImagePath", 0, REG_SZ,
478 lpBinaryPathName,strlen(lpBinaryPathName)+1 );
479 if (r!=ERROR_SUCCESS)
485 r = RegSetValueExA(hKey, "Group", 0, REG_SZ,
486 lpLoadOrderGroup, strlen(lpLoadOrderGroup)+1 );
487 if (r!=ERROR_SUCCESS)
491 r = RegSetValueExA(hKey, "ErrorControl", 0, REG_DWORD,
492 (LPVOID)&dwErrorControl, sizeof (DWORD) );
493 if (r!=ERROR_SUCCESS)
500 /* determine the length of a double null terminated multi string */
502 len += (strlen(&lpDependencies[len])+1);
503 } while (lpDependencies[len++]);
505 /* FIXME: this should be unicode */
506 r = RegSetValueExA(hKey, "Dependencies", 0, REG_MULTI_SZ,
507 lpDependencies, len );
508 if (r!=ERROR_SUCCESS)
514 FIXME("Don't know how to add a Password for a service.\n");
517 if(lpServiceStartName)
519 FIXME("Don't know how to add a ServiceStartName for a service.\n");
526 /******************************************************************************
527 * DeleteService [ADVAPI32.@]
530 * hService [I] Handle to service
536 DeleteService( SC_HANDLE hService )
538 FIXME("(%p): stub\n",hService);
543 /******************************************************************************
544 * StartServiceA [ADVAPI32.@]
548 StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
549 LPCSTR *lpServiceArgVectors )
552 UNICODE_STRING usBuffer;
555 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
558 lpwstr = (LPWSTR*) HeapAlloc( GetProcessHeap(), 0,
559 dwNumServiceArgs*sizeof(LPWSTR) );
563 for(i=0; i<dwNumServiceArgs; i++)
565 RtlCreateUnicodeStringFromAsciiz (&usBuffer,lpServiceArgVectors[i]);
566 lpwstr[i]=usBuffer.Buffer;
569 StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
573 for(i=0; i<dwNumServiceArgs; i++)
574 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
575 HeapFree(GetProcessHeap(), 0, lpwstr);
582 /******************************************************************************
583 * StartServiceW [ADVAPI32.@]
587 * hService [I] Handle of service
588 * dwNumServiceArgs [I] Number of arguments
589 * lpServiceArgVectors [I] Address of array of argument string pointers
593 * NT implements this function using an obscure RPC call...
595 * Might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
596 * to get things like %SystemRoot%\\System32\\service.exe to load.
598 * Will only work for shared address space. How should the service
599 * args be transferred when address spaces are separated?
601 * Can only start one service at a time.
603 * Has no concept of privilege.
609 StartServiceW( SC_HANDLE hService, DWORD dwNumServiceArgs,
610 LPCWSTR *lpServiceArgVectors )
612 static const WCHAR _WaitServiceStartW[] = {'A','D','V','A','P','I','_','W',
613 'a','i','t','S','e','r','v','i',
614 'c','e','S','t','a','r','t',0};
615 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
617 WCHAR path[MAX_PATH],str[MAX_PATH];
621 PROCESS_INFORMATION procinfo;
622 STARTUPINFOW startupinfo;
623 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,
624 lpServiceArgVectors);
627 r = RegQueryValueExW(hService, _ImagePathW, NULL, &type, (LPVOID)str, &size);
628 if (r!=ERROR_SUCCESS)
630 ExpandEnvironmentStringsW(str,path,sizeof(path));
632 TRACE("Starting service %s\n", debugstr_w(path) );
634 data = CreateSemaphoreW(NULL,1,1,_ServiceStartDataW);
637 ERR("Couldn't create data semaphore\n");
640 wait = CreateSemaphoreW(NULL,0,1,_WaitServiceStartW);
643 ERR("Couldn't create wait semaphore\n");
648 * FIXME: lpServiceArgsVectors need to be stored and returned to
649 * the service when it calls StartServiceCtrlDispatcher
651 * Chuck these in a global (yuk) so we can pass them to
652 * another process - address space separation will break this.
655 r = WaitForSingleObject(data,INFINITE);
657 if( r == WAIT_FAILED)
660 FIXME("problematic because of address space separation.\n");
661 start_dwNumServiceArgs = dwNumServiceArgs;
662 start_lpServiceArgVectors = (LPWSTR *)lpServiceArgVectors;
664 ZeroMemory(&startupinfo,sizeof(STARTUPINFOW));
665 startupinfo.cb = sizeof(STARTUPINFOW);
667 r = CreateProcessW(path,
669 NULL, /* process security attribs */
670 NULL, /* thread security attribs */
671 FALSE, /* inherit handles */
672 0, /* creation flags */
673 NULL, /* environment */
674 NULL, /* current directory */
675 &startupinfo, /* startup info */
676 &procinfo); /* process info */
680 ERR("Couldn't start process\n");
681 /* ReleaseSemaphore(data, 1, NULL);
685 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
686 r = WaitForSingleObject(wait,30000);
688 ReleaseSemaphore(data, 1, NULL);
690 if( r == WAIT_FAILED)
696 /******************************************************************************
697 * QueryServiceStatus [ADVAPI32.@]
705 QueryServiceStatus( SC_HANDLE hService, LPSERVICE_STATUS lpservicestatus )
708 DWORD type, val, size;
710 FIXME("(%p,%p) partial\n",hService,lpservicestatus);
712 /* read the service type from the registry */
714 r = RegQueryValueExA(hService, "Type", NULL, &type, (LPBYTE)&val, &size);
717 ERR("invalid Type\n");
720 lpservicestatus->dwServiceType = val;
721 /* FIXME: how are these determined or read from the registry? */
722 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
723 lpservicestatus->dwCurrentState = 1;
724 lpservicestatus->dwControlsAccepted = 0;
725 lpservicestatus->dwWin32ExitCode = NO_ERROR;
726 lpservicestatus->dwServiceSpecificExitCode = 0;
727 lpservicestatus->dwCheckPoint = 0;
728 lpservicestatus->dwWaitHint = 0;
733 /******************************************************************************
734 * QueryServiceStatusEx [ADVAPI32.@]
737 * hService [handle to service]
738 * InfoLevel [information level]
740 * cbBufSize [size of buffer]
741 * pcbBytesNeeded [bytes needed]
743 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
744 LPBYTE lpBuffer, DWORD cbBufSize,
745 LPDWORD pcbBytesNeeded)
748 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);