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
);