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 };
47 /******************************************************************************
51 #define MAX_SERVICE_NAME 256
53 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
57 struct sc_manager
/* SCM handle */
59 HKEY hkey_scm_db
; /* handle to services database in the registry */
60 LONG ref_count
; /* handle must remain alive until any related service */
61 /* handle exists because DeleteService requires it */
64 struct sc_service
/* service handle */
66 HKEY hkey
; /* handle to service entry in the registry (under hkey_scm_db) */
67 struct sc_handle
*sc_manager
; /* pointer to SCM handle */
68 WCHAR name
[ MAX_SERVICE_NAME
];
76 struct sc_manager manager
;
77 struct sc_service service
;
81 static struct sc_handle
* alloc_sc_handle( SC_HANDLE_TYPE htype
)
83 struct sc_handle
*retval
;
85 retval
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(struct sc_handle
) );
88 retval
->htype
= htype
;
90 TRACE("SC_HANDLE type=%d -> %p\n",htype
,retval
);
94 static void free_sc_handle( struct sc_handle
* handle
)
99 switch( handle
->htype
)
101 case SC_HTYPE_MANAGER
:
103 if( InterlockedDecrement( &handle
->u
.manager
.ref_count
) )
104 /* there are references to this handle */
107 if( handle
->u
.manager
.hkey_scm_db
)
108 RegCloseKey( handle
->u
.manager
.hkey_scm_db
);
112 case SC_HTYPE_SERVICE
:
114 struct sc_handle
*h
= handle
->u
.service
.sc_manager
;
118 /* release SCM handle */
119 if( 0 == InterlockedDecrement( &h
->u
.manager
.ref_count
) )
121 /* it's time to destroy SCM handle */
122 if( h
->u
.manager
.hkey_scm_db
)
123 RegCloseKey( h
->u
.manager
.hkey_scm_db
);
125 TRACE("SC_HANDLE (SCM) %p type=%d\n",h
,h
->htype
);
127 HeapFree( GetProcessHeap(), 0, h
);
130 if( handle
->u
.service
.hkey
)
131 RegCloseKey( handle
->u
.service
.hkey
);
136 TRACE("SC_HANDLE %p type=%d\n",handle
,handle
->htype
);
138 HeapFree( GetProcessHeap(), 0, handle
);
141 static void init_service_handle( struct sc_handle
* handle
,
142 struct sc_handle
* sc_manager
,
143 HKEY hKey
, LPCWSTR lpServiceName
)
145 /* init sc_service structure */
146 handle
->u
.service
.hkey
= hKey
;
147 lstrcpynW( handle
->u
.service
.name
, lpServiceName
, MAX_SERVICE_NAME
);
149 /* add reference to SCM handle */
150 InterlockedIncrement( &sc_manager
->u
.manager
.ref_count
);
151 handle
->u
.service
.sc_manager
= sc_manager
;
154 /******************************************************************************
155 * EnumServicesStatusA [ADVAPI32.@]
158 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
159 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
160 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
161 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
162 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
163 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
164 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
165 SetLastError (ERROR_ACCESS_DENIED
);
169 /******************************************************************************
170 * EnumServicesStatusW [ADVAPI32.@]
173 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
174 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
175 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
176 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
177 { FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager
,
178 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
179 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
180 SetLastError (ERROR_ACCESS_DENIED
);
184 /******************************************************************************
185 * StartServiceCtrlDispatcherA [ADVAPI32.@]
188 StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent
)
190 LPSERVICE_MAIN_FUNCTIONA fpMain
;
192 DWORD dwNumServiceArgs
;
197 TRACE("(%p)\n", servent
);
198 wait
= CreateSemaphoreW(NULL
,1,1,_ServiceStartDataW
);
201 ERR("Couldn't create data semaphore\n");
205 dwNumServiceArgs
= start_dwNumServiceArgs
;
206 lpArgVecW
= start_lpServiceArgVectors
;
208 ReleaseSemaphore(wait
, 1, NULL
);
210 /* Convert the Unicode arg vectors back to ASCII */
212 lpArgVecA
= (LPSTR
*) HeapAlloc( GetProcessHeap(), 0,
213 dwNumServiceArgs
*sizeof(LPSTR
) );
217 for(i
=0; i
<dwNumServiceArgs
; i
++)
218 lpArgVecA
[i
]=HEAP_strdupWtoA(GetProcessHeap(), 0, lpArgVecW
[i
]);
220 /* FIXME: should we blindly start all services? */
221 while (servent
->lpServiceName
) {
222 TRACE("%s at %p)\n", debugstr_a(servent
->lpServiceName
),servent
);
223 fpMain
= servent
->lpServiceProc
;
225 /* try to start the service */
226 fpMain( dwNumServiceArgs
, lpArgVecA
);
233 /* free arg strings */
234 for(i
=0; i
<dwNumServiceArgs
; i
++)
235 HeapFree(GetProcessHeap(), 0, lpArgVecA
[i
]);
236 HeapFree(GetProcessHeap(), 0, lpArgVecA
);
242 /******************************************************************************
243 * StartServiceCtrlDispatcherW [ADVAPI32.@]
249 StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent
)
251 LPSERVICE_MAIN_FUNCTIONW fpMain
;
253 DWORD dwNumServiceArgs
;
254 LPWSTR
*lpServiceArgVectors
;
256 TRACE("(%p)\n", servent
);
257 wait
= OpenSemaphoreW(SEMAPHORE_ALL_ACCESS
, FALSE
, _ServiceStartDataW
);
260 ERR("Couldn't find wait semaphore\n");
261 ERR("perhaps you need to start services using StartService\n");
265 dwNumServiceArgs
= start_dwNumServiceArgs
;
266 lpServiceArgVectors
= start_lpServiceArgVectors
;
268 ReleaseSemaphore(wait
, 1, NULL
);
270 /* FIXME: should we blindly start all services? */
271 while (servent
->lpServiceName
) {
272 TRACE("%s at %p)\n", debugstr_w(servent
->lpServiceName
),servent
);
273 fpMain
= servent
->lpServiceProc
;
275 /* try to start the service */
276 fpMain( dwNumServiceArgs
, lpServiceArgVectors
);
284 /******************************************************************************
285 * LockServiceDatabase [ADVAPI32.@]
287 LPVOID WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
289 FIXME("%p\n",hSCManager
);
290 return (SC_HANDLE
)0xcacacafe;
293 /******************************************************************************
294 * UnlockServiceDatabase [ADVAPI32.@]
296 BOOL WINAPI
UnlockServiceDatabase (LPVOID ScLock
)
298 FIXME(": %p\n",ScLock
);
302 /******************************************************************************
303 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
305 SERVICE_STATUS_HANDLE WINAPI
306 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
,
307 LPHANDLER_FUNCTION lpfHandler
)
308 { FIXME("%s %p\n", lpServiceName
, lpfHandler
);
312 /******************************************************************************
313 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
319 SERVICE_STATUS_HANDLE WINAPI
320 RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
321 LPHANDLER_FUNCTION lpfHandler
)
322 { FIXME("%s %p\n", debugstr_w(lpServiceName
), lpfHandler
);
326 /******************************************************************************
327 * SetServiceStatus [ADVAPI32.@]
334 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
335 { FIXME("0x%lx %p\n",hService
, lpStatus
);
336 TRACE("\tType:%lx\n",lpStatus
->dwServiceType
);
337 TRACE("\tState:%lx\n",lpStatus
->dwCurrentState
);
338 TRACE("\tControlAccepted:%lx\n",lpStatus
->dwControlsAccepted
);
339 TRACE("\tExitCode:%lx\n",lpStatus
->dwWin32ExitCode
);
340 TRACE("\tServiceExitCode:%lx\n",lpStatus
->dwServiceSpecificExitCode
);
341 TRACE("\tCheckPoint:%lx\n",lpStatus
->dwCheckPoint
);
342 TRACE("\tWaitHint:%lx\n",lpStatus
->dwWaitHint
);
346 /******************************************************************************
347 * OpenSCManagerA [ADVAPI32.@]
349 * Establish a connection to the service control manager and open its database.
352 * lpMachineName [I] Pointer to machine name string
353 * lpDatabaseName [I] Pointer to database name string
354 * dwDesiredAccess [I] Type of access
357 * Success: A Handle to the service control manager database
360 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
361 DWORD dwDesiredAccess
)
363 UNICODE_STRING lpMachineNameW
;
364 UNICODE_STRING lpDatabaseNameW
;
367 RtlCreateUnicodeStringFromAsciiz (&lpMachineNameW
,lpMachineName
);
368 RtlCreateUnicodeStringFromAsciiz (&lpDatabaseNameW
,lpDatabaseName
);
369 ret
= OpenSCManagerW(lpMachineNameW
.Buffer
,lpDatabaseNameW
.Buffer
, dwDesiredAccess
);
370 RtlFreeUnicodeString(&lpDatabaseNameW
);
371 RtlFreeUnicodeString(&lpMachineNameW
);
375 /******************************************************************************
376 * OpenSCManagerW [ADVAPI32.@]
378 * See OpenSCManagerA.
380 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
381 DWORD dwDesiredAccess
)
383 struct sc_handle
*retval
;
387 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName
),
388 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
391 * FIXME: what is lpDatabaseName?
392 * It should be set to "SERVICES_ACTIVE_DATABASE" according to
393 * docs, but what if it isn't?
396 retval
= alloc_sc_handle( SC_HTYPE_MANAGER
);
397 if( NULL
== retval
) return NULL
;
399 retval
->u
.manager
.ref_count
= 1;
401 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
402 if (r
!=ERROR_SUCCESS
)
405 r
= RegOpenKeyExW(hReg
, szServiceManagerKey
,
406 0, KEY_ALL_ACCESS
, &retval
->u
.manager
.hkey_scm_db
);
408 if (r
!=ERROR_SUCCESS
)
411 TRACE("returning %p\n", retval
);
413 return (SC_HANDLE
) retval
;
416 free_sc_handle( retval
);
421 /******************************************************************************
422 * AllocateLocallyUniqueId [ADVAPI32.@]
428 AllocateLocallyUniqueId( PLUID lpluid
)
430 lpluid
->LowPart
= time(NULL
);
431 lpluid
->HighPart
= 0;
436 /******************************************************************************
437 * ControlService [ADVAPI32.@]
439 * Send a control code to a service.
442 * hService [I] Handle of the service control manager database
443 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
444 * lpServiceStatus [O] Destination for the status of the service, if available
450 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
451 LPSERVICE_STATUS lpServiceStatus
)
453 FIXME("(%p,%ld,%p): stub\n",hService
,dwControl
,lpServiceStatus
);
458 /******************************************************************************
459 * CloseServiceHandle [ADVAPI32.@]
461 * Close a handle to a service or the service control manager database.
464 * hSCObject [I] Handle to service or service control manager database
471 CloseServiceHandle( SC_HANDLE hSCObject
)
473 TRACE("(%p)\n", hSCObject
);
475 free_sc_handle( (struct sc_handle
*) hSCObject
);
481 /******************************************************************************
482 * OpenServiceA [ADVAPI32.@]
484 * Open a handle to a service.
487 * hSCManager [I] Handle of the service control manager database
488 * lpServiceName [I] Name of the service to open
489 * dwDesiredAccess [I] Access required to the service
492 * Success: Handle to the service
495 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
496 DWORD dwDesiredAccess
)
498 UNICODE_STRING lpServiceNameW
;
500 RtlCreateUnicodeStringFromAsciiz (&lpServiceNameW
,lpServiceName
);
502 TRACE("Request for service %s\n",lpServiceName
);
505 ret
= OpenServiceW( hSCManager
, lpServiceNameW
.Buffer
, dwDesiredAccess
);
506 RtlFreeUnicodeString(&lpServiceNameW
);
511 /******************************************************************************
512 * OpenServiceW [ADVAPI32.@]
516 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
517 DWORD dwDesiredAccess
)
519 struct sc_handle
*hscm
= hSCManager
;
520 struct sc_handle
*retval
;
524 TRACE("(%p,%p,%ld)\n",hSCManager
, lpServiceName
,
527 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
531 r
= RegOpenKeyExW( hscm
->u
.manager
.hkey_scm_db
,
532 lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
533 if (r
!=ERROR_SUCCESS
)
535 free_sc_handle( retval
);
539 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
541 TRACE("returning %p\n",retval
);
543 return (SC_HANDLE
) retval
;
546 /******************************************************************************
547 * CreateServiceW [ADVAPI32.@]
550 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
551 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
552 DWORD dwServiceType
, DWORD dwStartType
,
553 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
554 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
555 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
558 struct sc_handle
*hscm
= hSCManager
;
559 struct sc_handle
*retval
;
563 static const WCHAR szDisplayName
[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
564 static const WCHAR szType
[] = {'T','y','p','e',0};
565 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
566 static const WCHAR szError
[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
567 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
568 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
569 static const WCHAR szDependencies
[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
571 FIXME("%p %s %s\n", hSCManager
,
572 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
574 retval
= alloc_sc_handle( SC_HTYPE_SERVICE
);
578 r
= RegCreateKeyExW(hscm
->u
.manager
.hkey_scm_db
, lpServiceName
, 0, NULL
,
579 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
580 if (r
!=ERROR_SUCCESS
)
583 init_service_handle( retval
, hscm
, hKey
, lpServiceName
);
585 if (dp
!= REG_CREATED_NEW_KEY
)
590 r
= RegSetValueExW(hKey
, szDisplayName
, 0, REG_SZ
, (LPBYTE
)lpDisplayName
,
591 (strlenW(lpDisplayName
)+1)*sizeof(WCHAR
) );
592 if (r
!=ERROR_SUCCESS
)
596 r
= RegSetValueExW(hKey
, szType
, 0, REG_DWORD
, (LPVOID
)&dwServiceType
, sizeof (DWORD
) );
597 if (r
!=ERROR_SUCCESS
)
600 r
= RegSetValueExW(hKey
, szStart
, 0, REG_DWORD
, (LPVOID
)&dwStartType
, sizeof (DWORD
) );
601 if (r
!=ERROR_SUCCESS
)
604 r
= RegSetValueExW(hKey
, szError
, 0, REG_DWORD
,
605 (LPVOID
)&dwErrorControl
, sizeof (DWORD
) );
606 if (r
!=ERROR_SUCCESS
)
611 r
= RegSetValueExW(hKey
, szImagePath
, 0, REG_SZ
, (LPBYTE
)lpBinaryPathName
,
612 (strlenW(lpBinaryPathName
)+1)*sizeof(WCHAR
) );
613 if (r
!=ERROR_SUCCESS
)
619 r
= RegSetValueExW(hKey
, szGroup
, 0, REG_SZ
, (LPBYTE
)lpLoadOrderGroup
,
620 (strlenW(lpLoadOrderGroup
)+1)*sizeof(WCHAR
) );
621 if (r
!=ERROR_SUCCESS
)
629 /* determine the length of a double null terminated multi string */
631 len
+= (strlenW(&lpDependencies
[len
])+1);
632 } while (lpDependencies
[len
++]);
634 r
= RegSetValueExW(hKey
, szDependencies
, 0, REG_MULTI_SZ
,
635 (LPBYTE
)lpDependencies
, len
);
636 if (r
!=ERROR_SUCCESS
)
642 FIXME("Don't know how to add a Password for a service.\n");
645 if(lpServiceStartName
)
647 FIXME("Don't know how to add a ServiceStartName for a service.\n");
650 return (SC_HANDLE
) retval
;
653 free_sc_handle( retval
);
658 static inline LPWSTR
SERV_dup( LPCSTR str
)
665 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
666 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
667 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
671 static inline LPWSTR
SERV_dupmulti( LPCSTR str
)
679 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
680 n
+= (strlen( &str
[n
] ) + 1);
685 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
686 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
690 static inline VOID
SERV_free( LPWSTR wstr
)
692 HeapFree( GetProcessHeap(), 0, wstr
);
695 /******************************************************************************
696 * CreateServiceA [ADVAPI32.@]
699 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
700 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
701 DWORD dwServiceType
, DWORD dwStartType
,
702 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
703 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
704 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
707 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
708 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
711 TRACE("%p %s %s\n", hSCManager
,
712 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
714 lpServiceNameW
= SERV_dup( lpServiceName
);
715 lpDisplayNameW
= SERV_dup( lpDisplayName
);
716 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
717 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
718 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
719 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
720 lpPasswordW
= SERV_dup( lpPassword
);
722 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
723 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
724 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
725 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
727 SERV_free( lpServiceNameW
);
728 SERV_free( lpDisplayNameW
);
729 SERV_free( lpBinaryPathNameW
);
730 SERV_free( lpLoadOrderGroupW
);
731 SERV_free( lpDependenciesW
);
732 SERV_free( lpServiceStartNameW
);
733 SERV_free( lpPasswordW
);
739 /******************************************************************************
740 * DeleteService [ADVAPI32.@]
742 * Delete a service from the service control manager database.
745 * hService [I] Handle of the service to delete
751 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
753 struct sc_handle
*hsvc
= hService
;
754 HKEY hKey
= hsvc
->u
.service
.hkey
;
755 WCHAR valname
[MAX_PATH
+1];
761 /* Clean out the values */
762 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
763 while (rc
== ERROR_SUCCESS
)
765 RegDeleteValueW(hKey
,valname
);
768 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
772 hsvc
->u
.service
.hkey
= NULL
;
775 RegDeleteKeyW(hsvc
->u
.service
.sc_manager
->u
.manager
.hkey_scm_db
,
776 hsvc
->u
.service
.name
);
782 /******************************************************************************
783 * StartServiceA [ADVAPI32.@]
788 * hService [I] Handle of service
789 * dwNumServiceArgs [I] Number of arguments
790 * lpServiceArgVectors [I] Address of array of argument strings
793 * - NT implements this function using an obscure RPC call.
794 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
795 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
796 * - This will only work for shared address space. How should the service
797 * args be transferred when address spaces are separated?
798 * - Can only start one service at a time.
799 * - Has no concept of privilege.
806 StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
807 LPCSTR
*lpServiceArgVectors
)
810 UNICODE_STRING usBuffer
;
813 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
816 lpwstr
= (LPWSTR
*) HeapAlloc( GetProcessHeap(), 0,
817 dwNumServiceArgs
*sizeof(LPWSTR
) );
821 for(i
=0; i
<dwNumServiceArgs
; i
++)
823 RtlCreateUnicodeStringFromAsciiz (&usBuffer
,lpServiceArgVectors
[i
]);
824 lpwstr
[i
]=usBuffer
.Buffer
;
827 StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
831 for(i
=0; i
<dwNumServiceArgs
; i
++)
832 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
833 HeapFree(GetProcessHeap(), 0, lpwstr
);
840 /******************************************************************************
841 * StartServiceW [ADVAPI32.@]
846 StartServiceW( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
847 LPCWSTR
*lpServiceArgVectors
)
849 static const WCHAR _WaitServiceStartW
[] = {'A','D','V','A','P','I','_','W',
850 'a','i','t','S','e','r','v','i',
851 'c','e','S','t','a','r','t',0};
852 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
854 struct sc_handle
*hsvc
= hService
;
855 WCHAR path
[MAX_PATH
],str
[MAX_PATH
];
859 PROCESS_INFORMATION procinfo
;
860 STARTUPINFOW startupinfo
;
861 TRACE("(%p,%ld,%p)\n",hService
,dwNumServiceArgs
,
862 lpServiceArgVectors
);
865 r
= RegQueryValueExW(hsvc
->u
.service
.hkey
, _ImagePathW
, NULL
, &type
, (LPVOID
)str
, &size
);
866 if (r
!=ERROR_SUCCESS
)
868 ExpandEnvironmentStringsW(str
,path
,sizeof(path
));
870 TRACE("Starting service %s\n", debugstr_w(path
) );
872 data
= CreateSemaphoreW(NULL
,1,1,_ServiceStartDataW
);
875 ERR("Couldn't create data semaphore\n");
878 wait
= CreateSemaphoreW(NULL
,0,1,_WaitServiceStartW
);
881 ERR("Couldn't create wait semaphore\n");
886 * FIXME: lpServiceArgsVectors need to be stored and returned to
887 * the service when it calls StartServiceCtrlDispatcher
889 * Chuck these in a global (yuk) so we can pass them to
890 * another process - address space separation will break this.
893 r
= WaitForSingleObject(data
,INFINITE
);
895 if( r
== WAIT_FAILED
)
898 FIXME("problematic because of address space separation.\n");
899 start_dwNumServiceArgs
= dwNumServiceArgs
;
900 start_lpServiceArgVectors
= (LPWSTR
*)lpServiceArgVectors
;
902 ZeroMemory(&startupinfo
,sizeof(STARTUPINFOW
));
903 startupinfo
.cb
= sizeof(STARTUPINFOW
);
905 r
= CreateProcessW(NULL
,
907 NULL
, /* process security attribs */
908 NULL
, /* thread security attribs */
909 FALSE
, /* inherit handles */
910 0, /* creation flags */
911 NULL
, /* environment */
912 NULL
, /* current directory */
913 &startupinfo
, /* startup info */
914 &procinfo
); /* process info */
918 ERR("Couldn't start process\n");
919 /* ReleaseSemaphore(data, 1, NULL);
923 /* docs for StartServiceCtrlDispatcher say this should be 30 sec */
924 r
= WaitForSingleObject(wait
,30000);
926 ReleaseSemaphore(data
, 1, NULL
);
928 if( r
== WAIT_FAILED
)
934 /******************************************************************************
935 * QueryServiceStatus [ADVAPI32.@]
943 QueryServiceStatus( SC_HANDLE hService
, LPSERVICE_STATUS lpservicestatus
)
945 struct sc_handle
*hsvc
= hService
;
947 DWORD type
, val
, size
;
949 FIXME("(%p,%p) partial\n",hService
,lpservicestatus
);
951 /* read the service type from the registry */
953 r
= RegQueryValueExA(hsvc
->u
.service
.hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
956 ERR("invalid Type\n");
959 lpservicestatus
->dwServiceType
= val
;
960 /* FIXME: how are these determined or read from the registry? */
961 /* SERVICE: unavailable=0, stopped=1, starting=2, running=3? */;
962 lpservicestatus
->dwCurrentState
= 1;
963 lpservicestatus
->dwControlsAccepted
= 0;
964 lpservicestatus
->dwWin32ExitCode
= NO_ERROR
;
965 lpservicestatus
->dwServiceSpecificExitCode
= 0;
966 lpservicestatus
->dwCheckPoint
= 0;
967 lpservicestatus
->dwWaitHint
= 0;
972 /******************************************************************************
973 * QueryServiceStatusEx [ADVAPI32.@]
975 * Get information about a service.
978 * hService [I] Handle to service to get information about
979 * InfoLevel [I] Level of information to get
980 * lpBuffer [O] Destination for requested information
981 * cbBufSize [I] Size of lpBuffer in bytes
982 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
988 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
989 LPBYTE lpBuffer
, DWORD cbBufSize
,
990 LPDWORD pcbBytesNeeded
)
993 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
997 /******************************************************************************
998 * QueryServiceConfigA [ADVAPI32.@]
1001 QueryServiceConfigA( SC_HANDLE hService
,
1002 LPQUERY_SERVICE_CONFIGA lpServiceConfig
,
1003 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1005 static const CHAR szDisplayName
[] = "DisplayName";
1006 static const CHAR szType
[] = "Type";
1007 static const CHAR szStart
[] = "Start";
1008 static const CHAR szError
[] = "ErrorControl";
1009 static const CHAR szImagePath
[] = "ImagePath";
1010 static const CHAR szGroup
[] = "Group";
1011 static const CHAR szDependencies
[] = "Dependencies";
1012 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1013 CHAR str_buffer
[ MAX_PATH
];
1015 DWORD type
, val
, sz
, total
, n
;
1018 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1019 cbBufSize
, pcbBytesNeeded
);
1021 /* calculate the size required first */
1022 total
= sizeof (QUERY_SERVICE_CONFIGA
);
1024 sz
= sizeof(str_buffer
);
1025 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1026 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1028 sz
= ExpandEnvironmentStringsA(str_buffer
,NULL
,0);
1029 if( 0 == sz
) return FALSE
;
1035 /* FIXME: set last error */
1040 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1041 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1045 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1046 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1050 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1051 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1055 r
= RegQueryValueExA( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1056 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1059 /* if there's not enough memory, return an error */
1060 if( total
> *pcbBytesNeeded
)
1062 *pcbBytesNeeded
= total
;
1063 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1067 *pcbBytesNeeded
= total
;
1068 ZeroMemory( lpServiceConfig
, total
);
1071 r
= RegQueryValueExA( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1072 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1073 lpServiceConfig
->dwServiceType
= val
;
1076 r
= RegQueryValueExA( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1077 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1078 lpServiceConfig
->dwStartType
= val
;
1081 r
= RegQueryValueExA( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1082 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1083 lpServiceConfig
->dwErrorControl
= val
;
1085 /* now do the strings */
1086 p
= (LPBYTE
) &lpServiceConfig
[1];
1087 n
= total
- sizeof (QUERY_SERVICE_CONFIGA
);
1089 sz
= sizeof(str_buffer
);
1090 r
= RegQueryValueExA( hKey
, szImagePath
, 0, &type
, str_buffer
, &sz
);
1091 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1093 sz
= ExpandEnvironmentStringsA(str_buffer
, p
, n
);
1094 if( 0 == sz
|| sz
> n
) return FALSE
;
1096 lpServiceConfig
->lpBinaryPathName
= (LPSTR
) p
;
1102 /* FIXME: set last error */
1107 r
= RegQueryValueExA( hKey
, szGroup
, 0, &type
, p
, &sz
);
1108 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1110 lpServiceConfig
->lpLoadOrderGroup
= (LPSTR
) p
;
1116 r
= RegQueryValueExA( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1117 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1119 lpServiceConfig
->lpDependencies
= (LPSTR
) p
;
1125 ERR("Buffer overflow!\n");
1127 TRACE("Image path = %s\n", lpServiceConfig
->lpBinaryPathName
);
1128 TRACE("Group = %s\n", lpServiceConfig
->lpLoadOrderGroup
);
1133 /******************************************************************************
1134 * QueryServiceConfigW [ADVAPI32.@]
1137 QueryServiceConfigW( SC_HANDLE hService
,
1138 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1139 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1141 static const WCHAR szDisplayName
[] = {
1142 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1143 static const WCHAR szType
[] = {'T','y','p','e',0};
1144 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
1145 static const WCHAR szError
[] = {
1146 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1147 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
1148 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
1149 static const WCHAR szDependencies
[] = {
1150 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1151 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1152 WCHAR str_buffer
[ MAX_PATH
];
1154 DWORD type
, val
, sz
, total
, n
;
1157 TRACE("%p %p %ld %p\n", hService
, lpServiceConfig
,
1158 cbBufSize
, pcbBytesNeeded
);
1160 /* calculate the size required first */
1161 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1163 sz
= sizeof(str_buffer
);
1164 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1165 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1167 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1168 if( 0 == sz
) return FALSE
;
1170 total
+= sizeof(WCHAR
) * sz
;
1174 /* FIXME: set last error */
1179 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1180 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1184 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1185 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1189 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, NULL
, &sz
);
1190 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1194 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1195 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1198 /* if there's not enough memory, return an error */
1199 if( total
> *pcbBytesNeeded
)
1201 *pcbBytesNeeded
= total
;
1202 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1206 *pcbBytesNeeded
= total
;
1207 ZeroMemory( lpServiceConfig
, total
);
1210 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1211 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1212 lpServiceConfig
->dwServiceType
= val
;
1215 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1216 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1217 lpServiceConfig
->dwStartType
= val
;
1220 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1221 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_DWORD
) )
1222 lpServiceConfig
->dwErrorControl
= val
;
1224 /* now do the strings */
1225 p
= (LPBYTE
) &lpServiceConfig
[1];
1226 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1228 sz
= sizeof(str_buffer
);
1229 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1230 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1232 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1233 sz
*= sizeof(WCHAR
);
1234 if( 0 == sz
|| sz
> n
) return FALSE
;
1236 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1242 /* FIXME: set last error */
1247 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1248 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1250 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1256 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1257 if( ( r
== ERROR_SUCCESS
) || ( type
== REG_SZ
) )
1259 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1265 ERR("Buffer overflow!\n");
1267 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1268 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1273 /******************************************************************************
1274 * ChangeServiceConfigW [ADVAPI32.@]
1276 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
1277 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1278 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
1279 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
1281 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1282 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1283 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
1284 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
1285 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
1289 /******************************************************************************
1290 * ChangeServiceConfigA [ADVAPI32.@]
1292 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
1293 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1294 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
1295 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
1297 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1298 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
1299 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
1300 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
1301 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
1305 /******************************************************************************
1306 * ChangeServiceConfig2A [ADVAPI32.@]
1308 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
1311 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);
1315 /******************************************************************************
1316 * ChangeServiceConfig2W [ADVAPI32.@]
1318 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
1321 HKEY hKey
= ((struct sc_handle
*) hService
)->u
.service
.hkey
;
1323 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
1325 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1326 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
1327 if (sd
->lpDescription
)
1329 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
1330 if (sd
->lpDescription
[0] == 0)
1331 RegDeleteValueW(hKey
,szDescription
);
1333 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
1334 (LPVOID
)sd
->lpDescription
,
1335 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
1339 FIXME("STUB: %p %ld %p\n",hService
, dwInfoLevel
, lpInfo
);