2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
32 #include "wine/unicode.h"
33 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
38 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
39 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
40 'S','e','r','v','i','c','e','s','\\',0 };
41 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
44 typedef struct service_start_info_t
51 #define WINESERV_STARTINFO 1
52 #define WINESERV_GETSTATUS 2
53 #define WINESERV_SENDCONTROL 3
55 typedef struct service_data_t
57 struct service_data_t *next;
58 LPHANDLER_FUNCTION handler;
59 SERVICE_STATUS status;
63 LPSERVICE_MAIN_FUNCTIONA a;
64 LPSERVICE_MAIN_FUNCTIONW w;
70 static CRITICAL_SECTION service_cs;
71 static CRITICAL_SECTION_DEBUG service_cs_debug =
74 { &service_cs_debug.ProcessLocksList,
75 &service_cs_debug.ProcessLocksList },
76 0, 0, { 0, (DWORD)(__FILE__ ": service_cs") }
78 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
80 service_data *service_list;
82 /******************************************************************************
86 #define MAX_SERVICE_NAME 256
88 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
91 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
97 sc_handle_destructor destroy;
100 struct sc_manager /* service control manager handle */
102 struct sc_handle hdr;
103 HKEY hkey; /* handle to services database in the registry */
106 struct sc_service /* service handle */
108 struct sc_handle hdr;
109 HKEY hkey; /* handle to service entry in the registry (under hkey) */
110 struct sc_manager *scm; /* pointer to SCM handle */
114 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
115 sc_handle_destructor destroy)
117 struct sc_handle *hdr;
119 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
124 hdr->destroy = destroy;
126 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
130 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
132 struct sc_handle *hdr = (struct sc_handle *) handle;
136 if (hdr->htype != htype)
141 static void sc_handle_free(struct sc_handle* hdr)
145 if (--hdr->ref_count)
148 HeapFree(GetProcessHeap(), 0, hdr);
151 static void sc_handle_destroy_manager(struct sc_handle *handle)
153 struct sc_manager *mgr = (struct sc_manager*) handle;
155 TRACE("destroying SC Manager %p\n", mgr);
157 RegCloseKey(mgr->hkey);
160 static void sc_handle_destroy_service(struct sc_handle *handle)
162 struct sc_service *svc = (struct sc_service*) handle;
164 TRACE("destroying service %p\n", svc);
166 RegCloseKey(svc->hkey);
168 sc_handle_free(&svc->scm->hdr);
172 /******************************************************************************
173 * String management functions
175 static inline LPWSTR SERV_dup( LPCSTR str )
182 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
183 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
184 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
188 static inline LPWSTR SERV_dupmulti(LPCSTR str)
196 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
197 n += (strlen( &str[n] ) + 1);
202 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
203 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
207 static inline VOID SERV_free( LPWSTR wstr )
209 HeapFree( GetProcessHeap(), 0, wstr );
213 /******************************************************************************
214 * Service IPC functions
216 static LPWSTR service_get_pipe_name(LPWSTR service)
218 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
219 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
223 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
224 name = HeapAlloc(GetProcessHeap(), 0, len);
225 strcpyW(name, prefix);
226 strcatW(name, service);
230 static HANDLE service_open_pipe(LPWSTR service)
232 LPWSTR szPipe = service_get_pipe_name( service );
233 HANDLE handle = INVALID_HANDLE_VALUE;
236 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
237 0, NULL, OPEN_ALWAYS, 0, NULL);
238 if (handle != INVALID_HANDLE_VALUE)
240 if (GetLastError() != ERROR_PIPE_BUSY)
242 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
248 /******************************************************************************
249 * service_get_event_handle
251 static HANDLE service_get_event_handle(LPWSTR service)
253 static const WCHAR prefix[] = {
254 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
259 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
260 name = HeapAlloc(GetProcessHeap(), 0, len);
261 strcpyW(name, prefix);
262 strcatW(name, service);
263 handle = CreateEventW(NULL, TRUE, FALSE, name);
268 /******************************************************************************
271 * Call into the main service routine provided by StartServiceCtrlDispatcher.
273 static DWORD WINAPI service_thread(LPVOID arg)
275 service_data *info = arg;
276 LPWSTR str = info->args;
277 DWORD argc = 0, len = 0;
283 len += strlenW(&str[len]) + 1;
291 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
292 for (argc=0, p=str; *p; p += strlenW(p) + 1)
296 info->proc.w(argc, argv);
297 HeapFree(GetProcessHeap(), 0, argv);
301 LPSTR strA, *argv, p;
304 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
305 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
306 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
308 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
309 for (argc=0, p=strA; *p; p += strlen(p) + 1)
313 info->proc.a(argc, argv);
314 HeapFree(GetProcessHeap(), 0, argv);
315 HeapFree(GetProcessHeap(), 0, strA);
320 /******************************************************************************
321 * service_handle_start
323 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
325 DWORD read = 0, result = 0;
329 TRACE("%p %p %ld\n", pipe, service, count);
331 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
332 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
333 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
335 ERR("pipe read failed r = %d count = %ld/%ld args[n-1]=%s\n",
336 r, count, read/sizeof(WCHAR), debugstr_wn(args, count));
342 ERR("service is not stopped\n");
347 SERV_free(service->args);
348 service->args = args;
350 service->thread = CreateThread( NULL, 0, service_thread,
354 HeapFree(GetProcessHeap(), 0, args);
355 WriteFile( pipe, &result, sizeof result, &read, NULL );
360 /******************************************************************************
361 * service_send_start_message
363 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
365 DWORD i, len, count, result;
366 service_start_info *ssi;
370 TRACE("%p %p %ld\n", pipe, argv, argc);
372 /* calculate how much space do we need to send the startup info */
374 for (i=0; i<argc; i++)
375 len += strlenW(argv[i])+1;
377 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
378 ssi->cmd = WINESERV_STARTINFO;
381 /* copy service args into a single buffer*/
383 for (i=0; i<argc; i++)
390 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
392 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
394 HeapFree(GetProcessHeap(),0,ssi);
399 /******************************************************************************
400 * service_handle_get_status
402 static BOOL service_handle_get_status(HANDLE pipe, service_data *service)
406 return WriteFile(pipe, &service->status,
407 sizeof service->status, &count, NULL);
410 /******************************************************************************
413 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS status)
415 DWORD cmd[2], count = 0;
418 cmd[0] = WINESERV_GETSTATUS;
420 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
421 if (!r || count != sizeof cmd)
423 ERR("service protocol error - failed to write pipe!\n");
426 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
427 if (!r || count != sizeof *status)
428 ERR("service protocol error - failed to read pipe "
429 "r = %d count = %ld/%d!\n", r, count, sizeof *status);
433 /******************************************************************************
434 * service_send_control
436 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
438 DWORD cmd[2], count = 0;
441 cmd[0] = WINESERV_SENDCONTROL;
443 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
444 if (!r || count != sizeof cmd)
446 ERR("service protocol error - failed to write pipe!\n");
449 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
450 if (!r || count != sizeof *result)
451 ERR("service protocol error - failed to read pipe "
452 "r = %d count = %ld/%d!\n", r, count, sizeof *result);
456 /******************************************************************************
457 * service_accepts_control
459 static BOOL service_accepts_control(service_data *service, DWORD dwControl)
461 DWORD a = service->status.dwControlsAccepted;
465 case SERVICE_CONTROL_INTERROGATE:
467 case SERVICE_CONTROL_STOP:
468 if (a&SERVICE_ACCEPT_STOP)
471 case SERVICE_CONTROL_SHUTDOWN:
472 if (a&SERVICE_ACCEPT_SHUTDOWN)
475 case SERVICE_CONTROL_PAUSE:
476 case SERVICE_CONTROL_CONTINUE:
477 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
480 case SERVICE_CONTROL_PARAMCHANGE:
481 if (a&SERVICE_ACCEPT_PARAMCHANGE)
484 case SERVICE_CONTROL_NETBINDADD:
485 case SERVICE_CONTROL_NETBINDREMOVE:
486 case SERVICE_CONTROL_NETBINDENABLE:
487 case SERVICE_CONTROL_NETBINDDISABLE:
488 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
491 if (1) /* (!service->handlerex) */
495 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
496 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
499 case SERVICE_CONTROL_POWEREVENT:
500 if (a&SERVICE_ACCEPT_POWEREVENT)
503 case SERVICE_CONTROL_SESSIONCHANGE:
504 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
511 /******************************************************************************
512 * service_handle_control
514 static BOOL service_handle_control(HANDLE pipe, service_data *service,
517 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
519 TRACE("received control %ld\n", dwControl);
521 if (service_accepts_control(service, dwControl) && service->handler)
523 service->handler(dwControl);
526 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
529 /******************************************************************************
530 * service_reap_thread
532 static DWORD service_reap_thread(service_data *service)
536 if (!service->thread)
538 GetExitCodeThread(service->thread, &exitcode);
539 if (exitcode!=STILL_ACTIVE)
541 CloseHandle(service->thread);
547 /******************************************************************************
548 * service_control_dispatcher
550 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
552 service_data *service = arg;
556 TRACE("%p %s\n", service, debugstr_w(service->name));
558 /* create a pipe to talk to the rest of the world with */
559 name = service_get_pipe_name(service->name);
560 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
561 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
564 /* let the process who started us know we've tried to create a pipe */
565 event = service_get_event_handle(service->name);
569 if (pipe==INVALID_HANDLE_VALUE)
571 ERR("failed to create pipe, error = %ld\n", GetLastError());
575 /* dispatcher loop */
579 DWORD count, req[2] = {0,0};
581 r = ConnectNamedPipe(pipe, NULL);
582 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
584 ERR("pipe connect failed\n");
588 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
589 if (!r || count!=sizeof req)
591 ERR("pipe read failed\n");
595 service_reap_thread(service);
597 /* handle the request */
600 case WINESERV_STARTINFO:
601 service_handle_start(pipe, service, req[1]);
603 case WINESERV_GETSTATUS:
604 service_handle_get_status(pipe, service);
606 case WINESERV_SENDCONTROL:
607 service_handle_control(pipe, service, req[1]);
610 ERR("received invalid command %ld length %ld\n", req[0], req[1]);
613 FlushFileBuffers(pipe);
614 DisconnectNamedPipe(pipe);
621 /******************************************************************************
622 * service_run_threads
624 static BOOL service_run_threads(void)
626 service_data *service;
627 DWORD count = 0, n = 0;
630 EnterCriticalSection( &service_cs );
632 /* count how many services there are */
633 for (service = service_list; service; service = service->next)
636 TRACE("starting %ld pipe listener threads\n", count);
638 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
640 for (n=0, service = service_list; service; service = service->next, n++)
641 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
645 LeaveCriticalSection( &service_cs );
647 /* wait for all the threads to pack up and exit */
648 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
650 HeapFree(GetProcessHeap(), 0, handles);
655 /******************************************************************************
656 * StartServiceCtrlDispatcherA [ADVAPI32.@]
658 * Connects a process containing one or more services to the service control
662 * servent [I] A list of the service names and service procedures
664 BOOL WINAPI StartServiceCtrlDispatcherA( LPSERVICE_TABLE_ENTRYA servent )
670 TRACE("%p\n", servent);
672 EnterCriticalSection( &service_cs );
673 while (servent->lpServiceName)
675 LPSTR name = servent->lpServiceName;
677 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
678 sz = len*sizeof(WCHAR) + sizeof *info;
679 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
680 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
681 info->proc.a = servent->lpServiceProc;
682 info->unicode = FALSE;
684 /* insert into the list */
685 info->next = service_list;
690 LeaveCriticalSection( &service_cs );
692 service_run_threads();
697 /******************************************************************************
698 * StartServiceCtrlDispatcherW [ADVAPI32.@]
700 * Connects a process containing one or more services to the service control
704 * servent [I] A list of the service names and service procedures
706 BOOL WINAPI StartServiceCtrlDispatcherW( LPSERVICE_TABLE_ENTRYW servent )
712 TRACE("%p\n", servent);
714 EnterCriticalSection( &service_cs );
715 while (servent->lpServiceName)
717 LPWSTR name = servent->lpServiceName;
720 sz = len*sizeof(WCHAR) + sizeof *info;
721 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
722 strcpyW(info->name, name);
723 info->proc.w = servent->lpServiceProc;
724 info->unicode = TRUE;
726 /* insert into the list */
727 info->next = service_list;
732 LeaveCriticalSection( &service_cs );
734 service_run_threads();
739 /******************************************************************************
740 * LockServiceDatabase [ADVAPI32.@]
742 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
746 TRACE("%p\n",hSCManager);
748 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
749 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
753 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
756 TRACE("returning %p\n", ret);
761 /******************************************************************************
762 * UnlockServiceDatabase [ADVAPI32.@]
764 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
766 TRACE("%p\n",ScLock);
768 return CloseHandle( ScLock );
771 /******************************************************************************
772 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
774 SERVICE_STATUS_HANDLE WINAPI
775 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
777 LPWSTR lpServiceNameW;
778 SERVICE_STATUS_HANDLE ret;
780 lpServiceNameW = SERV_dup(lpServiceName);
781 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
782 SERV_free(lpServiceNameW);
786 /******************************************************************************
787 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
793 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
794 LPHANDLER_FUNCTION lpfHandler )
796 service_data *service;
798 EnterCriticalSection( &service_cs );
799 for(service = service_list; service; service = service->next)
800 if(!strcmpW(lpServiceName, service->name))
803 service->handler = lpfHandler;
804 LeaveCriticalSection( &service_cs );
806 return (SERVICE_STATUS_HANDLE)service;
809 /******************************************************************************
810 * SetServiceStatus [ADVAPI32.@]
817 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
819 service_data *service;
822 TRACE("%lx %lx %lx %lx %lx %lx %lx %lx\n", hService,
823 lpStatus->dwServiceType, lpStatus->dwCurrentState,
824 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
825 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
826 lpStatus->dwWaitHint);
828 EnterCriticalSection( &service_cs );
829 for (service = service_list; service; service = service->next)
830 if(service == (service_data*)hService)
834 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
835 TRACE("Set service status to %ld\n",service->status.dwCurrentState);
839 LeaveCriticalSection( &service_cs );
845 /******************************************************************************
846 * OpenSCManagerA [ADVAPI32.@]
848 * Establish a connection to the service control manager and open its database.
851 * lpMachineName [I] Pointer to machine name string
852 * lpDatabaseName [I] Pointer to database name string
853 * dwDesiredAccess [I] Type of access
856 * Success: A Handle to the service control manager database
859 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
860 DWORD dwDesiredAccess )
862 LPWSTR lpMachineNameW, lpDatabaseNameW;
865 lpMachineNameW = SERV_dup(lpMachineName);
866 lpDatabaseNameW = SERV_dup(lpDatabaseName);
867 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
868 SERV_free(lpDatabaseNameW);
869 SERV_free(lpMachineNameW);
873 /******************************************************************************
874 * OpenSCManagerW [ADVAPI32.@]
876 * See OpenSCManagerA.
878 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
879 DWORD dwDesiredAccess )
881 struct sc_manager *manager;
885 TRACE("(%s,%s,0x%08lx)\n", debugstr_w(lpMachineName),
886 debugstr_w(lpDatabaseName), dwDesiredAccess);
888 if( lpDatabaseName && lpDatabaseName[0] )
890 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
892 /* noop, all right */
894 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
896 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
901 SetLastError( ERROR_INVALID_NAME );
906 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
907 sc_handle_destroy_manager );
911 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
912 if (r!=ERROR_SUCCESS)
915 r = RegOpenKeyExW(hReg, szServiceManagerKey,
916 0, KEY_ALL_ACCESS, &manager->hkey);
918 if (r!=ERROR_SUCCESS)
921 TRACE("returning %p\n", manager);
923 return (SC_HANDLE) &manager->hdr;
926 sc_handle_free( &manager->hdr );
930 /******************************************************************************
931 * ControlService [ADVAPI32.@]
933 * Send a control code to a service.
936 * hService [I] Handle of the service control manager database
937 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
938 * lpServiceStatus [O] Destination for the status of the service, if available
945 * Unlike M$' implementation, control requests are not serialized and may be
946 * processed asynchronously.
948 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
949 LPSERVICE_STATUS lpServiceStatus )
951 struct sc_service *hsvc;
955 TRACE("%p %ld %p\n", hService, dwControl, lpServiceStatus);
957 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
960 SetLastError( ERROR_INVALID_HANDLE );
964 ret = QueryServiceStatus(hService, lpServiceStatus);
967 ERR("failed to query service status\n");
968 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
972 switch (lpServiceStatus->dwCurrentState)
974 case SERVICE_STOPPED:
975 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
977 case SERVICE_START_PENDING:
978 if (dwControl==SERVICE_CONTROL_STOP)
981 case SERVICE_STOP_PENDING:
982 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
986 handle = service_open_pipe(hsvc->name);
987 if (handle!=INVALID_HANDLE_VALUE)
989 DWORD result = ERROR_SUCCESS;
990 ret = service_send_control(handle, dwControl, &result);
992 if (result!=ERROR_SUCCESS)
994 SetLastError(result);
1002 /******************************************************************************
1003 * CloseServiceHandle [ADVAPI32.@]
1005 * Close a handle to a service or the service control manager database.
1008 * hSCObject [I] Handle to service or service control manager database
1015 CloseServiceHandle( SC_HANDLE hSCObject )
1017 TRACE("%p\n", hSCObject);
1019 sc_handle_free( (struct sc_handle*) hSCObject );
1025 /******************************************************************************
1026 * OpenServiceA [ADVAPI32.@]
1028 * Open a handle to a service.
1031 * hSCManager [I] Handle of the service control manager database
1032 * lpServiceName [I] Name of the service to open
1033 * dwDesiredAccess [I] Access required to the service
1036 * Success: Handle to the service
1039 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1040 DWORD dwDesiredAccess )
1042 LPWSTR lpServiceNameW;
1045 TRACE("%p %s %ld\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1047 lpServiceNameW = SERV_dup(lpServiceName);
1048 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1049 SERV_free(lpServiceNameW);
1054 /******************************************************************************
1055 * OpenServiceW [ADVAPI32.@]
1059 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1060 DWORD dwDesiredAccess)
1062 struct sc_manager *hscm;
1063 struct sc_service *hsvc;
1068 TRACE("%p %s %ld\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1072 SetLastError(ERROR_INVALID_ADDRESS);
1076 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1079 SetLastError( ERROR_INVALID_HANDLE );
1083 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1084 if (r!=ERROR_SUCCESS)
1086 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1090 len = strlenW(lpServiceName)+1;
1091 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1092 sizeof (struct sc_service) + len*sizeof(WCHAR),
1093 sc_handle_destroy_service );
1096 strcpyW( hsvc->name, lpServiceName );
1099 /* add reference to SCM handle */
1100 hscm->hdr.ref_count++;
1103 TRACE("returning %p\n",hsvc);
1105 return (SC_HANDLE) &hsvc->hdr;
1108 /******************************************************************************
1109 * CreateServiceW [ADVAPI32.@]
1112 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1113 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1114 DWORD dwServiceType, DWORD dwStartType,
1115 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1116 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1117 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1118 LPCWSTR lpPassword )
1120 struct sc_manager *hscm;
1121 struct sc_service *hsvc = NULL;
1125 static const WCHAR szDisplayName[] = { 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1126 static const WCHAR szType[] = {'T','y','p','e',0};
1127 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1128 static const WCHAR szError[] = {'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1129 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1130 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1131 static const WCHAR szDependencies[] = { 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1133 FIXME("%p %s %s\n", hSCManager,
1134 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1136 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1139 SetLastError( ERROR_INVALID_HANDLE );
1143 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1144 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1145 if (r!=ERROR_SUCCESS)
1148 if (dp != REG_CREATED_NEW_KEY)
1150 SetLastError(ERROR_SERVICE_EXISTS);
1156 r = RegSetValueExW(hKey, szDisplayName, 0, REG_SZ, (const BYTE*)lpDisplayName,
1157 (strlenW(lpDisplayName)+1)*sizeof(WCHAR) );
1158 if (r!=ERROR_SUCCESS)
1162 r = RegSetValueExW(hKey, szType, 0, REG_DWORD, (LPVOID)&dwServiceType, sizeof (DWORD) );
1163 if (r!=ERROR_SUCCESS)
1166 r = RegSetValueExW(hKey, szStart, 0, REG_DWORD, (LPVOID)&dwStartType, sizeof (DWORD) );
1167 if (r!=ERROR_SUCCESS)
1170 r = RegSetValueExW(hKey, szError, 0, REG_DWORD,
1171 (LPVOID)&dwErrorControl, sizeof (DWORD) );
1172 if (r!=ERROR_SUCCESS)
1175 if(lpBinaryPathName)
1177 r = RegSetValueExW(hKey, szImagePath, 0, REG_SZ, (const BYTE*)lpBinaryPathName,
1178 (strlenW(lpBinaryPathName)+1)*sizeof(WCHAR) );
1179 if (r!=ERROR_SUCCESS)
1183 if(lpLoadOrderGroup)
1185 r = RegSetValueExW(hKey, szGroup, 0, REG_SZ, (const BYTE*)lpLoadOrderGroup,
1186 (strlenW(lpLoadOrderGroup)+1)*sizeof(WCHAR) );
1187 if (r!=ERROR_SUCCESS)
1195 /* determine the length of a double null terminated multi string */
1197 len += (strlenW(&lpDependencies[len])+1);
1198 } while (lpDependencies[len++]);
1200 r = RegSetValueExW(hKey, szDependencies, 0, REG_MULTI_SZ,
1201 (const BYTE*)lpDependencies, len );
1202 if (r!=ERROR_SUCCESS)
1208 FIXME("Don't know how to add a Password for a service.\n");
1211 if(lpServiceStartName)
1213 FIXME("Don't know how to add a ServiceStartName for a service.\n");
1216 len = strlenW(lpServiceName)+1;
1217 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1218 sizeof (struct sc_service) + len*sizeof(WCHAR),
1219 sc_handle_destroy_service );
1222 strcpyW( hsvc->name, lpServiceName );
1225 hscm->hdr.ref_count++;
1227 return (SC_HANDLE) &hsvc->hdr;
1231 sc_handle_free( &hsvc->hdr );
1236 /******************************************************************************
1237 * CreateServiceA [ADVAPI32.@]
1240 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1241 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1242 DWORD dwServiceType, DWORD dwStartType,
1243 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1244 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1245 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1248 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1249 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1252 TRACE("%p %s %s\n", hSCManager,
1253 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1255 lpServiceNameW = SERV_dup( lpServiceName );
1256 lpDisplayNameW = SERV_dup( lpDisplayName );
1257 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1258 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1259 lpDependenciesW = SERV_dupmulti( lpDependencies );
1260 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1261 lpPasswordW = SERV_dup( lpPassword );
1263 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1264 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1265 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1266 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1268 SERV_free( lpServiceNameW );
1269 SERV_free( lpDisplayNameW );
1270 SERV_free( lpBinaryPathNameW );
1271 SERV_free( lpLoadOrderGroupW );
1272 SERV_free( lpDependenciesW );
1273 SERV_free( lpServiceStartNameW );
1274 SERV_free( lpPasswordW );
1280 /******************************************************************************
1281 * DeleteService [ADVAPI32.@]
1283 * Delete a service from the service control manager database.
1286 * hService [I] Handle of the service to delete
1292 BOOL WINAPI DeleteService( SC_HANDLE hService )
1294 struct sc_service *hsvc;
1296 WCHAR valname[MAX_PATH+1];
1301 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1304 SetLastError( ERROR_INVALID_HANDLE );
1310 /* Clean out the values */
1311 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1312 while (rc == ERROR_SUCCESS)
1314 RegDeleteValueW(hKey,valname);
1317 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1323 /* delete the key */
1324 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1330 /******************************************************************************
1331 * StartServiceA [ADVAPI32.@]
1336 * hService [I] Handle of service
1337 * dwNumServiceArgs [I] Number of arguments
1338 * lpServiceArgVectors [I] Address of array of argument strings
1341 * - NT implements this function using an obscure RPC call.
1342 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1343 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1344 * - This will only work for shared address space. How should the service
1345 * args be transferred when address spaces are separated?
1346 * - Can only start one service at a time.
1347 * - Has no concept of privilege.
1353 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1354 LPCSTR *lpServiceArgVectors )
1356 LPWSTR *lpwstr=NULL;
1360 TRACE("(%p,%ld,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1362 if (dwNumServiceArgs)
1363 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1364 dwNumServiceArgs*sizeof(LPWSTR) );
1366 for(i=0; i<dwNumServiceArgs; i++)
1367 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1369 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1371 if (dwNumServiceArgs)
1373 for(i=0; i<dwNumServiceArgs; i++)
1374 SERV_free(lpwstr[i]);
1375 HeapFree(GetProcessHeap(), 0, lpwstr);
1381 /******************************************************************************
1382 * service_start_process [INTERNAL]
1384 static DWORD service_start_process(struct sc_service *hsvc)
1386 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1387 PROCESS_INFORMATION pi;
1389 LPWSTR path = NULL, str;
1390 DWORD type, size, ret;
1394 /* read the executable path from memory */
1396 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1397 if (ret!=ERROR_SUCCESS)
1399 str = HeapAlloc(GetProcessHeap(),0,size);
1400 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1401 if (ret==ERROR_SUCCESS)
1403 size = ExpandEnvironmentStringsW(str,NULL,0);
1404 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1405 ExpandEnvironmentStringsW(str,path,size);
1407 HeapFree(GetProcessHeap(),0,str);
1411 /* wait for the process to start and set an event or terminate */
1412 handles[0] = service_get_event_handle( hsvc->name );
1413 ZeroMemory(&si, sizeof(STARTUPINFOW));
1414 si.cb = sizeof(STARTUPINFOW);
1415 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1418 handles[1] = pi.hProcess;
1419 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1420 if(ret != WAIT_OBJECT_0)
1422 SetLastError(ERROR_IO_PENDING);
1426 CloseHandle( pi.hThread );
1427 CloseHandle( pi.hProcess );
1429 CloseHandle( handles[0] );
1430 HeapFree(GetProcessHeap(),0,path);
1434 static BOOL service_wait_for_startup(SC_HANDLE hService)
1437 SERVICE_STATUS status;
1440 TRACE("%p\n", hService);
1442 for (i=0; i<30; i++)
1444 status.dwCurrentState = 0;
1445 r = QueryServiceStatus(hService, &status);
1448 if (status.dwCurrentState == SERVICE_RUNNING)
1450 TRACE("Service started successfully\n");
1459 /******************************************************************************
1460 * StartServiceW [ADVAPI32.@]
1462 * See StartServiceA.
1464 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1465 LPCWSTR *lpServiceArgVectors)
1467 struct sc_service *hsvc;
1470 HANDLE handle = INVALID_HANDLE_VALUE;
1472 TRACE("%p %ld %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1474 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1477 SetLastError(ERROR_INVALID_HANDLE);
1481 hLock = LockServiceDatabase(hsvc->scm);
1485 handle = service_open_pipe(hsvc->name);
1486 if (handle==INVALID_HANDLE_VALUE)
1488 /* start the service process */
1489 if (service_start_process(hsvc))
1490 handle = service_open_pipe(hsvc->name);
1493 if (handle != INVALID_HANDLE_VALUE)
1495 service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1496 CloseHandle(handle);
1500 UnlockServiceDatabase( hLock );
1502 TRACE("returning %d\n", r);
1504 service_wait_for_startup(hService);
1509 /******************************************************************************
1510 * QueryServiceStatus [ADVAPI32.@]
1514 * lpservicestatus []
1517 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1518 LPSERVICE_STATUS lpservicestatus)
1520 struct sc_service *hsvc;
1521 DWORD size, type, val;
1525 TRACE("%p %p\n", hService, lpservicestatus);
1527 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1530 SetLastError( ERROR_INVALID_HANDLE );
1534 pipe = service_open_pipe(hsvc->name);
1535 if (pipe != INVALID_HANDLE_VALUE)
1537 r = service_get_status(pipe, lpservicestatus);
1543 TRACE("Failed to read service status\n");
1545 /* read the service type from the registry */
1547 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1548 if(r!=ERROR_SUCCESS || type!=REG_DWORD)
1551 lpservicestatus->dwServiceType = val;
1552 lpservicestatus->dwCurrentState = SERVICE_STOPPED; /* stopped */
1553 lpservicestatus->dwControlsAccepted = 0;
1554 lpservicestatus->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1555 lpservicestatus->dwServiceSpecificExitCode = 0;
1556 lpservicestatus->dwCheckPoint = 0;
1557 lpservicestatus->dwWaitHint = 0;
1562 /******************************************************************************
1563 * QueryServiceStatusEx [ADVAPI32.@]
1565 * Get information about a service.
1568 * hService [I] Handle to service to get information about
1569 * InfoLevel [I] Level of information to get
1570 * lpBuffer [O] Destination for requested information
1571 * cbBufSize [I] Size of lpBuffer in bytes
1572 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1578 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1579 LPBYTE lpBuffer, DWORD cbBufSize,
1580 LPDWORD pcbBytesNeeded)
1583 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
1587 /******************************************************************************
1588 * QueryServiceConfigA [ADVAPI32.@]
1591 QueryServiceConfigA( SC_HANDLE hService,
1592 LPQUERY_SERVICE_CONFIGA lpServiceConfig,
1593 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1595 static const CHAR szDisplayName[] = "DisplayName";
1596 static const CHAR szType[] = "Type";
1597 static const CHAR szStart[] = "Start";
1598 static const CHAR szError[] = "ErrorControl";
1599 static const CHAR szImagePath[] = "ImagePath";
1600 static const CHAR szGroup[] = "Group";
1601 static const CHAR szDependencies[] = "Dependencies";
1602 struct sc_service *hsvc;
1604 CHAR str_buffer[ MAX_PATH ];
1606 DWORD type, val, sz, total, n;
1609 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1610 cbBufSize, pcbBytesNeeded);
1612 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1615 SetLastError( ERROR_INVALID_HANDLE );
1620 /* calculate the size required first */
1621 total = sizeof (QUERY_SERVICE_CONFIGA);
1623 sz = sizeof(str_buffer);
1624 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1625 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1627 sz = ExpandEnvironmentStringsA(str_buffer,NULL,0);
1628 if( 0 == sz ) return FALSE;
1634 /* FIXME: set last error */
1639 r = RegQueryValueExA( hKey, szGroup, 0, &type, NULL, &sz );
1640 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1644 r = RegQueryValueExA( hKey, szDependencies, 0, &type, NULL, &sz );
1645 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1649 r = RegQueryValueExA( hKey, szStart, 0, &type, NULL, &sz );
1650 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1654 r = RegQueryValueExA( hKey, szDisplayName, 0, &type, NULL, &sz );
1655 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1658 /* if there's not enough memory, return an error */
1659 if( total > *pcbBytesNeeded )
1661 *pcbBytesNeeded = total;
1662 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1666 *pcbBytesNeeded = total;
1667 ZeroMemory( lpServiceConfig, total );
1670 r = RegQueryValueExA( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1671 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1672 lpServiceConfig->dwServiceType = val;
1675 r = RegQueryValueExA( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1676 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1677 lpServiceConfig->dwStartType = val;
1680 r = RegQueryValueExA( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1681 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1682 lpServiceConfig->dwErrorControl = val;
1684 /* now do the strings */
1685 p = (LPBYTE) &lpServiceConfig[1];
1686 n = total - sizeof (QUERY_SERVICE_CONFIGA);
1688 sz = sizeof(str_buffer);
1689 r = RegQueryValueExA( hKey, szImagePath, 0, &type, str_buffer, &sz );
1690 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1692 sz = ExpandEnvironmentStringsA(str_buffer, p, n);
1693 if( 0 == sz || sz > n ) return FALSE;
1695 lpServiceConfig->lpBinaryPathName = (LPSTR) p;
1701 /* FIXME: set last error */
1706 r = RegQueryValueExA( hKey, szGroup, 0, &type, p, &sz );
1707 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1709 lpServiceConfig->lpLoadOrderGroup = (LPSTR) p;
1715 r = RegQueryValueExA( hKey, szDependencies, 0, &type, p, &sz );
1716 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1718 lpServiceConfig->lpDependencies = (LPSTR) p;
1724 ERR("Buffer overflow!\n");
1726 TRACE("Image path = %s\n", lpServiceConfig->lpBinaryPathName );
1727 TRACE("Group = %s\n", lpServiceConfig->lpLoadOrderGroup );
1732 /******************************************************************************
1733 * QueryServiceConfigW [ADVAPI32.@]
1736 QueryServiceConfigW( SC_HANDLE hService,
1737 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1738 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1740 static const WCHAR szDisplayName[] = {
1741 'D','i','s','p','l','a','y','N','a','m','e', 0 };
1742 static const WCHAR szType[] = {'T','y','p','e',0};
1743 static const WCHAR szStart[] = {'S','t','a','r','t',0};
1744 static const WCHAR szError[] = {
1745 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
1746 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
1747 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
1748 static const WCHAR szDependencies[] = {
1749 'D','e','p','e','n','d','e','n','c','i','e','s',0};
1750 WCHAR str_buffer[ MAX_PATH ];
1752 DWORD type, val, sz, total, n;
1755 struct sc_service *hsvc;
1757 TRACE("%p %p %ld %p\n", hService, lpServiceConfig,
1758 cbBufSize, pcbBytesNeeded);
1760 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1763 SetLastError( ERROR_INVALID_HANDLE );
1768 /* calculate the size required first */
1769 total = sizeof (QUERY_SERVICE_CONFIGW);
1771 sz = sizeof(str_buffer);
1772 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1773 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1775 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1776 if( 0 == sz ) return FALSE;
1778 total += sizeof(WCHAR) * sz;
1782 /* FIXME: set last error */
1787 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1788 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1792 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1793 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1797 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1798 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1802 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1803 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1806 /* if there's not enough memory, return an error */
1807 if( total > *pcbBytesNeeded )
1809 *pcbBytesNeeded = total;
1810 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1814 *pcbBytesNeeded = total;
1815 ZeroMemory( lpServiceConfig, total );
1818 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1819 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1820 lpServiceConfig->dwServiceType = val;
1823 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1824 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1825 lpServiceConfig->dwStartType = val;
1828 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1829 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1830 lpServiceConfig->dwErrorControl = val;
1832 /* now do the strings */
1833 p = (LPBYTE) &lpServiceConfig[1];
1834 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1836 sz = sizeof(str_buffer);
1837 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1838 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1840 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1841 sz *= sizeof(WCHAR);
1842 if( 0 == sz || sz > n ) return FALSE;
1844 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1850 /* FIXME: set last error */
1855 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1856 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1858 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1864 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1865 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1867 lpServiceConfig->lpDependencies = (LPWSTR) p;
1873 ERR("Buffer overflow!\n");
1875 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1876 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1881 /******************************************************************************
1882 * EnumServicesStatusA [ADVAPI32.@]
1885 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1886 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1887 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1888 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1890 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1891 dwServiceType, dwServiceState, lpServices, cbBufSize,
1892 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1893 SetLastError (ERROR_ACCESS_DENIED);
1897 /******************************************************************************
1898 * EnumServicesStatusW [ADVAPI32.@]
1901 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1902 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1903 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1904 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1906 FIXME("%p type=%lx state=%lx %p %lx %p %p %p\n", hSCManager,
1907 dwServiceType, dwServiceState, lpServices, cbBufSize,
1908 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1909 SetLastError (ERROR_ACCESS_DENIED);
1913 /******************************************************************************
1914 * GetServiceKeyNameA [ADVAPI32.@]
1916 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1917 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1919 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1923 /******************************************************************************
1924 * GetServiceKeyNameW [ADVAPI32.@]
1926 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1927 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1929 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1933 /******************************************************************************
1934 * QueryServiceLockStatusA [ADVAPI32.@]
1936 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1937 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1938 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1940 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1945 /******************************************************************************
1946 * QueryServiceLockStatusW [ADVAPI32.@]
1948 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1949 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1950 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1952 FIXME("%p %p %08lx %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1957 /******************************************************************************
1958 * GetServiceDisplayNameA [ADVAPI32.@]
1960 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1961 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1963 FIXME("%p %s %p %p\n", hSCManager,
1964 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1968 /******************************************************************************
1969 * GetServiceDisplayNameW [ADVAPI32.@]
1971 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1972 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1974 FIXME("%p %s %p %p\n", hSCManager,
1975 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1979 /******************************************************************************
1980 * ChangeServiceConfigW [ADVAPI32.@]
1982 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1983 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1984 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1985 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1987 FIXME("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
1988 hService, dwServiceType, dwStartType, dwErrorControl,
1989 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1990 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1991 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1995 /******************************************************************************
1996 * ChangeServiceConfigA [ADVAPI32.@]
1998 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1999 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2000 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2001 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2003 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2004 LPWSTR wServiceStartName, wPassword, wDisplayName;
2007 TRACE("%p %ld %ld %ld %s %s %p %p %s %s %s\n",
2008 hService, dwServiceType, dwStartType, dwErrorControl,
2009 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2010 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2011 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2013 wBinaryPathName = SERV_dup( lpBinaryPathName );
2014 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2015 wDependencies = SERV_dupmulti( lpDependencies );
2016 wServiceStartName = SERV_dup( lpServiceStartName );
2017 wPassword = SERV_dup( lpPassword );
2018 wDisplayName = SERV_dup( lpDisplayName );
2020 r = ChangeServiceConfigW( hService, dwServiceType,
2021 dwStartType, dwErrorControl, wBinaryPathName,
2022 wLoadOrderGroup, lpdwTagId, wDependencies,
2023 wServiceStartName, wPassword, wDisplayName);
2025 SERV_free( wBinaryPathName );
2026 SERV_free( wLoadOrderGroup );
2027 SERV_free( wDependencies );
2028 SERV_free( wServiceStartName );
2029 SERV_free( wPassword );
2030 SERV_free( wDisplayName );
2035 /******************************************************************************
2036 * ChangeServiceConfig2A [ADVAPI32.@]
2038 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2043 TRACE("%p %ld %p\n",hService, dwInfoLevel, lpInfo);
2045 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2047 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2048 SERVICE_DESCRIPTIONW sdw;
2050 sdw.lpDescription = SERV_dup( sd->lpDescription );
2052 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2054 SERV_free( sdw.lpDescription );
2056 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2058 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2059 SERVICE_FAILURE_ACTIONSW faw;
2061 faw.dwResetPeriod = fa->dwResetPeriod;
2062 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2063 faw.lpCommand = SERV_dup( fa->lpCommand );
2064 faw.cActions = fa->cActions;
2065 faw.lpsaActions = fa->lpsaActions;
2067 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2069 SERV_free( faw.lpRebootMsg );
2070 SERV_free( faw.lpCommand );
2073 SetLastError( ERROR_INVALID_PARAMETER );
2078 /******************************************************************************
2079 * ChangeServiceConfig2W [ADVAPI32.@]
2081 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2085 struct sc_service *hsvc;
2087 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2090 SetLastError( ERROR_INVALID_HANDLE );
2095 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2097 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2098 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2099 if (sd->lpDescription)
2101 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2102 if (sd->lpDescription[0] == 0)
2103 RegDeleteValueW(hKey,szDescription);
2105 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2106 (LPVOID)sd->lpDescription,
2107 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2111 FIXME("STUB: %p %ld %p\n",hService, dwInfoLevel, lpInfo);
2115 /******************************************************************************
2116 * QueryServiceObjectSecurity [ADVAPI32.@]
2118 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2119 SECURITY_INFORMATION dwSecurityInformation,
2120 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2121 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2125 FIXME("%p %ld %p %lu %p\n", hService, dwSecurityInformation,
2126 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2128 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2130 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2131 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2132 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2136 /******************************************************************************
2137 * SetServiceObjectSecurity [ADVAPI32.@]
2139 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2140 SECURITY_INFORMATION dwSecurityInformation,
2141 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2143 FIXME("%p %ld %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2147 /******************************************************************************
2148 * SetServiceBits [ADVAPI32.@]
2150 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2151 DWORD dwServiceBits,
2153 BOOL bUpdateImmediately)
2155 FIXME("%08lx %08lx %x %x\n", hServiceStatus, dwServiceBits,
2156 bSetBitsOn, bUpdateImmediately);