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"
36 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
38 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
39 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
40 'S','e','r','v','i','c','e','s','\\',0 };
41 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
44 typedef struct service_start_info_t
51 #define WINESERV_STARTINFO 1
52 #define WINESERV_GETSTATUS 2
53 #define WINESERV_SENDCONTROL 3
55 typedef struct service_data_t
57 struct service_data_t *next;
58 LPHANDLER_FUNCTION handler;
59 SERVICE_STATUS status;
63 LPSERVICE_MAIN_FUNCTIONA a;
64 LPSERVICE_MAIN_FUNCTIONW w;
70 static CRITICAL_SECTION service_cs;
71 static CRITICAL_SECTION_DEBUG service_cs_debug =
74 { &service_cs_debug.ProcessLocksList,
75 &service_cs_debug.ProcessLocksList },
76 0, 0, { 0, (DWORD)(__FILE__ ": service_cs") }
78 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
80 service_data *service_list;
82 /******************************************************************************
86 #define MAX_SERVICE_NAME 256
88 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
91 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
97 sc_handle_destructor destroy;
100 struct sc_manager /* service control manager handle */
102 struct sc_handle hdr;
103 HKEY hkey; /* handle to services database in the registry */
106 struct sc_service /* service handle */
108 struct sc_handle hdr;
109 HKEY hkey; /* handle to service entry in the registry (under hkey) */
110 struct sc_manager *scm; /* pointer to SCM handle */
114 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
115 sc_handle_destructor destroy)
117 struct sc_handle *hdr;
119 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
124 hdr->destroy = destroy;
126 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
130 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
132 struct sc_handle *hdr = (struct sc_handle *) handle;
136 if (hdr->htype != htype)
141 static void sc_handle_free(struct sc_handle* hdr)
145 if (--hdr->ref_count)
148 HeapFree(GetProcessHeap(), 0, hdr);
151 static void sc_handle_destroy_manager(struct sc_handle *handle)
153 struct sc_manager *mgr = (struct sc_manager*) handle;
155 TRACE("destroying SC Manager %p\n", mgr);
157 RegCloseKey(mgr->hkey);
160 static void sc_handle_destroy_service(struct sc_handle *handle)
162 struct sc_service *svc = (struct sc_service*) handle;
164 TRACE("destroying service %p\n", svc);
166 RegCloseKey(svc->hkey);
168 sc_handle_free(&svc->scm->hdr);
172 /******************************************************************************
173 * String management functions
175 static inline LPWSTR SERV_dup( LPCSTR str )
182 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
183 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
184 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
188 static inline LPWSTR SERV_dupmulti(LPCSTR str)
196 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
197 n += (strlen( &str[n] ) + 1);
202 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
203 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
207 static inline VOID SERV_free( LPWSTR wstr )
209 HeapFree( GetProcessHeap(), 0, wstr );
212 /******************************************************************************
213 * registry access functions and data
215 static const WCHAR szDisplayName[] = {
216 'D','i','s','p','l','a','y','N','a','m','e', 0 };
217 static const WCHAR szType[] = {'T','y','p','e',0};
218 static const WCHAR szStart[] = {'S','t','a','r','t',0};
219 static const WCHAR szError[] = {
220 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
221 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
222 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
223 static const WCHAR szDependencies[] = {
224 'D','e','p','e','n','d','e','n','c','i','e','s',0};
225 static const WCHAR szDependOnService[] = {
226 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
235 static inline void service_set_value( struct reg_value *val,
236 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
244 static inline void service_set_dword( struct reg_value *val,
245 LPCWSTR name, DWORD *data )
247 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
250 static inline void service_set_string( struct reg_value *val,
251 LPCWSTR name, LPCWSTR string )
253 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
254 service_set_value( val, REG_SZ, name, string, len );
257 static inline void service_set_multi_string( struct reg_value *val,
258 LPCWSTR name, LPCWSTR string )
262 /* determine the length of a double null terminated multi string */
264 len += (lstrlenW( &string[ len ] )+1);
265 } while ( string[ len++ ] );
267 len *= sizeof (WCHAR);
268 service_set_value( val, REG_MULTI_SZ, name, string, len );
271 static inline LONG service_write_values( HKEY hKey,
272 struct reg_value *val, int n )
274 LONG r = ERROR_SUCCESS;
279 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
280 (const BYTE*)val[i].data, val[i].size );
281 if( r != ERROR_SUCCESS )
287 /******************************************************************************
288 * Service IPC functions
290 static LPWSTR service_get_pipe_name(LPWSTR service)
292 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
293 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
297 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
298 name = HeapAlloc(GetProcessHeap(), 0, len);
299 strcpyW(name, prefix);
300 strcatW(name, service);
304 static HANDLE service_open_pipe(LPWSTR service)
306 LPWSTR szPipe = service_get_pipe_name( service );
307 HANDLE handle = INVALID_HANDLE_VALUE;
310 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
311 0, NULL, OPEN_ALWAYS, 0, NULL);
312 if (handle != INVALID_HANDLE_VALUE)
314 if (GetLastError() != ERROR_PIPE_BUSY)
316 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
322 /******************************************************************************
323 * service_get_event_handle
325 static HANDLE service_get_event_handle(LPWSTR service)
327 static const WCHAR prefix[] = {
328 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
333 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
334 name = HeapAlloc(GetProcessHeap(), 0, len);
335 strcpyW(name, prefix);
336 strcatW(name, service);
337 handle = CreateEventW(NULL, TRUE, FALSE, name);
342 /******************************************************************************
345 * Call into the main service routine provided by StartServiceCtrlDispatcher.
347 static DWORD WINAPI service_thread(LPVOID arg)
349 service_data *info = arg;
350 LPWSTR str = info->args;
351 DWORD argc = 0, len = 0;
357 len += strlenW(&str[len]) + 1;
365 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
366 for (argc=0, p=str; *p; p += strlenW(p) + 1)
370 info->proc.w(argc, argv);
371 HeapFree(GetProcessHeap(), 0, argv);
375 LPSTR strA, *argv, p;
378 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
379 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
380 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
382 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
383 for (argc=0, p=strA; *p; p += strlen(p) + 1)
387 info->proc.a(argc, argv);
388 HeapFree(GetProcessHeap(), 0, argv);
389 HeapFree(GetProcessHeap(), 0, strA);
394 /******************************************************************************
395 * service_handle_start
397 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
399 DWORD read = 0, result = 0;
403 TRACE("%p %p %ld\n", pipe, service, count);
405 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
406 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
407 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
409 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
410 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
416 ERR("service is not stopped\n");
421 SERV_free(service->args);
422 service->args = args;
424 service->thread = CreateThread( NULL, 0, service_thread,
428 HeapFree(GetProcessHeap(), 0, args);
429 WriteFile( pipe, &result, sizeof result, &read, NULL );
434 /******************************************************************************
435 * service_send_start_message
437 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
439 DWORD i, len, count, result;
440 service_start_info *ssi;
444 TRACE("%p %p %ld\n", pipe, argv, argc);
446 /* calculate how much space do we need to send the startup info */
448 for (i=0; i<argc; i++)
449 len += strlenW(argv[i])+1;
451 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
452 ssi->cmd = WINESERV_STARTINFO;
455 /* copy service args into a single buffer*/
457 for (i=0; i<argc; i++)
464 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
466 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
468 HeapFree(GetProcessHeap(),0,ssi);
473 /******************************************************************************
474 * service_handle_get_status
476 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
480 return WriteFile(pipe, &service->status,
481 sizeof service->status, &count, NULL);
484 /******************************************************************************
487 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
489 DWORD cmd[2], count = 0;
492 cmd[0] = WINESERV_GETSTATUS;
494 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
495 if (!r || count != sizeof cmd)
497 ERR("service protocol error - failed to write pipe!\n");
500 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
501 if (!r || count != sizeof *status)
502 ERR("service protocol error - failed to read pipe "
503 "r = %d count = %ld/%d!\n", r, count, sizeof *status);
507 /******************************************************************************
508 * service_send_control
510 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
512 DWORD cmd[2], count = 0;
515 cmd[0] = WINESERV_SENDCONTROL;
517 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
518 if (!r || count != sizeof cmd)
520 ERR("service protocol error - failed to write pipe!\n");
523 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
524 if (!r || count != sizeof *result)
525 ERR("service protocol error - failed to read pipe "
526 "r = %d count = %ld/%d!\n", r, count, sizeof *result);
530 /******************************************************************************
531 * service_accepts_control
533 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
535 DWORD a = service->status.dwControlsAccepted;
539 case SERVICE_CONTROL_INTERROGATE:
541 case SERVICE_CONTROL_STOP:
542 if (a&SERVICE_ACCEPT_STOP)
545 case SERVICE_CONTROL_SHUTDOWN:
546 if (a&SERVICE_ACCEPT_SHUTDOWN)
549 case SERVICE_CONTROL_PAUSE:
550 case SERVICE_CONTROL_CONTINUE:
551 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
554 case SERVICE_CONTROL_PARAMCHANGE:
555 if (a&SERVICE_ACCEPT_PARAMCHANGE)
558 case SERVICE_CONTROL_NETBINDADD:
559 case SERVICE_CONTROL_NETBINDREMOVE:
560 case SERVICE_CONTROL_NETBINDENABLE:
561 case SERVICE_CONTROL_NETBINDDISABLE:
562 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
565 if (1) /* (!service->handlerex) */
569 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
570 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
573 case SERVICE_CONTROL_POWEREVENT:
574 if (a&SERVICE_ACCEPT_POWEREVENT)
577 case SERVICE_CONTROL_SESSIONCHANGE:
578 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
585 /******************************************************************************
586 * service_handle_control
588 static BOOL service_handle_control(HANDLE pipe, service_data *service,
591 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
593 TRACE("received control %ld\n", dwControl);
595 if (service_accepts_control(service, dwControl) && service->handler)
597 service->handler(dwControl);
600 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
603 /******************************************************************************
604 * service_reap_thread
606 static DWORD service_reap_thread(service_data *service)
610 if (!service->thread)
612 GetExitCodeThread(service->thread, &exitcode);
613 if (exitcode!=STILL_ACTIVE)
615 CloseHandle(service->thread);
621 /******************************************************************************
622 * service_control_dispatcher
624 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
626 service_data *service = arg;
630 TRACE("%p %s\n", service, debugstr_w(service->name));
632 /* create a pipe to talk to the rest of the world with */
633 name = service_get_pipe_name(service->name);
634 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
635 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
638 /* let the process who started us know we've tried to create a pipe */
639 event = service_get_event_handle(service->name);
643 if (pipe==INVALID_HANDLE_VALUE)
645 ERR("failed to create pipe, error = %ld\n", GetLastError());
649 /* dispatcher loop */
653 DWORD count, req[2] = {0,0};
655 r = ConnectNamedPipe(pipe, NULL);
656 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
658 ERR("pipe connect failed\n");
662 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
663 if (!r || count!=sizeof req)
665 ERR("pipe read failed\n");
669 service_reap_thread(service);
671 /* handle the request */
674 case WINESERV_STARTINFO:
675 service_handle_start(pipe, service, req[1]);
677 case WINESERV_GETSTATUS:
678 service_handle_get_status(pipe, service);
680 case WINESERV_SENDCONTROL:
681 service_handle_control(pipe, service, req[1]);
684 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
687 FlushFileBuffers(pipe);
688 DisconnectNamedPipe(pipe);
695 /******************************************************************************
696 * service_run_threads
698 static BOOL service_run_threads(void)
700 service_data *service;
701 DWORD count = 0, n = 0;
704 EnterCriticalSection( &service_cs );
706 /* count how many services there are */
707 for (service = service_list; service; service = service->next)
710 TRACE("starting %ld pipe listener threads\n", count);
712 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
714 for (n=0, service = service_list; service; service = service->next, n++)
715 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
719 LeaveCriticalSection( &service_cs );
721 /* wait for all the threads to pack up and exit */
722 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
724 HeapFree(GetProcessHeap(), 0, handles);
729 /******************************************************************************
730 * StartServiceCtrlDispatcherA [ADVAPI32.@]
732 * Connects a process containing one or more services to the service control
736 * servent [I] A list of the service names and service procedures
738 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
744 TRACE("%p\n", servent);
746 EnterCriticalSection( &service_cs );
747 while (servent->lpServiceName)
749 LPSTR name = servent->lpServiceName;
751 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
752 sz = len*sizeof(WCHAR) + sizeof *info;
753 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
754 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
755 info->proc.a = servent->lpServiceProc;
756 info->unicode = FALSE;
758 /* insert into the list */
759 info->next = service_list;
764 LeaveCriticalSection( &service_cs );
766 service_run_threads();
771 /******************************************************************************
772 * StartServiceCtrlDispatcherW [ADVAPI32.@]
774 * Connects a process containing one or more services to the service control
778 * servent [I] A list of the service names and service procedures
780 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
786 TRACE("%p\n", servent);
788 EnterCriticalSection( &service_cs );
789 while (servent->lpServiceName)
791 LPWSTR name = servent->lpServiceName;
794 sz = len*sizeof(WCHAR) + sizeof *info;
795 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
796 strcpyW(info->name, name);
797 info->proc.w = servent->lpServiceProc;
798 info->unicode = TRUE;
800 /* insert into the list */
801 info->next = service_list;
806 LeaveCriticalSection( &service_cs );
808 service_run_threads();
813 /******************************************************************************
814 * LockServiceDatabase [ADVAPI32.@]
816 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
820 TRACE("%p\n",hSCManager);
822 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
823 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
827 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
830 TRACE("returning %p\n", ret);
835 /******************************************************************************
836 * UnlockServiceDatabase [ADVAPI32.@]
838 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
840 TRACE("%p\n",ScLock);
842 return CloseHandle( ScLock );
845 /******************************************************************************
846 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
848 SERVICE_STATUS_HANDLE WINAPI
849 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
851 LPWSTR lpServiceNameW;
852 SERVICE_STATUS_HANDLE ret;
854 lpServiceNameW = SERV_dup(lpServiceName);
855 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
856 SERV_free(lpServiceNameW);
860 /******************************************************************************
861 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
867 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
868 LPHANDLER_FUNCTION lpfHandler )
870 service_data *service;
872 EnterCriticalSection( &service_cs );
873 for(service = service_list; service; service = service->next)
874 if(!strcmpW(lpServiceName, service->name))
877 service->handler = lpfHandler;
878 LeaveCriticalSection( &service_cs );
880 return (SERVICE_STATUS_HANDLE)service;
883 /******************************************************************************
884 * SetServiceStatus [ADVAPI32.@]
891 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
893 service_data *service;
896 TRACE("%lx %lx %lx %lx %lx %lx %lx %lx\n", hService,
897 lpStatus->dwServiceType, lpStatus->dwCurrentState,
898 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
899 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
900 lpStatus->dwWaitHint);
902 EnterCriticalSection( &service_cs );
903 for (service = service_list; service; service = service->next)
904 if(service == (service_data*)hService)
908 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
909 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
913 LeaveCriticalSection( &service_cs );
919 /******************************************************************************
920 * OpenSCManagerA [ADVAPI32.@]
922 * Establish a connection to the service control manager and open its database.
925 * lpMachineName [I] Pointer to machine name string
926 * lpDatabaseName [I] Pointer to database name string
927 * dwDesiredAccess [I] Type of access
930 * Success: A Handle to the service control manager database
933 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
934 DWORD dwDesiredAccess )
936 LPWSTR lpMachineNameW, lpDatabaseNameW;
939 lpMachineNameW = SERV_dup(lpMachineName);
940 lpDatabaseNameW = SERV_dup(lpDatabaseName);
941 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
942 SERV_free(lpDatabaseNameW);
943 SERV_free(lpMachineNameW);
947 /******************************************************************************
948 * OpenSCManagerW [ADVAPI32.@]
950 * See OpenSCManagerA.
952 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
953 DWORD dwDesiredAccess )
955 struct sc_manager *manager;
959 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
960 debugstr_w(lpDatabaseName), dwDesiredAccess);
962 if( lpDatabaseName && lpDatabaseName[0] )
964 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
966 /* noop, all right */
968 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
970 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
975 SetLastError( ERROR_INVALID_NAME );
980 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
981 sc_handle_destroy_manager );
985 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
986 if (r!=ERROR_SUCCESS)
989 r = RegOpenKeyExW(hReg, szServiceManagerKey,
990 0, KEY_ALL_ACCESS, &manager->hkey);
992 if (r!=ERROR_SUCCESS)
995 TRACE("returning %p\n", manager);
997 return (SC_HANDLE) &manager->hdr;
1000 sc_handle_free( &manager->hdr );
1004 /******************************************************************************
1005 * ControlService [ADVAPI32.@]
1007 * Send a control code to a service.
1010 * hService [I] Handle of the service control manager database
1011 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1012 * lpServiceStatus [O] Destination for the status of the service, if available
1019 * Unlike M$' implementation, control requests are not serialized and may be
1020 * processed asynchronously.
1022 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1023 LPSERVICE_STATUS lpServiceStatus )
1025 struct sc_service *hsvc;
1029 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1031 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1034 SetLastError( ERROR_INVALID_HANDLE );
1038 ret = QueryServiceStatus(hService, lpServiceStatus);
1041 ERR("failed to query service status\n");
1042 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1046 switch (lpServiceStatus->dwCurrentState)
1048 case SERVICE_STOPPED:
1049 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1051 case SERVICE_START_PENDING:
1052 if (dwControl==SERVICE_CONTROL_STOP)
1055 case SERVICE_STOP_PENDING:
1056 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1060 handle = service_open_pipe(hsvc->name);
1061 if (handle!=INVALID_HANDLE_VALUE)
1063 DWORD result = ERROR_SUCCESS;
1064 ret = service_send_control(handle, dwControl, &result);
1065 CloseHandle(handle);
1066 if (result!=ERROR_SUCCESS)
1068 SetLastError(result);
1076 /******************************************************************************
1077 * CloseServiceHandle [ADVAPI32.@]
1079 * Close a handle to a service or the service control manager database.
1082 * hSCObject [I] Handle to service or service control manager database
1089 CloseServiceHandle( SC_HANDLE hSCObject )
1091 TRACE("%p\n", hSCObject);
1093 sc_handle_free( (struct sc_handle*) hSCObject );
1099 /******************************************************************************
1100 * OpenServiceA [ADVAPI32.@]
1102 * Open a handle to a service.
1105 * hSCManager [I] Handle of the service control manager database
1106 * lpServiceName [I] Name of the service to open
1107 * dwDesiredAccess [I] Access required to the service
1110 * Success: Handle to the service
1113 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1114 DWORD dwDesiredAccess )
1116 LPWSTR lpServiceNameW;
1119 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1121 lpServiceNameW = SERV_dup(lpServiceName);
1122 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1123 SERV_free(lpServiceNameW);
1128 /******************************************************************************
1129 * OpenServiceW [ADVAPI32.@]
1133 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1134 DWORD dwDesiredAccess)
1136 struct sc_manager *hscm;
1137 struct sc_service *hsvc;
1142 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1146 SetLastError(ERROR_INVALID_ADDRESS);
1150 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1153 SetLastError( ERROR_INVALID_HANDLE );
1157 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1158 if (r!=ERROR_SUCCESS)
1160 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1164 len = strlenW(lpServiceName)+1;
1165 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1166 sizeof (struct sc_service) + len*sizeof(WCHAR),
1167 sc_handle_destroy_service );
1170 strcpyW( hsvc->name, lpServiceName );
1173 /* add reference to SCM handle */
1174 hscm->hdr.ref_count++;
1177 TRACE("returning %p\n",hsvc);
1179 return (SC_HANDLE) &hsvc->hdr;
1182 /******************************************************************************
1183 * CreateServiceW [ADVAPI32.@]
1186 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1187 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1188 DWORD dwServiceType, DWORD dwStartType,
1189 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1190 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1191 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1192 LPCWSTR lpPassword )
1194 struct sc_manager *hscm;
1195 struct sc_service *hsvc = NULL;
1199 struct reg_value val[10];
1202 TRACE("%p %s %s\n", hSCManager,
1203 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1205 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1208 SetLastError( ERROR_INVALID_HANDLE );
1212 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1213 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1214 if (r!=ERROR_SUCCESS)
1217 if (dp != REG_CREATED_NEW_KEY)
1219 SetLastError(ERROR_SERVICE_EXISTS);
1224 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1226 service_set_dword( &val[n++], szType, &dwServiceType );
1227 service_set_dword( &val[n++], szStart, &dwStartType );
1228 service_set_dword( &val[n++], szError, &dwErrorControl );
1230 if( lpBinaryPathName )
1231 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1233 if( lpLoadOrderGroup )
1234 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1236 if( lpDependencies )
1237 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1240 FIXME("Don't know how to add a Password for a service.\n");
1242 if( lpServiceStartName )
1243 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1245 r = service_write_values( hKey, val, n );
1246 if( r != ERROR_SUCCESS )
1249 len = strlenW(lpServiceName)+1;
1250 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1251 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1254 lstrcpyW( hsvc->name, lpServiceName );
1257 hscm->hdr.ref_count++;
1259 return (SC_HANDLE) &hsvc->hdr;
1262 RegCloseKey( hKey );
1267 /******************************************************************************
1268 * CreateServiceA [ADVAPI32.@]
1271 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1272 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1273 DWORD dwServiceType, DWORD dwStartType,
1274 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1275 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1276 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1279 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1280 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1283 TRACE("%p %s %s\n", hSCManager,
1284 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1286 lpServiceNameW = SERV_dup( lpServiceName );
1287 lpDisplayNameW = SERV_dup( lpDisplayName );
1288 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1289 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1290 lpDependenciesW = SERV_dupmulti( lpDependencies );
1291 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1292 lpPasswordW = SERV_dup( lpPassword );
1294 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1295 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1296 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1297 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1299 SERV_free( lpServiceNameW );
1300 SERV_free( lpDisplayNameW );
1301 SERV_free( lpBinaryPathNameW );
1302 SERV_free( lpLoadOrderGroupW );
1303 SERV_free( lpDependenciesW );
1304 SERV_free( lpServiceStartNameW );
1305 SERV_free( lpPasswordW );
1311 /******************************************************************************
1312 * DeleteService [ADVAPI32.@]
1314 * Delete a service from the service control manager database.
1317 * hService [I] Handle of the service to delete
1323 BOOL WINAPI DeleteService( SC_HANDLE hService )
1325 struct sc_service *hsvc;
1327 WCHAR valname[MAX_PATH+1];
1332 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1335 SetLastError( ERROR_INVALID_HANDLE );
1341 /* Clean out the values */
1342 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1343 while (rc == ERROR_SUCCESS)
1345 RegDeleteValueW(hKey,valname);
1348 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1354 /* delete the key */
1355 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1361 /******************************************************************************
1362 * StartServiceA [ADVAPI32.@]
1367 * hService [I] Handle of service
1368 * dwNumServiceArgs [I] Number of arguments
1369 * lpServiceArgVectors [I] Address of array of argument strings
1372 * - NT implements this function using an obscure RPC call.
1373 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1374 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1375 * - This will only work for shared address space. How should the service
1376 * args be transferred when address spaces are separated?
1377 * - Can only start one service at a time.
1378 * - Has no concept of privilege.
1384 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1385 LPCSTR *lpServiceArgVectors )
1387 LPWSTR *lpwstr=NULL;
1391 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1393 if (dwNumServiceArgs)
1394 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1395 dwNumServiceArgs*sizeof(LPWSTR) );
1397 for(i=0; i<dwNumServiceArgs; i++)
1398 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1400 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1402 if (dwNumServiceArgs)
1404 for(i=0; i<dwNumServiceArgs; i++)
1405 SERV_free(lpwstr[i]);
1406 HeapFree(GetProcessHeap(), 0, lpwstr);
1412 /******************************************************************************
1413 * service_start_process [INTERNAL]
1415 static DWORD service_start_process(struct sc_service *hsvc)
1417 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1418 PROCESS_INFORMATION pi;
1420 LPWSTR path = NULL, str;
1421 DWORD type, size, ret;
1425 /* read the executable path from memory */
1427 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1428 if (ret!=ERROR_SUCCESS)
1430 str = HeapAlloc(GetProcessHeap(),0,size);
1431 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1432 if (ret==ERROR_SUCCESS)
1434 size = ExpandEnvironmentStringsW(str,NULL,0);
1435 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1436 ExpandEnvironmentStringsW(str,path,size);
1438 HeapFree(GetProcessHeap(),0,str);
1442 /* wait for the process to start and set an event or terminate */
1443 handles[0] = service_get_event_handle( hsvc->name );
1444 ZeroMemory(&si, sizeof(STARTUPINFOW));
1445 si.cb = sizeof(STARTUPINFOW);
1446 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1449 handles[1] = pi.hProcess;
1450 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1451 if(ret != WAIT_OBJECT_0)
1453 SetLastError(ERROR_IO_PENDING);
1457 CloseHandle( pi.hThread );
1458 CloseHandle( pi.hProcess );
1460 CloseHandle( handles[0] );
1461 HeapFree(GetProcessHeap(),0,path);
1465 static BOOL service_wait_for_startup(SC_HANDLE hService)
1468 SERVICE_STATUS status;
1471 TRACE("%p\n", hService);
1473 for (i=0; i<30; i++)
1475 status.dwCurrentState = 0;
1476 r = QueryServiceStatus(hService, &status);
1479 if (status.dwCurrentState == SERVICE_RUNNING)
1481 TRACE("Service started successfully\n");
1490 /******************************************************************************
1491 * StartServiceW [ADVAPI32.@]
1493 * See StartServiceA.
1495 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1496 LPCWSTR *lpServiceArgVectors)
1498 struct sc_service *hsvc;
1501 HANDLE handle = INVALID_HANDLE_VALUE;
1503 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1505 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1508 SetLastError(ERROR_INVALID_HANDLE);
1512 hLock = LockServiceDatabase(hsvc->scm);
1516 handle = service_open_pipe(hsvc->name);
1517 if (handle==INVALID_HANDLE_VALUE)
1519 /* start the service process */
1520 if (service_start_process(hsvc))
1521 handle = service_open_pipe(hsvc->name);
1524 if (handle != INVALID_HANDLE_VALUE)
1526 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1527 CloseHandle(handle);
1531 UnlockServiceDatabase( hLock );
1533 TRACE("returning %d\n", r);
1535 service_wait_for_startup(hService);
1540 /******************************************************************************
1541 * QueryServiceStatus [ADVAPI32.@]
1545 * lpservicestatus []
1548 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1549 LPSERVICE_STATUS lpservicestatus)
1551 struct sc_service *hsvc;
1552 DWORD size, type, val;
1556 TRACE("%p %p\n", hService, lpservicestatus);
1558 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1561 SetLastError( ERROR_INVALID_HANDLE );
1565 pipe = service_open_pipe(hsvc->name);
1566 if (pipe != INVALID_HANDLE_VALUE)
1568 r = service_get_status(pipe, lpservicestatus);
1574 TRACE("Failed to read service status\n");
1576 /* read the service type from the registry */
1578 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1579 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1582 lpservicestatus->dwServiceType = val;
1583 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1584 lpservicestatus->dwControlsAccepted = 0;
1585 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1586 lpservicestatus->dwServiceSpecificExitCode = 0;
1587 lpservicestatus->dwCheckPoint = 0;
1588 lpservicestatus->dwWaitHint = 0;
1593 /******************************************************************************
1594 * QueryServiceStatusEx [ADVAPI32.@]
1596 * Get information about a service.
1599 * hService [I] Handle to service to get information about
1600 * InfoLevel [I] Level of information to get
1601 * lpBuffer [O] Destination for requested information
1602 * cbBufSize [I] Size of lpBuffer in bytes
1603 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1609 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1610 LPBYTE lpBuffer, DWORD cbBufSize,
1611 LPDWORD pcbBytesNeeded)
1614 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1618 /******************************************************************************
1619 * QueryServiceConfigA [ADVAPI32.@]
1622 QueryServiceConfigA( SC_HANDLE hService,
1623 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1624 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1626 static const CHAR szDisplayName[] = "DisplayName";
1627 static const CHAR szType[] = "Type";
1628 static const CHAR szStart[] = "Start";
1629 static const CHAR szError[] = "ErrorControl";
1630 static const CHAR szImagePath[] = "ImagePath";
1631 static const CHAR szGroup[] = "Group";
1632 static const CHAR szDependencies[] = "Dependencies";
1633 struct sc_service *hsvc;
1635 CHAR str_buffer[ MAX_PATH ];
1637 DWORD type, val, sz, total, n;
1640 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1641 cbBufSize, pcbBytesNeeded);
1643 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1646 SetLastError( ERROR_INVALID_HANDLE );
1651 /* calculate the size required first */
1652 total = sizeof (QUERY_SERVICE_CONFIGA);
1654 sz = sizeof(str_buffer);
1655 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1656 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1658 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1659 if( 0 == sz ) return FALSE;
1665 /* FIXME: set last error */
1670 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1671 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1675 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1676 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1680 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1681 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1685 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1686 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1689 *pcbBytesNeeded = total;
1691 /* if there's not enough memory, return an error */
1692 if( total > cbBufSize )
1694 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1698 ZeroMemory( lpServiceConfig, total );
1701 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1702 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1703 lpServiceConfig->dwServiceType = val;
1706 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1707 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1708 lpServiceConfig->dwStartType = val;
1711 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1712 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1713 lpServiceConfig->dwErrorControl = val;
1715 /* now do the strings */
1716 p = (LPBYTE) &lpServiceConfig[1];
1717 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1719 sz = sizeof(str_buffer);
1720 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1721 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1723 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1724 if( 0 == sz || sz > n ) return FALSE;
1726 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1732 /* FIXME: set last error */
1737 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1738 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1740 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1746 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1747 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1749 lpServiceConfig->lpDependencies = (LPSTR) p;
1755 ERR("Buffer overflow!\n");
1757 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1758 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1763 /******************************************************************************
1764 * QueryServiceConfigW [ADVAPI32.@]
1767 QueryServiceConfigW( SC_HANDLE hService,
1768 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1769 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1771 WCHAR str_buffer[ MAX_PATH ];
1773 DWORD type, val, sz, total, n;
1776 struct sc_service *hsvc;
1778 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1779 cbBufSize, pcbBytesNeeded);
1781 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1784 SetLastError( ERROR_INVALID_HANDLE );
1789 /* calculate the size required first */
1790 total = sizeof (QUERY_SERVICE_CONFIGW);
1792 sz = sizeof(str_buffer);
1793 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1794 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1796 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1797 if( 0 == sz ) return FALSE;
1799 total += sizeof(WCHAR) * sz;
1803 /* FIXME: set last error */
1808 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1809 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1813 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1814 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1817 total += sizeof(WCHAR);
1820 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1821 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1825 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1826 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1829 *pcbBytesNeeded = total;
1831 /* if there's not enough memory, return an error */
1832 if( total > cbBufSize )
1834 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1838 ZeroMemory( lpServiceConfig, total );
1841 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1842 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1843 lpServiceConfig->dwServiceType = val;
1846 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1847 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1848 lpServiceConfig->dwStartType = val;
1851 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1852 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1853 lpServiceConfig->dwErrorControl = val;
1855 /* now do the strings */
1856 p = (LPBYTE) &lpServiceConfig[1];
1857 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1859 sz = sizeof(str_buffer);
1860 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1861 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1863 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1864 sz *= sizeof(WCHAR);
1865 if( 0 == sz || sz > n ) return FALSE;
1867 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1873 /* FIXME: set last error */
1878 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1879 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1881 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1887 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1888 lpServiceConfig->lpDependencies = (LPWSTR) p;
1889 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1902 ERR("Buffer overflow!\n");
1904 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1905 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1910 /******************************************************************************
1911 * EnumServicesStatusA [ADVAPI32.@]
1914 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1915 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1916 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1917 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1919 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1920 dwServiceType, dwServiceState, lpServices, cbBufSize,
1921 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1922 SetLastError (ERROR_ACCESS_DENIED);
1926 /******************************************************************************
1927 * EnumServicesStatusW [ADVAPI32.@]
1930 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1931 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1932 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1933 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1935 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1936 dwServiceType, dwServiceState, lpServices, cbBufSize,
1937 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1938 SetLastError (ERROR_ACCESS_DENIED);
1942 /******************************************************************************
1943 * GetServiceKeyNameA [ADVAPI32.@]
1945 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1946 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1948 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1952 /******************************************************************************
1953 * GetServiceKeyNameW [ADVAPI32.@]
1955 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1956 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1958 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1962 /******************************************************************************
1963 * QueryServiceLockStatusA [ADVAPI32.@]
1965 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1966 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1967 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1969 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1974 /******************************************************************************
1975 * QueryServiceLockStatusW [ADVAPI32.@]
1977 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1978 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1979 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1981 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1986 /******************************************************************************
1987 * GetServiceDisplayNameA [ADVAPI32.@]
1989 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1990 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1992 FIXME("%p %s %p %p\n", hSCManager,
1993 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1997 /******************************************************************************
1998 * GetServiceDisplayNameW [ADVAPI32.@]
2000 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2001 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2003 FIXME("%p %s %p %p\n", hSCManager,
2004 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2008 /******************************************************************************
2009 * ChangeServiceConfigW [ADVAPI32.@]
2011 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2012 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2013 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2014 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2016 struct reg_value val[10];
2017 struct sc_service *hsvc;
2018 DWORD r = ERROR_SUCCESS;
2022 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2023 hService, dwServiceType, dwStartType, dwErrorControl,
2024 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2025 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2026 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2028 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2031 SetLastError( ERROR_INVALID_HANDLE );
2036 if( dwServiceType != SERVICE_NO_CHANGE )
2037 service_set_dword( &val[n++], szType, &dwServiceType );
2039 if( dwStartType != SERVICE_NO_CHANGE )
2040 service_set_dword( &val[n++], szStart, &dwStartType );
2042 if( dwErrorControl != SERVICE_NO_CHANGE )
2043 service_set_dword( &val[n++], szError, &dwErrorControl );
2045 if( lpBinaryPathName )
2046 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2048 if( lpLoadOrderGroup )
2049 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2051 if( lpDependencies )
2052 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2055 FIXME("ignoring password\n");
2057 if( lpServiceStartName )
2058 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2060 r = service_write_values( hsvc->hkey, val, n );
2062 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2065 /******************************************************************************
2066 * ChangeServiceConfigA [ADVAPI32.@]
2068 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2069 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2070 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2071 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2073 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2074 LPWSTR wServiceStartName, wPassword, wDisplayName;
2077 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2078 hService, dwServiceType, dwStartType, dwErrorControl,
2079 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2080 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2081 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2083 wBinaryPathName = SERV_dup( lpBinaryPathName );
2084 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2085 wDependencies = SERV_dupmulti( lpDependencies );
2086 wServiceStartName = SERV_dup( lpServiceStartName );
2087 wPassword = SERV_dup( lpPassword );
2088 wDisplayName = SERV_dup( lpDisplayName );
2090 r = ChangeServiceConfigW( hService, dwServiceType,
2091 dwStartType, dwErrorControl, wBinaryPathName,
2092 wLoadOrderGroup, lpdwTagId, wDependencies,
2093 wServiceStartName, wPassword, wDisplayName);
2095 SERV_free( wBinaryPathName );
2096 SERV_free( wLoadOrderGroup );
2097 SERV_free( wDependencies );
2098 SERV_free( wServiceStartName );
2099 SERV_free( wPassword );
2100 SERV_free( wDisplayName );
2105 /******************************************************************************
2106 * ChangeServiceConfig2A [ADVAPI32.@]
2108 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2113 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2115 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2117 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2118 SERVICE_DESCRIPTIONW sdw;
2120 sdw.lpDescription = SERV_dup( sd->lpDescription );
2122 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2124 SERV_free( sdw.lpDescription );
2126 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2128 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2129 SERVICE_FAILURE_ACTIONSW faw;
2131 faw.dwResetPeriod = fa->dwResetPeriod;
2132 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2133 faw.lpCommand = SERV_dup( fa->lpCommand );
2134 faw.cActions = fa->cActions;
2135 faw.lpsaActions = fa->lpsaActions;
2137 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2139 SERV_free( faw.lpRebootMsg );
2140 SERV_free( faw.lpCommand );
2143 SetLastError( ERROR_INVALID_PARAMETER );
2148 /******************************************************************************
2149 * ChangeServiceConfig2W [ADVAPI32.@]
2151 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2155 struct sc_service *hsvc;
2157 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2160 SetLastError( ERROR_INVALID_HANDLE );
2165 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2167 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2168 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2169 if (sd->lpDescription)
2171 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2172 if (sd->lpDescription[0] == 0)
2173 RegDeleteValueW(hKey,szDescription);
2175 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2176 (LPVOID)sd->lpDescription,
2177 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2181 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2185 /******************************************************************************
2186 * QueryServiceObjectSecurity [ADVAPI32.@]
2188 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2189 SECURITY_INFORMATION dwSecurityInformation,
2190 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2191 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2195 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2196 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2198 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2200 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2201 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2202 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2206 /******************************************************************************
2207 * SetServiceObjectSecurity [ADVAPI32.@]
2209 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2210 SECURITY_INFORMATION dwSecurityInformation,
2211 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2213 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2217 /******************************************************************************
2218 * SetServiceBits [ADVAPI32.@]
2220 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2221 DWORD dwServiceBits,
2223 BOOL bUpdateImmediately)
2225 FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2226 bSetBitsOn, bUpdateImmediately);