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};
43 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
44 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
45 'S','e','r','v','i','c','e','s','\\',0 };
46 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
49 /******************************************************************************
53 #define MAX_SERVICE_NAME 256
55 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
59 struct sc_manager
/* SCM handle */
61 HKEY hkey_scm_db
; /* handle to services database in the registry */
62 LONG ref_count
; /* handle must remain alive until any related service */
63 /* handle exists because DeleteService requires it */
66 struct sc_service
/* service handle */
68 HKEY hkey
; /* handle to service entry in the registry (under hkey_scm_db) */
69 struct sc_handle
*sc_manager
; /* pointer to SCM handle */
70 WCHAR name
[ MAX_SERVICE_NAME
];
78 struct sc_manager manager
;
79 struct sc_service service
;
83 static struct sc_handle
* alloc_sc_handle( SC_HANDLE_TYPE htype
)
85 struct sc_handle
*retval
;
87 retval
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct sc_handle
) );
90 retval
->htype
= htype
;
92 TRACE("SC_HANDLE type=%d -> %p\n",htype
,retval
);
96 static void free_sc_handle( struct sc_handle
* handle
)
101 switch( handle
->htype
)
103 case SC_HTYPE_MANAGER
:
105 if( InterlockedDecrement( &handle
->u
.manager
.ref_count
) )
106 /* there are references to this handle */
109 if( handle
->u
.manager
.hkey_scm_db
)
110 RegCloseKey( handle
->u
.manager
.hkey_scm_db
);
114 case SC_HTYPE_SERVICE
:
116 struct sc_handle
*h
= handle
->u
.service
.sc_manager
;
120 /* release SCM handle */
121 if( 0 == InterlockedDecrement( &h
->u
.manager
.ref_count
) )
123 /* it's time to destroy SCM handle */
124 if( h
->u
.manager
.hkey_scm_db
)
125 RegCloseKey( h
->u
.manager
.hkey_scm_db
);
127 TRACE("SC_HANDLE (SCM) %p type=%d\n",h
,h
->htype
);
129 HeapFree( GetProcessHeap(), 0, h
);
132 if( handle
->u
.service
.hkey
)
133 RegCloseKey( handle
->u
.service
.hkey
);
138 TRACE("SC_HANDLE %p type=%d\n",handle
,handle
->htype
);
140 HeapFree( GetProcessHeap(), 0, handle
);
143 static void init_service_handle( struct sc_handle
* handle
,
144 struct sc_handle
* sc_manager
,
145 HKEY hKey
, LPCWSTR lpServiceName
)
147 /* init sc_service structure */
148 handle
->u
.service
.hkey
= hKey
;
149 lstrcpynW( handle
->u
.service
.name
, lpServiceName
, MAX_SERVICE_NAME
);
151 /* add reference to SCM handle */
152 InterlockedIncrement( &sc_manager
->u
.manager
.ref_count
);
153 handle
->u
.service
.sc_manager
= sc_manager
;
156 /******************************************************************************
157 * EnumServicesStatusA [ADVAPI32.@]
160 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
161 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
162 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
163 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
164 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
165 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
166 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
167 SetLastError (ERROR_ACCESS_DENIED
);
171 /******************************************************************************
172 * EnumServicesStatusW [ADVAPI32.@]
175 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
176 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
177 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
178 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
179 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
180 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
181 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
182 SetLastError (ERROR_ACCESS_DENIED
);
186 /******************************************************************************
187 * StartServiceCtrlDispatcherA [ADVAPI32.@]
190 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
192 LPSERVICE_MAIN_FUNCTIONA fpMain
;
194 DWORD dwNumServiceArgs
;
199 TRACE("(%p)\n", servent
);
200 wait
= CreateSemaphoreW(NULL
,1,1,_ServiceStartDataW
);
203 ERR("Couldn't create data semaphore\n");
207 dwNumServiceArgs
= start_dwNumServiceArgs
;
208 lpArgVecW
= start_lpServiceArgVectors
;
210 ReleaseSemaphore(wait
, 1, NULL
);
212 /* Convert the Unicode arg vectors back to ASCII */
214 lpArgVecA
= (LPSTR
*) HeapAlloc( GetProcessHeap(), 0,
215 dwNumServiceArgs
*sizeof(LPSTR
) );
219 for(i
=0; i
<dwNumServiceArgs
; i
++)
220 lpArgVecA
[i
]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW
[i
]);
222 /* FIXME: should we blindly start all services? */
223 while (servent
->lpServiceName
) {
224 TRACE("%s at %p)\n", debugstr_a(servent
->lpServiceName
),servent
);
225 fpMain
= servent
->lpServiceProc
;
227 /* try to start the service */
228 fpMain( dwNumServiceArgs
, lpArgVecA
);
235 /* free arg strings */
236 for(i
=0; i
<dwNumServiceArgs
; i
++)
237 HeapFree(GetProcessHeap(), 0, lpArgVecA
[i
]);
238 HeapFree(GetProcessHeap(), 0, lpArgVecA
);
244 /******************************************************************************
245 * StartServiceCtrlDispatcherW [ADVAPI32.@]
251 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
253 LPSERVICE_MAIN_FUNCTIONW fpMain
;
255 DWORD dwNumServiceArgs
;
256 LPWSTR
*lpServiceArgVectors
;
258 TRACE("(%p)\n", servent
);
259 wait
= OpenSemaphoreW(SEMAPHORE_ALL_ACCESS
, FALSE
, _ServiceStartDataW
);
262 ERR("Couldn't find wait semaphore\n");
263 ERR("perhaps you need to start services using StartService\n");
267 dwNumServiceArgs
= start_dwNumServiceArgs
;
268 lpServiceArgVectors
= start_lpServiceArgVectors
;
270 ReleaseSemaphore(wait
, 1, NULL
);
272 /* FIXME: should we blindly start all services? */
273 while (servent
->lpServiceName
) {
274 TRACE("%s at %p)\n", debugstr_w(servent
->lpServiceName
),servent
);
275 fpMain
= servent
->lpServiceProc
;
277 /* try to start the service */
278 fpMain( dwNumServiceArgs
, lpServiceArgVectors
);
286 /******************************************************************************
287 * LockServiceDatabase [ADVAPI32.@]
289 LPVOID WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
293 TRACE("%p\n",hSCManager
);
295 ret
= CreateFileMappingW( INVALID_HANDLE_VALUE
, NULL
, PAGE_READWRITE
,
296 0, MAX_SERVICE_NAME
* sizeof(WCHAR
), szSCMLock
);
297 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
301 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
304 TRACE("returning %p\n", ret
);
309 /******************************************************************************
310 * UnlockServiceDatabase [ADVAPI32.@]
312 BOOL WINAPI
UnlockServiceDatabase (LPVOID ScLock
)
314 TRACE("%p\n",ScLock
);
316 return CloseHandle( (HANDLE
) ScLock
);
319 /******************************************************************************
320 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
322 SERVICE_STATUS_HANDLE WINAPI
323 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
,
324 LPHANDLER_FUNCTION lpfHandler
)
325 { FIXME("%s %p\n", lpServiceName
, lpfHandler
);
329 /******************************************************************************
330 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
336 SERVICE_STATUS_HANDLE WINAPI
337 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
338 LPHANDLER_FUNCTION lpfHandler
)
339 { FIXME("%s %p\n", debugstr_w(lpServiceName
), lpfHandler
);
343 /******************************************************************************
344 * SetServiceStatus [ADVAPI32.@]
351 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
352 { FIXME("0x%lx %p\n",hService
, lpStatus
);
353 TRACE("\tType:%lx\n",lpStatus
->dwServiceType
);
354 TRACE("\tState:%lx\n",lpStatus
->dwCurrentState
);
355 TRACE("\tControlAccepted:%lx\n",lpStatus
->dwControlsAccepted
);
356 TRACE("\tExitCode:%lx\n",lpStatus
->dwWin32ExitCode
);
357 TRACE("\tServiceExitCode:%lx\n",lpStatus
->dwServiceSpecificExitCode
);
358 TRACE("\tCheckPoint:%lx\n",lpStatus
->dwCheckPoint
);
359 TRACE("\tWaitHint:%lx\n",lpStatus
->dwWaitHint
);
363 /******************************************************************************
364 * OpenSCManagerA [ADVAPI32.@]
366 * Establish a connection to the service control manager and open its database.
369 * lpMachineName [I] Pointer to machine name string
370 * lpDatabaseName [I] Pointer to database name string
371 * dwDesiredAccess [I] Type of access
374 * Success: A Handle to the service control manager database
377 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
378 DWORD dwDesiredAccess
)
380 UNICODE_STRING lpMachineNameW
;
381 UNICODE_STRING lpDatabaseNameW
;
384 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW
,lpMachineName
);
385 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW
,lpDatabaseName
);
386 ret
= OpenSCManagerW(lpMachineNameW
.Buffer
,lpDatabaseNameW
.Buffer
, dwDesiredAccess
);
387 RtlFreeUnicodeString(&lpDatabaseNameW
);
388 RtlFreeUnicodeString(&lpMachineNameW
);
392 /******************************************************************************
393 * OpenSCManagerW [ADVAPI32.@]
395 * See OpenSCManagerA.
397 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
398 DWORD dwDesiredAccess
)
400 struct sc_handle
*retval
;
404 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
405 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
408 * FIXME: what is lpDatabaseName?
409 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
410 * docs, but what if it isn't?
413 retval
= alloc_sc_handle( SC_HTYPE_MANAGER
);
414 if( NULL
== retval
) return NULL
;
416 retval
->u
.manager
.ref_count
= 1;
418 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
419 if (r
!=ERROR_SUCCESS
)
422 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
423 0, KEY_ALL_ACCESS
, &retval
->u
.manager
.hkey_scm_db
);
425 if (r
!=ERROR_SUCCESS
)
428 TRACE("returning %p\n", retval
);
430 return (SC_HANDLE
) retval
;
433 free_sc_handle( retval
);
438 /******************************************************************************
439 * AllocateLocallyUniqueId [ADVAPI32.@]
445 AllocateLocallyUniqueId( PLUID lpluid
)
447 lpluid
->LowPart
= time(NULL
);
448 lpluid
->HighPart
= 0;
453 /******************************************************************************
454 * ControlService [ADVAPI32.@]
456 * Send a control code to a service.
459 * hService [I] Handle of the service control manager database
460 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
461 * lpServiceStatus [O] Destination for the status of the service, if available
467 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
468 LPSERVICE_STATUS lpServiceStatus
)
470 FIXME("(%p,%ld,%p): stub\n",hService
,dwControl
,lpServiceStatus
);
475 /******************************************************************************
476 * CloseServiceHandle [ADVAPI32.@]
478 * Close a handle to a service or the service control manager database.
481 * hSCObject [I] Handle to service or service control manager database
488 CloseServiceHandle( SC_HANDLE hSCObject
)
490 TRACE("(%p)\n", hSCObject
);
492 free_sc_handle( (struct sc_handle
*) hSCObject
);
498 /******************************************************************************
499 * OpenServiceA [ADVAPI32.@]
501 * Open a handle to a service.
504 * hSCManager [I] Handle of the service control manager database
505 * lpServiceName [I] Name of the service to open
506 * dwDesiredAccess [I] Access required to the service
509 * Success: Handle to the service
512 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
513 DWORD dwDesiredAccess
)
515 UNICODE_STRING lpServiceNameW
;
517 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW
,lpServiceName
);
519 TRACE("Request for service %s\n",lpServiceName
);
522 ret
= OpenServiceW( hSCManager
, lpServiceNameW
.Buffer
, dwDesiredAccess
);
523 RtlFreeUnicodeString(&lpServiceNameW
);
528 /******************************************************************************
529 * OpenServiceW [ADVAPI32.@]
533 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
534 DWORD dwDesiredAccess
)
536 struct sc_handle
*hscm
= hSCManager
;
537 struct sc_handle
*retval
;
541 TRACE("(%p,%p,%ld)\n",hSCManager
, lpServiceName
,
544 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
548 r
= RegOpenKeyExW( hscm
->u
.manager
.hkey_scm_db
,
549 lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
550 if (r
!=ERROR_SUCCESS
)
552 free_sc_handle( retval
);
553 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
557 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
559 TRACE("returning %p\n",retval
);
561 return (SC_HANDLE
) retval
;
564 /******************************************************************************
565 * CreateServiceW [ADVAPI32.@]
568 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
569 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
570 DWORD dwServiceType
, DWORD dwStartType
,
571 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
572 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
573 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
576 struct sc_handle
*hscm
= hSCManager
;
577 struct sc_handle
*retval
;
581 static const WCHAR szDisplayName
[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
582 static const WCHAR szType
[] = {'T','y','p','e',0};
583 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
584 static const WCHAR szError
[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
585 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
586 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
587 static const WCHAR szDependencies
[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
589 FIXME("%p %s %s\n", hSCManager
,
590 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
592 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
596 r
= RegCreateKeyExW(hscm
->u
.manager
.hkey_scm_db
, lpServiceName
, 0, NULL
,
597 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
598 if (r
!=ERROR_SUCCESS
)
601 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
603 if (dp
!= REG_CREATED_NEW_KEY
)
608 r
= RegSetValueExW(hKey
, szDisplayName
, 0, REG_SZ
, (LPBYTE
)lpDisplayName
,
609 (strlenW(lpDisplayName
)+1)*sizeof(WCHAR
) );
610 if (r
!=ERROR_SUCCESS
)
614 r
= RegSetValueExW(hKey
, szType
, 0, REG_DWORD
, (LPVOID
)&dwServiceType
, sizeof (DWORD
) );
615 if (r
!=ERROR_SUCCESS
)
618 r
= RegSetValueExW(hKey
, szStart
, 0, REG_DWORD
, (LPVOID
)&dwStartType
, sizeof (DWORD
) );
619 if (r
!=ERROR_SUCCESS
)
622 r
= RegSetValueExW(hKey
, szError
, 0, REG_DWORD
,
623 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
624 if (r
!=ERROR_SUCCESS
)
629 r
= RegSetValueExW(hKey
, szImagePath
, 0, REG_SZ
, (LPBYTE
)lpBinaryPathName
,
630 (strlenW(lpBinaryPathName
)+1)*sizeof(WCHAR
) );
631 if (r
!=ERROR_SUCCESS
)
637 r
= RegSetValueExW(hKey
, szGroup
, 0, REG_SZ
, (LPBYTE
)lpLoadOrderGroup
,
638 (strlenW(lpLoadOrderGroup
)+1)*sizeof(WCHAR
) );
639 if (r
!=ERROR_SUCCESS
)
647 /* determine the length of a double null terminated multi string */
649 len
+= (strlenW(&lpDependencies
[len
])+1);
650 } while (lpDependencies
[len
++]);
652 r
= RegSetValueExW(hKey
, szDependencies
, 0, REG_MULTI_SZ
,
653 (LPBYTE
)lpDependencies
, len
);
654 if (r
!=ERROR_SUCCESS
)
660 FIXME("Don't know how to add a Password for a service.\n");
663 if(lpServiceStartName
)
665 FIXME("Don't know how to add a ServiceStartName for a service.\n");
668 return (SC_HANDLE
) retval
;
671 free_sc_handle( retval
);
676 static inline LPWSTR
SERV_dup( LPCSTR str
)
683 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
684 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
685 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
689 static inline LPWSTR
SERV_dupmulti( LPCSTR str
)
697 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
698 n
+= (strlen( &str
[n
] ) + 1);
703 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
704 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
708 static inline VOID
SERV_free( LPWSTR wstr
)
710 HeapFree( GetProcessHeap(), 0, wstr
);
713 /******************************************************************************
714 * CreateServiceA [ADVAPI32.@]
717 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
718 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
719 DWORD dwServiceType
, DWORD dwStartType
,
720 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
721 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
722 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
725 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
726 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
729 TRACE("%p %s %s\n", hSCManager
,
730 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
732 lpServiceNameW
= SERV_dup( lpServiceName
);
733 lpDisplayNameW
= SERV_dup( lpDisplayName
);
734 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
735 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
736 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
737 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
738 lpPasswordW
= SERV_dup( lpPassword
);
740 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
741 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
742 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
743 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
745 SERV_free( lpServiceNameW
);
746 SERV_free( lpDisplayNameW
);
747 SERV_free( lpBinaryPathNameW
);
748 SERV_free( lpLoadOrderGroupW
);
749 SERV_free( lpDependenciesW
);
750 SERV_free( lpServiceStartNameW
);
751 SERV_free( lpPasswordW
);
757 /******************************************************************************
758 * DeleteService [ADVAPI32.@]
760 * Delete a service from the service control manager database.
763 * hService [I] Handle of the service to delete
769 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
771 struct sc_handle
*hsvc
= hService
;
772 HKEY hKey
= hsvc
->u
.service
.hkey
;
773 WCHAR valname
[MAX_PATH
+1];
779 /* Clean out the values */
780 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
781 while (rc
== ERROR_SUCCESS
)
783 RegDeleteValueW(hKey
,valname
);
786 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
790 hsvc
->u
.service
.hkey
= NULL
;
793 RegDeleteKeyW(hsvc
->u
.service
.sc_manager
->u
.manager
.hkey_scm_db
,
794 hsvc
->u
.service
.name
);
800 /******************************************************************************
801 * StartServiceA [ADVAPI32.@]
806 * hService [I] Handle of service
807 * dwNumServiceArgs [I] Number of arguments
808 * lpServiceArgVectors [I] Address of array of argument strings
811 * - NT implements this function using an obscure RPC call.
812 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
813 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
814 * - This will only work for shared address space. How should the service
815 * args be transferred when address spaces are separated?
816 * - Can only start one service at a time.
817 * - Has no concept of privilege.
824 StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
825 LPCSTR
*lpServiceArgVectors
)
828 UNICODE_STRING usBuffer
;
831 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
834 lpwstr
= (LPWSTR
*) HeapAlloc( GetProcessHeap(), 0,
835 dwNumServiceArgs
*sizeof(LPWSTR
) );
839 for(i
=0; i
<dwNumServiceArgs
; i
++)
841 RtlCreateUnicodeStringFromAsciiz (&usBuffer
,lpServiceArgVectors
[i
]);
842 lpwstr
[i
]=usBuffer
.Buffer
;
845 StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
849 for(i
=0; i
<dwNumServiceArgs
; i
++)
850 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
851 HeapFree(GetProcessHeap(), 0, lpwstr
);
858 /******************************************************************************
859 * StartServiceW [ADVAPI32.@]
864 StartServiceW( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
865 LPCWSTR
*lpServiceArgVectors
)
867 static const WCHAR _WaitServiceStartW
[] = {'A','D','V','A','P','I','_','W',
868 'a','i','t','S','e','r','v','i',
869 'c','e','S','t','a','r','t',0};
870 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
872 struct sc_handle
*hsvc
= hService
;
873 WCHAR path
[MAX_PATH
],str
[MAX_PATH
];
877 PROCESS_INFORMATION procinfo
;
878 STARTUPINFOW startupinfo
;
881 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,
882 lpServiceArgVectors
);
885 r
= RegQueryValueExW(hsvc
->u
.service
.hkey
, _ImagePathW
, NULL
, &type
, (LPVOID
)str
, &size
);
886 if (r
!=ERROR_SUCCESS
)
888 ExpandEnvironmentStringsW(str
,path
,sizeof(path
));
890 TRACE("Starting service %s\n", debugstr_w(path
) );
892 data
= CreateSemaphoreW(NULL
,1,1,_ServiceStartDataW
);
895 ERR("Couldn't create data semaphore\n");
898 wait
= CreateSemaphoreW(NULL
,0,1,_WaitServiceStartW
);
901 ERR("Couldn't create wait semaphore\n");
906 * FIXME: lpServiceArgsVectors need to be stored and returned to
907 * the service when it calls StartServiceCtrlDispatcher
909 * Chuck these in a global (yuk) so we can pass them to
910 * another process - address space separation will break this.
913 r
= WaitForSingleObject(data
,INFINITE
);
915 if( r
== WAIT_FAILED
)
918 FIXME("problematic because of address space separation.\n");
919 start_dwNumServiceArgs
= dwNumServiceArgs
;
920 start_lpServiceArgVectors
= (LPWSTR
*)lpServiceArgVectors
;
922 ZeroMemory(&startupinfo
,sizeof(STARTUPINFOW
));
923 startupinfo
.cb
= sizeof(STARTUPINFOW
);
925 r
= CreateProcessW(NULL
,
927 NULL
, /* process security attribs */
928 NULL
, /* thread security attribs */
929 FALSE
, /* inherit handles */
930 0, /* creation flags */
931 NULL
, /* environment */
932 NULL
, /* current directory */
933 &startupinfo
, /* startup info */
934 &procinfo
); /* process info */
938 ERR("Couldn't start process\n");
941 CloseHandle( procinfo
.hThread
);
943 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
944 r
= WaitForSingleObject(wait
,30000);
945 if( WAIT_FAILED
== r
)
947 CloseHandle( procinfo
.hProcess
);
952 CloseHandle( procinfo
.hProcess
);
957 ReleaseSemaphore(data
, 1, NULL
);
962 /******************************************************************************
963 * QueryServiceStatus [ADVAPI32.@]
971 QueryServiceStatus( SC_HANDLE hService
, LPSERVICE_STATUS lpservicestatus
)
973 struct sc_handle
*hsvc
= hService
;
975 DWORD type
, val
, size
;
977 FIXME("(%p,%p) partial\n",hService
,lpservicestatus
);
979 /* read the service type from the registry */
981 r
= RegQueryValueExA(hsvc
->u
.service
.hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
984 ERR("invalid Type\n");
987 lpservicestatus
->dwServiceType
= val
;
988 /* FIXME: how are these determined or read from the registry? */
989 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
990 lpservicestatus
->dwCurrentState
= 1;
991 lpservicestatus
->dwControlsAccepted
= 0;
992 lpservicestatus
->dwWin32ExitCode
= NO_ERROR
;
993 lpservicestatus
->dwServiceSpecificExitCode
= 0;
994 lpservicestatus
->dwCheckPoint
= 0;
995 lpservicestatus
->dwWaitHint
= 0;
1000 /******************************************************************************
1001 * QueryServiceStatusEx [ADVAPI32.@]
1003 * Get information about a service.
1006 * hService [I] Handle to service to get information about
1007 * InfoLevel [I] Level of information to get
1008 * lpBuffer [O] Destination for requested information
1009 * cbBufSize [I] Size of lpBuffer in bytes
1010 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1016 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1017 LPBYTE lpBuffer
, DWORD cbBufSize
,
1018 LPDWORD pcbBytesNeeded
)
1021 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
1025 /******************************************************************************
1026 * QueryServiceConfigA [ADVAPI32.@]
1029 QueryServiceConfigA( SC_HANDLE hService
,
1030 LPQUERY_SERVICE_CONFIGA lpServiceConfig
,
1031 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1033 static const CHAR szDisplayName
[] = "DisplayName";
1034 static const CHAR szType
[] = "Type";
1035 static const CHAR szStart
[] = "Start";
1036 static const CHAR szError
[] = "ErrorControl";
1037 static const CHAR szImagePath
[] = "ImagePath";
1038 static const CHAR szGroup
[] = "Group";
1039 static const CHAR szDependencies
[] = "Dependencies";
1040 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1041 CHAR str_buffer
[ MAX_PATH
];
1043 DWORD type
, val
, sz
, total
, n
;
1046 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1047 cbBufSize
, pcbBytesNeeded
);
1049 /* calculate the size required first */
1050 total
= sizeof (QUERY_SERVICE_CONFIGA
);
1052 sz
= sizeof(str_buffer
);
1053 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1054 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1056 sz
= ExpandEnvironmentStringsA(str_buffer
,NULL
,0);
1057 if( 0 == sz
) return FALSE
;
1063 /* FIXME: set last error */
1068 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1069 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1073 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1074 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1078 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1079 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1083 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1084 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1087 /* if there's not enough memory, return an error */
1088 if( total
> *pcbBytesNeeded
)
1090 *pcbBytesNeeded
= total
;
1091 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1095 *pcbBytesNeeded
= total
;
1096 ZeroMemory( lpServiceConfig
, total
);
1099 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1100 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1101 lpServiceConfig
->dwServiceType
= val
;
1104 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1105 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1106 lpServiceConfig
->dwStartType
= val
;
1109 r
= RegQueryValueExA( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1110 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1111 lpServiceConfig
->dwErrorControl
= val
;
1113 /* now do the strings */
1114 p
= (LPBYTE
) &lpServiceConfig
[1];
1115 n
= total
- sizeof (QUERY_SERVICE_CONFIGA
);
1117 sz
= sizeof(str_buffer
);
1118 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1119 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1121 sz
= ExpandEnvironmentStringsA(str_buffer
, p
, n
);
1122 if( 0 == sz
|| sz
> n
) return FALSE
;
1124 lpServiceConfig
->lpBinaryPathName
= (LPSTR
) p
;
1130 /* FIXME: set last error */
1135 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, p
, &sz
);
1136 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1138 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
) p
;
1144 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1145 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1147 lpServiceConfig
->lpDependencies
= (LPSTR
) p
;
1153 ERR("Buffer overflow!\n");
1155 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1156 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1161 /******************************************************************************
1162 * QueryServiceConfigW [ADVAPI32.@]
1165 QueryServiceConfigW( SC_HANDLE hService
,
1166 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1167 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1169 static const WCHAR szDisplayName
[] = {
1170 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1171 static const WCHAR szType
[] = {'T','y','p','e',0};
1172 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
1173 static const WCHAR szError
[] = {
1174 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1175 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
1176 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
1177 static const WCHAR szDependencies
[] = {
1178 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1179 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1180 WCHAR str_buffer
[ MAX_PATH
];
1182 DWORD type
, val
, sz
, total
, n
;
1185 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1186 cbBufSize
, pcbBytesNeeded
);
1188 /* calculate the size required first */
1189 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1191 sz
= sizeof(str_buffer
);
1192 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1193 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1195 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1196 if( 0 == sz
) return FALSE
;
1198 total
+= sizeof(WCHAR
) * sz
;
1202 /* FIXME: set last error */
1207 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1208 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1212 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1213 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1217 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1218 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1222 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1223 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1226 /* if there's not enough memory, return an error */
1227 if( total
> *pcbBytesNeeded
)
1229 *pcbBytesNeeded
= total
;
1230 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1234 *pcbBytesNeeded
= total
;
1235 ZeroMemory( lpServiceConfig
, total
);
1238 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1239 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1240 lpServiceConfig
->dwServiceType
= val
;
1243 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1244 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1245 lpServiceConfig
->dwStartType
= val
;
1248 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1249 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1250 lpServiceConfig
->dwErrorControl
= val
;
1252 /* now do the strings */
1253 p
= (LPBYTE
) &lpServiceConfig
[1];
1254 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1256 sz
= sizeof(str_buffer
);
1257 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1258 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1260 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1261 sz
*= sizeof(WCHAR
);
1262 if( 0 == sz
|| sz
> n
) return FALSE
;
1264 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1270 /* FIXME: set last error */
1275 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1276 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1278 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1284 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1285 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1287 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1293 ERR("Buffer overflow!\n");
1295 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1296 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1301 /******************************************************************************
1302 * ChangeServiceConfigW [ADVAPI32.@]
1304 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1305 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1306 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1307 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1309 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1310 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1311 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1312 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1313 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1317 /******************************************************************************
1318 * ChangeServiceConfigA [ADVAPI32.@]
1320 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1321 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1322 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
1323 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
1325 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1326 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1327 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
1328 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
1329 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
1333 /******************************************************************************
1334 * ChangeServiceConfig2A [ADVAPI32.@]
1336 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
1339 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
1343 /******************************************************************************
1344 * ChangeServiceConfig2W [ADVAPI32.@]
1346 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
1349 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1351 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
1353 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1354 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
1355 if (sd
->lpDescription
)
1357 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
1358 if (sd
->lpDescription
[0] == 0)
1359 RegDeleteValueW(hKey
,szDescription
);
1361 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
1362 (LPVOID
)sd
->lpDescription
,
1363 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
1367 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
1371 /******************************************************************************
1372 * QueryServiceObjectSecurity [ADVAPI32.@]
1374 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
1375 SECURITY_INFORMATION dwSecurityInformation
,
1376 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
1377 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1379 FIXME("%p %ld %p %lu %p\n", hService
, dwSecurityInformation
,
1380 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
1381 return ERROR_CALL_NOT_IMPLEMENTED
;