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;