2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
40 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
41 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
42 'S','e','r','v','i','c','e','s','\\',0 };
43 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
46 typedef struct service_start_info_t
53 #define WINESERV_STARTINFO 1
54 #define WINESERV_GETSTATUS 2
55 #define WINESERV_SENDCONTROL 3
57 typedef struct service_data_t
59 struct service_data_t *next;
60 LPHANDLER_FUNCTION handler;
61 SERVICE_STATUS status;
65 LPSERVICE_MAIN_FUNCTIONA a;
66 LPSERVICE_MAIN_FUNCTIONW w;
72 static CRITICAL_SECTION service_cs;
73 static CRITICAL_SECTION_DEBUG service_cs_debug =
76 { &service_cs_debug.ProcessLocksList,
77 &service_cs_debug.ProcessLocksList },
78 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
80 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
82 service_data *service_list;
84 /******************************************************************************
88 #define MAX_SERVICE_NAME 256
90 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
93 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
99 sc_handle_destructor destroy;
102 struct sc_manager /* service control manager handle */
104 struct sc_handle hdr;
105 HKEY hkey; /* handle to services database in the registry */
108 struct sc_service /* service handle */
110 struct sc_handle hdr;
111 HKEY hkey; /* handle to service entry in the registry (under hkey) */
112 struct sc_manager *scm; /* pointer to SCM handle */
116 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
117 sc_handle_destructor destroy)
119 struct sc_handle *hdr;
121 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
126 hdr->destroy = destroy;
128 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
132 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
134 struct sc_handle *hdr = (struct sc_handle *) handle;
138 if (hdr->htype != htype)
143 static void sc_handle_free(struct sc_handle* hdr)
147 if (--hdr->ref_count)
150 HeapFree(GetProcessHeap(), 0, hdr);
153 static void sc_handle_destroy_manager(struct sc_handle *handle)
155 struct sc_manager *mgr = (struct sc_manager*) handle;
157 TRACE("destroying SC Manager %p\n", mgr);
159 RegCloseKey(mgr->hkey);
162 static void sc_handle_destroy_service(struct sc_handle *handle)
164 struct sc_service *svc = (struct sc_service*) handle;
166 TRACE("destroying service %p\n", svc);
168 RegCloseKey(svc->hkey);
170 sc_handle_free(&svc->scm->hdr);
174 /******************************************************************************
175 * String management functions
177 static inline LPWSTR SERV_dup( LPCSTR str )
184 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
185 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
186 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
190 static inline LPWSTR SERV_dupmulti(LPCSTR str)
198 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
199 n += (strlen( &str[n] ) + 1);
204 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
205 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
209 static inline VOID SERV_free( LPWSTR wstr )
211 HeapFree( GetProcessHeap(), 0, wstr );
214 /******************************************************************************
215 * registry access functions and data
217 static const WCHAR szDisplayName[] = {
218 'D','i','s','p','l','a','y','N','a','m','e', 0 };
219 static const WCHAR szType[] = {'T','y','p','e',0};
220 static const WCHAR szStart[] = {'S','t','a','r','t',0};
221 static const WCHAR szError[] = {
222 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
223 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
224 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
225 static const WCHAR szDependencies[] = {
226 'D','e','p','e','n','d','e','n','c','i','e','s',0};
227 static const WCHAR szDependOnService[] = {
228 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
237 static inline void service_set_value( struct reg_value *val,
238 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
246 static inline void service_set_dword( struct reg_value *val,
247 LPCWSTR name, DWORD *data )
249 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
252 static inline void service_set_string( struct reg_value *val,
253 LPCWSTR name, LPCWSTR string )
255 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
256 service_set_value( val, REG_SZ, name, string, len );
259 static inline void service_set_multi_string( struct reg_value *val,
260 LPCWSTR name, LPCWSTR string )
264 /* determine the length of a double null terminated multi string */
266 len += (lstrlenW( &string[ len ] )+1);
267 } while ( string[ len++ ] );
269 len *= sizeof (WCHAR);
270 service_set_value( val, REG_MULTI_SZ, name, string, len );
273 static inline LONG service_write_values( HKEY hKey,
274 struct reg_value *val, int n )
276 LONG r = ERROR_SUCCESS;
281 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
282 (const BYTE*)val[i].data, val[i].size );
283 if( r != ERROR_SUCCESS )
289 /******************************************************************************
290 * Service IPC functions
292 static LPWSTR service_get_pipe_name(LPWSTR service)
294 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
295 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
299 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
300 name = HeapAlloc(GetProcessHeap(), 0, len);
301 strcpyW(name, prefix);
302 strcatW(name, service);
306 static HANDLE service_open_pipe(LPWSTR service)
308 LPWSTR szPipe = service_get_pipe_name( service );
309 HANDLE handle = INVALID_HANDLE_VALUE;
312 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
313 0, NULL, OPEN_ALWAYS, 0, NULL);
314 if (handle != INVALID_HANDLE_VALUE)
316 if (GetLastError() != ERROR_PIPE_BUSY)
318 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
324 /******************************************************************************
325 * service_get_event_handle
327 static HANDLE service_get_event_handle(LPWSTR service)
329 static const WCHAR prefix[] = {
330 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
335 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
336 name = HeapAlloc(GetProcessHeap(), 0, len);
337 strcpyW(name, prefix);
338 strcatW(name, service);
339 handle = CreateEventW(NULL, TRUE, FALSE, name);
344 /******************************************************************************
347 * Call into the main service routine provided by StartServiceCtrlDispatcher.
349 static DWORD WINAPI service_thread(LPVOID arg)
351 service_data *info = arg;
352 LPWSTR str = info->args;
353 DWORD argc = 0, len = 0;
359 len += strlenW(&str[len]) + 1;
367 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
368 for (argc=0, p=str; *p; p += strlenW(p) + 1)
372 info->proc.w(argc, argv);
373 HeapFree(GetProcessHeap(), 0, argv);
377 LPSTR strA, *argv, p;
380 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
381 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
382 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
384 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
385 for (argc=0, p=strA; *p; p += strlen(p) + 1)
389 info->proc.a(argc, argv);
390 HeapFree(GetProcessHeap(), 0, argv);
391 HeapFree(GetProcessHeap(), 0, strA);
396 /******************************************************************************
397 * service_handle_start
399 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
401 DWORD read = 0, result = 0;
405 TRACE("%p %p %ld\n", pipe, service, count);
407 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
408 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
409 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
411 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
412 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
418 ERR("service is not stopped\n");
423 SERV_free(service->args);
424 service->args = args;
426 service->thread = CreateThread( NULL, 0, service_thread,
430 HeapFree(GetProcessHeap(), 0, args);
431 WriteFile( pipe, &result, sizeof result, &read, NULL );
436 /******************************************************************************
437 * service_send_start_message
439 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
441 DWORD i, len, count, result;
442 service_start_info *ssi;
446 TRACE("%p %p %ld\n", pipe, argv, argc);
448 /* calculate how much space do we need to send the startup info */
450 for (i=0; i<argc; i++)
451 len += strlenW(argv[i])+1;
453 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
454 ssi->cmd = WINESERV_STARTINFO;
457 /* copy service args into a single buffer*/
459 for (i=0; i<argc; i++)
466 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
468 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
470 HeapFree(GetProcessHeap(),0,ssi);
475 /******************************************************************************
476 * service_handle_get_status
478 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
482 return WriteFile(pipe, &service->status,
483 sizeof service->status, &count, NULL);
486 /******************************************************************************
489 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
491 DWORD cmd[2], count = 0;
494 cmd[0] = WINESERV_GETSTATUS;
496 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
497 if (!r || count != sizeof cmd)
499 ERR("service protocol error - failed to write pipe!\n");
502 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
503 if (!r || count != sizeof *status)
504 ERR("service protocol error - failed to read pipe "
505 "r = %d count = %ld/%d!\n", r, count, sizeof *status);
509 /******************************************************************************
510 * service_send_control
512 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
514 DWORD cmd[2], count = 0;
517 cmd[0] = WINESERV_SENDCONTROL;
519 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
520 if (!r || count != sizeof cmd)
522 ERR("service protocol error - failed to write pipe!\n");
525 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
526 if (!r || count != sizeof *result)
527 ERR("service protocol error - failed to read pipe "
528 "r = %d count = %ld/%d!\n", r, count, sizeof *result);
532 /******************************************************************************
533 * service_accepts_control
535 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
537 DWORD a = service->status.dwControlsAccepted;
541 case SERVICE_CONTROL_INTERROGATE:
543 case SERVICE_CONTROL_STOP:
544 if (a&SERVICE_ACCEPT_STOP)
547 case SERVICE_CONTROL_SHUTDOWN:
548 if (a&SERVICE_ACCEPT_SHUTDOWN)
551 case SERVICE_CONTROL_PAUSE:
552 case SERVICE_CONTROL_CONTINUE:
553 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
556 case SERVICE_CONTROL_PARAMCHANGE:
557 if (a&SERVICE_ACCEPT_PARAMCHANGE)
560 case SERVICE_CONTROL_NETBINDADD:
561 case SERVICE_CONTROL_NETBINDREMOVE:
562 case SERVICE_CONTROL_NETBINDENABLE:
563 case SERVICE_CONTROL_NETBINDDISABLE:
564 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
567 if (1) /* (!service->handlerex) */
571 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
572 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
575 case SERVICE_CONTROL_POWEREVENT:
576 if (a&SERVICE_ACCEPT_POWEREVENT)
579 case SERVICE_CONTROL_SESSIONCHANGE:
580 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
587 /******************************************************************************
588 * service_handle_control
590 static BOOL service_handle_control(HANDLE pipe, service_data *service,
593 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
595 TRACE("received control %ld\n", dwControl);
597 if (service_accepts_control(service, dwControl) && service->handler)
599 service->handler(dwControl);
602 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
605 /******************************************************************************
606 * service_reap_thread
608 static DWORD service_reap_thread(service_data *service)
612 if (!service->thread)
614 GetExitCodeThread(service->thread, &exitcode);
615 if (exitcode!=STILL_ACTIVE)
617 CloseHandle(service->thread);
623 /******************************************************************************
624 * service_control_dispatcher
626 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
628 service_data *service = arg;
632 TRACE("%p %s\n", service, debugstr_w(service->name));
634 /* create a pipe to talk to the rest of the world with */
635 name = service_get_pipe_name(service->name);
636 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
637 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
640 /* let the process who started us know we've tried to create a pipe */
641 event = service_get_event_handle(service->name);
645 if (pipe==INVALID_HANDLE_VALUE)
647 ERR("failed to create pipe, error = %ld\n", GetLastError());
651 /* dispatcher loop */
655 DWORD count, req[2] = {0,0};
657 r = ConnectNamedPipe(pipe, NULL);
658 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
660 ERR("pipe connect failed\n");
664 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
665 if (!r || count!=sizeof req)
667 ERR("pipe read failed\n");
671 service_reap_thread(service);
673 /* handle the request */
676 case WINESERV_STARTINFO:
677 service_handle_start(pipe, service, req[1]);
679 case WINESERV_GETSTATUS:
680 service_handle_get_status(pipe, service);
682 case WINESERV_SENDCONTROL:
683 service_handle_control(pipe, service, req[1]);
686 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
689 FlushFileBuffers(pipe);
690 DisconnectNamedPipe(pipe);
697 /******************************************************************************
698 * service_run_threads
700 static BOOL service_run_threads(void)
702 service_data *service;
703 DWORD count = 0, n = 0;
706 EnterCriticalSection( &service_cs );
708 /* count how many services there are */
709 for (service = service_list; service; service = service->next)
712 TRACE("starting %ld pipe listener threads\n", count);
714 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
716 for (n=0, service = service_list; service; service = service->next, n++)
717 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
721 LeaveCriticalSection( &service_cs );
723 /* wait for all the threads to pack up and exit */
724 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
726 HeapFree(GetProcessHeap(), 0, handles);
731 /******************************************************************************
732 * StartServiceCtrlDispatcherA [ADVAPI32.@]
734 * Connects a process containing one or more services to the service control
738 * servent [I] A list of the service names and service procedures
740 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
746 TRACE("%p\n", servent);
748 EnterCriticalSection( &service_cs );
749 while (servent->lpServiceName)
751 LPSTR name = servent->lpServiceName;
753 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
754 sz = len*sizeof(WCHAR) + sizeof *info;
755 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
756 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
757 info->proc.a = servent->lpServiceProc;
758 info->unicode = FALSE;
760 /* insert into the list */
761 info->next = service_list;
766 LeaveCriticalSection( &service_cs );
768 service_run_threads();
773 /******************************************************************************
774 * StartServiceCtrlDispatcherW [ADVAPI32.@]
776 * Connects a process containing one or more services to the service control
780 * servent [I] A list of the service names and service procedures
782 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
788 TRACE("%p\n", servent);
790 EnterCriticalSection( &service_cs );
791 while (servent->lpServiceName)
793 LPWSTR name = servent->lpServiceName;
796 sz = len*sizeof(WCHAR) + sizeof *info;
797 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
798 strcpyW(info->name, name);
799 info->proc.w = servent->lpServiceProc;
800 info->unicode = TRUE;
802 /* insert into the list */
803 info->next = service_list;
808 LeaveCriticalSection( &service_cs );
810 service_run_threads();
815 /******************************************************************************
816 * LockServiceDatabase [ADVAPI32.@]
818 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
822 TRACE("%p\n",hSCManager);
824 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
825 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
829 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
832 TRACE("returning %p\n", ret);
837 /******************************************************************************
838 * UnlockServiceDatabase [ADVAPI32.@]
840 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
842 TRACE("%p\n",ScLock);
844 return CloseHandle( ScLock );
847 /******************************************************************************
848 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
850 SERVICE_STATUS_HANDLE WINAPI
851 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
853 LPWSTR lpServiceNameW;
854 SERVICE_STATUS_HANDLE ret;
856 lpServiceNameW = SERV_dup(lpServiceName);
857 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
858 SERV_free(lpServiceNameW);
862 /******************************************************************************
863 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
869 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
870 LPHANDLER_FUNCTION lpfHandler )
872 service_data *service;
874 EnterCriticalSection( &service_cs );
875 for(service = service_list; service; service = service->next)
876 if(!strcmpW(lpServiceName, service->name))
879 service->handler = lpfHandler;
880 LeaveCriticalSection( &service_cs );
882 return (SERVICE_STATUS_HANDLE)service;
885 /******************************************************************************
886 * SetServiceStatus [ADVAPI32.@]
893 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
895 service_data *service;
898 TRACE("%p %lx %lx %lx %lx %lx %lx %lx\n", hService,
899 lpStatus->dwServiceType, lpStatus->dwCurrentState,
900 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
901 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
902 lpStatus->dwWaitHint);
904 EnterCriticalSection( &service_cs );
905 for (service = service_list; service; service = service->next)
906 if(service == (service_data*)hService)
910 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
911 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
915 LeaveCriticalSection( &service_cs );
921 /******************************************************************************
922 * OpenSCManagerA [ADVAPI32.@]
924 * Establish a connection to the service control manager and open its database.
927 * lpMachineName [I] Pointer to machine name string
928 * lpDatabaseName [I] Pointer to database name string
929 * dwDesiredAccess [I] Type of access
932 * Success: A Handle to the service control manager database
935 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
936 DWORD dwDesiredAccess )
938 LPWSTR lpMachineNameW, lpDatabaseNameW;
941 lpMachineNameW = SERV_dup(lpMachineName);
942 lpDatabaseNameW = SERV_dup(lpDatabaseName);
943 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
944 SERV_free(lpDatabaseNameW);
945 SERV_free(lpMachineNameW);
949 /******************************************************************************
950 * OpenSCManagerW [ADVAPI32.@]
952 * See OpenSCManagerA.
954 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
955 DWORD dwDesiredAccess )
957 struct sc_manager *manager;
961 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
962 debugstr_w(lpDatabaseName), dwDesiredAccess);
964 if( lpDatabaseName && lpDatabaseName[0] )
966 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
968 /* noop, all right */
970 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
972 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
977 SetLastError( ERROR_INVALID_NAME );
982 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
983 sc_handle_destroy_manager );
987 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
988 if (r!=ERROR_SUCCESS)
991 r = RegOpenKeyExW(hReg, szServiceManagerKey,
992 0, KEY_ALL_ACCESS, &manager->hkey);
994 if (r!=ERROR_SUCCESS)
997 TRACE("returning %p\n", manager);
999 return (SC_HANDLE) &manager->hdr;
1002 sc_handle_free( &manager->hdr );
1007 /******************************************************************************
1008 * ControlService [ADVAPI32.@]
1010 * Send a control code to a service.
1013 * hService [I] Handle of the service control manager database
1014 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1015 * lpServiceStatus [O] Destination for the status of the service, if available
1022 * Unlike M$' implementation, control requests are not serialized and may be
1023 * processed asynchronously.
1025 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1026 LPSERVICE_STATUS lpServiceStatus )
1028 struct sc_service *hsvc;
1032 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
1034 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1037 SetLastError( ERROR_INVALID_HANDLE );
1041 ret = QueryServiceStatus(hService, lpServiceStatus);
1044 ERR("failed to query service status\n");
1045 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1049 switch (lpServiceStatus->dwCurrentState)
1051 case SERVICE_STOPPED:
1052 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1054 case SERVICE_START_PENDING:
1055 if (dwControl==SERVICE_CONTROL_STOP)
1058 case SERVICE_STOP_PENDING:
1059 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1063 handle = service_open_pipe(hsvc->name);
1064 if (handle!=INVALID_HANDLE_VALUE)
1066 DWORD result = ERROR_SUCCESS;
1067 ret = service_send_control(handle, dwControl, &result);
1068 CloseHandle(handle);
1069 if (result!=ERROR_SUCCESS)
1071 SetLastError(result);
1079 /******************************************************************************
1080 * CloseServiceHandle [ADVAPI32.@]
1082 * Close a handle to a service or the service control manager database.
1085 * hSCObject [I] Handle to service or service control manager database
1092 CloseServiceHandle( SC_HANDLE hSCObject )
1094 TRACE("%p\n", hSCObject);
1096 sc_handle_free( (struct sc_handle*) hSCObject );
1102 /******************************************************************************
1103 * OpenServiceA [ADVAPI32.@]
1105 * Open a handle to a service.
1108 * hSCManager [I] Handle of the service control manager database
1109 * lpServiceName [I] Name of the service to open
1110 * dwDesiredAccess [I] Access required to the service
1113 * Success: Handle to the service
1116 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1117 DWORD dwDesiredAccess )
1119 LPWSTR lpServiceNameW;
1122 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1124 lpServiceNameW = SERV_dup(lpServiceName);
1125 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1126 SERV_free(lpServiceNameW);
1131 /******************************************************************************
1132 * OpenServiceW [ADVAPI32.@]
1136 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1137 DWORD dwDesiredAccess)
1139 struct sc_manager *hscm;
1140 struct sc_service *hsvc;
1145 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1149 SetLastError(ERROR_INVALID_ADDRESS);
1153 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1156 SetLastError( ERROR_INVALID_HANDLE );
1160 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1161 if (r!=ERROR_SUCCESS)
1163 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1167 len = strlenW(lpServiceName)+1;
1168 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1169 sizeof (struct sc_service) + len*sizeof(WCHAR),
1170 sc_handle_destroy_service );
1173 strcpyW( hsvc->name, lpServiceName );
1176 /* add reference to SCM handle */
1177 hscm->hdr.ref_count++;
1180 TRACE("returning %p\n",hsvc);
1182 return (SC_HANDLE) &hsvc->hdr;
1185 /******************************************************************************
1186 * CreateServiceW [ADVAPI32.@]
1189 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1190 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1191 DWORD dwServiceType, DWORD dwStartType,
1192 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1193 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1194 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1195 LPCWSTR lpPassword )
1197 struct sc_manager *hscm;
1198 struct sc_service *hsvc = NULL;
1202 struct reg_value val[10];
1205 TRACE("%p %s %s\n", hSCManager,
1206 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1208 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1211 SetLastError( ERROR_INVALID_HANDLE );
1215 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1216 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1217 if (r!=ERROR_SUCCESS)
1220 if (dp != REG_CREATED_NEW_KEY)
1222 SetLastError(ERROR_SERVICE_EXISTS);
1227 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1229 service_set_dword( &val[n++], szType, &dwServiceType );
1230 service_set_dword( &val[n++], szStart, &dwStartType );
1231 service_set_dword( &val[n++], szError, &dwErrorControl );
1233 if( lpBinaryPathName )
1234 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1236 if( lpLoadOrderGroup )
1237 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1239 if( lpDependencies )
1240 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1243 FIXME("Don't know how to add a Password for a service.\n");
1245 if( lpServiceStartName )
1246 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1248 r = service_write_values( hKey, val, n );
1249 if( r != ERROR_SUCCESS )
1252 len = strlenW(lpServiceName)+1;
1253 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1254 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1257 lstrcpyW( hsvc->name, lpServiceName );
1260 hscm->hdr.ref_count++;
1262 return (SC_HANDLE) &hsvc->hdr;
1265 RegCloseKey( hKey );
1270 /******************************************************************************
1271 * CreateServiceA [ADVAPI32.@]
1274 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1275 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1276 DWORD dwServiceType, DWORD dwStartType,
1277 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1278 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1279 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1282 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1283 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1286 TRACE("%p %s %s\n", hSCManager,
1287 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1289 lpServiceNameW = SERV_dup( lpServiceName );
1290 lpDisplayNameW = SERV_dup( lpDisplayName );
1291 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1292 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1293 lpDependenciesW = SERV_dupmulti( lpDependencies );
1294 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1295 lpPasswordW = SERV_dup( lpPassword );
1297 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1298 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1299 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1300 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1302 SERV_free( lpServiceNameW );
1303 SERV_free( lpDisplayNameW );
1304 SERV_free( lpBinaryPathNameW );
1305 SERV_free( lpLoadOrderGroupW );
1306 SERV_free( lpDependenciesW );
1307 SERV_free( lpServiceStartNameW );
1308 SERV_free( lpPasswordW );
1314 /******************************************************************************
1315 * DeleteService [ADVAPI32.@]
1317 * Delete a service from the service control manager database.
1320 * hService [I] Handle of the service to delete
1326 BOOL WINAPI DeleteService( SC_HANDLE hService )
1328 struct sc_service *hsvc;
1330 WCHAR valname[MAX_PATH+1];
1335 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1338 SetLastError( ERROR_INVALID_HANDLE );
1344 /* Clean out the values */
1345 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1346 while (rc == ERROR_SUCCESS)
1348 RegDeleteValueW(hKey,valname);
1351 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1357 /* delete the key */
1358 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1364 /******************************************************************************
1365 * StartServiceA [ADVAPI32.@]
1370 * hService [I] Handle of service
1371 * dwNumServiceArgs [I] Number of arguments
1372 * lpServiceArgVectors [I] Address of array of argument strings
1375 * - NT implements this function using an obscure RPC call.
1376 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1377 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1378 * - This will only work for shared address space. How should the service
1379 * args be transferred when address spaces are separated?
1380 * - Can only start one service at a time.
1381 * - Has no concept of privilege.
1387 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1388 LPCSTR *lpServiceArgVectors )
1390 LPWSTR *lpwstr=NULL;
1394 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1396 if (dwNumServiceArgs)
1397 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1398 dwNumServiceArgs*sizeof(LPWSTR) );
1400 for(i=0; i<dwNumServiceArgs; i++)
1401 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1403 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1405 if (dwNumServiceArgs)
1407 for(i=0; i<dwNumServiceArgs; i++)
1408 SERV_free(lpwstr[i]);
1409 HeapFree(GetProcessHeap(), 0, lpwstr);
1415 /******************************************************************************
1416 * service_start_process [INTERNAL]
1418 static DWORD service_start_process(struct sc_service *hsvc)
1420 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1421 PROCESS_INFORMATION pi;
1423 LPWSTR path = NULL, str;
1424 DWORD type, size, ret;
1428 /* read the executable path from memory */
1430 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1431 if (ret!=ERROR_SUCCESS)
1433 str = HeapAlloc(GetProcessHeap(),0,size);
1434 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1435 if (ret==ERROR_SUCCESS)
1437 size = ExpandEnvironmentStringsW(str,NULL,0);
1438 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1439 ExpandEnvironmentStringsW(str,path,size);
1441 HeapFree(GetProcessHeap(),0,str);
1445 /* wait for the process to start and set an event or terminate */
1446 handles[0] = service_get_event_handle( hsvc->name );
1447 ZeroMemory(&si, sizeof(STARTUPINFOW));
1448 si.cb = sizeof(STARTUPINFOW);
1449 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1452 handles[1] = pi.hProcess;
1453 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1454 if(ret != WAIT_OBJECT_0)
1456 SetLastError(ERROR_IO_PENDING);
1460 CloseHandle( pi.hThread );
1461 CloseHandle( pi.hProcess );
1463 CloseHandle( handles[0] );
1464 HeapFree(GetProcessHeap(),0,path);
1468 static BOOL service_wait_for_startup(SC_HANDLE hService)
1471 SERVICE_STATUS status;
1474 TRACE("%p\n", hService);
1476 for (i=0; i<30; i++)
1478 status.dwCurrentState = 0;
1479 r = QueryServiceStatus(hService, &status);
1482 if (status.dwCurrentState == SERVICE_RUNNING)
1484 TRACE("Service started successfully\n");
1493 /******************************************************************************
1494 * StartServiceW [ADVAPI32.@]
1496 * See StartServiceA.
1498 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1499 LPCWSTR *lpServiceArgVectors)
1501 struct sc_service *hsvc;
1504 HANDLE handle = INVALID_HANDLE_VALUE;
1506 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1508 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1511 SetLastError(ERROR_INVALID_HANDLE);
1515 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1519 handle = service_open_pipe(hsvc->name);
1520 if (handle==INVALID_HANDLE_VALUE)
1522 /* start the service process */
1523 if (service_start_process(hsvc))
1524 handle = service_open_pipe(hsvc->name);
1527 if (handle != INVALID_HANDLE_VALUE)
1529 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1530 CloseHandle(handle);
1534 UnlockServiceDatabase( hLock );
1536 TRACE("returning %d\n", r);
1538 service_wait_for_startup(hService);
1543 /******************************************************************************
1544 * QueryServiceStatus [ADVAPI32.@]
1548 * lpservicestatus []
1551 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1552 LPSERVICE_STATUS lpservicestatus)
1554 struct sc_service *hsvc;
1555 DWORD size, type, val;
1559 TRACE("%p %p\n", hService, lpservicestatus);
1561 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1564 SetLastError( ERROR_INVALID_HANDLE );
1568 pipe = service_open_pipe(hsvc->name);
1569 if (pipe != INVALID_HANDLE_VALUE)
1571 r = service_get_status(pipe, lpservicestatus);
1577 TRACE("Failed to read service status\n");
1579 /* read the service type from the registry */
1581 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1582 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1585 lpservicestatus->dwServiceType = val;
1586 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1587 lpservicestatus->dwControlsAccepted = 0;
1588 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1589 lpservicestatus->dwServiceSpecificExitCode = 0;
1590 lpservicestatus->dwCheckPoint = 0;
1591 lpservicestatus->dwWaitHint = 0;
1596 /******************************************************************************
1597 * QueryServiceStatusEx [ADVAPI32.@]
1599 * Get information about a service.
1602 * hService [I] Handle to service to get information about
1603 * InfoLevel [I] Level of information to get
1604 * lpBuffer [O] Destination for requested information
1605 * cbBufSize [I] Size of lpBuffer in bytes
1606 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1612 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1613 LPBYTE lpBuffer, DWORD cbBufSize,
1614 LPDWORD pcbBytesNeeded)
1617 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1621 /******************************************************************************
1622 * QueryServiceConfigA [ADVAPI32.@]
1625 QueryServiceConfigA( SC_HANDLE hService,
1626 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1627 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1629 static const CHAR szDisplayName[] = "DisplayName";
1630 static const CHAR szType[] = "Type";
1631 static const CHAR szStart[] = "Start";
1632 static const CHAR szError[] = "ErrorControl";
1633 static const CHAR szImagePath[] = "ImagePath";
1634 static const CHAR szGroup[] = "Group";
1635 static const CHAR szDependencies[] = "Dependencies";
1636 struct sc_service *hsvc;
1638 CHAR str_buffer[ MAX_PATH ];
1640 DWORD type, val, sz, total, n;
1643 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1644 cbBufSize, pcbBytesNeeded);
1646 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1649 SetLastError( ERROR_INVALID_HANDLE );
1654 /* calculate the size required first */
1655 total = sizeof (QUERY_SERVICE_CONFIGA);
1657 sz = sizeof(str_buffer);
1658 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1659 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1661 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1662 if( 0 == sz ) return FALSE;
1668 /* FIXME: set last error */
1673 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1674 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1678 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1679 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1683 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1684 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1688 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1689 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1692 *pcbBytesNeeded = total;
1694 /* if there's not enough memory, return an error */
1695 if( total > cbBufSize )
1697 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1701 ZeroMemory( lpServiceConfig, total );
1704 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1705 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1706 lpServiceConfig->dwServiceType = val;
1709 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1710 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1711 lpServiceConfig->dwStartType = val;
1714 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1715 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1716 lpServiceConfig->dwErrorControl = val;
1718 /* now do the strings */
1719 p = (LPSTR) &lpServiceConfig[1];
1720 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1722 sz = sizeof(str_buffer);
1723 r = RegQueryValueExA( hKey, szImagePath, 0, &type, (LPBYTE)str_buffer, &sz );
1724 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1726 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1727 if( 0 == sz || sz > n ) return FALSE;
1729 lpServiceConfig->lpBinaryPathName = p;
1735 /* FIXME: set last error */
1740 r = RegQueryValueExA( hKey, szGroup, 0, &type, (LPBYTE)p, &sz );
1741 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1743 lpServiceConfig->lpLoadOrderGroup = p;
1749 r = RegQueryValueExA( hKey, szDependencies, 0, &type, (LPBYTE)p, &sz );
1750 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1752 lpServiceConfig->lpDependencies = p;
1758 ERR("Buffer overflow!\n");
1760 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1761 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1766 /******************************************************************************
1767 * QueryServiceConfigW [ADVAPI32.@]
1770 QueryServiceConfigW( SC_HANDLE hService,
1771 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1772 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1774 WCHAR str_buffer[ MAX_PATH ];
1776 DWORD type, val, sz, total, n;
1779 struct sc_service *hsvc;
1781 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1782 cbBufSize, pcbBytesNeeded);
1784 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1787 SetLastError( ERROR_INVALID_HANDLE );
1792 /* calculate the size required first */
1793 total = sizeof (QUERY_SERVICE_CONFIGW);
1795 sz = sizeof(str_buffer);
1796 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1797 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1799 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1800 if( 0 == sz ) return FALSE;
1802 total += sizeof(WCHAR) * sz;
1806 /* FIXME: set last error */
1811 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1812 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1816 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1817 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1820 total += sizeof(WCHAR);
1823 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1824 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1828 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1829 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1832 *pcbBytesNeeded = total;
1834 /* if there's not enough memory, return an error */
1835 if( total > cbBufSize )
1837 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1841 ZeroMemory( lpServiceConfig, total );
1844 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1845 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1846 lpServiceConfig->dwServiceType = val;
1849 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1850 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1851 lpServiceConfig->dwStartType = val;
1854 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1855 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1856 lpServiceConfig->dwErrorControl = val;
1858 /* now do the strings */
1859 p = (LPBYTE) &lpServiceConfig[1];
1860 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1862 sz = sizeof(str_buffer);
1863 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1864 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1866 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1867 sz *= sizeof(WCHAR);
1868 if( 0 == sz || sz > n ) return FALSE;
1870 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1876 /* FIXME: set last error */
1881 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1882 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1884 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1890 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1891 lpServiceConfig->lpDependencies = (LPWSTR) p;
1892 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1905 ERR("Buffer overflow!\n");
1907 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1908 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1913 /******************************************************************************
1914 * EnumServicesStatusA [ADVAPI32.@]
1917 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1918 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1919 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1920 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1922 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1923 dwServiceType, dwServiceState, lpServices, cbBufSize,
1924 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1925 SetLastError (ERROR_ACCESS_DENIED);
1929 /******************************************************************************
1930 * EnumServicesStatusW [ADVAPI32.@]
1933 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1934 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1935 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1936 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1938 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1939 dwServiceType, dwServiceState, lpServices, cbBufSize,
1940 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1941 SetLastError (ERROR_ACCESS_DENIED);
1945 /******************************************************************************
1946 * GetServiceKeyNameA [ADVAPI32.@]
1948 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1949 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1951 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1955 /******************************************************************************
1956 * GetServiceKeyNameW [ADVAPI32.@]
1958 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1959 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1961 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1965 /******************************************************************************
1966 * QueryServiceLockStatusA [ADVAPI32.@]
1968 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1969 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1970 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1972 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1977 /******************************************************************************
1978 * QueryServiceLockStatusW [ADVAPI32.@]
1980 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1981 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1982 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1984 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1989 /******************************************************************************
1990 * GetServiceDisplayNameA [ADVAPI32.@]
1992 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1993 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1995 FIXME("%p %s %p %p\n", hSCManager,
1996 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2000 /******************************************************************************
2001 * GetServiceDisplayNameW [ADVAPI32.@]
2003 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2004 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2006 FIXME("%p %s %p %p\n", hSCManager,
2007 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2011 /******************************************************************************
2012 * ChangeServiceConfigW [ADVAPI32.@]
2014 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2015 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2016 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2017 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2019 struct reg_value val[10];
2020 struct sc_service *hsvc;
2021 DWORD r = ERROR_SUCCESS;
2025 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2026 hService, dwServiceType, dwStartType, dwErrorControl,
2027 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2028 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2029 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2031 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2034 SetLastError( ERROR_INVALID_HANDLE );
2039 if( dwServiceType != SERVICE_NO_CHANGE )
2040 service_set_dword( &val[n++], szType, &dwServiceType );
2042 if( dwStartType != SERVICE_NO_CHANGE )
2043 service_set_dword( &val[n++], szStart, &dwStartType );
2045 if( dwErrorControl != SERVICE_NO_CHANGE )
2046 service_set_dword( &val[n++], szError, &dwErrorControl );
2048 if( lpBinaryPathName )
2049 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2051 if( lpLoadOrderGroup )
2052 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2054 if( lpDependencies )
2055 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2058 FIXME("ignoring password\n");
2060 if( lpServiceStartName )
2061 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2063 r = service_write_values( hsvc->hkey, val, n );
2065 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2068 /******************************************************************************
2069 * ChangeServiceConfigA [ADVAPI32.@]
2071 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2072 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2073 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2074 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2076 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2077 LPWSTR wServiceStartName, wPassword, wDisplayName;
2080 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2081 hService, dwServiceType, dwStartType, dwErrorControl,
2082 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2083 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2084 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2086 wBinaryPathName = SERV_dup( lpBinaryPathName );
2087 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2088 wDependencies = SERV_dupmulti( lpDependencies );
2089 wServiceStartName = SERV_dup( lpServiceStartName );
2090 wPassword = SERV_dup( lpPassword );
2091 wDisplayName = SERV_dup( lpDisplayName );
2093 r = ChangeServiceConfigW( hService, dwServiceType,
2094 dwStartType, dwErrorControl, wBinaryPathName,
2095 wLoadOrderGroup, lpdwTagId, wDependencies,
2096 wServiceStartName, wPassword, wDisplayName);
2098 SERV_free( wBinaryPathName );
2099 SERV_free( wLoadOrderGroup );
2100 SERV_free( wDependencies );
2101 SERV_free( wServiceStartName );
2102 SERV_free( wPassword );
2103 SERV_free( wDisplayName );
2108 /******************************************************************************
2109 * ChangeServiceConfig2A [ADVAPI32.@]
2111 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2116 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2118 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2120 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2121 SERVICE_DESCRIPTIONW sdw;
2123 sdw.lpDescription = SERV_dup( sd->lpDescription );
2125 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2127 SERV_free( sdw.lpDescription );
2129 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2131 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2132 SERVICE_FAILURE_ACTIONSW faw;
2134 faw.dwResetPeriod = fa->dwResetPeriod;
2135 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2136 faw.lpCommand = SERV_dup( fa->lpCommand );
2137 faw.cActions = fa->cActions;
2138 faw.lpsaActions = fa->lpsaActions;
2140 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2142 SERV_free( faw.lpRebootMsg );
2143 SERV_free( faw.lpCommand );
2146 SetLastError( ERROR_INVALID_PARAMETER );
2151 /******************************************************************************
2152 * ChangeServiceConfig2W [ADVAPI32.@]
2154 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2158 struct sc_service *hsvc;
2160 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2163 SetLastError( ERROR_INVALID_HANDLE );
2168 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2170 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2171 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2172 if (sd->lpDescription)
2174 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2175 if (sd->lpDescription[0] == 0)
2176 RegDeleteValueW(hKey,szDescription);
2178 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2179 (LPVOID)sd->lpDescription,
2180 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2184 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2188 /******************************************************************************
2189 * QueryServiceObjectSecurity [ADVAPI32.@]
2191 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2192 SECURITY_INFORMATION dwSecurityInformation,
2193 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2194 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2198 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2199 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2201 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2203 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2204 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2205 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2209 /******************************************************************************
2210 * SetServiceObjectSecurity [ADVAPI32.@]
2212 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2213 SECURITY_INFORMATION dwSecurityInformation,
2214 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2216 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2220 /******************************************************************************
2221 * SetServiceBits [ADVAPI32.@]
2223 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2224 DWORD dwServiceBits,
2226 BOOL bUpdateImmediately)
2228 FIXME("%p %08lx %x %x\n", hServiceStatus, dwServiceBits,
2229 bSetBitsOn, bUpdateImmediately);