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 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, 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 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(LPWSTR 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(LPWSTR 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(LPWSTR 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, 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 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(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( LPSERVICE_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( LPSERVICE_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 = RegOpenKeyExW(hReg, szServiceManagerKey,
1014 0, KEY_ALL_ACCESS, &manager->hkey);
1015 RegCloseKey( hReg );
1016 if (r!=ERROR_SUCCESS)
1019 TRACE("returning %p\n", manager);
1021 return (SC_HANDLE) &manager->hdr;
1024 sc_handle_free( &manager->hdr );
1029 /******************************************************************************
1030 * ControlService [ADVAPI32.@]
1032 * Send a control code to a service.
1035 * hService [I] Handle of the service control manager database
1036 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1037 * lpServiceStatus [O] Destination for the status of the service, if available
1044 * Unlike M$' implementation, control requests are not serialized and may be
1045 * processed asynchronously.
1047 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1048 LPSERVICE_STATUS lpServiceStatus )
1050 struct sc_service *hsvc;
1054 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1056 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1059 SetLastError( ERROR_INVALID_HANDLE );
1063 ret = QueryServiceStatus(hService, lpServiceStatus);
1066 ERR("failed to query service status\n");
1067 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1071 switch (lpServiceStatus->dwCurrentState)
1073 case SERVICE_STOPPED:
1074 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1076 case SERVICE_START_PENDING:
1077 if (dwControl==SERVICE_CONTROL_STOP)
1080 case SERVICE_STOP_PENDING:
1081 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1085 handle = service_open_pipe(hsvc->name);
1086 if (handle!=INVALID_HANDLE_VALUE)
1088 DWORD result = ERROR_SUCCESS;
1089 ret = service_send_control(handle, dwControl, &result);
1090 CloseHandle(handle);
1091 if (result!=ERROR_SUCCESS)
1093 SetLastError(result);
1101 /******************************************************************************
1102 * CloseServiceHandle [ADVAPI32.@]
1104 * Close a handle to a service or the service control manager database.
1107 * hSCObject [I] Handle to service or service control manager database
1114 CloseServiceHandle( SC_HANDLE hSCObject )
1116 TRACE("%p\n", hSCObject);
1118 sc_handle_free( (struct sc_handle*) hSCObject );
1124 /******************************************************************************
1125 * OpenServiceA [ADVAPI32.@]
1127 * Open a handle to a service.
1130 * hSCManager [I] Handle of the service control manager database
1131 * lpServiceName [I] Name of the service to open
1132 * dwDesiredAccess [I] Access required to the service
1135 * Success: Handle to the service
1138 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1139 DWORD dwDesiredAccess )
1141 LPWSTR lpServiceNameW;
1144 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1146 lpServiceNameW = SERV_dup(lpServiceName);
1147 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1148 SERV_free(lpServiceNameW);
1153 /******************************************************************************
1154 * OpenServiceW [ADVAPI32.@]
1158 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1159 DWORD dwDesiredAccess)
1161 struct sc_manager *hscm;
1162 struct sc_service *hsvc;
1167 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1171 SetLastError(ERROR_INVALID_ADDRESS);
1175 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1178 SetLastError( ERROR_INVALID_HANDLE );
1182 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1183 if (r!=ERROR_SUCCESS)
1185 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1189 len = strlenW(lpServiceName)+1;
1190 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1191 sizeof (struct sc_service) + len*sizeof(WCHAR),
1192 sc_handle_destroy_service );
1195 strcpyW( hsvc->name, lpServiceName );
1198 /* add reference to SCM handle */
1199 hscm->hdr.ref_count++;
1202 TRACE("returning %p\n",hsvc);
1204 return (SC_HANDLE) &hsvc->hdr;
1207 /******************************************************************************
1208 * CreateServiceW [ADVAPI32.@]
1211 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1212 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1213 DWORD dwServiceType, DWORD dwStartType,
1214 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1215 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1216 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1217 LPCWSTR lpPassword )
1219 struct sc_manager *hscm;
1220 struct sc_service *hsvc = NULL;
1224 struct reg_value val[10];
1227 TRACE("%p %s %s\n", hSCManager,
1228 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1230 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1233 SetLastError( ERROR_INVALID_HANDLE );
1237 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1238 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1239 if (r!=ERROR_SUCCESS)
1242 if (dp != REG_CREATED_NEW_KEY)
1244 SetLastError(ERROR_SERVICE_EXISTS);
1249 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1251 service_set_dword( &val[n++], szType, &dwServiceType );
1252 service_set_dword( &val[n++], szStart, &dwStartType );
1253 service_set_dword( &val[n++], szError, &dwErrorControl );
1255 if( lpBinaryPathName )
1256 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1258 if( lpLoadOrderGroup )
1259 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1261 if( lpDependencies )
1262 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1265 FIXME("Don't know how to add a Password for a service.\n");
1267 if( lpServiceStartName )
1268 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1270 r = service_write_values( hKey, val, n );
1271 if( r != ERROR_SUCCESS )
1274 len = strlenW(lpServiceName)+1;
1275 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1276 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1279 lstrcpyW( hsvc->name, lpServiceName );
1282 hscm->hdr.ref_count++;
1284 return (SC_HANDLE) &hsvc->hdr;
1287 RegCloseKey( hKey );
1292 /******************************************************************************
1293 * CreateServiceA [ADVAPI32.@]
1296 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1297 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1298 DWORD dwServiceType, DWORD dwStartType,
1299 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1300 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1301 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1304 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1305 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1308 TRACE("%p %s %s\n", hSCManager,
1309 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1311 lpServiceNameW = SERV_dup( lpServiceName );
1312 lpDisplayNameW = SERV_dup( lpDisplayName );
1313 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1314 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1315 lpDependenciesW = SERV_dupmulti( lpDependencies );
1316 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1317 lpPasswordW = SERV_dup( lpPassword );
1319 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1320 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1321 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1322 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1324 SERV_free( lpServiceNameW );
1325 SERV_free( lpDisplayNameW );
1326 SERV_free( lpBinaryPathNameW );
1327 SERV_free( lpLoadOrderGroupW );
1328 SERV_free( lpDependenciesW );
1329 SERV_free( lpServiceStartNameW );
1330 SERV_free( lpPasswordW );
1336 /******************************************************************************
1337 * DeleteService [ADVAPI32.@]
1339 * Delete a service from the service control manager database.
1342 * hService [I] Handle of the service to delete
1348 BOOL WINAPI DeleteService( SC_HANDLE hService )
1350 struct sc_service *hsvc;
1352 WCHAR valname[MAX_PATH+1];
1357 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1360 SetLastError( ERROR_INVALID_HANDLE );
1366 /* Clean out the values */
1367 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1368 while (rc == ERROR_SUCCESS)
1370 RegDeleteValueW(hKey,valname);
1373 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1379 /* delete the key */
1380 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1386 /******************************************************************************
1387 * StartServiceA [ADVAPI32.@]
1392 * hService [I] Handle of service
1393 * dwNumServiceArgs [I] Number of arguments
1394 * lpServiceArgVectors [I] Address of array of argument strings
1397 * - NT implements this function using an obscure RPC call.
1398 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1399 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1400 * - This will only work for shared address space. How should the service
1401 * args be transferred when address spaces are separated?
1402 * - Can only start one service at a time.
1403 * - Has no concept of privilege.
1409 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1410 LPCSTR *lpServiceArgVectors )
1412 LPWSTR *lpwstr=NULL;
1416 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1418 if (dwNumServiceArgs)
1419 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1420 dwNumServiceArgs*sizeof(LPWSTR) );
1422 for(i=0; i<dwNumServiceArgs; i++)
1423 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1425 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1427 if (dwNumServiceArgs)
1429 for(i=0; i<dwNumServiceArgs; i++)
1430 SERV_free(lpwstr[i]);
1431 HeapFree(GetProcessHeap(), 0, lpwstr);
1437 /******************************************************************************
1438 * service_start_process [INTERNAL]
1440 static DWORD service_start_process(struct sc_service *hsvc)
1442 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1443 PROCESS_INFORMATION pi;
1445 LPWSTR path = NULL, str;
1446 DWORD type, size, ret;
1450 /* read the executable path from memory */
1452 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1453 if (ret!=ERROR_SUCCESS)
1455 str = HeapAlloc(GetProcessHeap(),0,size);
1456 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1457 if (ret==ERROR_SUCCESS)
1459 size = ExpandEnvironmentStringsW(str,NULL,0);
1460 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1461 ExpandEnvironmentStringsW(str,path,size);
1463 HeapFree(GetProcessHeap(),0,str);
1467 /* wait for the process to start and set an event or terminate */
1468 handles[0] = service_get_event_handle( hsvc->name );
1469 ZeroMemory(&si, sizeof(STARTUPINFOW));
1470 si.cb = sizeof(STARTUPINFOW);
1471 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1474 handles[1] = pi.hProcess;
1475 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1476 if(ret != WAIT_OBJECT_0)
1478 SetLastError(ERROR_IO_PENDING);
1482 CloseHandle( pi.hThread );
1483 CloseHandle( pi.hProcess );
1485 CloseHandle( handles[0] );
1486 HeapFree(GetProcessHeap(),0,path);
1490 static BOOL service_wait_for_startup(SC_HANDLE hService)
1493 SERVICE_STATUS status;
1496 TRACE("%p\n", hService);
1498 for (i=0; i<30; i++)
1500 status.dwCurrentState = 0;
1501 r = QueryServiceStatus(hService, &status);
1504 if (status.dwCurrentState == SERVICE_RUNNING)
1506 TRACE("Service started successfully\n");
1515 /******************************************************************************
1516 * StartServiceW [ADVAPI32.@]
1518 * See StartServiceA.
1520 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1521 LPCWSTR *lpServiceArgVectors)
1523 struct sc_service *hsvc;
1526 HANDLE handle = INVALID_HANDLE_VALUE;
1528 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1530 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1533 SetLastError(ERROR_INVALID_HANDLE);
1537 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1541 handle = service_open_pipe(hsvc->name);
1542 if (handle==INVALID_HANDLE_VALUE)
1544 /* start the service process */
1545 if (service_start_process(hsvc))
1546 handle = service_open_pipe(hsvc->name);
1549 if (handle != INVALID_HANDLE_VALUE)
1551 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1552 CloseHandle(handle);
1556 UnlockServiceDatabase( hLock );
1558 TRACE("returning %d\n", r);
1561 service_wait_for_startup(hService);
1566 /******************************************************************************
1567 * QueryServiceStatus [ADVAPI32.@]
1571 * lpservicestatus []
1574 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1575 LPSERVICE_STATUS lpservicestatus)
1577 struct sc_service *hsvc;
1578 DWORD size, type, val;
1582 TRACE("%p %p\n", hService, lpservicestatus);
1584 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1587 SetLastError( ERROR_INVALID_HANDLE );
1591 pipe = service_open_pipe(hsvc->name);
1592 if (pipe != INVALID_HANDLE_VALUE)
1594 r = service_get_status(pipe, lpservicestatus);
1600 TRACE("Failed to read service status\n");
1602 /* read the service type from the registry */
1604 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1605 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1608 lpservicestatus->dwServiceType = val;
1609 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1610 lpservicestatus->dwControlsAccepted = 0;
1611 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1612 lpservicestatus->dwServiceSpecificExitCode = 0;
1613 lpservicestatus->dwCheckPoint = 0;
1614 lpservicestatus->dwWaitHint = 0;
1619 /******************************************************************************
1620 * QueryServiceStatusEx [ADVAPI32.@]
1622 * Get information about a service.
1625 * hService [I] Handle to service to get information about
1626 * InfoLevel [I] Level of information to get
1627 * lpBuffer [O] Destination for requested information
1628 * cbBufSize [I] Size of lpBuffer in bytes
1629 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1635 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1636 LPBYTE lpBuffer, DWORD cbBufSize,
1637 LPDWORD pcbBytesNeeded)
1640 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1644 /******************************************************************************
1645 * QueryServiceConfigA [ADVAPI32.@]
1648 QueryServiceConfigA( SC_HANDLE hService,
1649 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1650 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1652 static const CHAR szDisplayName[] = "DisplayName";
1653 static const CHAR szType[] = "Type";
1654 static const CHAR szStart[] = "Start";
1655 static const CHAR szError[] = "ErrorControl";
1656 static const CHAR szImagePath[] = "ImagePath";
1657 static const CHAR szGroup[] = "Group";
1658 static const CHAR szDependencies[] = "Dependencies";
1659 struct sc_service *hsvc;
1661 CHAR str_buffer[ MAX_PATH ];
1663 DWORD type, val, sz, total, n;
1666 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1667 cbBufSize, pcbBytesNeeded);
1669 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1672 SetLastError( ERROR_INVALID_HANDLE );
1677 /* calculate the size required first */
1678 total = sizeof (QUERY_SERVICE_CONFIGA);
1680 sz = sizeof(str_buffer);
1681 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1682 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1684 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1685 if( 0 == sz ) return FALSE;
1691 /* FIXME: set last error */
1696 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1697 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1701 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1702 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1706 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1707 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1711 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1712 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1715 *pcbBytesNeeded = total;
1717 /* if there's not enough memory, return an error */
1718 if( total > cbBufSize )
1720 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1724 ZeroMemory( lpServiceConfig, total );
1727 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1728 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1729 lpServiceConfig->dwServiceType = val;
1732 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1733 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1734 lpServiceConfig->dwStartType = val;
1737 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1738 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1739 lpServiceConfig->dwErrorControl = val;
1741 /* now do the strings */
1742 p = (LPSTR) &lpServiceConfig[1];
1743 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1745 sz = sizeof(str_buffer);
1746 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1747 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1749 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1750 if( 0 == sz || sz > n ) return FALSE;
1752 lpServiceConfig->lpBinaryPathName = p;
1758 /* FIXME: set last error */
1763 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1764 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1766 lpServiceConfig->lpLoadOrderGroup = p;
1772 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1773 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1775 lpServiceConfig->lpDependencies = p;
1781 ERR("Buffer overflow!\n");
1783 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1784 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1789 /******************************************************************************
1790 * QueryServiceConfigW [ADVAPI32.@]
1793 QueryServiceConfigW( SC_HANDLE hService,
1794 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1795 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1797 WCHAR str_buffer[ MAX_PATH ];
1799 DWORD type, val, sz, total, n;
1802 struct sc_service *hsvc;
1804 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1805 cbBufSize, pcbBytesNeeded);
1807 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1810 SetLastError( ERROR_INVALID_HANDLE );
1815 /* calculate the size required first */
1816 total = sizeof (QUERY_SERVICE_CONFIGW);
1818 sz = sizeof(str_buffer);
1819 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1820 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1822 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1823 if( 0 == sz ) return FALSE;
1825 total += sizeof(WCHAR) * sz;
1829 /* FIXME: set last error */
1834 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1835 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1839 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1840 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1843 total += sizeof(WCHAR);
1846 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1847 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1851 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1852 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1855 *pcbBytesNeeded = total;
1857 /* if there's not enough memory, return an error */
1858 if( total > cbBufSize )
1860 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1864 ZeroMemory( lpServiceConfig, total );
1867 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1868 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1869 lpServiceConfig->dwServiceType = val;
1872 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1873 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1874 lpServiceConfig->dwStartType = val;
1877 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1878 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1879 lpServiceConfig->dwErrorControl = val;
1881 /* now do the strings */
1882 p = (LPBYTE) &lpServiceConfig[1];
1883 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1885 sz = sizeof(str_buffer);
1886 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1887 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1889 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1890 sz *= sizeof(WCHAR);
1891 if( 0 == sz || sz > n ) return FALSE;
1893 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1899 /* FIXME: set last error */
1904 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1905 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1907 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1913 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1914 lpServiceConfig->lpDependencies = (LPWSTR) p;
1915 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1928 ERR("Buffer overflow!\n");
1930 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1931 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1936 /******************************************************************************
1937 * EnumServicesStatusA [ADVAPI32.@]
1940 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1941 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1942 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1943 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1945 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1946 dwServiceType, dwServiceState, lpServices, cbBufSize,
1947 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1948 SetLastError (ERROR_ACCESS_DENIED);
1952 /******************************************************************************
1953 * EnumServicesStatusW [ADVAPI32.@]
1956 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1957 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1958 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1959 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1961 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1962 dwServiceType, dwServiceState, lpServices, cbBufSize,
1963 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1964 SetLastError (ERROR_ACCESS_DENIED);
1968 /******************************************************************************
1969 * GetServiceKeyNameA [ADVAPI32.@]
1971 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1972 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1974 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1978 /******************************************************************************
1979 * GetServiceKeyNameW [ADVAPI32.@]
1981 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1982 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1984 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1988 /******************************************************************************
1989 * QueryServiceLockStatusA [ADVAPI32.@]
1991 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1992 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1993 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1995 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2000 /******************************************************************************
2001 * QueryServiceLockStatusW [ADVAPI32.@]
2003 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2004 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2005 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2007 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2012 /******************************************************************************
2013 * GetServiceDisplayNameA [ADVAPI32.@]
2015 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2016 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2018 FIXME("%p %s %p %p\n", hSCManager,
2019 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2023 /******************************************************************************
2024 * GetServiceDisplayNameW [ADVAPI32.@]
2026 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2027 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2029 FIXME("%p %s %p %p\n", hSCManager,
2030 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2034 /******************************************************************************
2035 * ChangeServiceConfigW [ADVAPI32.@]
2037 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2038 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2039 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2040 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2042 struct reg_value val[10];
2043 struct sc_service *hsvc;
2044 DWORD r = ERROR_SUCCESS;
2048 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2049 hService, dwServiceType, dwStartType, dwErrorControl,
2050 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2051 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2052 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2054 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2057 SetLastError( ERROR_INVALID_HANDLE );
2062 if( dwServiceType != SERVICE_NO_CHANGE )
2063 service_set_dword( &val[n++], szType, &dwServiceType );
2065 if( dwStartType != SERVICE_NO_CHANGE )
2066 service_set_dword( &val[n++], szStart, &dwStartType );
2068 if( dwErrorControl != SERVICE_NO_CHANGE )
2069 service_set_dword( &val[n++], szError, &dwErrorControl );
2071 if( lpBinaryPathName )
2072 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2074 if( lpLoadOrderGroup )
2075 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2077 if( lpDependencies )
2078 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2081 FIXME("ignoring password\n");
2083 if( lpServiceStartName )
2084 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2086 r = service_write_values( hsvc->hkey, val, n );
2088 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2091 /******************************************************************************
2092 * ChangeServiceConfigA [ADVAPI32.@]
2094 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2095 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2096 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2097 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2099 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2100 LPWSTR wServiceStartName, wPassword, wDisplayName;
2103 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2104 hService, dwServiceType, dwStartType, dwErrorControl,
2105 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2106 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2107 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2109 wBinaryPathName = SERV_dup( lpBinaryPathName );
2110 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2111 wDependencies = SERV_dupmulti( lpDependencies );
2112 wServiceStartName = SERV_dup( lpServiceStartName );
2113 wPassword = SERV_dup( lpPassword );
2114 wDisplayName = SERV_dup( lpDisplayName );
2116 r = ChangeServiceConfigW( hService, dwServiceType,
2117 dwStartType, dwErrorControl, wBinaryPathName,
2118 wLoadOrderGroup, lpdwTagId, wDependencies,
2119 wServiceStartName, wPassword, wDisplayName);
2121 SERV_free( wBinaryPathName );
2122 SERV_free( wLoadOrderGroup );
2123 SERV_free( wDependencies );
2124 SERV_free( wServiceStartName );
2125 SERV_free( wPassword );
2126 SERV_free( wDisplayName );
2131 /******************************************************************************
2132 * ChangeServiceConfig2A [ADVAPI32.@]
2134 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2139 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2141 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2143 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2144 SERVICE_DESCRIPTIONW sdw;
2146 sdw.lpDescription = SERV_dup( sd->lpDescription );
2148 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2150 SERV_free( sdw.lpDescription );
2152 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2154 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2155 SERVICE_FAILURE_ACTIONSW faw;
2157 faw.dwResetPeriod = fa->dwResetPeriod;
2158 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2159 faw.lpCommand = SERV_dup( fa->lpCommand );
2160 faw.cActions = fa->cActions;
2161 faw.lpsaActions = fa->lpsaActions;
2163 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2165 SERV_free( faw.lpRebootMsg );
2166 SERV_free( faw.lpCommand );
2169 SetLastError( ERROR_INVALID_PARAMETER );
2174 /******************************************************************************
2175 * ChangeServiceConfig2W [ADVAPI32.@]
2177 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2181 struct sc_service *hsvc;
2183 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2186 SetLastError( ERROR_INVALID_HANDLE );
2191 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2193 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2194 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2195 if (sd->lpDescription)
2197 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2198 if (sd->lpDescription[0] == 0)
2199 RegDeleteValueW(hKey,szDescription);
2201 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2202 (LPVOID)sd->lpDescription,
2203 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2207 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2211 /******************************************************************************
2212 * QueryServiceObjectSecurity [ADVAPI32.@]
2214 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2215 SECURITY_INFORMATION dwSecurityInformation,
2216 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2217 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2221 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2222 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2224 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2226 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2227 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2228 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2232 /******************************************************************************
2233 * SetServiceObjectSecurity [ADVAPI32.@]
2235 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2236 SECURITY_INFORMATION dwSecurityInformation,
2237 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2239 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2243 /******************************************************************************
2244 * SetServiceBits [ADVAPI32.@]
2246 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2247 DWORD dwServiceBits,
2249 BOOL bUpdateImmediately)
2251 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2252 bSetBitsOn, bUpdateImmediately);
2256 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2257 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2259 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2263 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2264 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2266 service_data *service;
2268 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2270 EnterCriticalSection( &service_cs );
2271 for(service = service_list; service; service = service->next)
2272 if(!strcmpW(lpServiceName, service->name))
2276 service->handler.handler_ex = lpHandlerProc;
2277 service->context = lpContext;
2278 service->extended = TRUE;
2280 LeaveCriticalSection( &service_cs );
2282 return (SERVICE_STATUS_HANDLE)service;