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 extern HANDLE __wine_make_process_system(void);
94 /******************************************************************************
98 #define MAX_SERVICE_NAME 256
100 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
103 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
107 SC_HANDLE_TYPE htype;
109 sc_handle_destructor destroy;
112 struct sc_manager /* service control manager handle */
114 struct sc_handle hdr;
115 HKEY hkey; /* handle to services database in the registry */
119 struct sc_service /* service handle */
121 struct sc_handle hdr;
122 HKEY hkey; /* handle to service entry in the registry (under hkey) */
124 struct sc_manager *scm; /* pointer to SCM handle */
128 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
129 sc_handle_destructor destroy)
131 struct sc_handle *hdr;
133 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
138 hdr->destroy = destroy;
140 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
144 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
146 struct sc_handle *hdr = (struct sc_handle *) handle;
150 if (hdr->htype != htype)
155 static void sc_handle_free(struct sc_handle* hdr)
159 if (--hdr->ref_count)
162 HeapFree(GetProcessHeap(), 0, hdr);
165 static void sc_handle_destroy_manager(struct sc_handle *handle)
167 struct sc_manager *mgr = (struct sc_manager*) handle;
169 TRACE("destroying SC Manager %p\n", mgr);
171 RegCloseKey(mgr->hkey);
174 static void sc_handle_destroy_service(struct sc_handle *handle)
176 struct sc_service *svc = (struct sc_service*) handle;
178 TRACE("destroying service %p\n", svc);
180 RegCloseKey(svc->hkey);
182 sc_handle_free(&svc->scm->hdr);
186 /******************************************************************************
187 * String management functions
189 static inline LPWSTR SERV_dup( LPCSTR str )
196 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
197 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
198 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
202 static inline LPWSTR SERV_dupmulti(LPCSTR str)
210 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
211 n += (strlen( &str[n] ) + 1);
216 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
217 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
221 static inline VOID SERV_free( LPWSTR wstr )
223 HeapFree( GetProcessHeap(), 0, wstr );
226 /******************************************************************************
227 * registry access functions and data
229 static const WCHAR szDisplayName[] = {
230 'D','i','s','p','l','a','y','N','a','m','e', 0 };
231 static const WCHAR szType[] = {'T','y','p','e',0};
232 static const WCHAR szStart[] = {'S','t','a','r','t',0};
233 static const WCHAR szError[] = {
234 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
235 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
236 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
237 static const WCHAR szDependencies[] = {
238 'D','e','p','e','n','d','e','n','c','i','e','s',0};
239 static const WCHAR szDependOnService[] = {
240 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
249 static inline void service_set_value( struct reg_value *val,
250 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
258 static inline void service_set_dword( struct reg_value *val,
259 LPCWSTR name, const DWORD *data )
261 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
264 static inline void service_set_string( struct reg_value *val,
265 LPCWSTR name, LPCWSTR string )
267 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
268 service_set_value( val, REG_SZ, name, string, len );
271 static inline void service_set_multi_string( struct reg_value *val,
272 LPCWSTR name, LPCWSTR string )
276 /* determine the length of a double null terminated multi string */
278 len += (lstrlenW( &string[ len ] )+1);
279 } while ( string[ len++ ] );
281 len *= sizeof (WCHAR);
282 service_set_value( val, REG_MULTI_SZ, name, string, len );
285 static inline LONG service_write_values( HKEY hKey,
286 const struct reg_value *val, int n )
288 LONG r = ERROR_SUCCESS;
293 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
294 (const BYTE*)val[i].data, val[i].size );
295 if( r != ERROR_SUCCESS )
301 /******************************************************************************
302 * Service IPC functions
304 static LPWSTR service_get_pipe_name(LPCWSTR service)
306 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
307 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
311 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
312 name = HeapAlloc(GetProcessHeap(), 0, len);
313 strcpyW(name, prefix);
314 strcatW(name, service);
318 static HANDLE service_open_pipe(LPCWSTR service)
320 LPWSTR szPipe = service_get_pipe_name( service );
321 HANDLE handle = INVALID_HANDLE_VALUE;
324 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
325 0, NULL, OPEN_ALWAYS, 0, NULL);
326 if (handle != INVALID_HANDLE_VALUE)
328 if (GetLastError() != ERROR_PIPE_BUSY)
330 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
336 /******************************************************************************
337 * service_get_event_handle
339 static HANDLE service_get_event_handle(LPCWSTR service)
341 static const WCHAR prefix[] = {
342 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
347 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
348 name = HeapAlloc(GetProcessHeap(), 0, len);
349 strcpyW(name, prefix);
350 strcatW(name, service);
351 handle = CreateEventW(NULL, TRUE, FALSE, name);
356 /******************************************************************************
359 * Call into the main service routine provided by StartServiceCtrlDispatcher.
361 static DWORD WINAPI service_thread(LPVOID arg)
363 service_data *info = arg;
364 LPWSTR str = info->args;
365 DWORD argc = 0, len = 0;
371 len += strlenW(&str[len]) + 1;
378 info->proc.w(0, NULL);
380 info->proc.a(0, NULL);
388 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
389 for (argc=0, p=str; *p; p += strlenW(p) + 1)
393 info->proc.w(argc, argv);
394 HeapFree(GetProcessHeap(), 0, argv);
398 LPSTR strA, *argv, p;
401 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
402 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
403 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
405 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
406 for (argc=0, p=strA; *p; p += strlen(p) + 1)
410 info->proc.a(argc, argv);
411 HeapFree(GetProcessHeap(), 0, argv);
412 HeapFree(GetProcessHeap(), 0, strA);
417 /******************************************************************************
418 * service_handle_start
420 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
422 DWORD read = 0, result = 0;
426 TRACE("%p %p %d\n", pipe, service, count);
428 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
429 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
430 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
432 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
433 r, count, read, debugstr_wn(args, count));
439 ERR("service is not stopped\n");
443 SERV_free(service->args);
444 service->args = args;
446 service->thread = CreateThread( NULL, 0, service_thread,
450 HeapFree(GetProcessHeap(), 0, args);
451 WriteFile( pipe, &result, sizeof result, &read, NULL );
456 /******************************************************************************
457 * service_send_start_message
459 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
461 DWORD i, len, count, result;
462 service_start_info *ssi;
466 TRACE("%p %p %d\n", pipe, argv, argc);
468 /* calculate how much space do we need to send the startup info */
470 for (i=0; i<argc; i++)
471 len += strlenW(argv[i])+1;
473 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
474 ssi->cmd = WINESERV_STARTINFO;
477 /* copy service args into a single buffer*/
479 for (i=0; i<argc; i++)
486 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
488 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
490 HeapFree(GetProcessHeap(),0,ssi);
495 /******************************************************************************
496 * service_handle_get_status
498 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
502 return WriteFile(pipe, &service->status,
503 sizeof service->status, &count, NULL);
506 /******************************************************************************
509 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
511 DWORD cmd[2], count = 0;
514 cmd[0] = WINESERV_GETSTATUS;
516 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
517 if (!r || count != sizeof cmd)
519 ERR("service protocol error - failed to write pipe!\n");
522 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
523 if (!r || count != sizeof *status)
524 ERR("service protocol error - failed to read pipe "
525 "r = %d count = %d!\n", r, count);
529 /******************************************************************************
530 * service_handle_set_processID
532 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
534 DWORD count, ret = ERROR_SUCCESS;
536 TRACE("received control %d\n", dwProcessId);
537 service->status.dwProcessId = dwProcessId;
538 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
541 /******************************************************************************
542 * service_set_processID
544 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
546 DWORD cmd[2], count = 0;
549 cmd[0] = WINESERV_SETPID;
550 cmd[1] = dwprocessId;
551 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
552 if (!r || count != sizeof cmd)
554 ERR("service protocol error - failed to write pipe!\n");
557 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
558 if (!r || count != sizeof *dwResult)
559 ERR("service protocol error - failed to read pipe "
560 "r = %d count = %d!\n", r, count);
564 /******************************************************************************
565 * service_send_control
567 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
569 DWORD cmd[2], count = 0;
572 cmd[0] = WINESERV_SENDCONTROL;
574 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
575 if (!r || count != sizeof cmd)
577 ERR("service protocol error - failed to write pipe!\n");
580 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
581 if (!r || count != sizeof *result)
582 ERR("service protocol error - failed to read pipe "
583 "r = %d count = %d!\n", r, count);
587 /******************************************************************************
588 * service_accepts_control
590 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
592 DWORD a = service->status.dwControlsAccepted;
596 case SERVICE_CONTROL_INTERROGATE:
598 case SERVICE_CONTROL_STOP:
599 if (a&SERVICE_ACCEPT_STOP)
602 case SERVICE_CONTROL_SHUTDOWN:
603 if (a&SERVICE_ACCEPT_SHUTDOWN)
606 case SERVICE_CONTROL_PAUSE:
607 case SERVICE_CONTROL_CONTINUE:
608 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
611 case SERVICE_CONTROL_PARAMCHANGE:
612 if (a&SERVICE_ACCEPT_PARAMCHANGE)
615 case SERVICE_CONTROL_NETBINDADD:
616 case SERVICE_CONTROL_NETBINDREMOVE:
617 case SERVICE_CONTROL_NETBINDENABLE:
618 case SERVICE_CONTROL_NETBINDDISABLE:
619 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
622 if (!service->extended)
626 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
627 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
630 case SERVICE_CONTROL_POWEREVENT:
631 if (a&SERVICE_ACCEPT_POWEREVENT)
634 case SERVICE_CONTROL_SESSIONCHANGE:
635 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
642 /******************************************************************************
643 * service_handle_control
645 static BOOL service_handle_control(HANDLE pipe, service_data *service,
648 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
650 TRACE("received control %d\n", dwControl);
652 if (service_accepts_control(service, dwControl))
654 if (service->extended && service->handler.handler_ex)
656 service->handler.handler_ex(dwControl, 0, NULL, service->context);
659 else if (service->handler.handler)
661 service->handler.handler(dwControl);
665 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
668 /******************************************************************************
669 * service_reap_thread
671 static DWORD service_reap_thread(service_data *service)
675 if (!service->thread)
677 GetExitCodeThread(service->thread, &exitcode);
678 if (exitcode!=STILL_ACTIVE)
680 CloseHandle(service->thread);
686 /******************************************************************************
687 * service_control_dispatcher
689 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
691 service_data *service = arg;
695 TRACE("%p %s\n", service, debugstr_w(service->name));
697 /* create a pipe to talk to the rest of the world with */
698 name = service_get_pipe_name(service->name);
699 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
700 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
703 /* let the process who started us know we've tried to create a pipe */
704 event = service_get_event_handle(service->name);
708 if (pipe==INVALID_HANDLE_VALUE)
710 ERR("failed to create pipe for %s, error = %d\n",
711 debugstr_w(service->name), GetLastError());
715 /* dispatcher loop */
719 DWORD count, req[2] = {0,0};
721 r = ConnectNamedPipe(pipe, NULL);
722 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
724 ERR("pipe connect failed\n");
728 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
729 if (!r || count!=sizeof req)
731 ERR("pipe read failed\n");
735 service_reap_thread(service);
737 /* handle the request */
740 case WINESERV_STARTINFO:
741 service_handle_start(pipe, service, req[1]);
743 case WINESERV_GETSTATUS:
744 service_handle_get_status(pipe, service);
746 case WINESERV_SENDCONTROL:
747 service_handle_control(pipe, service, req[1]);
749 case WINESERV_SETPID:
750 service_handle_set_processID(pipe, service, req[1]);
753 ERR("received invalid command %d length %d\n", req[0], req[1]);
756 FlushFileBuffers(pipe);
757 DisconnectNamedPipe(pipe);
764 /******************************************************************************
765 * service_run_threads
767 static BOOL service_run_threads(void)
769 service_data *service;
773 EnterCriticalSection( &service_cs );
775 count = list_count( &service_list );
777 TRACE("starting %d pipe listener threads\n", count);
779 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE) * (count + 1));
781 handles[n++] = __wine_make_process_system();
783 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
784 handles[n++] = CreateThread( NULL, 0, service_control_dispatcher,
786 assert(n == count + 1);
788 LeaveCriticalSection( &service_cs );
790 /* wait for all the threads to pack up and exit */
793 DWORD ret = WaitForMultipleObjects( min(n,MAXIMUM_WAIT_OBJECTS), handles, FALSE, INFINITE );
794 if (!ret) /* system process event */
796 TRACE( "last user process exited, shutting down\n" );
797 /* FIXME: we should maybe send a shutdown control to running services */
800 if (ret < MAXIMUM_WAIT_OBJECTS)
802 CloseHandle( handles[ret] );
803 memmove( &handles[ret], &handles[ret+1], (n - ret - 1) * sizeof(HANDLE) );
809 while (n) CloseHandle( handles[--n] );
810 HeapFree(GetProcessHeap(), 0, handles);
815 /******************************************************************************
816 * StartServiceCtrlDispatcherA [ADVAPI32.@]
818 * See StartServiceCtrlDispatcherW.
820 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
826 TRACE("%p\n", servent);
828 EnterCriticalSection( &service_cs );
829 while (servent->lpServiceName)
831 LPSTR name = servent->lpServiceName;
833 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
834 sz = len*sizeof(WCHAR) + sizeof *info;
835 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
836 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
837 info->proc.a = servent->lpServiceProc;
838 info->unicode = FALSE;
839 list_add_head( &service_list, &info->entry );
842 LeaveCriticalSection( &service_cs );
844 service_run_threads();
849 /******************************************************************************
850 * StartServiceCtrlDispatcherW [ADVAPI32.@]
852 * Connects a process containing one or more services to the service control
856 * servent [I] A list of the service names and service procedures
862 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
868 TRACE("%p\n", servent);
870 EnterCriticalSection( &service_cs );
871 while (servent->lpServiceName)
873 LPWSTR name = servent->lpServiceName;
876 sz = len*sizeof(WCHAR) + sizeof *info;
877 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
878 strcpyW(info->name, name);
879 info->proc.w = servent->lpServiceProc;
880 info->unicode = TRUE;
881 list_add_head( &service_list, &info->entry );
884 LeaveCriticalSection( &service_cs );
886 service_run_threads();
891 /******************************************************************************
892 * LockServiceDatabase [ADVAPI32.@]
894 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
898 TRACE("%p\n",hSCManager);
900 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
901 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
905 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
908 TRACE("returning %p\n", ret);
913 /******************************************************************************
914 * UnlockServiceDatabase [ADVAPI32.@]
916 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
918 TRACE("%p\n",ScLock);
920 return CloseHandle( ScLock );
923 /******************************************************************************
924 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
926 SERVICE_STATUS_HANDLE WINAPI
927 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
929 LPWSTR lpServiceNameW;
930 SERVICE_STATUS_HANDLE ret;
932 lpServiceNameW = SERV_dup(lpServiceName);
933 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
934 SERV_free(lpServiceNameW);
938 /******************************************************************************
939 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
945 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
946 LPHANDLER_FUNCTION lpfHandler )
948 service_data *service;
949 SERVICE_STATUS_HANDLE handle = 0;
951 EnterCriticalSection( &service_cs );
952 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
954 if(!strcmpW(lpServiceName, service->name))
956 service->handler.handler = lpfHandler;
957 handle = (SERVICE_STATUS_HANDLE)service;
961 LeaveCriticalSection( &service_cs );
965 /******************************************************************************
966 * SetServiceStatus [ADVAPI32.@]
973 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
975 service_data *service;
978 TRACE("%p %x %x %x %x %x %x %x\n", hService,
979 lpStatus->dwServiceType, lpStatus->dwCurrentState,
980 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
981 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
982 lpStatus->dwWaitHint);
984 EnterCriticalSection( &service_cs );
985 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
987 if(service == (service_data*)hService)
989 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
990 TRACE("Set service status to %d\n",service->status.dwCurrentState);
995 LeaveCriticalSection( &service_cs );
1001 /******************************************************************************
1002 * OpenSCManagerA [ADVAPI32.@]
1004 * Establish a connection to the service control manager and open its database.
1007 * lpMachineName [I] Pointer to machine name string
1008 * lpDatabaseName [I] Pointer to database name string
1009 * dwDesiredAccess [I] Type of access
1012 * Success: A Handle to the service control manager database
1015 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1016 DWORD dwDesiredAccess )
1018 LPWSTR lpMachineNameW, lpDatabaseNameW;
1021 lpMachineNameW = SERV_dup(lpMachineName);
1022 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1023 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1024 SERV_free(lpDatabaseNameW);
1025 SERV_free(lpMachineNameW);
1029 /******************************************************************************
1030 * OpenSCManagerW [ADVAPI32.@]
1032 * See OpenSCManagerA.
1034 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1035 DWORD dwDesiredAccess )
1037 struct sc_manager *manager;
1041 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1042 debugstr_w(lpDatabaseName), dwDesiredAccess);
1044 if( lpDatabaseName && lpDatabaseName[0] )
1046 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1048 /* noop, all right */
1050 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1052 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1057 SetLastError( ERROR_INVALID_NAME );
1062 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1063 sc_handle_destroy_manager );
1067 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1068 if (r!=ERROR_SUCCESS)
1071 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1072 RegCloseKey( hReg );
1073 if (r!=ERROR_SUCCESS)
1076 manager->dwAccess = dwDesiredAccess;
1077 TRACE("returning %p\n", manager);
1079 return (SC_HANDLE) &manager->hdr;
1082 sc_handle_free( &manager->hdr );
1087 /******************************************************************************
1088 * ControlService [ADVAPI32.@]
1090 * Send a control code to a service.
1093 * hService [I] Handle of the service control manager database
1094 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1095 * lpServiceStatus [O] Destination for the status of the service, if available
1102 * Unlike M$' implementation, control requests are not serialized and may be
1103 * processed asynchronously.
1105 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1106 LPSERVICE_STATUS lpServiceStatus )
1108 struct sc_service *hsvc;
1112 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1114 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1117 SetLastError( ERROR_INVALID_HANDLE );
1121 ret = QueryServiceStatus(hService, lpServiceStatus);
1124 ERR("failed to query service status\n");
1125 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1129 switch (lpServiceStatus->dwCurrentState)
1131 case SERVICE_STOPPED:
1132 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1134 case SERVICE_START_PENDING:
1135 if (dwControl==SERVICE_CONTROL_STOP)
1138 case SERVICE_STOP_PENDING:
1139 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1143 handle = service_open_pipe(hsvc->name);
1144 if (handle!=INVALID_HANDLE_VALUE)
1146 DWORD result = ERROR_SUCCESS;
1147 ret = service_send_control(handle, dwControl, &result);
1148 CloseHandle(handle);
1149 if (result!=ERROR_SUCCESS)
1151 SetLastError(result);
1159 /******************************************************************************
1160 * CloseServiceHandle [ADVAPI32.@]
1162 * Close a handle to a service or the service control manager database.
1165 * hSCObject [I] Handle to service or service control manager database
1172 CloseServiceHandle( SC_HANDLE hSCObject )
1174 TRACE("%p\n", hSCObject);
1176 sc_handle_free( (struct sc_handle*) hSCObject );
1182 /******************************************************************************
1183 * OpenServiceA [ADVAPI32.@]
1185 * Open a handle to a service.
1188 * hSCManager [I] Handle of the service control manager database
1189 * lpServiceName [I] Name of the service to open
1190 * dwDesiredAccess [I] Access required to the service
1193 * Success: Handle to the service
1196 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1197 DWORD dwDesiredAccess )
1199 LPWSTR lpServiceNameW;
1202 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1204 lpServiceNameW = SERV_dup(lpServiceName);
1205 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1206 SERV_free(lpServiceNameW);
1211 /******************************************************************************
1212 * OpenServiceW [ADVAPI32.@]
1216 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1217 DWORD dwDesiredAccess)
1219 struct sc_manager *hscm;
1220 struct sc_service *hsvc;
1225 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1229 SetLastError(ERROR_INVALID_ADDRESS);
1233 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1236 SetLastError( ERROR_INVALID_HANDLE );
1240 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1241 if (r!=ERROR_SUCCESS)
1243 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1247 len = strlenW(lpServiceName)+1;
1248 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1249 sizeof (struct sc_service) + len*sizeof(WCHAR),
1250 sc_handle_destroy_service );
1253 strcpyW( hsvc->name, lpServiceName );
1255 hsvc->dwAccess = dwDesiredAccess;
1257 /* add reference to SCM handle */
1258 hscm->hdr.ref_count++;
1261 TRACE("returning %p\n",hsvc);
1263 return (SC_HANDLE) &hsvc->hdr;
1266 /******************************************************************************
1267 * CreateServiceW [ADVAPI32.@]
1270 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1271 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1272 DWORD dwServiceType, DWORD dwStartType,
1273 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1274 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1275 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1276 LPCWSTR lpPassword )
1278 struct sc_manager *hscm;
1279 struct sc_service *hsvc = NULL;
1283 struct reg_value val[10];
1286 TRACE("%p %s %s\n", hSCManager,
1287 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1289 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1292 SetLastError( ERROR_INVALID_HANDLE );
1296 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1297 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1298 if (r!=ERROR_SUCCESS)
1301 if (dp != REG_CREATED_NEW_KEY)
1303 SetLastError(ERROR_SERVICE_EXISTS);
1308 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1310 service_set_dword( &val[n++], szType, &dwServiceType );
1311 service_set_dword( &val[n++], szStart, &dwStartType );
1312 service_set_dword( &val[n++], szError, &dwErrorControl );
1314 if( lpBinaryPathName )
1315 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1317 if( lpLoadOrderGroup )
1318 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1320 if( lpDependencies )
1321 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1324 FIXME("Don't know how to add a Password for a service.\n");
1326 if( lpServiceStartName )
1327 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1329 r = service_write_values( hKey, val, n );
1330 if( r != ERROR_SUCCESS )
1333 len = strlenW(lpServiceName)+1;
1334 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1335 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1338 lstrcpyW( hsvc->name, lpServiceName );
1341 hscm->hdr.ref_count++;
1343 return (SC_HANDLE) &hsvc->hdr;
1346 RegCloseKey( hKey );
1351 /******************************************************************************
1352 * CreateServiceA [ADVAPI32.@]
1355 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1356 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1357 DWORD dwServiceType, DWORD dwStartType,
1358 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1359 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1360 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1363 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1364 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1367 TRACE("%p %s %s\n", hSCManager,
1368 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1370 lpServiceNameW = SERV_dup( lpServiceName );
1371 lpDisplayNameW = SERV_dup( lpDisplayName );
1372 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1373 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1374 lpDependenciesW = SERV_dupmulti( lpDependencies );
1375 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1376 lpPasswordW = SERV_dup( lpPassword );
1378 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1379 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1380 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1381 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1383 SERV_free( lpServiceNameW );
1384 SERV_free( lpDisplayNameW );
1385 SERV_free( lpBinaryPathNameW );
1386 SERV_free( lpLoadOrderGroupW );
1387 SERV_free( lpDependenciesW );
1388 SERV_free( lpServiceStartNameW );
1389 SERV_free( lpPasswordW );
1395 /******************************************************************************
1396 * DeleteService [ADVAPI32.@]
1398 * Delete a service from the service control manager database.
1401 * hService [I] Handle of the service to delete
1407 BOOL WINAPI DeleteService( SC_HANDLE hService )
1409 struct sc_service *hsvc;
1411 WCHAR valname[MAX_PATH+1];
1416 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1419 SetLastError( ERROR_INVALID_HANDLE );
1425 /* Clean out the values */
1426 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1427 while (rc == ERROR_SUCCESS)
1429 RegDeleteValueW(hKey,valname);
1432 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1438 /* delete the key */
1439 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1445 /******************************************************************************
1446 * StartServiceA [ADVAPI32.@]
1451 * hService [I] Handle of service
1452 * dwNumServiceArgs [I] Number of arguments
1453 * lpServiceArgVectors [I] Address of array of argument strings
1456 * - NT implements this function using an obscure RPC call.
1457 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1458 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1459 * - This will only work for shared address space. How should the service
1460 * args be transferred when address spaces are separated?
1461 * - Can only start one service at a time.
1462 * - Has no concept of privilege.
1468 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1469 LPCSTR *lpServiceArgVectors )
1471 LPWSTR *lpwstr=NULL;
1475 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1477 if (dwNumServiceArgs)
1478 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1479 dwNumServiceArgs*sizeof(LPWSTR) );
1481 for(i=0; i<dwNumServiceArgs; i++)
1482 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1484 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1486 if (dwNumServiceArgs)
1488 for(i=0; i<dwNumServiceArgs; i++)
1489 SERV_free(lpwstr[i]);
1490 HeapFree(GetProcessHeap(), 0, lpwstr);
1496 /******************************************************************************
1497 * service_start_process [INTERNAL]
1499 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1501 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1502 PROCESS_INFORMATION pi;
1504 LPWSTR path = NULL, str;
1505 DWORD type, size, ret, svc_type;
1509 size = sizeof(svc_type);
1510 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1513 if (svc_type == SERVICE_KERNEL_DRIVER)
1515 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1516 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1518 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1519 GetSystemDirectoryW( path, len );
1520 lstrcatW( path, winedeviceW );
1521 lstrcatW( path, hsvc->name );
1525 /* read the executable path from the registry */
1527 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1528 if (ret!=ERROR_SUCCESS)
1530 str = HeapAlloc(GetProcessHeap(),0,size);
1531 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1532 if (ret==ERROR_SUCCESS)
1534 size = ExpandEnvironmentStringsW(str,NULL,0);
1535 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1536 ExpandEnvironmentStringsW(str,path,size);
1538 HeapFree(GetProcessHeap(),0,str);
1543 /* wait for the process to start and set an event or terminate */
1544 handles[0] = service_get_event_handle( hsvc->name );
1545 ZeroMemory(&si, sizeof(STARTUPINFOW));
1546 si.cb = sizeof(STARTUPINFOW);
1547 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1550 if (ppid) *ppid = pi.dwProcessId;
1552 handles[1] = pi.hProcess;
1553 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1554 if(ret != WAIT_OBJECT_0)
1556 SetLastError(ERROR_IO_PENDING);
1560 CloseHandle( pi.hThread );
1561 CloseHandle( pi.hProcess );
1563 CloseHandle( handles[0] );
1564 HeapFree(GetProcessHeap(),0,path);
1568 static BOOL service_wait_for_startup(SC_HANDLE hService)
1571 SERVICE_STATUS status;
1574 TRACE("%p\n", hService);
1576 for (i=0; i<30; i++)
1578 status.dwCurrentState = 0;
1579 r = QueryServiceStatus(hService, &status);
1582 if (status.dwCurrentState == SERVICE_RUNNING)
1584 TRACE("Service started successfully\n");
1593 /******************************************************************************
1594 * StartServiceW [ADVAPI32.@]
1596 * See StartServiceA.
1598 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1599 LPCWSTR *lpServiceArgVectors)
1601 struct sc_service *hsvc;
1603 DWORD dwResult, dwProcessId = 0;
1605 HANDLE handle = INVALID_HANDLE_VALUE;
1607 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1609 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1612 SetLastError(ERROR_INVALID_HANDLE);
1616 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1620 handle = service_open_pipe(hsvc->name);
1621 if (handle==INVALID_HANDLE_VALUE)
1623 /* start the service process */
1624 if (service_start_process(hsvc, &dwProcessId))
1625 handle = service_open_pipe(hsvc->name);
1628 if (handle != INVALID_HANDLE_VALUE)
1630 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1631 CloseHandle(handle);
1634 handle = service_open_pipe(hsvc->name);
1635 if (handle != INVALID_HANDLE_VALUE)
1637 service_set_processID(handle, dwProcessId, &dwResult);
1638 CloseHandle(handle);
1641 UnlockServiceDatabase( hLock );
1643 TRACE("returning %d\n", r);
1646 service_wait_for_startup(hService);
1651 /******************************************************************************
1652 * QueryServiceStatus [ADVAPI32.@]
1655 * hService [I] Handle to service to get information about
1656 * lpservicestatus [O] buffer to receive the status information for the service
1659 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1660 LPSERVICE_STATUS lpservicestatus)
1662 SERVICE_STATUS_PROCESS SvcStatusData;
1665 TRACE("%p %p\n", hService, lpservicestatus);
1667 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1668 sizeof(SERVICE_STATUS_PROCESS), NULL);
1669 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1674 /******************************************************************************
1675 * QueryServiceStatusEx [ADVAPI32.@]
1677 * Get information about a service.
1680 * hService [I] Handle to service to get information about
1681 * InfoLevel [I] Level of information to get
1682 * lpBuffer [O] Destination for requested information
1683 * cbBufSize [I] Size of lpBuffer in bytes
1684 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1690 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1691 LPBYTE lpBuffer, DWORD cbBufSize,
1692 LPDWORD pcbBytesNeeded)
1694 struct sc_service *hsvc;
1695 DWORD size, type, val;
1698 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1700 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1702 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1704 SetLastError( ERROR_INVALID_LEVEL);
1708 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1709 if (pSvcStatusData == NULL)
1711 SetLastError( ERROR_INVALID_PARAMETER);
1715 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1717 if( pcbBytesNeeded != NULL)
1718 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1720 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1724 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1727 SetLastError( ERROR_INVALID_HANDLE );
1731 pipe = service_open_pipe(hsvc->name);
1732 if (pipe != INVALID_HANDLE_VALUE)
1734 r = service_get_status(pipe, pSvcStatusData);
1740 TRACE("Failed to read service status\n");
1742 /* read the service type from the registry */
1744 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1745 if (r != ERROR_SUCCESS || type != REG_DWORD)
1748 pSvcStatusData->dwServiceType = val;
1749 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1750 pSvcStatusData->dwControlsAccepted = 0;
1751 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1752 pSvcStatusData->dwServiceSpecificExitCode = 0;
1753 pSvcStatusData->dwCheckPoint = 0;
1754 pSvcStatusData->dwWaitHint = 0;
1759 /******************************************************************************
1760 * QueryServiceConfigA [ADVAPI32.@]
1762 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1763 DWORD size, LPDWORD needed )
1768 QUERY_SERVICE_CONFIGW *configW;
1770 TRACE("%p %p %d %p\n", hService, config, size, needed);
1772 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1774 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1777 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1778 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1779 if (!ret) goto done;
1781 config->dwServiceType = configW->dwServiceType;
1782 config->dwStartType = configW->dwStartType;
1783 config->dwErrorControl = configW->dwErrorControl;
1784 config->lpBinaryPathName = NULL;
1785 config->lpLoadOrderGroup = NULL;
1786 config->dwTagId = configW->dwTagId;
1787 config->lpDependencies = NULL;
1788 config->lpServiceStartName = NULL;
1789 config->lpDisplayName = NULL;
1791 p = (LPSTR)(config + 1);
1792 n = size - sizeof(*config);
1795 #define MAP_STR(str) \
1799 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1800 if (!sz) goto done; \
1807 MAP_STR( lpBinaryPathName );
1808 MAP_STR( lpLoadOrderGroup );
1809 MAP_STR( lpDependencies );
1810 MAP_STR( lpServiceStartName );
1811 MAP_STR( lpDisplayName );
1814 *needed = p - buffer;
1818 HeapFree( GetProcessHeap(), 0, buffer );
1822 /******************************************************************************
1823 * QueryServiceConfigW [ADVAPI32.@]
1826 QueryServiceConfigW( SC_HANDLE hService,
1827 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1828 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1830 WCHAR str_buffer[ MAX_PATH ];
1832 DWORD type, val, sz, total, n;
1835 struct sc_service *hsvc;
1837 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1838 cbBufSize, pcbBytesNeeded);
1840 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1843 SetLastError( ERROR_INVALID_HANDLE );
1848 /* calculate the size required first */
1849 total = sizeof (QUERY_SERVICE_CONFIGW);
1851 sz = sizeof(str_buffer);
1852 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1853 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1855 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1856 if( 0 == sz ) return FALSE;
1858 total += sizeof(WCHAR) * sz;
1862 /* FIXME: set last error */
1867 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1868 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1872 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1873 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1876 total += sizeof(WCHAR);
1879 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1880 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1884 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1885 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1888 *pcbBytesNeeded = total;
1890 /* if there's not enough memory, return an error */
1891 if( total > cbBufSize )
1893 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1897 ZeroMemory( lpServiceConfig, total );
1900 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1901 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1902 lpServiceConfig->dwServiceType = val;
1905 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1906 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1907 lpServiceConfig->dwStartType = val;
1910 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1911 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1912 lpServiceConfig->dwErrorControl = val;
1914 /* now do the strings */
1915 p = (LPBYTE) &lpServiceConfig[1];
1916 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1918 sz = sizeof(str_buffer);
1919 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1920 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1922 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1923 sz *= sizeof(WCHAR);
1924 if( 0 == sz || sz > n ) return FALSE;
1926 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1932 /* FIXME: set last error */
1937 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1938 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1940 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1946 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1947 lpServiceConfig->lpDependencies = (LPWSTR) p;
1948 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1961 ERR("Buffer overflow!\n");
1963 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1964 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1969 /******************************************************************************
1970 * EnumServicesStatusA [ADVAPI32.@]
1973 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1974 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1975 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1976 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1978 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1979 dwServiceType, dwServiceState, lpServices, cbBufSize,
1980 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1981 SetLastError (ERROR_ACCESS_DENIED);
1985 /******************************************************************************
1986 * EnumServicesStatusW [ADVAPI32.@]
1989 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1990 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1991 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1992 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1994 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1995 dwServiceType, dwServiceState, lpServices, cbBufSize,
1996 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1997 SetLastError (ERROR_ACCESS_DENIED);
2001 /******************************************************************************
2002 * EnumServicesStatusExA [ADVAPI32.@]
2005 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2006 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2007 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
2009 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2010 dwServiceType, dwServiceState, lpServices, cbBufSize,
2011 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
2012 SetLastError (ERROR_ACCESS_DENIED);
2016 /******************************************************************************
2017 * EnumServicesStatusExW [ADVAPI32.@]
2020 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2021 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2022 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2024 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2025 dwServiceType, dwServiceState, lpServices, cbBufSize,
2026 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2027 SetLastError (ERROR_ACCESS_DENIED);
2031 /******************************************************************************
2032 * GetServiceKeyNameA [ADVAPI32.@]
2034 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2035 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2037 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2041 /******************************************************************************
2042 * GetServiceKeyNameW [ADVAPI32.@]
2044 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2045 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2047 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2051 /******************************************************************************
2052 * QueryServiceLockStatusA [ADVAPI32.@]
2054 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2055 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2056 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2058 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2063 /******************************************************************************
2064 * QueryServiceLockStatusW [ADVAPI32.@]
2066 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2067 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2068 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2070 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2075 /******************************************************************************
2076 * GetServiceDisplayNameA [ADVAPI32.@]
2078 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2079 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2081 struct sc_manager *hscm;
2085 TRACE("%p %s %p %p\n", hSCManager,
2086 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2090 SetLastError(ERROR_INVALID_PARAMETER);
2094 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2097 SetLastError(ERROR_INVALID_HANDLE);
2101 size = *lpcchBuffer;
2102 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2103 if (!ret && !lpDisplayName && size)
2104 ret = ERROR_MORE_DATA;
2108 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2110 if (ret == ERROR_MORE_DATA)
2112 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2113 *lpcchBuffer = size - 1;
2122 /******************************************************************************
2123 * GetServiceDisplayNameW [ADVAPI32.@]
2125 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2126 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2128 struct sc_manager *hscm;
2132 TRACE("%p %s %p %p\n", hSCManager,
2133 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2137 SetLastError(ERROR_INVALID_PARAMETER);
2141 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2144 SetLastError(ERROR_INVALID_HANDLE);
2148 size = *lpcchBuffer * sizeof(WCHAR);
2149 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2150 if (!ret && !lpDisplayName && size)
2151 ret = ERROR_MORE_DATA;
2155 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2157 if (ret == ERROR_MORE_DATA)
2159 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2160 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2169 /******************************************************************************
2170 * ChangeServiceConfigW [ADVAPI32.@]
2172 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2173 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2174 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2175 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2177 struct reg_value val[10];
2178 struct sc_service *hsvc;
2179 DWORD r = ERROR_SUCCESS;
2183 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2184 hService, dwServiceType, dwStartType, dwErrorControl,
2185 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2186 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2187 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2189 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2192 SetLastError( ERROR_INVALID_HANDLE );
2197 if( dwServiceType != SERVICE_NO_CHANGE )
2198 service_set_dword( &val[n++], szType, &dwServiceType );
2200 if( dwStartType != SERVICE_NO_CHANGE )
2201 service_set_dword( &val[n++], szStart, &dwStartType );
2203 if( dwErrorControl != SERVICE_NO_CHANGE )
2204 service_set_dword( &val[n++], szError, &dwErrorControl );
2206 if( lpBinaryPathName )
2207 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2209 if( lpLoadOrderGroup )
2210 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2212 if( lpDependencies )
2213 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2216 FIXME("ignoring password\n");
2218 if( lpServiceStartName )
2219 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2221 r = service_write_values( hsvc->hkey, val, n );
2223 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2226 /******************************************************************************
2227 * ChangeServiceConfigA [ADVAPI32.@]
2229 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2230 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2231 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2232 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2234 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2235 LPWSTR wServiceStartName, wPassword, wDisplayName;
2238 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2239 hService, dwServiceType, dwStartType, dwErrorControl,
2240 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2241 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2242 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2244 wBinaryPathName = SERV_dup( lpBinaryPathName );
2245 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2246 wDependencies = SERV_dupmulti( lpDependencies );
2247 wServiceStartName = SERV_dup( lpServiceStartName );
2248 wPassword = SERV_dup( lpPassword );
2249 wDisplayName = SERV_dup( lpDisplayName );
2251 r = ChangeServiceConfigW( hService, dwServiceType,
2252 dwStartType, dwErrorControl, wBinaryPathName,
2253 wLoadOrderGroup, lpdwTagId, wDependencies,
2254 wServiceStartName, wPassword, wDisplayName);
2256 SERV_free( wBinaryPathName );
2257 SERV_free( wLoadOrderGroup );
2258 SERV_free( wDependencies );
2259 SERV_free( wServiceStartName );
2260 SERV_free( wPassword );
2261 SERV_free( wDisplayName );
2266 /******************************************************************************
2267 * ChangeServiceConfig2A [ADVAPI32.@]
2269 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2274 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2276 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2278 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2279 SERVICE_DESCRIPTIONW sdw;
2281 sdw.lpDescription = SERV_dup( sd->lpDescription );
2283 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2285 SERV_free( sdw.lpDescription );
2287 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2289 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2290 SERVICE_FAILURE_ACTIONSW faw;
2292 faw.dwResetPeriod = fa->dwResetPeriod;
2293 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2294 faw.lpCommand = SERV_dup( fa->lpCommand );
2295 faw.cActions = fa->cActions;
2296 faw.lpsaActions = fa->lpsaActions;
2298 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2300 SERV_free( faw.lpRebootMsg );
2301 SERV_free( faw.lpCommand );
2304 SetLastError( ERROR_INVALID_PARAMETER );
2309 /******************************************************************************
2310 * ChangeServiceConfig2W [ADVAPI32.@]
2312 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2316 struct sc_service *hsvc;
2318 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2321 SetLastError( ERROR_INVALID_HANDLE );
2326 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2328 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2329 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2330 if (sd->lpDescription)
2332 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2333 if (sd->lpDescription[0] == 0)
2334 RegDeleteValueW(hKey,szDescription);
2336 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2337 (LPVOID)sd->lpDescription,
2338 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2342 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2346 /******************************************************************************
2347 * QueryServiceObjectSecurity [ADVAPI32.@]
2349 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2350 SECURITY_INFORMATION dwSecurityInformation,
2351 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2352 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2356 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2357 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2359 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2361 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2362 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2363 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2367 /******************************************************************************
2368 * SetServiceObjectSecurity [ADVAPI32.@]
2370 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2371 SECURITY_INFORMATION dwSecurityInformation,
2372 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2374 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2378 /******************************************************************************
2379 * SetServiceBits [ADVAPI32.@]
2381 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2382 DWORD dwServiceBits,
2384 BOOL bUpdateImmediately)
2386 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2387 bSetBitsOn, bUpdateImmediately);
2391 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2392 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2394 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2398 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2399 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2401 service_data *service;
2402 SERVICE_STATUS_HANDLE handle = 0;
2404 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2406 EnterCriticalSection( &service_cs );
2407 LIST_FOR_EACH_ENTRY( service, &service_list, service_data, entry )
2409 if(!strcmpW(lpServiceName, service->name))
2411 service->handler.handler_ex = lpHandlerProc;
2412 service->context = lpContext;
2413 service->extended = TRUE;
2414 handle = (SERVICE_STATUS_HANDLE)service;
2418 LeaveCriticalSection( &service_cs );