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, { (DWORD_PTR)(__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;
366 info->proc.w(0, NULL);
368 info->proc.a(0, NULL);
376 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
377 for (argc=0, p=str; *p; p += strlenW(p) + 1)
381 info->proc.w(argc, argv);
382 HeapFree(GetProcessHeap(), 0, argv);
386 LPSTR strA, *argv, p;
389 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
390 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
391 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
393 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
394 for (argc=0, p=strA; *p; p += strlen(p) + 1)
398 info->proc.a(argc, argv);
399 HeapFree(GetProcessHeap(), 0, argv);
400 HeapFree(GetProcessHeap(), 0, strA);
405 /******************************************************************************
406 * service_handle_start
408 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
410 DWORD read = 0, result = 0;
414 TRACE("%p %p %ld\n", pipe, service, count);
416 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
417 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
418 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
420 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
421 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
427 ERR("service is not stopped\n");
432 SERV_free(service->args);
433 service->args = args;
435 service->thread = CreateThread( NULL, 0, service_thread,
439 HeapFree(GetProcessHeap(), 0, args);
440 WriteFile( pipe, &result, sizeof result, &read, NULL );
445 /******************************************************************************
446 * service_send_start_message
448 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
450 DWORD i, len, count, result;
451 service_start_info *ssi;
455 TRACE("%p %p %ld\n", pipe, argv, argc);
457 /* calculate how much space do we need to send the startup info */
459 for (i=0; i<argc; i++)
460 len += strlenW(argv[i])+1;
462 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
463 ssi->cmd = WINESERV_STARTINFO;
466 /* copy service args into a single buffer*/
468 for (i=0; i<argc; i++)
475 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
477 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
479 HeapFree(GetProcessHeap(),0,ssi);
484 /******************************************************************************
485 * service_handle_get_status
487 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
491 return WriteFile(pipe, &service->status,
492 sizeof service->status, &count, NULL);
495 /******************************************************************************
498 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
500 DWORD cmd[2], count = 0;
503 cmd[0] = WINESERV_GETSTATUS;
505 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
506 if (!r || count != sizeof cmd)
508 ERR("service protocol error - failed to write pipe!\n");
511 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
512 if (!r || count != sizeof *status)
513 ERR("service protocol error - failed to read pipe "
514 "r = %d count = %ld/%d!\n", r, count, sizeof *status);
518 /******************************************************************************
519 * service_send_control
521 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
523 DWORD cmd[2], count = 0;
526 cmd[0] = WINESERV_SENDCONTROL;
528 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
529 if (!r || count != sizeof cmd)
531 ERR("service protocol error - failed to write pipe!\n");
534 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
535 if (!r || count != sizeof *result)
536 ERR("service protocol error - failed to read pipe "
537 "r = %d count = %ld/%d!\n", r, count, sizeof *result);
541 /******************************************************************************
542 * service_accepts_control
544 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
546 DWORD a = service->status.dwControlsAccepted;
550 case SERVICE_CONTROL_INTERROGATE:
552 case SERVICE_CONTROL_STOP:
553 if (a&SERVICE_ACCEPT_STOP)
556 case SERVICE_CONTROL_SHUTDOWN:
557 if (a&SERVICE_ACCEPT_SHUTDOWN)
560 case SERVICE_CONTROL_PAUSE:
561 case SERVICE_CONTROL_CONTINUE:
562 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
565 case SERVICE_CONTROL_PARAMCHANGE:
566 if (a&SERVICE_ACCEPT_PARAMCHANGE)
569 case SERVICE_CONTROL_NETBINDADD:
570 case SERVICE_CONTROL_NETBINDREMOVE:
571 case SERVICE_CONTROL_NETBINDENABLE:
572 case SERVICE_CONTROL_NETBINDDISABLE:
573 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
576 if (1) /* (!service->handlerex) */
580 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
581 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
584 case SERVICE_CONTROL_POWEREVENT:
585 if (a&SERVICE_ACCEPT_POWEREVENT)
588 case SERVICE_CONTROL_SESSIONCHANGE:
589 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
596 /******************************************************************************
597 * service_handle_control
599 static BOOL service_handle_control(HANDLE pipe, service_data *service,
602 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
604 TRACE("received control %ld\n", dwControl);
606 if (service_accepts_control(service, dwControl) && service->handler)
608 service->handler(dwControl);
611 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
614 /******************************************************************************
615 * service_reap_thread
617 static DWORD service_reap_thread(service_data *service)
621 if (!service->thread)
623 GetExitCodeThread(service->thread, &exitcode);
624 if (exitcode!=STILL_ACTIVE)
626 CloseHandle(service->thread);
632 /******************************************************************************
633 * service_control_dispatcher
635 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
637 service_data *service = arg;
641 TRACE("%p %s\n", service, debugstr_w(service->name));
643 /* create a pipe to talk to the rest of the world with */
644 name = service_get_pipe_name(service->name);
645 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
646 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
649 /* let the process who started us know we've tried to create a pipe */
650 event = service_get_event_handle(service->name);
654 if (pipe==INVALID_HANDLE_VALUE)
656 ERR("failed to create pipe for %s, error = %ld\n",
657 debugstr_w(service->name), GetLastError());
661 /* dispatcher loop */
665 DWORD count, req[2] = {0,0};
667 r = ConnectNamedPipe(pipe, NULL);
668 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
670 ERR("pipe connect failed\n");
674 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
675 if (!r || count!=sizeof req)
677 ERR("pipe read failed\n");
681 service_reap_thread(service);
683 /* handle the request */
686 case WINESERV_STARTINFO:
687 service_handle_start(pipe, service, req[1]);
689 case WINESERV_GETSTATUS:
690 service_handle_get_status(pipe, service);
692 case WINESERV_SENDCONTROL:
693 service_handle_control(pipe, service, req[1]);
696 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
699 FlushFileBuffers(pipe);
700 DisconnectNamedPipe(pipe);
707 /******************************************************************************
708 * service_run_threads
710 static BOOL service_run_threads(void)
712 service_data *service;
713 DWORD count = 0, n = 0;
716 EnterCriticalSection( &service_cs );
718 /* count how many services there are */
719 for (service = service_list; service; service = service->next)
722 TRACE("starting %ld pipe listener threads\n", count);
724 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
726 for (n=0, service = service_list; service; service = service->next, n++)
727 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
731 LeaveCriticalSection( &service_cs );
733 /* wait for all the threads to pack up and exit */
734 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
736 HeapFree(GetProcessHeap(), 0, handles);
741 /******************************************************************************
742 * StartServiceCtrlDispatcherA [ADVAPI32.@]
744 * See StartServiceCtrlDispatcherW.
746 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
752 TRACE("%p\n", servent);
754 EnterCriticalSection( &service_cs );
755 while (servent->lpServiceName)
757 LPSTR name = servent->lpServiceName;
759 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
760 sz = len*sizeof(WCHAR) + sizeof *info;
761 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
762 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
763 info->proc.a = servent->lpServiceProc;
764 info->unicode = FALSE;
766 /* insert into the list */
767 info->next = service_list;
772 LeaveCriticalSection( &service_cs );
774 service_run_threads();
779 /******************************************************************************
780 * StartServiceCtrlDispatcherW [ADVAPI32.@]
782 * Connects a process containing one or more services to the service control
786 * servent [I] A list of the service names and service procedures
792 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
798 TRACE("%p\n", servent);
800 EnterCriticalSection( &service_cs );
801 while (servent->lpServiceName)
803 LPWSTR name = servent->lpServiceName;
806 sz = len*sizeof(WCHAR) + sizeof *info;
807 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
808 strcpyW(info->name, name);
809 info->proc.w = servent->lpServiceProc;
810 info->unicode = TRUE;
812 /* insert into the list */
813 info->next = service_list;
818 LeaveCriticalSection( &service_cs );
820 service_run_threads();
825 /******************************************************************************
826 * LockServiceDatabase [ADVAPI32.@]
828 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
832 TRACE("%p\n",hSCManager);
834 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
835 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
839 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
842 TRACE("returning %p\n", ret);
847 /******************************************************************************
848 * UnlockServiceDatabase [ADVAPI32.@]
850 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
852 TRACE("%p\n",ScLock);
854 return CloseHandle( ScLock );
857 /******************************************************************************
858 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
860 SERVICE_STATUS_HANDLE WINAPI
861 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
863 LPWSTR lpServiceNameW;
864 SERVICE_STATUS_HANDLE ret;
866 lpServiceNameW = SERV_dup(lpServiceName);
867 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
868 SERV_free(lpServiceNameW);
872 /******************************************************************************
873 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
879 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
880 LPHANDLER_FUNCTION lpfHandler )
882 service_data *service;
884 EnterCriticalSection( &service_cs );
885 for(service = service_list; service; service = service->next)
886 if(!strcmpW(lpServiceName, service->name))
889 service->handler = lpfHandler;
890 LeaveCriticalSection( &service_cs );
892 return (SERVICE_STATUS_HANDLE)service;
895 /******************************************************************************
896 * SetServiceStatus [ADVAPI32.@]
903 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
905 service_data *service;
908 TRACE("%p %lx %lx %lx %lx %lx %lx %lx\n", hService,
909 lpStatus->dwServiceType, lpStatus->dwCurrentState,
910 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
911 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
912 lpStatus->dwWaitHint);
914 EnterCriticalSection( &service_cs );
915 for (service = service_list; service; service = service->next)
916 if(service == (service_data*)hService)
920 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
921 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
925 LeaveCriticalSection( &service_cs );
931 /******************************************************************************
932 * OpenSCManagerA [ADVAPI32.@]
934 * Establish a connection to the service control manager and open its database.
937 * lpMachineName [I] Pointer to machine name string
938 * lpDatabaseName [I] Pointer to database name string
939 * dwDesiredAccess [I] Type of access
942 * Success: A Handle to the service control manager database
945 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
946 DWORD dwDesiredAccess )
948 LPWSTR lpMachineNameW, lpDatabaseNameW;
951 lpMachineNameW = SERV_dup(lpMachineName);
952 lpDatabaseNameW = SERV_dup(lpDatabaseName);
953 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
954 SERV_free(lpDatabaseNameW);
955 SERV_free(lpMachineNameW);
959 /******************************************************************************
960 * OpenSCManagerW [ADVAPI32.@]
962 * See OpenSCManagerA.
964 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
965 DWORD dwDesiredAccess )
967 struct sc_manager *manager;
971 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
972 debugstr_w(lpDatabaseName), dwDesiredAccess);
974 if( lpDatabaseName && lpDatabaseName[0] )
976 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
978 /* noop, all right */
980 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
982 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
987 SetLastError( ERROR_INVALID_NAME );
992 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
993 sc_handle_destroy_manager );
997 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
998 if (r!=ERROR_SUCCESS)
1001 r = RegOpenKeyExW(hReg, szServiceManagerKey,
1002 0, KEY_ALL_ACCESS, &manager->hkey);
1003 RegCloseKey( hReg );
1004 if (r!=ERROR_SUCCESS)
1007 TRACE("returning %p\n", manager);
1009 return (SC_HANDLE) &manager->hdr;
1012 sc_handle_free( &manager->hdr );
1017 /******************************************************************************
1018 * ControlService [ADVAPI32.@]
1020 * Send a control code to a service.
1023 * hService [I] Handle of the service control manager database
1024 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1025 * lpServiceStatus [O] Destination for the status of the service, if available
1032 * Unlike M$' implementation, control requests are not serialized and may be
1033 * processed asynchronously.
1035 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1036 LPSERVICE_STATUS lpServiceStatus )
1038 struct sc_service *hsvc;
1042 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1044 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1047 SetLastError( ERROR_INVALID_HANDLE );
1051 ret = QueryServiceStatus(hService, lpServiceStatus);
1054 ERR("failed to query service status\n");
1055 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1059 switch (lpServiceStatus->dwCurrentState)
1061 case SERVICE_STOPPED:
1062 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1064 case SERVICE_START_PENDING:
1065 if (dwControl==SERVICE_CONTROL_STOP)
1068 case SERVICE_STOP_PENDING:
1069 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1073 handle = service_open_pipe(hsvc->name);
1074 if (handle!=INVALID_HANDLE_VALUE)
1076 DWORD result = ERROR_SUCCESS;
1077 ret = service_send_control(handle, dwControl, &result);
1078 CloseHandle(handle);
1079 if (result!=ERROR_SUCCESS)
1081 SetLastError(result);
1089 /******************************************************************************
1090 * CloseServiceHandle [ADVAPI32.@]
1092 * Close a handle to a service or the service control manager database.
1095 * hSCObject [I] Handle to service or service control manager database
1102 CloseServiceHandle( SC_HANDLE hSCObject )
1104 TRACE("%p\n", hSCObject);
1106 sc_handle_free( (struct sc_handle*) hSCObject );
1112 /******************************************************************************
1113 * OpenServiceA [ADVAPI32.@]
1115 * Open a handle to a service.
1118 * hSCManager [I] Handle of the service control manager database
1119 * lpServiceName [I] Name of the service to open
1120 * dwDesiredAccess [I] Access required to the service
1123 * Success: Handle to the service
1126 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1127 DWORD dwDesiredAccess )
1129 LPWSTR lpServiceNameW;
1132 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1134 lpServiceNameW = SERV_dup(lpServiceName);
1135 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1136 SERV_free(lpServiceNameW);
1141 /******************************************************************************
1142 * OpenServiceW [ADVAPI32.@]
1146 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1147 DWORD dwDesiredAccess)
1149 struct sc_manager *hscm;
1150 struct sc_service *hsvc;
1155 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1159 SetLastError(ERROR_INVALID_ADDRESS);
1163 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1166 SetLastError( ERROR_INVALID_HANDLE );
1170 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1171 if (r!=ERROR_SUCCESS)
1173 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1177 len = strlenW(lpServiceName)+1;
1178 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1179 sizeof (struct sc_service) + len*sizeof(WCHAR),
1180 sc_handle_destroy_service );
1183 strcpyW( hsvc->name, lpServiceName );
1186 /* add reference to SCM handle */
1187 hscm->hdr.ref_count++;
1190 TRACE("returning %p\n",hsvc);
1192 return (SC_HANDLE) &hsvc->hdr;
1195 /******************************************************************************
1196 * CreateServiceW [ADVAPI32.@]
1199 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1200 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1201 DWORD dwServiceType, DWORD dwStartType,
1202 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1203 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1204 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1205 LPCWSTR lpPassword )
1207 struct sc_manager *hscm;
1208 struct sc_service *hsvc = NULL;
1212 struct reg_value val[10];
1215 TRACE("%p %s %s\n", hSCManager,
1216 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1218 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1221 SetLastError( ERROR_INVALID_HANDLE );
1225 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1226 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1227 if (r!=ERROR_SUCCESS)
1230 if (dp != REG_CREATED_NEW_KEY)
1232 SetLastError(ERROR_SERVICE_EXISTS);
1237 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1239 service_set_dword( &val[n++], szType, &dwServiceType );
1240 service_set_dword( &val[n++], szStart, &dwStartType );
1241 service_set_dword( &val[n++], szError, &dwErrorControl );
1243 if( lpBinaryPathName )
1244 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1246 if( lpLoadOrderGroup )
1247 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1249 if( lpDependencies )
1250 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1253 FIXME("Don't know how to add a Password for a service.\n");
1255 if( lpServiceStartName )
1256 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1258 r = service_write_values( hKey, val, n );
1259 if( r != ERROR_SUCCESS )
1262 len = strlenW(lpServiceName)+1;
1263 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1264 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1267 lstrcpyW( hsvc->name, lpServiceName );
1270 hscm->hdr.ref_count++;
1272 return (SC_HANDLE) &hsvc->hdr;
1275 RegCloseKey( hKey );
1280 /******************************************************************************
1281 * CreateServiceA [ADVAPI32.@]
1284 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1285 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1286 DWORD dwServiceType, DWORD dwStartType,
1287 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1288 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1289 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1292 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1293 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1296 TRACE("%p %s %s\n", hSCManager,
1297 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1299 lpServiceNameW = SERV_dup( lpServiceName );
1300 lpDisplayNameW = SERV_dup( lpDisplayName );
1301 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1302 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1303 lpDependenciesW = SERV_dupmulti( lpDependencies );
1304 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1305 lpPasswordW = SERV_dup( lpPassword );
1307 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1308 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1309 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1310 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1312 SERV_free( lpServiceNameW );
1313 SERV_free( lpDisplayNameW );
1314 SERV_free( lpBinaryPathNameW );
1315 SERV_free( lpLoadOrderGroupW );
1316 SERV_free( lpDependenciesW );
1317 SERV_free( lpServiceStartNameW );
1318 SERV_free( lpPasswordW );
1324 /******************************************************************************
1325 * DeleteService [ADVAPI32.@]
1327 * Delete a service from the service control manager database.
1330 * hService [I] Handle of the service to delete
1336 BOOL WINAPI DeleteService( SC_HANDLE hService )
1338 struct sc_service *hsvc;
1340 WCHAR valname[MAX_PATH+1];
1345 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1348 SetLastError( ERROR_INVALID_HANDLE );
1354 /* Clean out the values */
1355 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1356 while (rc == ERROR_SUCCESS)
1358 RegDeleteValueW(hKey,valname);
1361 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1367 /* delete the key */
1368 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1374 /******************************************************************************
1375 * StartServiceA [ADVAPI32.@]
1380 * hService [I] Handle of service
1381 * dwNumServiceArgs [I] Number of arguments
1382 * lpServiceArgVectors [I] Address of array of argument strings
1385 * - NT implements this function using an obscure RPC call.
1386 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1387 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1388 * - This will only work for shared address space. How should the service
1389 * args be transferred when address spaces are separated?
1390 * - Can only start one service at a time.
1391 * - Has no concept of privilege.
1397 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1398 LPCSTR *lpServiceArgVectors )
1400 LPWSTR *lpwstr=NULL;
1404 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1406 if (dwNumServiceArgs)
1407 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1408 dwNumServiceArgs*sizeof(LPWSTR) );
1410 for(i=0; i<dwNumServiceArgs; i++)
1411 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1413 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1415 if (dwNumServiceArgs)
1417 for(i=0; i<dwNumServiceArgs; i++)
1418 SERV_free(lpwstr[i]);
1419 HeapFree(GetProcessHeap(), 0, lpwstr);
1425 /******************************************************************************
1426 * service_start_process [INTERNAL]
1428 static DWORD service_start_process(struct sc_service *hsvc)
1430 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1431 PROCESS_INFORMATION pi;
1433 LPWSTR path = NULL, str;
1434 DWORD type, size, ret;
1438 /* read the executable path from memory */
1440 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1441 if (ret!=ERROR_SUCCESS)
1443 str = HeapAlloc(GetProcessHeap(),0,size);
1444 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1445 if (ret==ERROR_SUCCESS)
1447 size = ExpandEnvironmentStringsW(str,NULL,0);
1448 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1449 ExpandEnvironmentStringsW(str,path,size);
1451 HeapFree(GetProcessHeap(),0,str);
1455 /* wait for the process to start and set an event or terminate */
1456 handles[0] = service_get_event_handle( hsvc->name );
1457 ZeroMemory(&si, sizeof(STARTUPINFOW));
1458 si.cb = sizeof(STARTUPINFOW);
1459 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1462 handles[1] = pi.hProcess;
1463 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1464 if(ret != WAIT_OBJECT_0)
1466 SetLastError(ERROR_IO_PENDING);
1470 CloseHandle( pi.hThread );
1471 CloseHandle( pi.hProcess );
1473 CloseHandle( handles[0] );
1474 HeapFree(GetProcessHeap(),0,path);
1478 static BOOL service_wait_for_startup(SC_HANDLE hService)
1481 SERVICE_STATUS status;
1484 TRACE("%p\n", hService);
1486 for (i=0; i<30; i++)
1488 status.dwCurrentState = 0;
1489 r = QueryServiceStatus(hService, &status);
1492 if (status.dwCurrentState == SERVICE_RUNNING)
1494 TRACE("Service started successfully\n");
1503 /******************************************************************************
1504 * StartServiceW [ADVAPI32.@]
1506 * See StartServiceA.
1508 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1509 LPCWSTR *lpServiceArgVectors)
1511 struct sc_service *hsvc;
1514 HANDLE handle = INVALID_HANDLE_VALUE;
1516 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1518 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1521 SetLastError(ERROR_INVALID_HANDLE);
1525 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1529 handle = service_open_pipe(hsvc->name);
1530 if (handle==INVALID_HANDLE_VALUE)
1532 /* start the service process */
1533 if (service_start_process(hsvc))
1534 handle = service_open_pipe(hsvc->name);
1537 if (handle != INVALID_HANDLE_VALUE)
1539 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1540 CloseHandle(handle);
1544 UnlockServiceDatabase( hLock );
1546 TRACE("returning %d\n", r);
1549 service_wait_for_startup(hService);
1554 /******************************************************************************
1555 * QueryServiceStatus [ADVAPI32.@]
1559 * lpservicestatus []
1562 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1563 LPSERVICE_STATUS lpservicestatus)
1565 struct sc_service *hsvc;
1566 DWORD size, type, val;
1570 TRACE("%p %p\n", hService, lpservicestatus);
1572 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1575 SetLastError( ERROR_INVALID_HANDLE );
1579 pipe = service_open_pipe(hsvc->name);
1580 if (pipe != INVALID_HANDLE_VALUE)
1582 r = service_get_status(pipe, lpservicestatus);
1588 TRACE("Failed to read service status\n");
1590 /* read the service type from the registry */
1592 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1593 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1596 lpservicestatus->dwServiceType = val;
1597 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1598 lpservicestatus->dwControlsAccepted = 0;
1599 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1600 lpservicestatus->dwServiceSpecificExitCode = 0;
1601 lpservicestatus->dwCheckPoint = 0;
1602 lpservicestatus->dwWaitHint = 0;
1607 /******************************************************************************
1608 * QueryServiceStatusEx [ADVAPI32.@]
1610 * Get information about a service.
1613 * hService [I] Handle to service to get information about
1614 * InfoLevel [I] Level of information to get
1615 * lpBuffer [O] Destination for requested information
1616 * cbBufSize [I] Size of lpBuffer in bytes
1617 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1623 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1624 LPBYTE lpBuffer, DWORD cbBufSize,
1625 LPDWORD pcbBytesNeeded)
1628 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1632 /******************************************************************************
1633 * QueryServiceConfigA [ADVAPI32.@]
1636 QueryServiceConfigA( SC_HANDLE hService,
1637 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1638 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1640 static const CHAR szDisplayName[] = "DisplayName";
1641 static const CHAR szType[] = "Type";
1642 static const CHAR szStart[] = "Start";
1643 static const CHAR szError[] = "ErrorControl";
1644 static const CHAR szImagePath[] = "ImagePath";
1645 static const CHAR szGroup[] = "Group";
1646 static const CHAR szDependencies[] = "Dependencies";
1647 struct sc_service *hsvc;
1649 CHAR str_buffer[ MAX_PATH ];
1651 DWORD type, val, sz, total, n;
1654 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1655 cbBufSize, pcbBytesNeeded);
1657 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1660 SetLastError( ERROR_INVALID_HANDLE );
1665 /* calculate the size required first */
1666 total = sizeof (QUERY_SERVICE_CONFIGA);
1668 sz = sizeof(str_buffer);
1669 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1670 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1672 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1673 if( 0 == sz ) return FALSE;
1679 /* FIXME: set last error */
1684 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1685 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1689 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1690 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1694 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1695 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1699 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1700 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1703 *pcbBytesNeeded = total;
1705 /* if there's not enough memory, return an error */
1706 if( total > cbBufSize )
1708 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1712 ZeroMemory( lpServiceConfig, total );
1715 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1716 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1717 lpServiceConfig->dwServiceType = val;
1720 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1721 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1722 lpServiceConfig->dwStartType = val;
1725 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1726 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1727 lpServiceConfig->dwErrorControl = val;
1729 /* now do the strings */
1730 p = (LPSTR) &lpServiceConfig[1];
1731 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1733 sz = sizeof(str_buffer);
1734 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1735 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1737 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1738 if( 0 == sz || sz > n ) return FALSE;
1740 lpServiceConfig->lpBinaryPathName = p;
1746 /* FIXME: set last error */
1751 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1752 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1754 lpServiceConfig->lpLoadOrderGroup = p;
1760 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1761 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1763 lpServiceConfig->lpDependencies = p;
1769 ERR("Buffer overflow!\n");
1771 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1772 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1777 /******************************************************************************
1778 * QueryServiceConfigW [ADVAPI32.@]
1781 QueryServiceConfigW( SC_HANDLE hService,
1782 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1783 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1785 WCHAR str_buffer[ MAX_PATH ];
1787 DWORD type, val, sz, total, n;
1790 struct sc_service *hsvc;
1792 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1793 cbBufSize, pcbBytesNeeded);
1795 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1798 SetLastError( ERROR_INVALID_HANDLE );
1803 /* calculate the size required first */
1804 total = sizeof (QUERY_SERVICE_CONFIGW);
1806 sz = sizeof(str_buffer);
1807 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1808 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1810 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1811 if( 0 == sz ) return FALSE;
1813 total += sizeof(WCHAR) * sz;
1817 /* FIXME: set last error */
1822 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1823 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1827 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1828 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1831 total += sizeof(WCHAR);
1834 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1835 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1839 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1840 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1843 *pcbBytesNeeded = total;
1845 /* if there's not enough memory, return an error */
1846 if( total > cbBufSize )
1848 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1852 ZeroMemory( lpServiceConfig, total );
1855 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1856 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1857 lpServiceConfig->dwServiceType = val;
1860 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1861 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1862 lpServiceConfig->dwStartType = val;
1865 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1866 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1867 lpServiceConfig->dwErrorControl = val;
1869 /* now do the strings */
1870 p = (LPBYTE) &lpServiceConfig[1];
1871 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1873 sz = sizeof(str_buffer);
1874 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1875 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1877 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1878 sz *= sizeof(WCHAR);
1879 if( 0 == sz || sz > n ) return FALSE;
1881 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1887 /* FIXME: set last error */
1892 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1893 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1895 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1901 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1902 lpServiceConfig->lpDependencies = (LPWSTR) p;
1903 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1916 ERR("Buffer overflow!\n");
1918 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1919 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1924 /******************************************************************************
1925 * EnumServicesStatusA [ADVAPI32.@]
1928 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1929 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1930 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1931 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1933 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1934 dwServiceType, dwServiceState, lpServices, cbBufSize,
1935 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1936 SetLastError (ERROR_ACCESS_DENIED);
1940 /******************************************************************************
1941 * EnumServicesStatusW [ADVAPI32.@]
1944 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1945 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1946 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1947 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1949 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1950 dwServiceType, dwServiceState, lpServices, cbBufSize,
1951 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1952 SetLastError (ERROR_ACCESS_DENIED);
1956 /******************************************************************************
1957 * GetServiceKeyNameA [ADVAPI32.@]
1959 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1960 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1962 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1966 /******************************************************************************
1967 * GetServiceKeyNameW [ADVAPI32.@]
1969 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1970 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1972 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1976 /******************************************************************************
1977 * QueryServiceLockStatusA [ADVAPI32.@]
1979 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1980 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1981 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1983 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1988 /******************************************************************************
1989 * QueryServiceLockStatusW [ADVAPI32.@]
1991 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1992 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1993 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1995 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2000 /******************************************************************************
2001 * GetServiceDisplayNameA [ADVAPI32.@]
2003 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2004 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2006 FIXME("%p %s %p %p\n", hSCManager,
2007 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2011 /******************************************************************************
2012 * GetServiceDisplayNameW [ADVAPI32.@]
2014 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2015 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2017 FIXME("%p %s %p %p\n", hSCManager,
2018 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2022 /******************************************************************************
2023 * ChangeServiceConfigW [ADVAPI32.@]
2025 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2026 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2027 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2028 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2030 struct reg_value val[10];
2031 struct sc_service *hsvc;
2032 DWORD r = ERROR_SUCCESS;
2036 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2037 hService, dwServiceType, dwStartType, dwErrorControl,
2038 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2039 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2040 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2042 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2045 SetLastError( ERROR_INVALID_HANDLE );
2050 if( dwServiceType != SERVICE_NO_CHANGE )
2051 service_set_dword( &val[n++], szType, &dwServiceType );
2053 if( dwStartType != SERVICE_NO_CHANGE )
2054 service_set_dword( &val[n++], szStart, &dwStartType );
2056 if( dwErrorControl != SERVICE_NO_CHANGE )
2057 service_set_dword( &val[n++], szError, &dwErrorControl );
2059 if( lpBinaryPathName )
2060 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2062 if( lpLoadOrderGroup )
2063 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2065 if( lpDependencies )
2066 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2069 FIXME("ignoring password\n");
2071 if( lpServiceStartName )
2072 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2074 r = service_write_values( hsvc->hkey, val, n );
2076 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2079 /******************************************************************************
2080 * ChangeServiceConfigA [ADVAPI32.@]
2082 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2083 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2084 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2085 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2087 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2088 LPWSTR wServiceStartName, wPassword, wDisplayName;
2091 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2092 hService, dwServiceType, dwStartType, dwErrorControl,
2093 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2094 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2095 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2097 wBinaryPathName = SERV_dup( lpBinaryPathName );
2098 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2099 wDependencies = SERV_dupmulti( lpDependencies );
2100 wServiceStartName = SERV_dup( lpServiceStartName );
2101 wPassword = SERV_dup( lpPassword );
2102 wDisplayName = SERV_dup( lpDisplayName );
2104 r = ChangeServiceConfigW( hService, dwServiceType,
2105 dwStartType, dwErrorControl, wBinaryPathName,
2106 wLoadOrderGroup, lpdwTagId, wDependencies,
2107 wServiceStartName, wPassword, wDisplayName);
2109 SERV_free( wBinaryPathName );
2110 SERV_free( wLoadOrderGroup );
2111 SERV_free( wDependencies );
2112 SERV_free( wServiceStartName );
2113 SERV_free( wPassword );
2114 SERV_free( wDisplayName );
2119 /******************************************************************************
2120 * ChangeServiceConfig2A [ADVAPI32.@]
2122 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2127 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2129 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2131 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2132 SERVICE_DESCRIPTIONW sdw;
2134 sdw.lpDescription = SERV_dup( sd->lpDescription );
2136 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2138 SERV_free( sdw.lpDescription );
2140 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2142 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2143 SERVICE_FAILURE_ACTIONSW faw;
2145 faw.dwResetPeriod = fa->dwResetPeriod;
2146 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2147 faw.lpCommand = SERV_dup( fa->lpCommand );
2148 faw.cActions = fa->cActions;
2149 faw.lpsaActions = fa->lpsaActions;
2151 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2153 SERV_free( faw.lpRebootMsg );
2154 SERV_free( faw.lpCommand );
2157 SetLastError( ERROR_INVALID_PARAMETER );
2162 /******************************************************************************
2163 * ChangeServiceConfig2W [ADVAPI32.@]
2165 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2169 struct sc_service *hsvc;
2171 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2174 SetLastError( ERROR_INVALID_HANDLE );
2179 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2181 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2182 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2183 if (sd->lpDescription)
2185 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2186 if (sd->lpDescription[0] == 0)
2187 RegDeleteValueW(hKey,szDescription);
2189 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2190 (LPVOID)sd->lpDescription,
2191 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2195 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2199 /******************************************************************************
2200 * QueryServiceObjectSecurity [ADVAPI32.@]
2202 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2203 SECURITY_INFORMATION dwSecurityInformation,
2204 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2205 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2209 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2210 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2212 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2214 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2215 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2216 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2220 /******************************************************************************
2221 * SetServiceObjectSecurity [ADVAPI32.@]
2223 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2224 SECURITY_INFORMATION dwSecurityInformation,
2225 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2227 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2231 /******************************************************************************
2232 * SetServiceBits [ADVAPI32.@]
2234 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2235 DWORD dwServiceBits,
2237 BOOL bUpdateImmediately)
2239 FIXME("%p %08lx %x %x\n", hServiceStatus, dwServiceBits,
2240 bSetBitsOn, bUpdateImmediately);
2244 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2245 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2247 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2251 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2252 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2254 FIXME("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);