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