2 * Win32 advapi functions
4 * Copyright 1995 Sven Verdoolaege
5 * Copyright 2005 Mike McCormack
6 * Copyright 2007 Rolf Kalbermatter
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
38 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
42 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
43 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
44 'S','e','r','v','i','c','e','s',0 };
45 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
48 typedef struct service_start_info_t
55 #define WINESERV_STARTINFO 1
56 #define WINESERV_GETSTATUS 2
57 #define WINESERV_SENDCONTROL 3
58 #define WINESERV_SETPID 4
60 typedef struct service_data_t
64 LPHANDLER_FUNCTION handler;
65 LPHANDLER_FUNCTION_EX handler_ex;
68 SERVICE_STATUS_PROCESS status;
71 BOOL extended : 1; /* uses handler_ex instead of handler? */
73 LPSERVICE_MAIN_FUNCTIONA a;
74 LPSERVICE_MAIN_FUNCTIONW w;
80 static CRITICAL_SECTION service_cs;
81 static CRITICAL_SECTION_DEBUG service_cs_debug =
84 { &service_cs_debug.ProcessLocksList,
85 &service_cs_debug.ProcessLocksList },
86 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
88 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
90 static struct list service_list = LIST_INIT(service_list);
92 /******************************************************************************
96 #define MAX_SERVICE_NAME 256
98 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
101 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
105 SC_HANDLE_TYPE htype;
107 sc_handle_destructor destroy;
110 struct sc_manager /* service control manager handle */
112 struct sc_handle hdr;
113 HKEY hkey; /* handle to services database in the registry */
117 struct sc_service /* service handle */
119 struct sc_handle hdr;
120 HKEY hkey; /* handle to service entry in the registry (under hkey) */
122 struct sc_manager *scm; /* pointer to SCM handle */
126 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
127 sc_handle_destructor destroy)
129 struct sc_handle *hdr;
131 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
136 hdr->destroy = destroy;
138 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
142 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
144 struct sc_handle *hdr = (struct sc_handle *) handle;
148 if (hdr->htype != htype)
153 static void sc_handle_free(struct sc_handle* hdr)
157 if (--hdr->ref_count)
160 HeapFree(GetProcessHeap(), 0, hdr);
163 static void sc_handle_destroy_manager(struct sc_handle *handle)
165 struct sc_manager *mgr = (struct sc_manager*) handle;
167 TRACE("destroying SC Manager %p\n", mgr);
169 RegCloseKey(mgr->hkey);
172 static void sc_handle_destroy_service(struct sc_handle *handle)
174 struct sc_service *svc = (struct sc_service*) handle;
176 TRACE("destroying service %p\n", svc);
178 RegCloseKey(svc->hkey);
180 sc_handle_free(&svc->scm->hdr);
184 /******************************************************************************
185 * String management functions
187 static inline LPWSTR SERV_dup( LPCSTR str )
194 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
195 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
196 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
200 static inline LPWSTR SERV_dupmulti(LPCSTR str)
208 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
209 n += (strlen( &str[n] ) + 1);
214 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
215 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
219 static inline VOID SERV_free( LPWSTR wstr )
221 HeapFree( GetProcessHeap(), 0, wstr );
224 /******************************************************************************
225 * registry access functions and data
227 static const WCHAR szDisplayName[] = {
228 'D','i','s','p','l','a','y','N','a','m','e', 0 };
229 static const WCHAR szType[] = {'T','y','p','e',0};
230 static const WCHAR szStart[] = {'S','t','a','r','t',0};
231 static const WCHAR szError[] = {
232 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
233 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
234 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
235 static const WCHAR szDependencies[] = {
236 'D','e','p','e','n','d','e','n','c','i','e','s',0};
237 static const WCHAR szDependOnService[] = {
238 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
247 static inline void service_set_value( struct reg_value *val,
248 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
256 static inline void service_set_dword( struct reg_value *val,
257 LPCWSTR name, const DWORD *data )
259 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
262 static inline void service_set_string( struct reg_value *val,
263 LPCWSTR name, LPCWSTR string )
265 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
266 service_set_value( val, REG_SZ, name, string, len );
269 static inline void service_set_multi_string( struct reg_value *val,
270 LPCWSTR name, LPCWSTR string )
274 /* determine the length of a double null terminated multi string */
276 len += (lstrlenW( &string[ len ] )+1);
277 } while ( string[ len++ ] );
279 len *= sizeof (WCHAR);
280 service_set_value( val, REG_MULTI_SZ, name, string, len );
283 static inline LONG service_write_values( HKEY hKey,
284 const struct reg_value *val, int n )
286 LONG r = ERROR_SUCCESS;
291 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
292 (const BYTE*)val[i].data, val[i].size );
293 if( r != ERROR_SUCCESS )
299 /******************************************************************************
300 * Service IPC functions
302 static LPWSTR service_get_pipe_name(LPCWSTR service)
304 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
305 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
309 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
310 name = HeapAlloc(GetProcessHeap(), 0, len);
311 strcpyW(name, prefix);
312 strcatW(name, service);
316 static HANDLE service_open_pipe(LPCWSTR service)
318 LPWSTR szPipe = service_get_pipe_name( service );
319 HANDLE handle = INVALID_HANDLE_VALUE;
322 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
323 0, NULL, OPEN_ALWAYS, 0, NULL);
324 if (handle != INVALID_HANDLE_VALUE)
326 if (GetLastError() != ERROR_PIPE_BUSY)
328 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
334 /******************************************************************************
335 * service_get_event_handle
337 static HANDLE service_get_event_handle(LPCWSTR service)
339 static const WCHAR prefix[] = {
340 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
345 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
346 name = HeapAlloc(GetProcessHeap(), 0, len);
347 strcpyW(name, prefix);
348 strcatW(name, service);
349 handle = CreateEventW(NULL, TRUE, FALSE, name);
354 /******************************************************************************
357 * Call into the main service routine provided by StartServiceCtrlDispatcher.
359 static DWORD WINAPI service_thread(LPVOID arg)
361 service_data *info = arg;
362 LPWSTR str = info->args;
363 DWORD argc = 0, len = 0;
369 len += strlenW(&str[len]) + 1;
376 info->proc.w(0, NULL);
378 info->proc.a(0, NULL);
386 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
387 for (argc=0, p=str; *p; p += strlenW(p) + 1)
391 info->proc.w(argc, argv);
392 HeapFree(GetProcessHeap(), 0, argv);
396 LPSTR strA, *argv, p;
399 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
400 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
401 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
403 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
404 for (argc=0, p=strA; *p; p += strlen(p) + 1)
408 info->proc.a(argc, argv);
409 HeapFree(GetProcessHeap(), 0, argv);
410 HeapFree(GetProcessHeap(), 0, strA);
415 /******************************************************************************
416 * service_handle_start
418 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
420 DWORD read = 0, result = 0;
424 TRACE("%p %p %d\n", pipe, service, count);
426 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
427 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
428 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
430 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
431 r, count, read, debugstr_wn(args, count));
437 ERR("service is not stopped\n");
441 SERV_free(service->args);
442 service->args = args;
444 service->thread = CreateThread( NULL, 0, service_thread,
448 HeapFree(GetProcessHeap(), 0, args);
449 WriteFile( pipe, &result, sizeof result, &read, NULL );
454 /******************************************************************************
455 * service_send_start_message
457 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
459 DWORD i, len, count, result;
460 service_start_info *ssi;
464 TRACE("%p %p %d\n", pipe, argv, argc);
466 /* calculate how much space do we need to send the startup info */
468 for (i=0; i<argc; i++)
469 len += strlenW(argv[i])+1;
471 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
472 ssi->cmd = WINESERV_STARTINFO;
475 /* copy service args into a single buffer*/
477 for (i=0; i<argc; i++)
484 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
486 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
488 HeapFree(GetProcessHeap(),0,ssi);
493 /******************************************************************************
494 * service_handle_get_status
496 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
500 return WriteFile(pipe, &service->status,
501 sizeof service->status, &count, NULL);
504 /******************************************************************************
507 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
509 DWORD cmd[2], count = 0;
512 cmd[0] = WINESERV_GETSTATUS;
514 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
515 if (!r || count != sizeof cmd)
517 ERR("service protocol error - failed to write pipe!\n");
520 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
521 if (!r || count != sizeof *status)
522 ERR("service protocol error - failed to read pipe "
523 "r = %d count = %d!\n", r, count);
527 /******************************************************************************
528 * service_handle_set_processID
530 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
532 DWORD count, ret = ERROR_SUCCESS;
534 TRACE("received control %d\n", dwProcessId);
535 service->status.dwProcessId = dwProcessId;
536 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
539 /******************************************************************************
540 * service_set_processID
542 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
544 DWORD cmd[2], count = 0;
547 cmd[0] = WINESERV_SETPID;
548 cmd[1] = dwprocessId;
549 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
550 if (!r || count != sizeof cmd)
552 ERR("service protocol error - failed to write pipe!\n");
555 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
556 if (!r || count != sizeof *dwResult)
557 ERR("service protocol error - failed to read pipe "
558 "r = %d count = %d!\n", r, count);
562 /******************************************************************************
563 * service_send_control
565 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
567 DWORD cmd[2], count = 0;
570 cmd[0] = WINESERV_SENDCONTROL;
572 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
573 if (!r || count != sizeof cmd)
575 ERR("service protocol error - failed to write pipe!\n");
578 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
579 if (!r || count != sizeof *result)
580 ERR("service protocol error - failed to read pipe "
581 "r = %d count = %d!\n", r, count);
585 /******************************************************************************
586 * service_accepts_control
588 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
590 DWORD a = service->status.dwControlsAccepted;
594 case SERVICE_CONTROL_INTERROGATE:
596 case SERVICE_CONTROL_STOP:
597 if (a&SERVICE_ACCEPT_STOP)
600 case SERVICE_CONTROL_SHUTDOWN:
601 if (a&SERVICE_ACCEPT_SHUTDOWN)
604 case SERVICE_CONTROL_PAUSE:
605 case SERVICE_CONTROL_CONTINUE:
606 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
609 case SERVICE_CONTROL_PARAMCHANGE:
610 if (a&SERVICE_ACCEPT_PARAMCHANGE)
613 case SERVICE_CONTROL_NETBINDADD:
614 case SERVICE_CONTROL_NETBINDREMOVE:
615 case SERVICE_CONTROL_NETBINDENABLE:
616 case SERVICE_CONTROL_NETBINDDISABLE:
617 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
620 if (!service->extended)
624 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
625 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
628 case SERVICE_CONTROL_POWEREVENT:
629 if (a&SERVICE_ACCEPT_POWEREVENT)
632 case SERVICE_CONTROL_SESSIONCHANGE:
633 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
640 /******************************************************************************
641 * service_handle_control
643 static BOOL service_handle_control(HANDLE pipe, service_data *service,
646 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
648 TRACE("received control %d\n", dwControl);
650 if (service_accepts_control(service, dwControl))
652 if (service->extended && service->handler.handler_ex)
654 service->handler.handler_ex(dwControl, 0, NULL, service->context);
657 else if (service->handler.handler)
659 service->handler.handler(dwControl);
663 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
666 /******************************************************************************
667 * service_reap_thread
669 static DWORD service_reap_thread(service_data *service)
673 if (!service->thread)
675 GetExitCodeThread(service->thread, &exitcode);
676 if (exitcode!=STILL_ACTIVE)
678 CloseHandle(service->thread);
684 /******************************************************************************
685 * service_control_dispatcher
687 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
689 service_data *service = arg;
693 TRACE("%p %s\n", service, debugstr_w(service->name));
695 /* create a pipe to talk to the rest of the world with */
696 name = service_get_pipe_name(service->name);
697 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
698 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
701 /* let the process who started us know we've tried to create a pipe */
702 event = service_get_event_handle(service->name);
706 if (pipe==INVALID_HANDLE_VALUE)
708 ERR("failed to create pipe for %s, error = %d\n",
709 debugstr_w(service->name), GetLastError());
713 /* dispatcher loop */
717 DWORD count, req[2] = {0,0};
719 r = ConnectNamedPipe(pipe, NULL);
720 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
722 ERR("pipe connect failed\n");
726 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
727 if (!r || count!=sizeof req)
729 ERR("pipe read failed\n");
733 service_reap_thread(service);
735 /* handle the request */
738 case WINESERV_STARTINFO:
739 service_handle_start(pipe, service, req[1]);
741 case WINESERV_GETSTATUS:
742 service_handle_get_status(pipe, service);
744 case WINESERV_SENDCONTROL:
745 service_handle_control(pipe, service, req[1]);
747 case WINESERV_SETPID:
748 service_handle_set_processID(pipe, service, req[1]);
751 ERR("received invalid command %d length %d\n", req[0], req[1]);
754 FlushFileBuffers(pipe);
755 DisconnectNamedPipe(pipe);
762 /******************************************************************************
763 * service_run_threads
765 static BOOL service_run_threads(void)
767 service_data *service;
771 EnterCriticalSection( &service_cs );
773 count = list_count( &service_list );
775 TRACE("starting %d pipe listener threads\n", count);
777 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
779 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
780 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
784 LeaveCriticalSection( &service_cs );
786 /* wait for all the threads to pack up and exit */
787 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
789 HeapFree(GetProcessHeap(), 0, handles);
794 /******************************************************************************
795 * StartServiceCtrlDispatcherA [ADVAPI32.@]
797 * See StartServiceCtrlDispatcherW.
799 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
805 TRACE("%p\n", servent);
807 EnterCriticalSection( &service_cs );
808 while (servent->lpServiceName)
810 LPSTR name = servent->lpServiceName;
812 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
813 sz = len*sizeof(WCHAR) + sizeof *info;
814 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
815 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
816 info->proc.a = servent->lpServiceProc;
817 info->unicode = FALSE;
818 list_add_head( &service_list, &info->entry );
821 LeaveCriticalSection( &service_cs );
823 service_run_threads();
828 /******************************************************************************
829 * StartServiceCtrlDispatcherW [ADVAPI32.@]
831 * Connects a process containing one or more services to the service control
835 * servent [I] A list of the service names and service procedures
841 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
847 TRACE("%p\n", servent);
849 EnterCriticalSection( &service_cs );
850 while (servent->lpServiceName)
852 LPWSTR name = servent->lpServiceName;
855 sz = len*sizeof(WCHAR) + sizeof *info;
856 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
857 strcpyW(info->name, name);
858 info->proc.w = servent->lpServiceProc;
859 info->unicode = TRUE;
860 list_add_head( &service_list, &info->entry );
863 LeaveCriticalSection( &service_cs );
865 service_run_threads();
870 /******************************************************************************
871 * LockServiceDatabase [ADVAPI32.@]
873 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
877 TRACE("%p\n",hSCManager);
879 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
880 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
884 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
887 TRACE("returning %p\n", ret);
892 /******************************************************************************
893 * UnlockServiceDatabase [ADVAPI32.@]
895 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
897 TRACE("%p\n",ScLock);
899 return CloseHandle( ScLock );
902 /******************************************************************************
903 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
905 SERVICE_STATUS_HANDLE WINAPI
906 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
908 LPWSTR lpServiceNameW;
909 SERVICE_STATUS_HANDLE ret;
911 lpServiceNameW = SERV_dup(lpServiceName);
912 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
913 SERV_free(lpServiceNameW);
917 /******************************************************************************
918 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
924 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
925 LPHANDLER_FUNCTION lpfHandler )
927 service_data *service;
928 SERVICE_STATUS_HANDLE handle = 0;
930 EnterCriticalSection( &service_cs );
931 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
933 if(!strcmpW(lpServiceName, service->name))
935 service->handler.handler = lpfHandler;
936 handle = (SERVICE_STATUS_HANDLE)service;
940 LeaveCriticalSection( &service_cs );
944 /******************************************************************************
945 * SetServiceStatus [ADVAPI32.@]
952 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
954 service_data *service;
957 TRACE("%p %x %x %x %x %x %x %x\n", hService,
958 lpStatus->dwServiceType, lpStatus->dwCurrentState,
959 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
960 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
961 lpStatus->dwWaitHint);
963 EnterCriticalSection( &service_cs );
964 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
966 if(service == (service_data*)hService)
968 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
969 TRACE("Set service status to %d\n",service->status.dwCurrentState);
974 LeaveCriticalSection( &service_cs );
980 /******************************************************************************
981 * OpenSCManagerA [ADVAPI32.@]
983 * Establish a connection to the service control manager and open its database.
986 * lpMachineName [I] Pointer to machine name string
987 * lpDatabaseName [I] Pointer to database name string
988 * dwDesiredAccess [I] Type of access
991 * Success: A Handle to the service control manager database
994 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
995 DWORD dwDesiredAccess )
997 LPWSTR lpMachineNameW, lpDatabaseNameW;
1000 lpMachineNameW = SERV_dup(lpMachineName);
1001 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1002 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1003 SERV_free(lpDatabaseNameW);
1004 SERV_free(lpMachineNameW);
1008 /******************************************************************************
1009 * OpenSCManagerW [ADVAPI32.@]
1011 * See OpenSCManagerA.
1013 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1014 DWORD dwDesiredAccess )
1016 struct sc_manager *manager;
1020 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1021 debugstr_w(lpDatabaseName), dwDesiredAccess);
1023 if( lpDatabaseName && lpDatabaseName[0] )
1025 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1027 /* noop, all right */
1029 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1031 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1036 SetLastError( ERROR_INVALID_NAME );
1041 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1042 sc_handle_destroy_manager );
1046 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1047 if (r!=ERROR_SUCCESS)
1050 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1051 RegCloseKey( hReg );
1052 if (r!=ERROR_SUCCESS)
1055 manager->dwAccess = dwDesiredAccess;
1056 TRACE("returning %p\n", manager);
1058 return (SC_HANDLE) &manager->hdr;
1061 sc_handle_free( &manager->hdr );
1066 /******************************************************************************
1067 * ControlService [ADVAPI32.@]
1069 * Send a control code to a service.
1072 * hService [I] Handle of the service control manager database
1073 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1074 * lpServiceStatus [O] Destination for the status of the service, if available
1081 * Unlike M$' implementation, control requests are not serialized and may be
1082 * processed asynchronously.
1084 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1085 LPSERVICE_STATUS lpServiceStatus )
1087 struct sc_service *hsvc;
1091 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1093 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1096 SetLastError( ERROR_INVALID_HANDLE );
1100 ret = QueryServiceStatus(hService, lpServiceStatus);
1103 ERR("failed to query service status\n");
1104 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1108 switch (lpServiceStatus->dwCurrentState)
1110 case SERVICE_STOPPED:
1111 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1113 case SERVICE_START_PENDING:
1114 if (dwControl==SERVICE_CONTROL_STOP)
1117 case SERVICE_STOP_PENDING:
1118 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1122 handle = service_open_pipe(hsvc->name);
1123 if (handle!=INVALID_HANDLE_VALUE)
1125 DWORD result = ERROR_SUCCESS;
1126 ret = service_send_control(handle, dwControl, &result);
1127 CloseHandle(handle);
1128 if (result!=ERROR_SUCCESS)
1130 SetLastError(result);
1138 /******************************************************************************
1139 * CloseServiceHandle [ADVAPI32.@]
1141 * Close a handle to a service or the service control manager database.
1144 * hSCObject [I] Handle to service or service control manager database
1151 CloseServiceHandle( SC_HANDLE hSCObject )
1153 TRACE("%p\n", hSCObject);
1155 sc_handle_free( (struct sc_handle*) hSCObject );
1161 /******************************************************************************
1162 * OpenServiceA [ADVAPI32.@]
1164 * Open a handle to a service.
1167 * hSCManager [I] Handle of the service control manager database
1168 * lpServiceName [I] Name of the service to open
1169 * dwDesiredAccess [I] Access required to the service
1172 * Success: Handle to the service
1175 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1176 DWORD dwDesiredAccess )
1178 LPWSTR lpServiceNameW;
1181 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1183 lpServiceNameW = SERV_dup(lpServiceName);
1184 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1185 SERV_free(lpServiceNameW);
1190 /******************************************************************************
1191 * OpenServiceW [ADVAPI32.@]
1195 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1196 DWORD dwDesiredAccess)
1198 struct sc_manager *hscm;
1199 struct sc_service *hsvc;
1204 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1208 SetLastError(ERROR_INVALID_ADDRESS);
1212 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1215 SetLastError( ERROR_INVALID_HANDLE );
1219 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1220 if (r!=ERROR_SUCCESS)
1222 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1226 len = strlenW(lpServiceName)+1;
1227 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1228 sizeof (struct sc_service) + len*sizeof(WCHAR),
1229 sc_handle_destroy_service );
1232 strcpyW( hsvc->name, lpServiceName );
1234 hsvc->dwAccess = dwDesiredAccess;
1236 /* add reference to SCM handle */
1237 hscm->hdr.ref_count++;
1240 TRACE("returning %p\n",hsvc);
1242 return (SC_HANDLE) &hsvc->hdr;
1245 /******************************************************************************
1246 * CreateServiceW [ADVAPI32.@]
1249 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1250 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1251 DWORD dwServiceType, DWORD dwStartType,
1252 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1253 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1254 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1255 LPCWSTR lpPassword )
1257 struct sc_manager *hscm;
1258 struct sc_service *hsvc = NULL;
1262 struct reg_value val[10];
1265 TRACE("%p %s %s\n", hSCManager,
1266 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1268 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1271 SetLastError( ERROR_INVALID_HANDLE );
1275 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1276 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1277 if (r!=ERROR_SUCCESS)
1280 if (dp != REG_CREATED_NEW_KEY)
1282 SetLastError(ERROR_SERVICE_EXISTS);
1287 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1289 service_set_dword( &val[n++], szType, &dwServiceType );
1290 service_set_dword( &val[n++], szStart, &dwStartType );
1291 service_set_dword( &val[n++], szError, &dwErrorControl );
1293 if( lpBinaryPathName )
1294 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1296 if( lpLoadOrderGroup )
1297 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1299 if( lpDependencies )
1300 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1303 FIXME("Don't know how to add a Password for a service.\n");
1305 if( lpServiceStartName )
1306 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1308 r = service_write_values( hKey, val, n );
1309 if( r != ERROR_SUCCESS )
1312 len = strlenW(lpServiceName)+1;
1313 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1314 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1317 lstrcpyW( hsvc->name, lpServiceName );
1320 hscm->hdr.ref_count++;
1322 return (SC_HANDLE) &hsvc->hdr;
1325 RegCloseKey( hKey );
1330 /******************************************************************************
1331 * CreateServiceA [ADVAPI32.@]
1334 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1335 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1336 DWORD dwServiceType, DWORD dwStartType,
1337 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1338 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1339 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1342 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1343 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1346 TRACE("%p %s %s\n", hSCManager,
1347 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1349 lpServiceNameW = SERV_dup( lpServiceName );
1350 lpDisplayNameW = SERV_dup( lpDisplayName );
1351 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1352 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1353 lpDependenciesW = SERV_dupmulti( lpDependencies );
1354 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1355 lpPasswordW = SERV_dup( lpPassword );
1357 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1358 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1359 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1360 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1362 SERV_free( lpServiceNameW );
1363 SERV_free( lpDisplayNameW );
1364 SERV_free( lpBinaryPathNameW );
1365 SERV_free( lpLoadOrderGroupW );
1366 SERV_free( lpDependenciesW );
1367 SERV_free( lpServiceStartNameW );
1368 SERV_free( lpPasswordW );
1374 /******************************************************************************
1375 * DeleteService [ADVAPI32.@]
1377 * Delete a service from the service control manager database.
1380 * hService [I] Handle of the service to delete
1386 BOOL WINAPI DeleteService( SC_HANDLE hService )
1388 struct sc_service *hsvc;
1390 WCHAR valname[MAX_PATH+1];
1395 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1398 SetLastError( ERROR_INVALID_HANDLE );
1404 /* Clean out the values */
1405 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1406 while (rc == ERROR_SUCCESS)
1408 RegDeleteValueW(hKey,valname);
1411 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1417 /* delete the key */
1418 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1424 /******************************************************************************
1425 * StartServiceA [ADVAPI32.@]
1430 * hService [I] Handle of service
1431 * dwNumServiceArgs [I] Number of arguments
1432 * lpServiceArgVectors [I] Address of array of argument strings
1435 * - NT implements this function using an obscure RPC call.
1436 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1437 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1438 * - This will only work for shared address space. How should the service
1439 * args be transferred when address spaces are separated?
1440 * - Can only start one service at a time.
1441 * - Has no concept of privilege.
1447 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1448 LPCSTR *lpServiceArgVectors )
1450 LPWSTR *lpwstr=NULL;
1454 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1456 if (dwNumServiceArgs)
1457 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1458 dwNumServiceArgs*sizeof(LPWSTR) );
1460 for(i=0; i<dwNumServiceArgs; i++)
1461 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1463 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1465 if (dwNumServiceArgs)
1467 for(i=0; i<dwNumServiceArgs; i++)
1468 SERV_free(lpwstr[i]);
1469 HeapFree(GetProcessHeap(), 0, lpwstr);
1475 /******************************************************************************
1476 * service_start_process [INTERNAL]
1478 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1480 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1481 PROCESS_INFORMATION pi;
1483 LPWSTR path = NULL, str;
1484 DWORD type, size, ret, svc_type;
1488 size = sizeof(svc_type);
1489 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1492 if (svc_type == SERVICE_KERNEL_DRIVER)
1494 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1495 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1497 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1498 GetSystemDirectoryW( path, len );
1499 lstrcatW( path, winedeviceW );
1500 lstrcatW( path, hsvc->name );
1504 /* read the executable path from the registry */
1506 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1507 if (ret!=ERROR_SUCCESS)
1509 str = HeapAlloc(GetProcessHeap(),0,size);
1510 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1511 if (ret==ERROR_SUCCESS)
1513 size = ExpandEnvironmentStringsW(str,NULL,0);
1514 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1515 ExpandEnvironmentStringsW(str,path,size);
1517 HeapFree(GetProcessHeap(),0,str);
1522 /* wait for the process to start and set an event or terminate */
1523 handles[0] = service_get_event_handle( hsvc->name );
1524 ZeroMemory(&si, sizeof(STARTUPINFOW));
1525 si.cb = sizeof(STARTUPINFOW);
1526 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1529 if (ppid) *ppid = pi.dwProcessId;
1531 handles[1] = pi.hProcess;
1532 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1533 if(ret != WAIT_OBJECT_0)
1535 SetLastError(ERROR_IO_PENDING);
1539 CloseHandle( pi.hThread );
1540 CloseHandle( pi.hProcess );
1542 CloseHandle( handles[0] );
1543 HeapFree(GetProcessHeap(),0,path);
1547 static BOOL service_wait_for_startup(SC_HANDLE hService)
1550 SERVICE_STATUS status;
1553 TRACE("%p\n", hService);
1555 for (i=0; i<30; i++)
1557 status.dwCurrentState = 0;
1558 r = QueryServiceStatus(hService, &status);
1561 if (status.dwCurrentState == SERVICE_RUNNING)
1563 TRACE("Service started successfully\n");
1572 /******************************************************************************
1573 * StartServiceW [ADVAPI32.@]
1575 * See StartServiceA.
1577 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1578 LPCWSTR *lpServiceArgVectors)
1580 struct sc_service *hsvc;
1582 DWORD dwResult, dwProcessId = 0;
1584 HANDLE handle = INVALID_HANDLE_VALUE;
1586 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1588 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1591 SetLastError(ERROR_INVALID_HANDLE);
1595 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1599 handle = service_open_pipe(hsvc->name);
1600 if (handle==INVALID_HANDLE_VALUE)
1602 /* start the service process */
1603 if (service_start_process(hsvc, &dwProcessId))
1604 handle = service_open_pipe(hsvc->name);
1607 if (handle != INVALID_HANDLE_VALUE)
1609 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1610 CloseHandle(handle);
1613 handle = service_open_pipe(hsvc->name);
1614 if (handle != INVALID_HANDLE_VALUE)
1616 service_set_processID(handle, dwProcessId, &dwResult);
1617 CloseHandle(handle);
1620 UnlockServiceDatabase( hLock );
1622 TRACE("returning %d\n", r);
1625 service_wait_for_startup(hService);
1630 /******************************************************************************
1631 * QueryServiceStatus [ADVAPI32.@]
1634 * hService [I] Handle to service to get information about
1635 * lpservicestatus [O] buffer to receive the status information for the service
1638 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1639 LPSERVICE_STATUS lpservicestatus)
1641 SERVICE_STATUS_PROCESS SvcStatusData;
1644 TRACE("%p %p\n", hService, lpservicestatus);
1646 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1647 sizeof(SERVICE_STATUS_PROCESS), NULL);
1648 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1653 /******************************************************************************
1654 * QueryServiceStatusEx [ADVAPI32.@]
1656 * Get information about a service.
1659 * hService [I] Handle to service to get information about
1660 * InfoLevel [I] Level of information to get
1661 * lpBuffer [O] Destination for requested information
1662 * cbBufSize [I] Size of lpBuffer in bytes
1663 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1669 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1670 LPBYTE lpBuffer, DWORD cbBufSize,
1671 LPDWORD pcbBytesNeeded)
1673 struct sc_service *hsvc;
1674 DWORD size, type, val;
1677 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1679 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1681 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1683 SetLastError( ERROR_INVALID_LEVEL);
1687 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1688 if (pSvcStatusData == NULL)
1690 SetLastError( ERROR_INVALID_PARAMETER);
1694 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1696 if( pcbBytesNeeded != NULL)
1697 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1699 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1703 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1706 SetLastError( ERROR_INVALID_HANDLE );
1710 pipe = service_open_pipe(hsvc->name);
1711 if (pipe != INVALID_HANDLE_VALUE)
1713 r = service_get_status(pipe, pSvcStatusData);
1719 TRACE("Failed to read service status\n");
1721 /* read the service type from the registry */
1723 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1724 if (r != ERROR_SUCCESS || type != REG_DWORD)
1727 pSvcStatusData->dwServiceType = val;
1728 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1729 pSvcStatusData->dwControlsAccepted = 0;
1730 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1731 pSvcStatusData->dwServiceSpecificExitCode = 0;
1732 pSvcStatusData->dwCheckPoint = 0;
1733 pSvcStatusData->dwWaitHint = 0;
1738 /******************************************************************************
1739 * QueryServiceConfigA [ADVAPI32.@]
1741 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1742 DWORD size, LPDWORD needed )
1747 QUERY_SERVICE_CONFIGW *configW;
1749 TRACE("%p %p %d %p\n", hService, config, size, needed);
1751 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1753 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1756 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1757 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1758 if (!ret) goto done;
1760 config->dwServiceType = configW->dwServiceType;
1761 config->dwStartType = configW->dwStartType;
1762 config->dwErrorControl = configW->dwErrorControl;
1763 config->lpBinaryPathName = NULL;
1764 config->lpLoadOrderGroup = NULL;
1765 config->dwTagId = configW->dwTagId;
1766 config->lpDependencies = NULL;
1767 config->lpServiceStartName = NULL;
1768 config->lpDisplayName = NULL;
1770 p = (LPSTR)(config + 1);
1771 n = size - sizeof(*config);
1774 #define MAP_STR(str) \
1778 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1779 if (!sz) goto done; \
1786 MAP_STR( lpBinaryPathName );
1787 MAP_STR( lpLoadOrderGroup );
1788 MAP_STR( lpDependencies );
1789 MAP_STR( lpServiceStartName );
1790 MAP_STR( lpDisplayName );
1793 *needed = p - buffer;
1797 HeapFree( GetProcessHeap(), 0, buffer );
1801 /******************************************************************************
1802 * QueryServiceConfigW [ADVAPI32.@]
1805 QueryServiceConfigW( SC_HANDLE hService,
1806 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1807 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1809 WCHAR str_buffer[ MAX_PATH ];
1811 DWORD type, val, sz, total, n;
1814 struct sc_service *hsvc;
1816 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1817 cbBufSize, pcbBytesNeeded);
1819 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1822 SetLastError( ERROR_INVALID_HANDLE );
1827 /* calculate the size required first */
1828 total = sizeof (QUERY_SERVICE_CONFIGW);
1830 sz = sizeof(str_buffer);
1831 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1832 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1834 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1835 if( 0 == sz ) return FALSE;
1837 total += sizeof(WCHAR) * sz;
1841 /* FIXME: set last error */
1846 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1847 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1851 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1852 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1855 total += sizeof(WCHAR);
1858 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1859 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1863 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1864 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1867 *pcbBytesNeeded = total;
1869 /* if there's not enough memory, return an error */
1870 if( total > cbBufSize )
1872 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1876 ZeroMemory( lpServiceConfig, total );
1879 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1880 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1881 lpServiceConfig->dwServiceType = val;
1884 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1885 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1886 lpServiceConfig->dwStartType = val;
1889 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1890 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1891 lpServiceConfig->dwErrorControl = val;
1893 /* now do the strings */
1894 p = (LPBYTE) &lpServiceConfig[1];
1895 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1897 sz = sizeof(str_buffer);
1898 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1899 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1901 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1902 sz *= sizeof(WCHAR);
1903 if( 0 == sz || sz > n ) return FALSE;
1905 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1911 /* FIXME: set last error */
1916 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1917 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1919 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1925 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1926 lpServiceConfig->lpDependencies = (LPWSTR) p;
1927 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1940 ERR("Buffer overflow!\n");
1942 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1943 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1948 /******************************************************************************
1949 * EnumServicesStatusA [ADVAPI32.@]
1952 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1953 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1954 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1955 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1957 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1958 dwServiceType, dwServiceState, lpServices, cbBufSize,
1959 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1960 SetLastError (ERROR_ACCESS_DENIED);
1964 /******************************************************************************
1965 * EnumServicesStatusW [ADVAPI32.@]
1968 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1969 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1970 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1971 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1973 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1974 dwServiceType, dwServiceState, lpServices, cbBufSize,
1975 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1976 SetLastError (ERROR_ACCESS_DENIED);
1980 /******************************************************************************
1981 * EnumServicesStatusExA [ADVAPI32.@]
1984 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1985 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1986 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1988 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1989 dwServiceType, dwServiceState, lpServices, cbBufSize,
1990 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1991 SetLastError (ERROR_ACCESS_DENIED);
1995 /******************************************************************************
1996 * EnumServicesStatusExW [ADVAPI32.@]
1999 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2000 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2001 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2003 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2004 dwServiceType, dwServiceState, lpServices, cbBufSize,
2005 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2006 SetLastError (ERROR_ACCESS_DENIED);
2010 /******************************************************************************
2011 * GetServiceKeyNameA [ADVAPI32.@]
2013 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2014 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2016 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2020 /******************************************************************************
2021 * GetServiceKeyNameW [ADVAPI32.@]
2023 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2024 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2026 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2030 /******************************************************************************
2031 * QueryServiceLockStatusA [ADVAPI32.@]
2033 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2034 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2035 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2037 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2042 /******************************************************************************
2043 * QueryServiceLockStatusW [ADVAPI32.@]
2045 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2046 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2047 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2049 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2054 /******************************************************************************
2055 * GetServiceDisplayNameA [ADVAPI32.@]
2057 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2058 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2060 struct sc_manager *hscm;
2064 TRACE("%p %s %p %p\n", hSCManager,
2065 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2069 SetLastError(ERROR_INVALID_PARAMETER);
2073 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2076 SetLastError(ERROR_INVALID_HANDLE);
2080 size = *lpcchBuffer;
2081 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2082 if (!ret && !lpDisplayName && size)
2083 ret = ERROR_MORE_DATA;
2087 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2089 if (ret == ERROR_MORE_DATA)
2091 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2092 *lpcchBuffer = size - 1;
2101 /******************************************************************************
2102 * GetServiceDisplayNameW [ADVAPI32.@]
2104 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2105 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2107 struct sc_manager *hscm;
2111 TRACE("%p %s %p %p\n", hSCManager,
2112 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2116 SetLastError(ERROR_INVALID_PARAMETER);
2120 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2123 SetLastError(ERROR_INVALID_HANDLE);
2127 size = *lpcchBuffer * sizeof(WCHAR);
2128 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2129 if (!ret && !lpDisplayName && size)
2130 ret = ERROR_MORE_DATA;
2134 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2136 if (ret == ERROR_MORE_DATA)
2138 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2139 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2148 /******************************************************************************
2149 * ChangeServiceConfigW [ADVAPI32.@]
2151 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2152 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2153 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2154 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2156 struct reg_value val[10];
2157 struct sc_service *hsvc;
2158 DWORD r = ERROR_SUCCESS;
2162 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2163 hService, dwServiceType, dwStartType, dwErrorControl,
2164 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2165 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2166 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2168 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2171 SetLastError( ERROR_INVALID_HANDLE );
2176 if( dwServiceType != SERVICE_NO_CHANGE )
2177 service_set_dword( &val[n++], szType, &dwServiceType );
2179 if( dwStartType != SERVICE_NO_CHANGE )
2180 service_set_dword( &val[n++], szStart, &dwStartType );
2182 if( dwErrorControl != SERVICE_NO_CHANGE )
2183 service_set_dword( &val[n++], szError, &dwErrorControl );
2185 if( lpBinaryPathName )
2186 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2188 if( lpLoadOrderGroup )
2189 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2191 if( lpDependencies )
2192 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2195 FIXME("ignoring password\n");
2197 if( lpServiceStartName )
2198 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2200 r = service_write_values( hsvc->hkey, val, n );
2202 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2205 /******************************************************************************
2206 * ChangeServiceConfigA [ADVAPI32.@]
2208 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2209 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2210 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2211 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2213 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2214 LPWSTR wServiceStartName, wPassword, wDisplayName;
2217 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2218 hService, dwServiceType, dwStartType, dwErrorControl,
2219 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2220 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2221 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2223 wBinaryPathName = SERV_dup( lpBinaryPathName );
2224 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2225 wDependencies = SERV_dupmulti( lpDependencies );
2226 wServiceStartName = SERV_dup( lpServiceStartName );
2227 wPassword = SERV_dup( lpPassword );
2228 wDisplayName = SERV_dup( lpDisplayName );
2230 r = ChangeServiceConfigW( hService, dwServiceType,
2231 dwStartType, dwErrorControl, wBinaryPathName,
2232 wLoadOrderGroup, lpdwTagId, wDependencies,
2233 wServiceStartName, wPassword, wDisplayName);
2235 SERV_free( wBinaryPathName );
2236 SERV_free( wLoadOrderGroup );
2237 SERV_free( wDependencies );
2238 SERV_free( wServiceStartName );
2239 SERV_free( wPassword );
2240 SERV_free( wDisplayName );
2245 /******************************************************************************
2246 * ChangeServiceConfig2A [ADVAPI32.@]
2248 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2253 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2255 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2257 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2258 SERVICE_DESCRIPTIONW sdw;
2260 sdw.lpDescription = SERV_dup( sd->lpDescription );
2262 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2264 SERV_free( sdw.lpDescription );
2266 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2268 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2269 SERVICE_FAILURE_ACTIONSW faw;
2271 faw.dwResetPeriod = fa->dwResetPeriod;
2272 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2273 faw.lpCommand = SERV_dup( fa->lpCommand );
2274 faw.cActions = fa->cActions;
2275 faw.lpsaActions = fa->lpsaActions;
2277 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2279 SERV_free( faw.lpRebootMsg );
2280 SERV_free( faw.lpCommand );
2283 SetLastError( ERROR_INVALID_PARAMETER );
2288 /******************************************************************************
2289 * ChangeServiceConfig2W [ADVAPI32.@]
2291 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2295 struct sc_service *hsvc;
2297 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2300 SetLastError( ERROR_INVALID_HANDLE );
2305 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2307 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2308 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2309 if (sd->lpDescription)
2311 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2312 if (sd->lpDescription[0] == 0)
2313 RegDeleteValueW(hKey,szDescription);
2315 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2316 (LPVOID)sd->lpDescription,
2317 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2321 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2325 /******************************************************************************
2326 * QueryServiceObjectSecurity [ADVAPI32.@]
2328 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2329 SECURITY_INFORMATION dwSecurityInformation,
2330 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2331 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2335 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2336 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2338 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2340 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2341 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2342 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2346 /******************************************************************************
2347 * SetServiceObjectSecurity [ADVAPI32.@]
2349 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2350 SECURITY_INFORMATION dwSecurityInformation,
2351 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2353 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2357 /******************************************************************************
2358 * SetServiceBits [ADVAPI32.@]
2360 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2361 DWORD dwServiceBits,
2363 BOOL bUpdateImmediately)
2365 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2366 bSetBitsOn, bUpdateImmediately);
2370 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2371 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2373 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2377 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2378 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2380 service_data *service;
2381 SERVICE_STATUS_HANDLE handle = 0;
2383 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2385 EnterCriticalSection( &service_cs );
2386 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2388 if(!strcmpW(lpServiceName, service->name))
2390 service->handler.handler_ex = lpHandlerProc;
2391 service->context = lpContext;
2392 service->extended = TRUE;
2393 handle = (SERVICE_STATUS_HANDLE)service;
2397 LeaveCriticalSection( &service_cs );