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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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;
61 LPHANDLER_FUNCTION handler;
62 LPHANDLER_FUNCTION_EX handler_ex;
65 SERVICE_STATUS_PROCESS status;
68 BOOL extended : 1; /* uses handler_ex instead of handler? */
70 LPSERVICE_MAIN_FUNCTIONA a;
71 LPSERVICE_MAIN_FUNCTIONW w;
77 static CRITICAL_SECTION service_cs;
78 static CRITICAL_SECTION_DEBUG service_cs_debug =
81 { &service_cs_debug.ProcessLocksList,
82 &service_cs_debug.ProcessLocksList },
83 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
85 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
87 static service_data *service_list;
89 /******************************************************************************
93 #define MAX_SERVICE_NAME 256
95 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
98 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
102 SC_HANDLE_TYPE htype;
104 sc_handle_destructor destroy;
107 struct sc_manager /* service control manager handle */
109 struct sc_handle hdr;
110 HKEY hkey; /* handle to services database in the registry */
113 struct sc_service /* service handle */
115 struct sc_handle hdr;
116 HKEY hkey; /* handle to service entry in the registry (under hkey) */
117 struct sc_manager *scm; /* pointer to SCM handle */
121 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
122 sc_handle_destructor destroy)
124 struct sc_handle *hdr;
126 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
131 hdr->destroy = destroy;
133 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
137 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
139 struct sc_handle *hdr = (struct sc_handle *) handle;
143 if (hdr->htype != htype)
148 static void sc_handle_free(struct sc_handle* hdr)
152 if (--hdr->ref_count)
155 HeapFree(GetProcessHeap(), 0, hdr);
158 static void sc_handle_destroy_manager(struct sc_handle *handle)
160 struct sc_manager *mgr = (struct sc_manager*) handle;
162 TRACE("destroying SC Manager %p\n", mgr);
164 RegCloseKey(mgr->hkey);
167 static void sc_handle_destroy_service(struct sc_handle *handle)
169 struct sc_service *svc = (struct sc_service*) handle;
171 TRACE("destroying service %p\n", svc);
173 RegCloseKey(svc->hkey);
175 sc_handle_free(&svc->scm->hdr);
179 /******************************************************************************
180 * String management functions
182 static inline LPWSTR SERV_dup( LPCSTR str )
189 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
190 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
191 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
195 static inline LPWSTR SERV_dupmulti(LPCSTR str)
203 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
204 n += (strlen( &str[n] ) + 1);
209 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
210 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
214 static inline VOID SERV_free( LPWSTR wstr )
216 HeapFree( GetProcessHeap(), 0, wstr );
219 /******************************************************************************
220 * registry access functions and data
222 static const WCHAR szDisplayName[] = {
223 'D','i','s','p','l','a','y','N','a','m','e', 0 };
224 static const WCHAR szType[] = {'T','y','p','e',0};
225 static const WCHAR szStart[] = {'S','t','a','r','t',0};
226 static const WCHAR szError[] = {
227 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
228 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
229 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
230 static const WCHAR szDependencies[] = {
231 'D','e','p','e','n','d','e','n','c','i','e','s',0};
232 static const WCHAR szDependOnService[] = {
233 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
242 static inline void service_set_value( struct reg_value *val,
243 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
251 static inline void service_set_dword( struct reg_value *val,
252 LPCWSTR name, const DWORD *data )
254 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
257 static inline void service_set_string( struct reg_value *val,
258 LPCWSTR name, LPCWSTR string )
260 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
261 service_set_value( val, REG_SZ, name, string, len );
264 static inline void service_set_multi_string( struct reg_value *val,
265 LPCWSTR name, LPCWSTR string )
269 /* determine the length of a double null terminated multi string */
271 len += (lstrlenW( &string[ len ] )+1);
272 } while ( string[ len++ ] );
274 len *= sizeof (WCHAR);
275 service_set_value( val, REG_MULTI_SZ, name, string, len );
278 static inline LONG service_write_values( HKEY hKey,
279 const struct reg_value *val, int n )
281 LONG r = ERROR_SUCCESS;
286 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
287 (const BYTE*)val[i].data, val[i].size );
288 if( r != ERROR_SUCCESS )
294 /******************************************************************************
295 * Service IPC functions
297 static LPWSTR service_get_pipe_name(LPCWSTR service)
299 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
300 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
304 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
305 name = HeapAlloc(GetProcessHeap(), 0, len);
306 strcpyW(name, prefix);
307 strcatW(name, service);
311 static HANDLE service_open_pipe(LPCWSTR service)
313 LPWSTR szPipe = service_get_pipe_name( service );
314 HANDLE handle = INVALID_HANDLE_VALUE;
317 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
318 0, NULL, OPEN_ALWAYS, 0, NULL);
319 if (handle != INVALID_HANDLE_VALUE)
321 if (GetLastError() != ERROR_PIPE_BUSY)
323 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
329 /******************************************************************************
330 * service_get_event_handle
332 static HANDLE service_get_event_handle(LPCWSTR service)
334 static const WCHAR prefix[] = {
335 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
340 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
341 name = HeapAlloc(GetProcessHeap(), 0, len);
342 strcpyW(name, prefix);
343 strcatW(name, service);
344 handle = CreateEventW(NULL, TRUE, FALSE, name);
349 /******************************************************************************
352 * Call into the main service routine provided by StartServiceCtrlDispatcher.
354 static DWORD WINAPI service_thread(LPVOID arg)
356 service_data *info = arg;
357 LPWSTR str = info->args;
358 DWORD argc = 0, len = 0;
364 len += strlenW(&str[len]) + 1;
371 info->proc.w(0, NULL);
373 info->proc.a(0, NULL);
381 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
382 for (argc=0, p=str; *p; p += strlenW(p) + 1)
386 info->proc.w(argc, argv);
387 HeapFree(GetProcessHeap(), 0, argv);
391 LPSTR strA, *argv, p;
394 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
395 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
396 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
398 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
399 for (argc=0, p=strA; *p; p += strlen(p) + 1)
403 info->proc.a(argc, argv);
404 HeapFree(GetProcessHeap(), 0, argv);
405 HeapFree(GetProcessHeap(), 0, strA);
410 /******************************************************************************
411 * service_handle_start
413 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
415 DWORD read = 0, result = 0;
419 TRACE("%p %p %d\n", pipe, service, count);
421 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
422 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
423 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
425 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
426 r, count, read, debugstr_wn(args, count));
432 ERR("service is not stopped\n");
436 SERV_free(service->args);
437 service->args = args;
439 service->thread = CreateThread( NULL, 0, service_thread,
443 HeapFree(GetProcessHeap(), 0, args);
444 WriteFile( pipe, &result, sizeof result, &read, NULL );
449 /******************************************************************************
450 * service_send_start_message
452 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
454 DWORD i, len, count, result;
455 service_start_info *ssi;
459 TRACE("%p %p %d\n", pipe, argv, argc);
461 /* calculate how much space do we need to send the startup info */
463 for (i=0; i<argc; i++)
464 len += strlenW(argv[i])+1;
466 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
467 ssi->cmd = WINESERV_STARTINFO;
470 /* copy service args into a single buffer*/
472 for (i=0; i<argc; i++)
479 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
481 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
483 HeapFree(GetProcessHeap(),0,ssi);
488 /******************************************************************************
489 * service_handle_get_status
491 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
495 return WriteFile(pipe, &service->status,
496 sizeof service->status, &count, NULL);
499 /******************************************************************************
502 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
504 DWORD cmd[2], count = 0;
507 cmd[0] = WINESERV_GETSTATUS;
509 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
510 if (!r || count != sizeof cmd)
512 ERR("service protocol error - failed to write pipe!\n");
515 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
516 if (!r || count != sizeof *status)
517 ERR("service protocol error - failed to read pipe "
518 "r = %d count = %d!\n", r, count);
522 /******************************************************************************
523 * service_send_control
525 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
527 DWORD cmd[2], count = 0;
530 cmd[0] = WINESERV_SENDCONTROL;
532 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
533 if (!r || count != sizeof cmd)
535 ERR("service protocol error - failed to write pipe!\n");
538 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
539 if (!r || count != sizeof *result)
540 ERR("service protocol error - failed to read pipe "
541 "r = %d count = %d!\n", r, count);
545 /******************************************************************************
546 * service_accepts_control
548 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
550 DWORD a = service->status.dwControlsAccepted;
554 case SERVICE_CONTROL_INTERROGATE:
556 case SERVICE_CONTROL_STOP:
557 if (a&SERVICE_ACCEPT_STOP)
560 case SERVICE_CONTROL_SHUTDOWN:
561 if (a&SERVICE_ACCEPT_SHUTDOWN)
564 case SERVICE_CONTROL_PAUSE:
565 case SERVICE_CONTROL_CONTINUE:
566 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
569 case SERVICE_CONTROL_PARAMCHANGE:
570 if (a&SERVICE_ACCEPT_PARAMCHANGE)
573 case SERVICE_CONTROL_NETBINDADD:
574 case SERVICE_CONTROL_NETBINDREMOVE:
575 case SERVICE_CONTROL_NETBINDENABLE:
576 case SERVICE_CONTROL_NETBINDDISABLE:
577 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
580 if (!service->extended)
584 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
585 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
588 case SERVICE_CONTROL_POWEREVENT:
589 if (a&SERVICE_ACCEPT_POWEREVENT)
592 case SERVICE_CONTROL_SESSIONCHANGE:
593 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
600 /******************************************************************************
601 * service_handle_control
603 static BOOL service_handle_control(HANDLE pipe, service_data *service,
606 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
608 TRACE("received control %d\n", dwControl);
610 if (service_accepts_control(service, dwControl))
612 if (service->extended && service->handler.handler_ex)
614 service->handler.handler_ex(dwControl, 0, NULL, service->context);
617 else if (service->handler.handler)
619 service->handler.handler(dwControl);
623 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
626 /******************************************************************************
627 * service_reap_thread
629 static DWORD service_reap_thread(service_data *service)
633 if (!service->thread)
635 GetExitCodeThread(service->thread, &exitcode);
636 if (exitcode!=STILL_ACTIVE)
638 CloseHandle(service->thread);
644 /******************************************************************************
645 * service_control_dispatcher
647 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
649 service_data *service = arg;
653 TRACE("%p %s\n", service, debugstr_w(service->name));
655 /* create a pipe to talk to the rest of the world with */
656 name = service_get_pipe_name(service->name);
657 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
658 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
661 /* let the process who started us know we've tried to create a pipe */
662 event = service_get_event_handle(service->name);
666 if (pipe==INVALID_HANDLE_VALUE)
668 ERR("failed to create pipe for %s, error = %d\n",
669 debugstr_w(service->name), GetLastError());
673 /* dispatcher loop */
677 DWORD count, req[2] = {0,0};
679 r = ConnectNamedPipe(pipe, NULL);
680 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
682 ERR("pipe connect failed\n");
686 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
687 if (!r || count!=sizeof req)
689 ERR("pipe read failed\n");
693 service_reap_thread(service);
695 /* handle the request */
698 case WINESERV_STARTINFO:
699 service_handle_start(pipe, service, req[1]);
701 case WINESERV_GETSTATUS:
702 service_handle_get_status(pipe, service);
704 case WINESERV_SENDCONTROL:
705 service_handle_control(pipe, service, req[1]);
708 ERR("received invalid command %d length %d\n", req[0], req[1]);
711 FlushFileBuffers(pipe);
712 DisconnectNamedPipe(pipe);
719 /******************************************************************************
720 * service_run_threads
722 static BOOL service_run_threads(void)
724 service_data *service;
725 DWORD count = 0, n = 0;
728 EnterCriticalSection( &service_cs );
730 /* count how many services there are */
731 for (service = service_list; service; service = service->next)
734 TRACE("starting %d pipe listener threads\n", count);
736 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
738 for (n=0, service = service_list; service; service = service->next, n++)
739 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
743 LeaveCriticalSection( &service_cs );
745 /* wait for all the threads to pack up and exit */
746 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
748 HeapFree(GetProcessHeap(), 0, handles);
753 /******************************************************************************
754 * StartServiceCtrlDispatcherA [ADVAPI32.@]
756 * See StartServiceCtrlDispatcherW.
758 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
764 TRACE("%p\n", servent);
766 EnterCriticalSection( &service_cs );
767 while (servent->lpServiceName)
769 LPSTR name = servent->lpServiceName;
771 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
772 sz = len*sizeof(WCHAR) + sizeof *info;
773 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
774 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
775 info->proc.a = servent->lpServiceProc;
776 info->unicode = FALSE;
778 /* insert into the list */
779 info->next = service_list;
784 LeaveCriticalSection( &service_cs );
786 service_run_threads();
791 /******************************************************************************
792 * StartServiceCtrlDispatcherW [ADVAPI32.@]
794 * Connects a process containing one or more services to the service control
798 * servent [I] A list of the service names and service procedures
804 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
810 TRACE("%p\n", servent);
812 EnterCriticalSection( &service_cs );
813 while (servent->lpServiceName)
815 LPWSTR name = servent->lpServiceName;
818 sz = len*sizeof(WCHAR) + sizeof *info;
819 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
820 strcpyW(info->name, name);
821 info->proc.w = servent->lpServiceProc;
822 info->unicode = TRUE;
824 /* insert into the list */
825 info->next = service_list;
830 LeaveCriticalSection( &service_cs );
832 service_run_threads();
837 /******************************************************************************
838 * LockServiceDatabase [ADVAPI32.@]
840 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
844 TRACE("%p\n",hSCManager);
846 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
847 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
851 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
854 TRACE("returning %p\n", ret);
859 /******************************************************************************
860 * UnlockServiceDatabase [ADVAPI32.@]
862 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
864 TRACE("%p\n",ScLock);
866 return CloseHandle( ScLock );
869 /******************************************************************************
870 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
872 SERVICE_STATUS_HANDLE WINAPI
873 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
875 LPWSTR lpServiceNameW;
876 SERVICE_STATUS_HANDLE ret;
878 lpServiceNameW = SERV_dup(lpServiceName);
879 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
880 SERV_free(lpServiceNameW);
884 /******************************************************************************
885 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
891 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
892 LPHANDLER_FUNCTION lpfHandler )
894 service_data *service;
896 EnterCriticalSection( &service_cs );
897 for(service = service_list; service; service = service->next)
898 if(!strcmpW(lpServiceName, service->name))
901 service->handler.handler = lpfHandler;
902 LeaveCriticalSection( &service_cs );
904 return (SERVICE_STATUS_HANDLE)service;
907 /******************************************************************************
908 * SetServiceStatus [ADVAPI32.@]
915 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
917 service_data *service;
920 TRACE("%p %x %x %x %x %x %x %x\n", hService,
921 lpStatus->dwServiceType, lpStatus->dwCurrentState,
922 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
923 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
924 lpStatus->dwWaitHint);
926 EnterCriticalSection( &service_cs );
927 for (service = service_list; service; service = service->next)
928 if(service == (service_data*)hService)
932 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
933 TRACE("Set service status to %d\n",service->status.dwCurrentState);
937 LeaveCriticalSection( &service_cs );
943 /******************************************************************************
944 * OpenSCManagerA [ADVAPI32.@]
946 * Establish a connection to the service control manager and open its database.
949 * lpMachineName [I] Pointer to machine name string
950 * lpDatabaseName [I] Pointer to database name string
951 * dwDesiredAccess [I] Type of access
954 * Success: A Handle to the service control manager database
957 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
958 DWORD dwDesiredAccess )
960 LPWSTR lpMachineNameW, lpDatabaseNameW;
963 lpMachineNameW = SERV_dup(lpMachineName);
964 lpDatabaseNameW = SERV_dup(lpDatabaseName);
965 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
966 SERV_free(lpDatabaseNameW);
967 SERV_free(lpMachineNameW);
971 /******************************************************************************
972 * OpenSCManagerW [ADVAPI32.@]
974 * See OpenSCManagerA.
976 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
977 DWORD dwDesiredAccess )
979 struct sc_manager *manager;
983 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
984 debugstr_w(lpDatabaseName), dwDesiredAccess);
986 if( lpDatabaseName && lpDatabaseName[0] )
988 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
990 /* noop, all right */
992 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
994 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
999 SetLastError( ERROR_INVALID_NAME );
1004 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1005 sc_handle_destroy_manager );
1009 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1010 if (r!=ERROR_SUCCESS)
1013 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1014 RegCloseKey( hReg );
1015 if (r!=ERROR_SUCCESS)
1018 TRACE("returning %p\n", manager);
1020 return (SC_HANDLE) &manager->hdr;
1023 sc_handle_free( &manager->hdr );
1028 /******************************************************************************
1029 * ControlService [ADVAPI32.@]
1031 * Send a control code to a service.
1034 * hService [I] Handle of the service control manager database
1035 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1036 * lpServiceStatus [O] Destination for the status of the service, if available
1043 * Unlike M$' implementation, control requests are not serialized and may be
1044 * processed asynchronously.
1046 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1047 LPSERVICE_STATUS lpServiceStatus )
1049 struct sc_service *hsvc;
1053 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1055 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1058 SetLastError( ERROR_INVALID_HANDLE );
1062 ret = QueryServiceStatus(hService, lpServiceStatus);
1065 ERR("failed to query service status\n");
1066 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1070 switch (lpServiceStatus->dwCurrentState)
1072 case SERVICE_STOPPED:
1073 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1075 case SERVICE_START_PENDING:
1076 if (dwControl==SERVICE_CONTROL_STOP)
1079 case SERVICE_STOP_PENDING:
1080 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1084 handle = service_open_pipe(hsvc->name);
1085 if (handle!=INVALID_HANDLE_VALUE)
1087 DWORD result = ERROR_SUCCESS;
1088 ret = service_send_control(handle, dwControl, &result);
1089 CloseHandle(handle);
1090 if (result!=ERROR_SUCCESS)
1092 SetLastError(result);
1100 /******************************************************************************
1101 * CloseServiceHandle [ADVAPI32.@]
1103 * Close a handle to a service or the service control manager database.
1106 * hSCObject [I] Handle to service or service control manager database
1113 CloseServiceHandle( SC_HANDLE hSCObject )
1115 TRACE("%p\n", hSCObject);
1117 sc_handle_free( (struct sc_handle*) hSCObject );
1123 /******************************************************************************
1124 * OpenServiceA [ADVAPI32.@]
1126 * Open a handle to a service.
1129 * hSCManager [I] Handle of the service control manager database
1130 * lpServiceName [I] Name of the service to open
1131 * dwDesiredAccess [I] Access required to the service
1134 * Success: Handle to the service
1137 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1138 DWORD dwDesiredAccess )
1140 LPWSTR lpServiceNameW;
1143 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1145 lpServiceNameW = SERV_dup(lpServiceName);
1146 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1147 SERV_free(lpServiceNameW);
1152 /******************************************************************************
1153 * OpenServiceW [ADVAPI32.@]
1157 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1158 DWORD dwDesiredAccess)
1160 struct sc_manager *hscm;
1161 struct sc_service *hsvc;
1166 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1170 SetLastError(ERROR_INVALID_ADDRESS);
1174 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1177 SetLastError( ERROR_INVALID_HANDLE );
1181 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1182 if (r!=ERROR_SUCCESS)
1184 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1188 len = strlenW(lpServiceName)+1;
1189 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1190 sizeof (struct sc_service) + len*sizeof(WCHAR),
1191 sc_handle_destroy_service );
1194 strcpyW( hsvc->name, lpServiceName );
1197 /* add reference to SCM handle */
1198 hscm->hdr.ref_count++;
1201 TRACE("returning %p\n",hsvc);
1203 return (SC_HANDLE) &hsvc->hdr;
1206 /******************************************************************************
1207 * CreateServiceW [ADVAPI32.@]
1210 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1211 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1212 DWORD dwServiceType, DWORD dwStartType,
1213 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1214 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1215 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1216 LPCWSTR lpPassword )
1218 struct sc_manager *hscm;
1219 struct sc_service *hsvc = NULL;
1223 struct reg_value val[10];
1226 TRACE("%p %s %s\n", hSCManager,
1227 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1229 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1232 SetLastError( ERROR_INVALID_HANDLE );
1236 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1237 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1238 if (r!=ERROR_SUCCESS)
1241 if (dp != REG_CREATED_NEW_KEY)
1243 SetLastError(ERROR_SERVICE_EXISTS);
1248 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1250 service_set_dword( &val[n++], szType, &dwServiceType );
1251 service_set_dword( &val[n++], szStart, &dwStartType );
1252 service_set_dword( &val[n++], szError, &dwErrorControl );
1254 if( lpBinaryPathName )
1255 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1257 if( lpLoadOrderGroup )
1258 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1260 if( lpDependencies )
1261 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1264 FIXME("Don't know how to add a Password for a service.\n");
1266 if( lpServiceStartName )
1267 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1269 r = service_write_values( hKey, val, n );
1270 if( r != ERROR_SUCCESS )
1273 len = strlenW(lpServiceName)+1;
1274 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1275 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1278 lstrcpyW( hsvc->name, lpServiceName );
1281 hscm->hdr.ref_count++;
1283 return (SC_HANDLE) &hsvc->hdr;
1286 RegCloseKey( hKey );
1291 /******************************************************************************
1292 * CreateServiceA [ADVAPI32.@]
1295 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1296 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1297 DWORD dwServiceType, DWORD dwStartType,
1298 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1299 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1300 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1303 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1304 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1307 TRACE("%p %s %s\n", hSCManager,
1308 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1310 lpServiceNameW = SERV_dup( lpServiceName );
1311 lpDisplayNameW = SERV_dup( lpDisplayName );
1312 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1313 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1314 lpDependenciesW = SERV_dupmulti( lpDependencies );
1315 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1316 lpPasswordW = SERV_dup( lpPassword );
1318 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1319 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1320 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1321 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1323 SERV_free( lpServiceNameW );
1324 SERV_free( lpDisplayNameW );
1325 SERV_free( lpBinaryPathNameW );
1326 SERV_free( lpLoadOrderGroupW );
1327 SERV_free( lpDependenciesW );
1328 SERV_free( lpServiceStartNameW );
1329 SERV_free( lpPasswordW );
1335 /******************************************************************************
1336 * DeleteService [ADVAPI32.@]
1338 * Delete a service from the service control manager database.
1341 * hService [I] Handle of the service to delete
1347 BOOL WINAPI DeleteService( SC_HANDLE hService )
1349 struct sc_service *hsvc;
1351 WCHAR valname[MAX_PATH+1];
1356 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1359 SetLastError( ERROR_INVALID_HANDLE );
1365 /* Clean out the values */
1366 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1367 while (rc == ERROR_SUCCESS)
1369 RegDeleteValueW(hKey,valname);
1372 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1378 /* delete the key */
1379 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1385 /******************************************************************************
1386 * StartServiceA [ADVAPI32.@]
1391 * hService [I] Handle of service
1392 * dwNumServiceArgs [I] Number of arguments
1393 * lpServiceArgVectors [I] Address of array of argument strings
1396 * - NT implements this function using an obscure RPC call.
1397 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1398 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1399 * - This will only work for shared address space. How should the service
1400 * args be transferred when address spaces are separated?
1401 * - Can only start one service at a time.
1402 * - Has no concept of privilege.
1408 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1409 LPCSTR *lpServiceArgVectors )
1411 LPWSTR *lpwstr=NULL;
1415 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1417 if (dwNumServiceArgs)
1418 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1419 dwNumServiceArgs*sizeof(LPWSTR) );
1421 for(i=0; i<dwNumServiceArgs; i++)
1422 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1424 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1426 if (dwNumServiceArgs)
1428 for(i=0; i<dwNumServiceArgs; i++)
1429 SERV_free(lpwstr[i]);
1430 HeapFree(GetProcessHeap(), 0, lpwstr);
1436 /******************************************************************************
1437 * service_start_process [INTERNAL]
1439 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1441 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1442 PROCESS_INFORMATION pi;
1444 LPWSTR path = NULL, str;
1445 DWORD type, size, ret;
1449 /* read the executable path from memory */
1451 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1452 if (ret!=ERROR_SUCCESS)
1454 str = HeapAlloc(GetProcessHeap(),0,size);
1455 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1456 if (ret==ERROR_SUCCESS)
1458 size = ExpandEnvironmentStringsW(str,NULL,0);
1459 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1460 ExpandEnvironmentStringsW(str,path,size);
1462 HeapFree(GetProcessHeap(),0,str);
1466 /* wait for the process to start and set an event or terminate */
1467 handles[0] = service_get_event_handle( hsvc->name );
1468 ZeroMemory(&si, sizeof(STARTUPINFOW));
1469 si.cb = sizeof(STARTUPINFOW);
1470 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1473 if (ppid) *ppid = pi.dwProcessId;
1475 handles[1] = pi.hProcess;
1476 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1477 if(ret != WAIT_OBJECT_0)
1479 SetLastError(ERROR_IO_PENDING);
1483 CloseHandle( pi.hThread );
1484 CloseHandle( pi.hProcess );
1486 CloseHandle( handles[0] );
1487 HeapFree(GetProcessHeap(),0,path);
1491 static BOOL service_wait_for_startup(SC_HANDLE hService)
1494 SERVICE_STATUS status;
1497 TRACE("%p\n", hService);
1499 for (i=0; i<30; i++)
1501 status.dwCurrentState = 0;
1502 r = QueryServiceStatus(hService, &status);
1505 if (status.dwCurrentState == SERVICE_RUNNING)
1507 TRACE("Service started successfully\n");
1516 /******************************************************************************
1517 * StartServiceW [ADVAPI32.@]
1519 * See StartServiceA.
1521 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1522 LPCWSTR *lpServiceArgVectors)
1524 struct sc_service *hsvc;
1528 HANDLE handle = INVALID_HANDLE_VALUE;
1530 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1532 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1535 SetLastError(ERROR_INVALID_HANDLE);
1539 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1543 handle = service_open_pipe(hsvc->name);
1544 if (handle==INVALID_HANDLE_VALUE)
1546 /* start the service process */
1547 if (service_start_process(hsvc, &pid))
1548 handle = service_open_pipe(hsvc->name);
1551 if (handle != INVALID_HANDLE_VALUE)
1553 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1554 CloseHandle(handle);
1558 UnlockServiceDatabase( hLock );
1560 TRACE("returning %d\n", r);
1563 service_wait_for_startup(hService);
1568 /******************************************************************************
1569 * QueryServiceStatus [ADVAPI32.@]
1572 * hService [I] Handle to service to get information about
1573 * lpservicestatus [O] buffer to receive the status information for the service
1576 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1577 LPSERVICE_STATUS lpservicestatus)
1579 SERVICE_STATUS_PROCESS SvcStatusData;
1582 TRACE("%p %p\n", hService, lpservicestatus);
1584 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1585 sizeof(SERVICE_STATUS_PROCESS), NULL);
1586 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1591 /******************************************************************************
1592 * QueryServiceStatusEx [ADVAPI32.@]
1594 * Get information about a service.
1597 * hService [I] Handle to service to get information about
1598 * InfoLevel [I] Level of information to get
1599 * lpBuffer [O] Destination for requested information
1600 * cbBufSize [I] Size of lpBuffer in bytes
1601 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1607 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1608 LPBYTE lpBuffer, DWORD cbBufSize,
1609 LPDWORD pcbBytesNeeded)
1611 struct sc_service *hsvc;
1612 DWORD size, type, val;
1615 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1617 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1619 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1621 SetLastError( ERROR_INVALID_LEVEL);
1625 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1626 if (pSvcStatusData == NULL)
1628 SetLastError( ERROR_INVALID_PARAMETER);
1632 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1634 if( pcbBytesNeeded != NULL)
1635 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1637 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1641 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1644 SetLastError( ERROR_INVALID_HANDLE );
1648 pipe = service_open_pipe(hsvc->name);
1649 if (pipe != INVALID_HANDLE_VALUE)
1651 r = service_get_status(pipe, pSvcStatusData);
1657 TRACE("Failed to read service status\n");
1659 /* read the service type from the registry */
1661 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1662 if (r != ERROR_SUCCESS || type != REG_DWORD)
1665 pSvcStatusData->dwServiceType = val;
1666 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1667 pSvcStatusData->dwControlsAccepted = 0;
1668 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1669 pSvcStatusData->dwServiceSpecificExitCode = 0;
1670 pSvcStatusData->dwCheckPoint = 0;
1671 pSvcStatusData->dwWaitHint = 0;
1676 /******************************************************************************
1677 * QueryServiceConfigA [ADVAPI32.@]
1679 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1680 DWORD size, LPDWORD needed )
1685 QUERY_SERVICE_CONFIGW *configW;
1687 TRACE("%p %p %d %p\n", hService, config, size, needed);
1689 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1691 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1694 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1695 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1696 if (!ret) goto done;
1698 config->dwServiceType = configW->dwServiceType;
1699 config->dwStartType = configW->dwStartType;
1700 config->dwErrorControl = configW->dwErrorControl;
1701 config->lpBinaryPathName = NULL;
1702 config->lpLoadOrderGroup = NULL;
1703 config->dwTagId = configW->dwTagId;
1704 config->lpDependencies = NULL;
1705 config->lpServiceStartName = NULL;
1706 config->lpDisplayName = NULL;
1708 p = (LPSTR)(config + 1);
1709 n = size - sizeof(*config);
1712 #define MAP_STR(str) \
1716 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1717 if (!sz) goto done; \
1724 MAP_STR( lpBinaryPathName );
1725 MAP_STR( lpLoadOrderGroup );
1726 MAP_STR( lpDependencies );
1727 MAP_STR( lpServiceStartName );
1728 MAP_STR( lpDisplayName );
1731 *needed = p - buffer;
1735 HeapFree( GetProcessHeap(), 0, buffer );
1739 /******************************************************************************
1740 * QueryServiceConfigW [ADVAPI32.@]
1743 QueryServiceConfigW( SC_HANDLE hService,
1744 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1745 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1747 WCHAR str_buffer[ MAX_PATH ];
1749 DWORD type, val, sz, total, n;
1752 struct sc_service *hsvc;
1754 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1755 cbBufSize, pcbBytesNeeded);
1757 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1760 SetLastError( ERROR_INVALID_HANDLE );
1765 /* calculate the size required first */
1766 total = sizeof (QUERY_SERVICE_CONFIGW);
1768 sz = sizeof(str_buffer);
1769 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1770 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1772 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1773 if( 0 == sz ) return FALSE;
1775 total += sizeof(WCHAR) * sz;
1779 /* FIXME: set last error */
1784 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1785 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1789 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1790 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1793 total += sizeof(WCHAR);
1796 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1797 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1801 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1802 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1805 *pcbBytesNeeded = total;
1807 /* if there's not enough memory, return an error */
1808 if( total > cbBufSize )
1810 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1814 ZeroMemory( lpServiceConfig, total );
1817 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1818 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1819 lpServiceConfig->dwServiceType = val;
1822 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1823 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1824 lpServiceConfig->dwStartType = val;
1827 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1828 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1829 lpServiceConfig->dwErrorControl = val;
1831 /* now do the strings */
1832 p = (LPBYTE) &lpServiceConfig[1];
1833 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1835 sz = sizeof(str_buffer);
1836 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1837 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1839 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1840 sz *= sizeof(WCHAR);
1841 if( 0 == sz || sz > n ) return FALSE;
1843 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1849 /* FIXME: set last error */
1854 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1855 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1857 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1863 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1864 lpServiceConfig->lpDependencies = (LPWSTR) p;
1865 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1878 ERR("Buffer overflow!\n");
1880 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1881 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1886 /******************************************************************************
1887 * EnumServicesStatusA [ADVAPI32.@]
1890 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1891 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1892 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1893 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1895 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1896 dwServiceType, dwServiceState, lpServices, cbBufSize,
1897 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1898 SetLastError (ERROR_ACCESS_DENIED);
1902 /******************************************************************************
1903 * EnumServicesStatusW [ADVAPI32.@]
1906 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1907 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1908 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1909 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1911 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1912 dwServiceType, dwServiceState, lpServices, cbBufSize,
1913 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1914 SetLastError (ERROR_ACCESS_DENIED);
1918 /******************************************************************************
1919 * EnumServicesStatusExA [ADVAPI32.@]
1922 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1923 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1924 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1926 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1927 dwServiceType, dwServiceState, lpServices, cbBufSize,
1928 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1929 SetLastError (ERROR_ACCESS_DENIED);
1933 /******************************************************************************
1934 * EnumServicesStatusExW [ADVAPI32.@]
1937 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1938 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1939 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1941 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1942 dwServiceType, dwServiceState, lpServices, cbBufSize,
1943 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
1944 SetLastError (ERROR_ACCESS_DENIED);
1948 /******************************************************************************
1949 * GetServiceKeyNameA [ADVAPI32.@]
1951 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1952 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1954 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1958 /******************************************************************************
1959 * GetServiceKeyNameW [ADVAPI32.@]
1961 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1962 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1964 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1968 /******************************************************************************
1969 * QueryServiceLockStatusA [ADVAPI32.@]
1971 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1972 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1973 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1975 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1980 /******************************************************************************
1981 * QueryServiceLockStatusW [ADVAPI32.@]
1983 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1984 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1985 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1987 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1992 /******************************************************************************
1993 * GetServiceDisplayNameA [ADVAPI32.@]
1995 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1996 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1998 FIXME("%p %s %p %p\n", hSCManager,
1999 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2003 /******************************************************************************
2004 * GetServiceDisplayNameW [ADVAPI32.@]
2006 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2007 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2009 FIXME("%p %s %p %p\n", hSCManager,
2010 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2014 /******************************************************************************
2015 * ChangeServiceConfigW [ADVAPI32.@]
2017 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2018 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2019 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2020 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2022 struct reg_value val[10];
2023 struct sc_service *hsvc;
2024 DWORD r = ERROR_SUCCESS;
2028 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2029 hService, dwServiceType, dwStartType, dwErrorControl,
2030 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2031 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2032 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2034 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2037 SetLastError( ERROR_INVALID_HANDLE );
2042 if( dwServiceType != SERVICE_NO_CHANGE )
2043 service_set_dword( &val[n++], szType, &dwServiceType );
2045 if( dwStartType != SERVICE_NO_CHANGE )
2046 service_set_dword( &val[n++], szStart, &dwStartType );
2048 if( dwErrorControl != SERVICE_NO_CHANGE )
2049 service_set_dword( &val[n++], szError, &dwErrorControl );
2051 if( lpBinaryPathName )
2052 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2054 if( lpLoadOrderGroup )
2055 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2057 if( lpDependencies )
2058 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2061 FIXME("ignoring password\n");
2063 if( lpServiceStartName )
2064 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2066 r = service_write_values( hsvc->hkey, val, n );
2068 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2071 /******************************************************************************
2072 * ChangeServiceConfigA [ADVAPI32.@]
2074 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2075 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2076 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2077 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2079 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2080 LPWSTR wServiceStartName, wPassword, wDisplayName;
2083 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2084 hService, dwServiceType, dwStartType, dwErrorControl,
2085 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2086 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2087 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2089 wBinaryPathName = SERV_dup( lpBinaryPathName );
2090 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2091 wDependencies = SERV_dupmulti( lpDependencies );
2092 wServiceStartName = SERV_dup( lpServiceStartName );
2093 wPassword = SERV_dup( lpPassword );
2094 wDisplayName = SERV_dup( lpDisplayName );
2096 r = ChangeServiceConfigW( hService, dwServiceType,
2097 dwStartType, dwErrorControl, wBinaryPathName,
2098 wLoadOrderGroup, lpdwTagId, wDependencies,
2099 wServiceStartName, wPassword, wDisplayName);
2101 SERV_free( wBinaryPathName );
2102 SERV_free( wLoadOrderGroup );
2103 SERV_free( wDependencies );
2104 SERV_free( wServiceStartName );
2105 SERV_free( wPassword );
2106 SERV_free( wDisplayName );
2111 /******************************************************************************
2112 * ChangeServiceConfig2A [ADVAPI32.@]
2114 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2119 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2121 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2123 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2124 SERVICE_DESCRIPTIONW sdw;
2126 sdw.lpDescription = SERV_dup( sd->lpDescription );
2128 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2130 SERV_free( sdw.lpDescription );
2132 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2134 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2135 SERVICE_FAILURE_ACTIONSW faw;
2137 faw.dwResetPeriod = fa->dwResetPeriod;
2138 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2139 faw.lpCommand = SERV_dup( fa->lpCommand );
2140 faw.cActions = fa->cActions;
2141 faw.lpsaActions = fa->lpsaActions;
2143 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2145 SERV_free( faw.lpRebootMsg );
2146 SERV_free( faw.lpCommand );
2149 SetLastError( ERROR_INVALID_PARAMETER );
2154 /******************************************************************************
2155 * ChangeServiceConfig2W [ADVAPI32.@]
2157 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2161 struct sc_service *hsvc;
2163 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2166 SetLastError( ERROR_INVALID_HANDLE );
2171 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2173 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2174 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2175 if (sd->lpDescription)
2177 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2178 if (sd->lpDescription[0] == 0)
2179 RegDeleteValueW(hKey,szDescription);
2181 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2182 (LPVOID)sd->lpDescription,
2183 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2187 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2191 /******************************************************************************
2192 * QueryServiceObjectSecurity [ADVAPI32.@]
2194 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2195 SECURITY_INFORMATION dwSecurityInformation,
2196 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2197 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2201 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2202 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2204 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2206 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2207 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2208 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2212 /******************************************************************************
2213 * SetServiceObjectSecurity [ADVAPI32.@]
2215 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2216 SECURITY_INFORMATION dwSecurityInformation,
2217 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2219 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2223 /******************************************************************************
2224 * SetServiceBits [ADVAPI32.@]
2226 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2227 DWORD dwServiceBits,
2229 BOOL bUpdateImmediately)
2231 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2232 bSetBitsOn, bUpdateImmediately);
2236 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2237 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2239 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2243 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2244 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2246 service_data *service;
2248 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2250 EnterCriticalSection( &service_cs );
2251 for(service = service_list; service; service = service->next)
2252 if(!strcmpW(lpServiceName, service->name))
2256 service->handler.handler_ex = lpHandlerProc;
2257 service->context = lpContext;
2258 service->extended = TRUE;
2260 LeaveCriticalSection( &service_cs );
2262 return (SERVICE_STATUS_HANDLE)service;