2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
40 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
41 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
42 'S','e','r','v','i','c','e','s','\\',0 };
43 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
46 typedef struct service_start_info_t
53 #define WINESERV_STARTINFO 1
54 #define WINESERV_GETSTATUS 2
55 #define WINESERV_SENDCONTROL 3
57 typedef struct service_data_t
59 struct service_data_t *next;
60 LPHANDLER_FUNCTION handler;
61 SERVICE_STATUS status;
65 LPSERVICE_MAIN_FUNCTIONA a;
66 LPSERVICE_MAIN_FUNCTIONW w;
72 static CRITICAL_SECTION service_cs;
73 static CRITICAL_SECTION_DEBUG service_cs_debug =
76 { &service_cs_debug.ProcessLocksList,
77 &service_cs_debug.ProcessLocksList },
78 0, 0, { 0, (DWORD)(__FILE__ ": service_cs") }
80 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
82 service_data *service_list;
84 /******************************************************************************
88 #define MAX_SERVICE_NAME 256
90 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
93 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
99 sc_handle_destructor destroy;
102 struct sc_manager /* service control manager handle */
104 struct sc_handle hdr;
105 HKEY hkey; /* handle to services database in the registry */
108 struct sc_service /* service handle */
110 struct sc_handle hdr;
111 HKEY hkey; /* handle to service entry in the registry (under hkey) */
112 struct sc_manager *scm; /* pointer to SCM handle */
116 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
117 sc_handle_destructor destroy)
119 struct sc_handle *hdr;
121 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
126 hdr->destroy = destroy;
128 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
132 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
134 struct sc_handle *hdr = (struct sc_handle *) handle;
138 if (hdr->htype != htype)
143 static void sc_handle_free(struct sc_handle* hdr)
147 if (--hdr->ref_count)
150 HeapFree(GetProcessHeap(), 0, hdr);
153 static void sc_handle_destroy_manager(struct sc_handle *handle)
155 struct sc_manager *mgr = (struct sc_manager*) handle;
157 TRACE("destroying SC Manager %p\n", mgr);
159 RegCloseKey(mgr->hkey);
162 static void sc_handle_destroy_service(struct sc_handle *handle)
164 struct sc_service *svc = (struct sc_service*) handle;
166 TRACE("destroying service %p\n", svc);
168 RegCloseKey(svc->hkey);
170 sc_handle_free(&svc->scm->hdr);
174 /******************************************************************************
175 * String management functions
177 static inline LPWSTR SERV_dup( LPCSTR str )
184 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
185 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
186 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
190 static inline LPWSTR SERV_dupmulti(LPCSTR str)
198 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
199 n += (strlen( &str[n] ) + 1);
204 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
205 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
209 static inline VOID SERV_free( LPWSTR wstr )
211 HeapFree( GetProcessHeap(), 0, wstr );
214 /******************************************************************************
215 * registry access functions and data
217 static const WCHAR szDisplayName[] = {
218 'D','i','s','p','l','a','y','N','a','m','e', 0 };
219 static const WCHAR szType[] = {'T','y','p','e',0};
220 static const WCHAR szStart[] = {'S','t','a','r','t',0};
221 static const WCHAR szError[] = {
222 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
223 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
224 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
225 static const WCHAR szDependencies[] = {
226 'D','e','p','e','n','d','e','n','c','i','e','s',0};
227 static const WCHAR szDependOnService[] = {
228 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
237 static inline void service_set_value( struct reg_value *val,
238 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
246 static inline void service_set_dword( struct reg_value *val,
247 LPCWSTR name, DWORD *data )
249 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
252 static inline void service_set_string( struct reg_value *val,
253 LPCWSTR name, LPCWSTR string )
255 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
256 service_set_value( val, REG_SZ, name, string, len );
259 static inline void service_set_multi_string( struct reg_value *val,
260 LPCWSTR name, LPCWSTR string )
264 /* determine the length of a double null terminated multi string */
266 len += (lstrlenW( &string[ len ] )+1);
267 } while ( string[ len++ ] );
269 len *= sizeof (WCHAR);
270 service_set_value( val, REG_MULTI_SZ, name, string, len );
273 static inline LONG service_write_values( HKEY hKey,
274 struct reg_value *val, int n )
276 LONG r = ERROR_SUCCESS;
281 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
282 (const BYTE*)val[i].data, val[i].size );
283 if( r != ERROR_SUCCESS )
289 /******************************************************************************
290 * Service IPC functions
292 static LPWSTR service_get_pipe_name(LPWSTR service)
294 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
295 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
299 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
300 name = HeapAlloc(GetProcessHeap(), 0, len);
301 strcpyW(name, prefix);
302 strcatW(name, service);
306 static HANDLE service_open_pipe(LPWSTR service)
308 LPWSTR szPipe = service_get_pipe_name( service );
309 HANDLE handle = INVALID_HANDLE_VALUE;
312 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
313 0, NULL, OPEN_ALWAYS, 0, NULL);
314 if (handle != INVALID_HANDLE_VALUE)
316 if (GetLastError() != ERROR_PIPE_BUSY)
318 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
324 /******************************************************************************
325 * service_get_event_handle
327 static HANDLE service_get_event_handle(LPWSTR service)
329 static const WCHAR prefix[] = {
330 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
335 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
336 name = HeapAlloc(GetProcessHeap(), 0, len);
337 strcpyW(name, prefix);
338 strcatW(name, service);
339 handle = CreateEventW(NULL, TRUE, FALSE, name);
344 /******************************************************************************
347 * Call into the main service routine provided by StartServiceCtrlDispatcher.
349 static DWORD WINAPI service_thread(LPVOID arg)
351 service_data *info = arg;
352 LPWSTR str = info->args;
353 DWORD argc = 0, len = 0;
359 len += strlenW(&str[len]) + 1;
367 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
368 for (argc=0, p=str; *p; p += strlenW(p) + 1)
372 info->proc.w(argc, argv);
373 HeapFree(GetProcessHeap(), 0, argv);
377 LPSTR strA, *argv, p;
380 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
381 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
382 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
384 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
385 for (argc=0, p=strA; *p; p += strlen(p) + 1)
389 info->proc.a(argc, argv);
390 HeapFree(GetProcessHeap(), 0, argv);
391 HeapFree(GetProcessHeap(), 0, strA);
396 /******************************************************************************
397 * service_handle_start
399 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
401 DWORD read = 0, result = 0;
405 TRACE("%p %p %ld\n", pipe, service, count);
407 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
408 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
409 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
411 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
412 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
418 ERR("service is not stopped\n");
423 SERV_free(service->args);
424 service->args = args;
426 service->thread = CreateThread( NULL, 0, service_thread,
430 HeapFree(GetProcessHeap(), 0, args);
431 WriteFile( pipe, &result, sizeof result, &read, NULL );
436 /******************************************************************************
437 * service_send_start_message
439 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
441 DWORD i, len, count, result;
442 service_start_info *ssi;
446 TRACE("%p %p %ld\n", pipe, argv, argc);
448 /* calculate how much space do we need to send the startup info */
450 for (i=0; i<argc; i++)
451 len += strlenW(argv[i])+1;
453 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
454 ssi->cmd = WINESERV_STARTINFO;
457 /* copy service args into a single buffer*/
459 for (i=0; i<argc; i++)
466 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
468 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
470 HeapFree(GetProcessHeap(),0,ssi);
475 /******************************************************************************
476 * service_handle_get_status
478 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
482 return WriteFile(pipe, &service->status,
483 sizeof service->status, &count, NULL);
486 /******************************************************************************
489 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
491 DWORD cmd[2], count = 0;
494 cmd[0] = WINESERV_GETSTATUS;
496 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
497 if (!r || count != sizeof cmd)
499 ERR("service protocol error - failed to write pipe!\n");
502 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
503 if (!r || count != sizeof *status)
504 ERR("service protocol error - failed to read pipe "
505 "r = %d count = %ld/%d!\n", r, count, sizeof *status);
509 /******************************************************************************
510 * service_send_control
512 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
514 DWORD cmd[2], count = 0;
517 cmd[0] = WINESERV_SENDCONTROL;
519 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
520 if (!r || count != sizeof cmd)
522 ERR("service protocol error - failed to write pipe!\n");
525 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
526 if (!r || count != sizeof *result)
527 ERR("service protocol error - failed to read pipe "
528 "r = %d count = %ld/%d!\n", r, count, sizeof *result);
532 /******************************************************************************
533 * service_accepts_control
535 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
537 DWORD a = service->status.dwControlsAccepted;
541 case SERVICE_CONTROL_INTERROGATE:
543 case SERVICE_CONTROL_STOP:
544 if (a&SERVICE_ACCEPT_STOP)
547 case SERVICE_CONTROL_SHUTDOWN:
548 if (a&SERVICE_ACCEPT_SHUTDOWN)
551 case SERVICE_CONTROL_PAUSE:
552 case SERVICE_CONTROL_CONTINUE:
553 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
556 case SERVICE_CONTROL_PARAMCHANGE:
557 if (a&SERVICE_ACCEPT_PARAMCHANGE)
560 case SERVICE_CONTROL_NETBINDADD:
561 case SERVICE_CONTROL_NETBINDREMOVE:
562 case SERVICE_CONTROL_NETBINDENABLE:
563 case SERVICE_CONTROL_NETBINDDISABLE:
564 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
567 if (1) /* (!service->handlerex) */
571 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
572 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
575 case SERVICE_CONTROL_POWEREVENT:
576 if (a&SERVICE_ACCEPT_POWEREVENT)
579 case SERVICE_CONTROL_SESSIONCHANGE:
580 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
587 /******************************************************************************
588 * service_handle_control
590 static BOOL service_handle_control(HANDLE pipe, service_data *service,
593 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
595 TRACE("received control %ld\n", dwControl);
597 if (service_accepts_control(service, dwControl) && service->handler)
599 service->handler(dwControl);
602 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
605 /******************************************************************************
606 * service_reap_thread
608 static DWORD service_reap_thread(service_data *service)
612 if (!service->thread)
614 GetExitCodeThread(service->thread, &exitcode);
615 if (exitcode!=STILL_ACTIVE)
617 CloseHandle(service->thread);
623 /******************************************************************************
624 * service_control_dispatcher
626 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
628 service_data *service = arg;
632 TRACE("%p %s\n", service, debugstr_w(service->name));
634 /* create a pipe to talk to the rest of the world with */
635 name = service_get_pipe_name(service->name);
636 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
637 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
640 /* let the process who started us know we've tried to create a pipe */
641 event = service_get_event_handle(service->name);
645 if (pipe==INVALID_HANDLE_VALUE)
647 ERR("failed to create pipe, error = %ld\n", GetLastError());
651 /* dispatcher loop */
655 DWORD count, req[2] = {0,0};
657 r = ConnectNamedPipe(pipe, NULL);
658 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
660 ERR("pipe connect failed\n");
664 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
665 if (!r || count!=sizeof req)
667 ERR("pipe read failed\n");
671 service_reap_thread(service);
673 /* handle the request */
676 case WINESERV_STARTINFO:
677 service_handle_start(pipe, service, req[1]);
679 case WINESERV_GETSTATUS:
680 service_handle_get_status(pipe, service);
682 case WINESERV_SENDCONTROL:
683 service_handle_control(pipe, service, req[1]);
686 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
689 FlushFileBuffers(pipe);
690 DisconnectNamedPipe(pipe);
697 /******************************************************************************
698 * service_run_threads
700 static BOOL service_run_threads(void)
702 service_data *service;
703 DWORD count = 0, n = 0;
706 EnterCriticalSection( &service_cs );
708 /* count how many services there are */
709 for (service = service_list; service; service = service->next)
712 TRACE("starting %ld pipe listener threads\n", count);
714 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
716 for (n=0, service = service_list; service; service = service->next, n++)
717 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
721 LeaveCriticalSection( &service_cs );
723 /* wait for all the threads to pack up and exit */
724 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
726 HeapFree(GetProcessHeap(), 0, handles);
731 /******************************************************************************
732 * StartServiceCtrlDispatcherA [ADVAPI32.@]
734 * Connects a process containing one or more services to the service control
738 * servent [I] A list of the service names and service procedures
740 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
746 TRACE("%p\n", servent);
748 EnterCriticalSection( &service_cs );
749 while (servent->lpServiceName)
751 LPSTR name = servent->lpServiceName;
753 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
754 sz = len*sizeof(WCHAR) + sizeof *info;
755 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
756 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
757 info->proc.a = servent->lpServiceProc;
758 info->unicode = FALSE;
760 /* insert into the list */
761 info->next = service_list;
766 LeaveCriticalSection( &service_cs );
768 service_run_threads();
773 /******************************************************************************
774 * StartServiceCtrlDispatcherW [ADVAPI32.@]
776 * Connects a process containing one or more services to the service control
780 * servent [I] A list of the service names and service procedures
782 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
788 TRACE("%p\n", servent);
790 EnterCriticalSection( &service_cs );
791 while (servent->lpServiceName)
793 LPWSTR name = servent->lpServiceName;
796 sz = len*sizeof(WCHAR) + sizeof *info;
797 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
798 strcpyW(info->name, name);
799 info->proc.w = servent->lpServiceProc;
800 info->unicode = TRUE;
802 /* insert into the list */
803 info->next = service_list;
808 LeaveCriticalSection( &service_cs );
810 service_run_threads();
815 /******************************************************************************
816 * LockServiceDatabase [ADVAPI32.@]
818 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
822 TRACE("%p\n",hSCManager);
824 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
825 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
829 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
832 TRACE("returning %p\n", ret);
837 /******************************************************************************
838 * UnlockServiceDatabase [ADVAPI32.@]
840 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
842 TRACE("%p\n",ScLock);
844 return CloseHandle( ScLock );
847 /******************************************************************************
848 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
850 SERVICE_STATUS_HANDLE WINAPI
851 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
853 LPWSTR lpServiceNameW;
854 SERVICE_STATUS_HANDLE ret;
856 lpServiceNameW = SERV_dup(lpServiceName);
857 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
858 SERV_free(lpServiceNameW);
862 /******************************************************************************
863 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
869 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
870 LPHANDLER_FUNCTION lpfHandler )
872 service_data *service;
874 EnterCriticalSection( &service_cs );
875 for(service = service_list; service; service = service->next)
876 if(!strcmpW(lpServiceName, service->name))
879 service->handler = lpfHandler;
880 LeaveCriticalSection( &service_cs );
882 return (SERVICE_STATUS_HANDLE)service;
885 /******************************************************************************
886 * SetServiceStatus [ADVAPI32.@]
893 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
895 service_data *service;
898 TRACE("%lx %lx %lx %lx %lx %lx %lx %lx\n", hService,
899 lpStatus->dwServiceType, lpStatus->dwCurrentState,
900 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
901 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
902 lpStatus->dwWaitHint);
904 EnterCriticalSection( &service_cs );
905 for (service = service_list; service; service = service->next)
906 if(service == (service_data*)hService)
910 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
911 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
915 LeaveCriticalSection( &service_cs );
921 /******************************************************************************
922 * OpenSCManagerA [ADVAPI32.@]
924 * Establish a connection to the service control manager and open its database.
927 * lpMachineName [I] Pointer to machine name string
928 * lpDatabaseName [I] Pointer to database name string
929 * dwDesiredAccess [I] Type of access
932 * Success: A Handle to the service control manager database
935 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
936 DWORD dwDesiredAccess )
938 LPWSTR lpMachineNameW, lpDatabaseNameW;
941 lpMachineNameW = SERV_dup(lpMachineName);
942 lpDatabaseNameW = SERV_dup(lpDatabaseName);
943 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
944 SERV_free(lpDatabaseNameW);
945 SERV_free(lpMachineNameW);
949 /******************************************************************************
950 * OpenSCManagerW [ADVAPI32.@]
952 * See OpenSCManagerA.
954 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
955 DWORD dwDesiredAccess )
957 struct sc_manager *manager;
961 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
962 debugstr_w(lpDatabaseName), dwDesiredAccess);
964 if( lpDatabaseName && lpDatabaseName[0] )
966 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
968 /* noop, all right */
970 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
972 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
977 SetLastError( ERROR_INVALID_NAME );
982 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
983 sc_handle_destroy_manager );
987 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
988 if (r!=ERROR_SUCCESS)
991 r = RegOpenKeyExW(hReg, szServiceManagerKey,
992 0, KEY_ALL_ACCESS, &manager->hkey);
994 if (r!=ERROR_SUCCESS)
997 TRACE("returning %p\n", manager);
999 return (SC_HANDLE) &manager->hdr;
1002 sc_handle_free( &manager->hdr );
1006 /******************************************************************************
1007 * ControlService [ADVAPI32.@]
1009 * Send a control code to a service.
1012 * hService [I] Handle of the service control manager database
1013 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1014 * lpServiceStatus [O] Destination for the status of the service, if available
1021 * Unlike M$' implementation, control requests are not serialized and may be
1022 * processed asynchronously.
1024 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1025 LPSERVICE_STATUS lpServiceStatus )
1027 struct sc_service *hsvc;
1031 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1033 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1036 SetLastError( ERROR_INVALID_HANDLE );
1040 ret = QueryServiceStatus(hService, lpServiceStatus);
1043 ERR("failed to query service status\n");
1044 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1048 switch (lpServiceStatus->dwCurrentState)
1050 case SERVICE_STOPPED:
1051 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1053 case SERVICE_START_PENDING:
1054 if (dwControl==SERVICE_CONTROL_STOP)
1057 case SERVICE_STOP_PENDING:
1058 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1062 handle = service_open_pipe(hsvc->name);
1063 if (handle!=INVALID_HANDLE_VALUE)
1065 DWORD result = ERROR_SUCCESS;
1066 ret = service_send_control(handle, dwControl, &result);
1067 CloseHandle(handle);
1068 if (result!=ERROR_SUCCESS)
1070 SetLastError(result);
1078 /******************************************************************************
1079 * CloseServiceHandle [ADVAPI32.@]
1081 * Close a handle to a service or the service control manager database.
1084 * hSCObject [I] Handle to service or service control manager database
1091 CloseServiceHandle( SC_HANDLE hSCObject )
1093 TRACE("%p\n", hSCObject);
1095 sc_handle_free( (struct sc_handle*) hSCObject );
1101 /******************************************************************************
1102 * OpenServiceA [ADVAPI32.@]
1104 * Open a handle to a service.
1107 * hSCManager [I] Handle of the service control manager database
1108 * lpServiceName [I] Name of the service to open
1109 * dwDesiredAccess [I] Access required to the service
1112 * Success: Handle to the service
1115 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1116 DWORD dwDesiredAccess )
1118 LPWSTR lpServiceNameW;
1121 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1123 lpServiceNameW = SERV_dup(lpServiceName);
1124 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1125 SERV_free(lpServiceNameW);
1130 /******************************************************************************
1131 * OpenServiceW [ADVAPI32.@]
1135 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1136 DWORD dwDesiredAccess)
1138 struct sc_manager *hscm;
1139 struct sc_service *hsvc;
1144 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1148 SetLastError(ERROR_INVALID_ADDRESS);
1152 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1155 SetLastError( ERROR_INVALID_HANDLE );
1159 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1160 if (r!=ERROR_SUCCESS)
1162 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1166 len = strlenW(lpServiceName)+1;
1167 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1168 sizeof (struct sc_service) + len*sizeof(WCHAR),
1169 sc_handle_destroy_service );
1172 strcpyW( hsvc->name, lpServiceName );
1175 /* add reference to SCM handle */
1176 hscm->hdr.ref_count++;
1179 TRACE("returning %p\n",hsvc);
1181 return (SC_HANDLE) &hsvc->hdr;
1184 /******************************************************************************
1185 * CreateServiceW [ADVAPI32.@]
1188 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1189 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1190 DWORD dwServiceType, DWORD dwStartType,
1191 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1192 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1193 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1194 LPCWSTR lpPassword )
1196 struct sc_manager *hscm;
1197 struct sc_service *hsvc = NULL;
1201 struct reg_value val[10];
1204 TRACE("%p %s %s\n", hSCManager,
1205 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1207 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1210 SetLastError( ERROR_INVALID_HANDLE );
1214 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1215 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1216 if (r!=ERROR_SUCCESS)
1219 if (dp != REG_CREATED_NEW_KEY)
1221 SetLastError(ERROR_SERVICE_EXISTS);
1226 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1228 service_set_dword( &val[n++], szType, &dwServiceType );
1229 service_set_dword( &val[n++], szStart, &dwStartType );
1230 service_set_dword( &val[n++], szError, &dwErrorControl );
1232 if( lpBinaryPathName )
1233 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1235 if( lpLoadOrderGroup )
1236 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1238 if( lpDependencies )
1239 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1242 FIXME("Don't know how to add a Password for a service.\n");
1244 if( lpServiceStartName )
1245 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1247 r = service_write_values( hKey, val, n );
1248 if( r != ERROR_SUCCESS )
1251 len = strlenW(lpServiceName)+1;
1252 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1253 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1256 lstrcpyW( hsvc->name, lpServiceName );
1259 hscm->hdr.ref_count++;
1261 return (SC_HANDLE) &hsvc->hdr;
1264 RegCloseKey( hKey );
1269 /******************************************************************************
1270 * CreateServiceA [ADVAPI32.@]
1273 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1274 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1275 DWORD dwServiceType, DWORD dwStartType,
1276 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1277 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1278 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1281 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1282 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1285 TRACE("%p %s %s\n", hSCManager,
1286 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1288 lpServiceNameW = SERV_dup( lpServiceName );
1289 lpDisplayNameW = SERV_dup( lpDisplayName );
1290 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1291 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1292 lpDependenciesW = SERV_dupmulti( lpDependencies );
1293 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1294 lpPasswordW = SERV_dup( lpPassword );
1296 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1297 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1298 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1299 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1301 SERV_free( lpServiceNameW );
1302 SERV_free( lpDisplayNameW );
1303 SERV_free( lpBinaryPathNameW );
1304 SERV_free( lpLoadOrderGroupW );
1305 SERV_free( lpDependenciesW );
1306 SERV_free( lpServiceStartNameW );
1307 SERV_free( lpPasswordW );
1313 /******************************************************************************
1314 * DeleteService [ADVAPI32.@]
1316 * Delete a service from the service control manager database.
1319 * hService [I] Handle of the service to delete
1325 BOOL WINAPI DeleteService( SC_HANDLE hService )
1327 struct sc_service *hsvc;
1329 WCHAR valname[MAX_PATH+1];
1334 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1337 SetLastError( ERROR_INVALID_HANDLE );
1343 /* Clean out the values */
1344 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1345 while (rc == ERROR_SUCCESS)
1347 RegDeleteValueW(hKey,valname);
1350 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1356 /* delete the key */
1357 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1363 /******************************************************************************
1364 * StartServiceA [ADVAPI32.@]
1369 * hService [I] Handle of service
1370 * dwNumServiceArgs [I] Number of arguments
1371 * lpServiceArgVectors [I] Address of array of argument strings
1374 * - NT implements this function using an obscure RPC call.
1375 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1376 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1377 * - This will only work for shared address space. How should the service
1378 * args be transferred when address spaces are separated?
1379 * - Can only start one service at a time.
1380 * - Has no concept of privilege.
1386 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1387 LPCSTR *lpServiceArgVectors )
1389 LPWSTR *lpwstr=NULL;
1393 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1395 if (dwNumServiceArgs)
1396 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1397 dwNumServiceArgs*sizeof(LPWSTR) );
1399 for(i=0; i<dwNumServiceArgs; i++)
1400 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1402 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1404 if (dwNumServiceArgs)
1406 for(i=0; i<dwNumServiceArgs; i++)
1407 SERV_free(lpwstr[i]);
1408 HeapFree(GetProcessHeap(), 0, lpwstr);
1414 /******************************************************************************
1415 * service_start_process [INTERNAL]
1417 static DWORD service_start_process(struct sc_service *hsvc)
1419 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1420 PROCESS_INFORMATION pi;
1422 LPWSTR path = NULL, str;
1423 DWORD type, size, ret;
1427 /* read the executable path from memory */
1429 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1430 if (ret!=ERROR_SUCCESS)
1432 str = HeapAlloc(GetProcessHeap(),0,size);
1433 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1434 if (ret==ERROR_SUCCESS)
1436 size = ExpandEnvironmentStringsW(str,NULL,0);
1437 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1438 ExpandEnvironmentStringsW(str,path,size);
1440 HeapFree(GetProcessHeap(),0,str);
1444 /* wait for the process to start and set an event or terminate */
1445 handles[0] = service_get_event_handle( hsvc->name );
1446 ZeroMemory(&si, sizeof(STARTUPINFOW));
1447 si.cb = sizeof(STARTUPINFOW);
1448 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1451 handles[1] = pi.hProcess;
1452 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1453 if(ret != WAIT_OBJECT_0)
1455 SetLastError(ERROR_IO_PENDING);
1459 CloseHandle( pi.hThread );
1460 CloseHandle( pi.hProcess );
1462 CloseHandle( handles[0] );
1463 HeapFree(GetProcessHeap(),0,path);
1467 static BOOL service_wait_for_startup(SC_HANDLE hService)
1470 SERVICE_STATUS status;
1473 TRACE("%p\n", hService);
1475 for (i=0; i<30; i++)
1477 status.dwCurrentState = 0;
1478 r = QueryServiceStatus(hService, &status);
1481 if (status.dwCurrentState == SERVICE_RUNNING)
1483 TRACE("Service started successfully\n");
1492 /******************************************************************************
1493 * StartServiceW [ADVAPI32.@]
1495 * See StartServiceA.
1497 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1498 LPCWSTR *lpServiceArgVectors)
1500 struct sc_service *hsvc;
1503 HANDLE handle = INVALID_HANDLE_VALUE;
1505 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1507 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1510 SetLastError(ERROR_INVALID_HANDLE);
1514 hLock = LockServiceDatabase(hsvc->scm);
1518 handle = service_open_pipe(hsvc->name);
1519 if (handle==INVALID_HANDLE_VALUE)
1521 /* start the service process */
1522 if (service_start_process(hsvc))
1523 handle = service_open_pipe(hsvc->name);
1526 if (handle != INVALID_HANDLE_VALUE)
1528 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1529 CloseHandle(handle);
1533 UnlockServiceDatabase( hLock );
1535 TRACE("returning %d\n", r);
1537 service_wait_for_startup(hService);
1542 /******************************************************************************
1543 * QueryServiceStatus [ADVAPI32.@]
1547 * lpservicestatus []
1550 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1551 LPSERVICE_STATUS lpservicestatus)
1553 struct sc_service *hsvc;
1554 DWORD size, type, val;
1558 TRACE("%p %p\n", hService, lpservicestatus);
1560 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1563 SetLastError( ERROR_INVALID_HANDLE );
1567 pipe = service_open_pipe(hsvc->name);
1568 if (pipe != INVALID_HANDLE_VALUE)
1570 r = service_get_status(pipe, lpservicestatus);
1576 TRACE("Failed to read service status\n");
1578 /* read the service type from the registry */
1580 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1581 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1584 lpservicestatus->dwServiceType = val;
1585 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1586 lpservicestatus->dwControlsAccepted = 0;
1587 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1588 lpservicestatus->dwServiceSpecificExitCode = 0;
1589 lpservicestatus->dwCheckPoint = 0;
1590 lpservicestatus->dwWaitHint = 0;
1595 /******************************************************************************
1596 * QueryServiceStatusEx [ADVAPI32.@]
1598 * Get information about a service.
1601 * hService [I] Handle to service to get information about
1602 * InfoLevel [I] Level of information to get
1603 * lpBuffer [O] Destination for requested information
1604 * cbBufSize [I] Size of lpBuffer in bytes
1605 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1611 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1612 LPBYTE lpBuffer, DWORD cbBufSize,
1613 LPDWORD pcbBytesNeeded)
1616 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1620 /******************************************************************************
1621 * QueryServiceConfigA [ADVAPI32.@]
1624 QueryServiceConfigA( SC_HANDLE hService,
1625 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1626 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1628 static const CHAR szDisplayName[] = "DisplayName";
1629 static const CHAR szType[] = "Type";
1630 static const CHAR szStart[] = "Start";
1631 static const CHAR szError[] = "ErrorControl";
1632 static const CHAR szImagePath[] = "ImagePath";
1633 static const CHAR szGroup[] = "Group";
1634 static const CHAR szDependencies[] = "Dependencies";
1635 struct sc_service *hsvc;
1637 CHAR str_buffer[ MAX_PATH ];
1639 DWORD type, val, sz, total, n;
1642 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1643 cbBufSize, pcbBytesNeeded);
1645 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1648 SetLastError( ERROR_INVALID_HANDLE );
1653 /* calculate the size required first */
1654 total = sizeof (QUERY_SERVICE_CONFIGA);
1656 sz = sizeof(str_buffer);
1657 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1658 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1660 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1661 if( 0 == sz ) return FALSE;
1667 /* FIXME: set last error */
1672 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1673 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1677 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1678 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1682 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1683 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1687 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1688 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1691 *pcbBytesNeeded = total;
1693 /* if there's not enough memory, return an error */
1694 if( total > cbBufSize )
1696 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1700 ZeroMemory( lpServiceConfig, total );
1703 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1704 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1705 lpServiceConfig->dwServiceType = val;
1708 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1709 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1710 lpServiceConfig->dwStartType = val;
1713 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1714 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1715 lpServiceConfig->dwErrorControl = val;
1717 /* now do the strings */
1718 p = (LPBYTE) &lpServiceConfig[1];
1719 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1721 sz = sizeof(str_buffer);
1722 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1723 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1725 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1726 if( 0 == sz || sz > n ) return FALSE;
1728 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1734 /* FIXME: set last error */
1739 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1740 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1742 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1748 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1749 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1751 lpServiceConfig->lpDependencies = (LPSTR) p;
1757 ERR("Buffer overflow!\n");
1759 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1760 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1765 /******************************************************************************
1766 * QueryServiceConfigW [ADVAPI32.@]
1769 QueryServiceConfigW( SC_HANDLE hService,
1770 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1771 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1773 WCHAR str_buffer[ MAX_PATH ];
1775 DWORD type, val, sz, total, n;
1778 struct sc_service *hsvc;
1780 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1781 cbBufSize, pcbBytesNeeded);
1783 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1786 SetLastError( ERROR_INVALID_HANDLE );
1791 /* calculate the size required first */
1792 total = sizeof (QUERY_SERVICE_CONFIGW);
1794 sz = sizeof(str_buffer);
1795 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1796 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1798 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1799 if( 0 == sz ) return FALSE;
1801 total += sizeof(WCHAR) * sz;
1805 /* FIXME: set last error */
1810 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1811 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1815 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1816 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1819 total += sizeof(WCHAR);
1822 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1823 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1827 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1828 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1831 *pcbBytesNeeded = total;
1833 /* if there's not enough memory, return an error */
1834 if( total > cbBufSize )
1836 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1840 ZeroMemory( lpServiceConfig, total );
1843 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1844 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1845 lpServiceConfig->dwServiceType = val;
1848 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1849 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1850 lpServiceConfig->dwStartType = val;
1853 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1854 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1855 lpServiceConfig->dwErrorControl = val;
1857 /* now do the strings */
1858 p = (LPBYTE) &lpServiceConfig[1];
1859 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1861 sz = sizeof(str_buffer);
1862 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1863 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1865 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1866 sz *= sizeof(WCHAR);
1867 if( 0 == sz || sz > n ) return FALSE;
1869 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1875 /* FIXME: set last error */
1880 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1881 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1883 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1889 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1890 lpServiceConfig->lpDependencies = (LPWSTR) p;
1891 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1904 ERR("Buffer overflow!\n");
1906 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1907 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1912 /******************************************************************************
1913 * EnumServicesStatusA [ADVAPI32.@]
1916 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1917 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1918 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1919 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1921 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1922 dwServiceType, dwServiceState, lpServices, cbBufSize,
1923 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1924 SetLastError (ERROR_ACCESS_DENIED);
1928 /******************************************************************************
1929 * EnumServicesStatusW [ADVAPI32.@]
1932 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1933 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1934 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1935 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1937 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1938 dwServiceType, dwServiceState, lpServices, cbBufSize,
1939 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1940 SetLastError (ERROR_ACCESS_DENIED);
1944 /******************************************************************************
1945 * GetServiceKeyNameA [ADVAPI32.@]
1947 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1948 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1950 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1954 /******************************************************************************
1955 * GetServiceKeyNameW [ADVAPI32.@]
1957 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1958 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1960 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1964 /******************************************************************************
1965 * QueryServiceLockStatusA [ADVAPI32.@]
1967 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1968 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1969 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1971 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1976 /******************************************************************************
1977 * QueryServiceLockStatusW [ADVAPI32.@]
1979 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1980 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1981 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1983 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1988 /******************************************************************************
1989 * GetServiceDisplayNameA [ADVAPI32.@]
1991 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1992 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1994 FIXME("%p %s %p %p\n", hSCManager,
1995 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1999 /******************************************************************************
2000 * GetServiceDisplayNameW [ADVAPI32.@]
2002 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2003 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2005 FIXME("%p %s %p %p\n", hSCManager,
2006 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2010 /******************************************************************************
2011 * ChangeServiceConfigW [ADVAPI32.@]
2013 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2014 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2015 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2016 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2018 struct reg_value val[10];
2019 struct sc_service *hsvc;
2020 DWORD r = ERROR_SUCCESS;
2024 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2025 hService, dwServiceType, dwStartType, dwErrorControl,
2026 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2027 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2028 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2030 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2033 SetLastError( ERROR_INVALID_HANDLE );
2038 if( dwServiceType != SERVICE_NO_CHANGE )
2039 service_set_dword( &val[n++], szType, &dwServiceType );
2041 if( dwStartType != SERVICE_NO_CHANGE )
2042 service_set_dword( &val[n++], szStart, &dwStartType );
2044 if( dwErrorControl != SERVICE_NO_CHANGE )
2045 service_set_dword( &val[n++], szError, &dwErrorControl );
2047 if( lpBinaryPathName )
2048 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2050 if( lpLoadOrderGroup )
2051 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2053 if( lpDependencies )
2054 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2057 FIXME("ignoring password\n");
2059 if( lpServiceStartName )
2060 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2062 r = service_write_values( hsvc->hkey, val, n );
2064 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2067 /******************************************************************************
2068 * ChangeServiceConfigA [ADVAPI32.@]
2070 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2071 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2072 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2073 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2075 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2076 LPWSTR wServiceStartName, wPassword, wDisplayName;
2079 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2080 hService, dwServiceType, dwStartType, dwErrorControl,
2081 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2082 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2083 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2085 wBinaryPathName = SERV_dup( lpBinaryPathName );
2086 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2087 wDependencies = SERV_dupmulti( lpDependencies );
2088 wServiceStartName = SERV_dup( lpServiceStartName );
2089 wPassword = SERV_dup( lpPassword );
2090 wDisplayName = SERV_dup( lpDisplayName );
2092 r = ChangeServiceConfigW( hService, dwServiceType,
2093 dwStartType, dwErrorControl, wBinaryPathName,
2094 wLoadOrderGroup, lpdwTagId, wDependencies,
2095 wServiceStartName, wPassword, wDisplayName);
2097 SERV_free( wBinaryPathName );
2098 SERV_free( wLoadOrderGroup );
2099 SERV_free( wDependencies );
2100 SERV_free( wServiceStartName );
2101 SERV_free( wPassword );
2102 SERV_free( wDisplayName );
2107 /******************************************************************************
2108 * ChangeServiceConfig2A [ADVAPI32.@]
2110 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2115 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2117 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2119 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2120 SERVICE_DESCRIPTIONW sdw;
2122 sdw.lpDescription = SERV_dup( sd->lpDescription );
2124 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2126 SERV_free( sdw.lpDescription );
2128 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2130 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2131 SERVICE_FAILURE_ACTIONSW faw;
2133 faw.dwResetPeriod = fa->dwResetPeriod;
2134 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2135 faw.lpCommand = SERV_dup( fa->lpCommand );
2136 faw.cActions = fa->cActions;
2137 faw.lpsaActions = fa->lpsaActions;
2139 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2141 SERV_free( faw.lpRebootMsg );
2142 SERV_free( faw.lpCommand );
2145 SetLastError( ERROR_INVALID_PARAMETER );
2150 /******************************************************************************
2151 * ChangeServiceConfig2W [ADVAPI32.@]
2153 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2157 struct sc_service *hsvc;
2159 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2162 SetLastError( ERROR_INVALID_HANDLE );
2167 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2169 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2170 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2171 if (sd->lpDescription)
2173 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2174 if (sd->lpDescription[0] == 0)
2175 RegDeleteValueW(hKey,szDescription);
2177 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2178 (LPVOID)sd->lpDescription,
2179 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2183 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2187 /******************************************************************************
2188 * QueryServiceObjectSecurity [ADVAPI32.@]
2190 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2191 SECURITY_INFORMATION dwSecurityInformation,
2192 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2193 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2197 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2198 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2200 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2202 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2203 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2204 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2208 /******************************************************************************
2209 * SetServiceObjectSecurity [ADVAPI32.@]
2211 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2212 SECURITY_INFORMATION dwSecurityInformation,
2213 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2215 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2219 /******************************************************************************
2220 * SetServiceBits [ADVAPI32.@]
2222 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2223 DWORD dwServiceBits,
2225 BOOL bUpdateImmediately)
2227 FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2228 bSetBitsOn, bUpdateImmediately);