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"
39 WINE_DEFAULT_DEBUG_CHANNEL(advapi);
41 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
42 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
43 'S','e','r','v','i','c','e','s',0 };
44 static const WCHAR szSCMLock[] = {'A','D','V','A','P','I','_','S','C','M',
47 typedef struct service_start_info_t
54 #define WINESERV_STARTINFO 1
55 #define WINESERV_GETSTATUS 2
56 #define WINESERV_SENDCONTROL 3
57 #define WINESERV_SETPID 4
59 typedef struct service_data_t
61 struct service_data_t *next;
63 LPHANDLER_FUNCTION handler;
64 LPHANDLER_FUNCTION_EX handler_ex;
67 SERVICE_STATUS_PROCESS status;
70 BOOL extended : 1; /* uses handler_ex instead of handler? */
72 LPSERVICE_MAIN_FUNCTIONA a;
73 LPSERVICE_MAIN_FUNCTIONW w;
79 static CRITICAL_SECTION service_cs;
80 static CRITICAL_SECTION_DEBUG service_cs_debug =
83 { &service_cs_debug.ProcessLocksList,
84 &service_cs_debug.ProcessLocksList },
85 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
87 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
89 static service_data *service_list;
91 /******************************************************************************
95 #define MAX_SERVICE_NAME 256
97 typedef enum { SC_HTYPE_MANAGER, SC_HTYPE_SERVICE } SC_HANDLE_TYPE;
100 typedef VOID (*sc_handle_destructor)(struct sc_handle *);
104 SC_HANDLE_TYPE htype;
106 sc_handle_destructor destroy;
109 struct sc_manager /* service control manager handle */
111 struct sc_handle hdr;
112 HKEY hkey; /* handle to services database in the registry */
116 struct sc_service /* service handle */
118 struct sc_handle hdr;
119 HKEY hkey; /* handle to service entry in the registry (under hkey) */
121 struct sc_manager *scm; /* pointer to SCM handle */
125 static void *sc_handle_alloc(SC_HANDLE_TYPE htype, DWORD size,
126 sc_handle_destructor destroy)
128 struct sc_handle *hdr;
130 hdr = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, size );
135 hdr->destroy = destroy;
137 TRACE("sc_handle type=%d -> %p\n", htype, hdr);
141 static void *sc_handle_get_handle_data(SC_HANDLE handle, DWORD htype)
143 struct sc_handle *hdr = (struct sc_handle *) handle;
147 if (hdr->htype != htype)
152 static void sc_handle_free(struct sc_handle* hdr)
156 if (--hdr->ref_count)
159 HeapFree(GetProcessHeap(), 0, hdr);
162 static void sc_handle_destroy_manager(struct sc_handle *handle)
164 struct sc_manager *mgr = (struct sc_manager*) handle;
166 TRACE("destroying SC Manager %p\n", mgr);
168 RegCloseKey(mgr->hkey);
171 static void sc_handle_destroy_service(struct sc_handle *handle)
173 struct sc_service *svc = (struct sc_service*) handle;
175 TRACE("destroying service %p\n", svc);
177 RegCloseKey(svc->hkey);
179 sc_handle_free(&svc->scm->hdr);
183 /******************************************************************************
184 * String management functions
186 static inline LPWSTR SERV_dup( LPCSTR str )
193 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
194 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
195 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
199 static inline LPWSTR SERV_dupmulti(LPCSTR str)
207 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
208 n += (strlen( &str[n] ) + 1);
213 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
214 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
218 static inline VOID SERV_free( LPWSTR wstr )
220 HeapFree( GetProcessHeap(), 0, wstr );
223 /******************************************************************************
224 * registry access functions and data
226 static const WCHAR szDisplayName[] = {
227 'D','i','s','p','l','a','y','N','a','m','e', 0 };
228 static const WCHAR szType[] = {'T','y','p','e',0};
229 static const WCHAR szStart[] = {'S','t','a','r','t',0};
230 static const WCHAR szError[] = {
231 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
232 static const WCHAR szImagePath[] = {'I','m','a','g','e','P','a','t','h',0};
233 static const WCHAR szGroup[] = {'G','r','o','u','p',0};
234 static const WCHAR szDependencies[] = {
235 'D','e','p','e','n','d','e','n','c','i','e','s',0};
236 static const WCHAR szDependOnService[] = {
237 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
246 static inline void service_set_value( struct reg_value *val,
247 DWORD type, LPCWSTR name, LPCVOID data, DWORD size )
255 static inline void service_set_dword( struct reg_value *val,
256 LPCWSTR name, const DWORD *data )
258 service_set_value( val, REG_DWORD, name, data, sizeof (DWORD));
261 static inline void service_set_string( struct reg_value *val,
262 LPCWSTR name, LPCWSTR string )
264 DWORD len = (lstrlenW(string)+1) * sizeof (WCHAR);
265 service_set_value( val, REG_SZ, name, string, len );
268 static inline void service_set_multi_string( struct reg_value *val,
269 LPCWSTR name, LPCWSTR string )
273 /* determine the length of a double null terminated multi string */
275 len += (lstrlenW( &string[ len ] )+1);
276 } while ( string[ len++ ] );
278 len *= sizeof (WCHAR);
279 service_set_value( val, REG_MULTI_SZ, name, string, len );
282 static inline LONG service_write_values( HKEY hKey,
283 const struct reg_value *val, int n )
285 LONG r = ERROR_SUCCESS;
290 r = RegSetValueExW(hKey, val[i].name, 0, val[i].type,
291 (const BYTE*)val[i].data, val[i].size );
292 if( r != ERROR_SUCCESS )
298 /******************************************************************************
299 * Service IPC functions
301 static LPWSTR service_get_pipe_name(LPCWSTR service)
303 static const WCHAR prefix[] = { '\\','\\','.','\\','p','i','p','e','\\',
304 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
308 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
309 name = HeapAlloc(GetProcessHeap(), 0, len);
310 strcpyW(name, prefix);
311 strcatW(name, service);
315 static HANDLE service_open_pipe(LPCWSTR service)
317 LPWSTR szPipe = service_get_pipe_name( service );
318 HANDLE handle = INVALID_HANDLE_VALUE;
321 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
322 0, NULL, OPEN_ALWAYS, 0, NULL);
323 if (handle != INVALID_HANDLE_VALUE)
325 if (GetLastError() != ERROR_PIPE_BUSY)
327 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
333 /******************************************************************************
334 * service_get_event_handle
336 static HANDLE service_get_event_handle(LPCWSTR service)
338 static const WCHAR prefix[] = {
339 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
344 len = sizeof prefix + strlenW(service)*sizeof(WCHAR);
345 name = HeapAlloc(GetProcessHeap(), 0, len);
346 strcpyW(name, prefix);
347 strcatW(name, service);
348 handle = CreateEventW(NULL, TRUE, FALSE, name);
353 /******************************************************************************
356 * Call into the main service routine provided by StartServiceCtrlDispatcher.
358 static DWORD WINAPI service_thread(LPVOID arg)
360 service_data *info = arg;
361 LPWSTR str = info->args;
362 DWORD argc = 0, len = 0;
368 len += strlenW(&str[len]) + 1;
375 info->proc.w(0, NULL);
377 info->proc.a(0, NULL);
385 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
386 for (argc=0, p=str; *p; p += strlenW(p) + 1)
390 info->proc.w(argc, argv);
391 HeapFree(GetProcessHeap(), 0, argv);
395 LPSTR strA, *argv, p;
398 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
399 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
400 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
402 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
403 for (argc=0, p=strA; *p; p += strlen(p) + 1)
407 info->proc.a(argc, argv);
408 HeapFree(GetProcessHeap(), 0, argv);
409 HeapFree(GetProcessHeap(), 0, strA);
414 /******************************************************************************
415 * service_handle_start
417 static BOOL service_handle_start(HANDLE pipe, service_data *service, DWORD count)
419 DWORD read = 0, result = 0;
423 TRACE("%p %p %d\n", pipe, service, count);
425 args = HeapAlloc(GetProcessHeap(), 0, count*sizeof(WCHAR));
426 r = ReadFile(pipe, args, count*sizeof(WCHAR), &read, NULL);
427 if (!r || count!=read/sizeof(WCHAR) || args[count-1])
429 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
430 r, count, read, debugstr_wn(args, count));
436 ERR("service is not stopped\n");
440 SERV_free(service->args);
441 service->args = args;
443 service->thread = CreateThread( NULL, 0, service_thread,
447 HeapFree(GetProcessHeap(), 0, args);
448 WriteFile( pipe, &result, sizeof result, &read, NULL );
453 /******************************************************************************
454 * service_send_start_message
456 static BOOL service_send_start_message(HANDLE pipe, LPCWSTR *argv, DWORD argc)
458 DWORD i, len, count, result;
459 service_start_info *ssi;
463 TRACE("%p %p %d\n", pipe, argv, argc);
465 /* calculate how much space do we need to send the startup info */
467 for (i=0; i<argc; i++)
468 len += strlenW(argv[i])+1;
470 ssi = HeapAlloc(GetProcessHeap(),0,sizeof *ssi + (len-1)*sizeof(WCHAR));
471 ssi->cmd = WINESERV_STARTINFO;
474 /* copy service args into a single buffer*/
476 for (i=0; i<argc; i++)
483 r = WriteFile(pipe, ssi, sizeof *ssi + len*sizeof(WCHAR), &count, NULL);
485 r = ReadFile(pipe, &result, sizeof result, &count, NULL);
487 HeapFree(GetProcessHeap(),0,ssi);
492 /******************************************************************************
493 * service_handle_get_status
495 static BOOL service_handle_get_status(HANDLE pipe, const service_data *service)
499 return WriteFile(pipe, &service->status,
500 sizeof service->status, &count, NULL);
503 /******************************************************************************
506 static BOOL service_get_status(HANDLE pipe, LPSERVICE_STATUS_PROCESS status)
508 DWORD cmd[2], count = 0;
511 cmd[0] = WINESERV_GETSTATUS;
513 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
514 if (!r || count != sizeof cmd)
516 ERR("service protocol error - failed to write pipe!\n");
519 r = ReadFile( pipe, status, sizeof *status, &count, NULL );
520 if (!r || count != sizeof *status)
521 ERR("service protocol error - failed to read pipe "
522 "r = %d count = %d!\n", r, count);
526 /******************************************************************************
527 * service_handle_set_processID
529 static BOOL service_handle_set_processID(HANDLE pipe, service_data *service, DWORD dwProcessId)
531 DWORD count, ret = ERROR_SUCCESS;
533 TRACE("received control %d\n", dwProcessId);
534 service->status.dwProcessId = dwProcessId;
535 return WriteFile(pipe, &ret, sizeof ret , &count, NULL);
538 /******************************************************************************
539 * service_set_processID
541 static BOOL service_set_processID(HANDLE pipe, DWORD dwprocessId, LPDWORD dwResult)
543 DWORD cmd[2], count = 0;
546 cmd[0] = WINESERV_SETPID;
547 cmd[1] = dwprocessId;
548 r = WriteFile( pipe, cmd, sizeof cmd, &count, NULL );
549 if (!r || count != sizeof cmd)
551 ERR("service protocol error - failed to write pipe!\n");
554 r = ReadFile( pipe, dwResult, sizeof *dwResult, &count, NULL );
555 if (!r || count != sizeof *dwResult)
556 ERR("service protocol error - failed to read pipe "
557 "r = %d count = %d!\n", r, count);
561 /******************************************************************************
562 * service_send_control
564 static BOOL service_send_control(HANDLE pipe, DWORD dwControl, DWORD *result)
566 DWORD cmd[2], count = 0;
569 cmd[0] = WINESERV_SENDCONTROL;
571 r = WriteFile(pipe, cmd, sizeof cmd, &count, NULL);
572 if (!r || count != sizeof cmd)
574 ERR("service protocol error - failed to write pipe!\n");
577 r = ReadFile(pipe, result, sizeof *result, &count, NULL);
578 if (!r || count != sizeof *result)
579 ERR("service protocol error - failed to read pipe "
580 "r = %d count = %d!\n", r, count);
584 /******************************************************************************
585 * service_accepts_control
587 static BOOL service_accepts_control(const service_data *service, DWORD dwControl)
589 DWORD a = service->status.dwControlsAccepted;
593 case SERVICE_CONTROL_INTERROGATE:
595 case SERVICE_CONTROL_STOP:
596 if (a&SERVICE_ACCEPT_STOP)
599 case SERVICE_CONTROL_SHUTDOWN:
600 if (a&SERVICE_ACCEPT_SHUTDOWN)
603 case SERVICE_CONTROL_PAUSE:
604 case SERVICE_CONTROL_CONTINUE:
605 if (a&SERVICE_ACCEPT_PAUSE_CONTINUE)
608 case SERVICE_CONTROL_PARAMCHANGE:
609 if (a&SERVICE_ACCEPT_PARAMCHANGE)
612 case SERVICE_CONTROL_NETBINDADD:
613 case SERVICE_CONTROL_NETBINDREMOVE:
614 case SERVICE_CONTROL_NETBINDENABLE:
615 case SERVICE_CONTROL_NETBINDDISABLE:
616 if (a&SERVICE_ACCEPT_NETBINDCHANGE)
619 if (!service->extended)
623 case SERVICE_CONTROL_HARDWAREPROFILECHANGE:
624 if (a&SERVICE_ACCEPT_HARDWAREPROFILECHANGE)
627 case SERVICE_CONTROL_POWEREVENT:
628 if (a&SERVICE_ACCEPT_POWEREVENT)
631 case SERVICE_CONTROL_SESSIONCHANGE:
632 if (a&SERVICE_ACCEPT_SESSIONCHANGE)
639 /******************************************************************************
640 * service_handle_control
642 static BOOL service_handle_control(HANDLE pipe, service_data *service,
645 DWORD count, ret = ERROR_INVALID_SERVICE_CONTROL;
647 TRACE("received control %d\n", dwControl);
649 if (service_accepts_control(service, dwControl))
651 if (service->extended && service->handler.handler_ex)
653 service->handler.handler_ex(dwControl, 0, NULL, service->context);
656 else if (service->handler.handler)
658 service->handler.handler(dwControl);
662 return WriteFile(pipe, &ret, sizeof ret, &count, NULL);
665 /******************************************************************************
666 * service_reap_thread
668 static DWORD service_reap_thread(service_data *service)
672 if (!service->thread)
674 GetExitCodeThread(service->thread, &exitcode);
675 if (exitcode!=STILL_ACTIVE)
677 CloseHandle(service->thread);
683 /******************************************************************************
684 * service_control_dispatcher
686 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
688 service_data *service = arg;
692 TRACE("%p %s\n", service, debugstr_w(service->name));
694 /* create a pipe to talk to the rest of the world with */
695 name = service_get_pipe_name(service->name);
696 pipe = CreateNamedPipeW(name, PIPE_ACCESS_DUPLEX,
697 PIPE_TYPE_BYTE|PIPE_WAIT, 1, 256, 256, 10000, NULL );
700 /* let the process who started us know we've tried to create a pipe */
701 event = service_get_event_handle(service->name);
705 if (pipe==INVALID_HANDLE_VALUE)
707 ERR("failed to create pipe for %s, error = %d\n",
708 debugstr_w(service->name), GetLastError());
712 /* dispatcher loop */
716 DWORD count, req[2] = {0,0};
718 r = ConnectNamedPipe(pipe, NULL);
719 if (!r && GetLastError() != ERROR_PIPE_CONNECTED)
721 ERR("pipe connect failed\n");
725 r = ReadFile( pipe, &req, sizeof req, &count, NULL );
726 if (!r || count!=sizeof req)
728 ERR("pipe read failed\n");
732 service_reap_thread(service);
734 /* handle the request */
737 case WINESERV_STARTINFO:
738 service_handle_start(pipe, service, req[1]);
740 case WINESERV_GETSTATUS:
741 service_handle_get_status(pipe, service);
743 case WINESERV_SENDCONTROL:
744 service_handle_control(pipe, service, req[1]);
746 case WINESERV_SETPID:
747 service_handle_set_processID(pipe, service, req[1]);
750 ERR("received invalid command %d length %d\n", req[0], req[1]);
753 FlushFileBuffers(pipe);
754 DisconnectNamedPipe(pipe);
761 /******************************************************************************
762 * service_run_threads
764 static BOOL service_run_threads(void)
766 service_data *service;
767 DWORD count = 0, n = 0;
770 EnterCriticalSection( &service_cs );
772 /* count how many services there are */
773 for (service = service_list; service; service = service->next)
776 TRACE("starting %d pipe listener threads\n", count);
778 handles = HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE)*count);
780 for (n=0, service = service_list; service; service = service->next, n++)
781 handles[n] = CreateThread( NULL, 0, service_control_dispatcher,
785 LeaveCriticalSection( &service_cs );
787 /* wait for all the threads to pack up and exit */
788 WaitForMultipleObjectsEx(count, handles, TRUE, INFINITE, FALSE);
790 HeapFree(GetProcessHeap(), 0, handles);
795 /******************************************************************************
796 * StartServiceCtrlDispatcherA [ADVAPI32.@]
798 * See StartServiceCtrlDispatcherW.
800 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
806 TRACE("%p\n", servent);
808 EnterCriticalSection( &service_cs );
809 while (servent->lpServiceName)
811 LPSTR name = servent->lpServiceName;
813 len = MultiByteToWideChar(CP_ACP, 0, name, -1, NULL, 0);
814 sz = len*sizeof(WCHAR) + sizeof *info;
815 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
816 MultiByteToWideChar(CP_ACP, 0, name, -1, info->name, len);
817 info->proc.a = servent->lpServiceProc;
818 info->unicode = FALSE;
820 /* insert into the list */
821 info->next = service_list;
826 LeaveCriticalSection( &service_cs );
828 service_run_threads();
833 /******************************************************************************
834 * StartServiceCtrlDispatcherW [ADVAPI32.@]
836 * Connects a process containing one or more services to the service control
840 * servent [I] A list of the service names and service procedures
846 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
852 TRACE("%p\n", servent);
854 EnterCriticalSection( &service_cs );
855 while (servent->lpServiceName)
857 LPWSTR name = servent->lpServiceName;
860 sz = len*sizeof(WCHAR) + sizeof *info;
861 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
862 strcpyW(info->name, name);
863 info->proc.w = servent->lpServiceProc;
864 info->unicode = TRUE;
866 /* insert into the list */
867 info->next = service_list;
872 LeaveCriticalSection( &service_cs );
874 service_run_threads();
879 /******************************************************************************
880 * LockServiceDatabase [ADVAPI32.@]
882 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
886 TRACE("%p\n",hSCManager);
888 ret = CreateSemaphoreW( NULL, 1, 1, szSCMLock );
889 if( ret && GetLastError() == ERROR_ALREADY_EXISTS )
893 SetLastError( ERROR_SERVICE_DATABASE_LOCKED );
896 TRACE("returning %p\n", ret);
901 /******************************************************************************
902 * UnlockServiceDatabase [ADVAPI32.@]
904 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
906 TRACE("%p\n",ScLock);
908 return CloseHandle( ScLock );
911 /******************************************************************************
912 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
914 SERVICE_STATUS_HANDLE WINAPI
915 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName, LPHANDLER_FUNCTION lpfHandler )
917 LPWSTR lpServiceNameW;
918 SERVICE_STATUS_HANDLE ret;
920 lpServiceNameW = SERV_dup(lpServiceName);
921 ret = RegisterServiceCtrlHandlerW( lpServiceNameW, lpfHandler );
922 SERV_free(lpServiceNameW);
926 /******************************************************************************
927 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
933 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName,
934 LPHANDLER_FUNCTION lpfHandler )
936 service_data *service;
938 EnterCriticalSection( &service_cs );
939 for(service = service_list; service; service = service->next)
940 if(!strcmpW(lpServiceName, service->name))
943 service->handler.handler = lpfHandler;
944 LeaveCriticalSection( &service_cs );
946 return (SERVICE_STATUS_HANDLE)service;
949 /******************************************************************************
950 * SetServiceStatus [ADVAPI32.@]
957 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
959 service_data *service;
962 TRACE("%p %x %x %x %x %x %x %x\n", hService,
963 lpStatus->dwServiceType, lpStatus->dwCurrentState,
964 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
965 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
966 lpStatus->dwWaitHint);
968 EnterCriticalSection( &service_cs );
969 for (service = service_list; service; service = service->next)
970 if(service == (service_data*)hService)
974 memcpy( &service->status, lpStatus, sizeof(SERVICE_STATUS) );
975 TRACE("Set service status to %d\n",service->status.dwCurrentState);
979 LeaveCriticalSection( &service_cs );
985 /******************************************************************************
986 * OpenSCManagerA [ADVAPI32.@]
988 * Establish a connection to the service control manager and open its database.
991 * lpMachineName [I] Pointer to machine name string
992 * lpDatabaseName [I] Pointer to database name string
993 * dwDesiredAccess [I] Type of access
996 * Success: A Handle to the service control manager database
999 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
1000 DWORD dwDesiredAccess )
1002 LPWSTR lpMachineNameW, lpDatabaseNameW;
1005 lpMachineNameW = SERV_dup(lpMachineName);
1006 lpDatabaseNameW = SERV_dup(lpDatabaseName);
1007 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
1008 SERV_free(lpDatabaseNameW);
1009 SERV_free(lpMachineNameW);
1013 /******************************************************************************
1014 * OpenSCManagerW [ADVAPI32.@]
1016 * See OpenSCManagerA.
1018 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
1019 DWORD dwDesiredAccess )
1021 struct sc_manager *manager;
1025 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
1026 debugstr_w(lpDatabaseName), dwDesiredAccess);
1028 if( lpDatabaseName && lpDatabaseName[0] )
1030 if( strcmpiW( lpDatabaseName, SERVICES_ACTIVE_DATABASEW ) == 0 )
1032 /* noop, all right */
1034 else if( strcmpiW( lpDatabaseName, SERVICES_FAILED_DATABASEW ) == 0 )
1036 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST );
1041 SetLastError( ERROR_INVALID_NAME );
1046 manager = sc_handle_alloc( SC_HTYPE_MANAGER, sizeof (struct sc_manager),
1047 sc_handle_destroy_manager );
1051 r = RegConnectRegistryW(lpMachineName,HKEY_LOCAL_MACHINE,&hReg);
1052 if (r!=ERROR_SUCCESS)
1055 r = RegCreateKeyW(hReg, szServiceManagerKey, &manager->hkey);
1056 RegCloseKey( hReg );
1057 if (r!=ERROR_SUCCESS)
1060 manager->dwAccess = dwDesiredAccess;
1061 TRACE("returning %p\n", manager);
1063 return (SC_HANDLE) &manager->hdr;
1066 sc_handle_free( &manager->hdr );
1071 /******************************************************************************
1072 * ControlService [ADVAPI32.@]
1074 * Send a control code to a service.
1077 * hService [I] Handle of the service control manager database
1078 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1079 * lpServiceStatus [O] Destination for the status of the service, if available
1086 * Unlike M$' implementation, control requests are not serialized and may be
1087 * processed asynchronously.
1089 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
1090 LPSERVICE_STATUS lpServiceStatus )
1092 struct sc_service *hsvc;
1096 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
1098 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1101 SetLastError( ERROR_INVALID_HANDLE );
1105 ret = QueryServiceStatus(hService, lpServiceStatus);
1108 ERR("failed to query service status\n");
1109 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1113 switch (lpServiceStatus->dwCurrentState)
1115 case SERVICE_STOPPED:
1116 SetLastError(ERROR_SERVICE_NOT_ACTIVE);
1118 case SERVICE_START_PENDING:
1119 if (dwControl==SERVICE_CONTROL_STOP)
1122 case SERVICE_STOP_PENDING:
1123 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL);
1127 handle = service_open_pipe(hsvc->name);
1128 if (handle!=INVALID_HANDLE_VALUE)
1130 DWORD result = ERROR_SUCCESS;
1131 ret = service_send_control(handle, dwControl, &result);
1132 CloseHandle(handle);
1133 if (result!=ERROR_SUCCESS)
1135 SetLastError(result);
1143 /******************************************************************************
1144 * CloseServiceHandle [ADVAPI32.@]
1146 * Close a handle to a service or the service control manager database.
1149 * hSCObject [I] Handle to service or service control manager database
1156 CloseServiceHandle( SC_HANDLE hSCObject )
1158 TRACE("%p\n", hSCObject);
1160 sc_handle_free( (struct sc_handle*) hSCObject );
1166 /******************************************************************************
1167 * OpenServiceA [ADVAPI32.@]
1169 * Open a handle to a service.
1172 * hSCManager [I] Handle of the service control manager database
1173 * lpServiceName [I] Name of the service to open
1174 * dwDesiredAccess [I] Access required to the service
1177 * Success: Handle to the service
1180 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1181 DWORD dwDesiredAccess )
1183 LPWSTR lpServiceNameW;
1186 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
1188 lpServiceNameW = SERV_dup(lpServiceName);
1189 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
1190 SERV_free(lpServiceNameW);
1195 /******************************************************************************
1196 * OpenServiceW [ADVAPI32.@]
1200 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1201 DWORD dwDesiredAccess)
1203 struct sc_manager *hscm;
1204 struct sc_service *hsvc;
1209 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
1213 SetLastError(ERROR_INVALID_ADDRESS);
1217 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1220 SetLastError( ERROR_INVALID_HANDLE );
1224 r = RegOpenKeyExW( hscm->hkey, lpServiceName, 0, KEY_ALL_ACCESS, &hKey );
1225 if (r!=ERROR_SUCCESS)
1227 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1231 len = strlenW(lpServiceName)+1;
1232 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE,
1233 sizeof (struct sc_service) + len*sizeof(WCHAR),
1234 sc_handle_destroy_service );
1237 strcpyW( hsvc->name, lpServiceName );
1239 hsvc->dwAccess = dwDesiredAccess;
1241 /* add reference to SCM handle */
1242 hscm->hdr.ref_count++;
1245 TRACE("returning %p\n",hsvc);
1247 return (SC_HANDLE) &hsvc->hdr;
1250 /******************************************************************************
1251 * CreateServiceW [ADVAPI32.@]
1254 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1255 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
1256 DWORD dwServiceType, DWORD dwStartType,
1257 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1258 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1259 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
1260 LPCWSTR lpPassword )
1262 struct sc_manager *hscm;
1263 struct sc_service *hsvc = NULL;
1267 struct reg_value val[10];
1270 TRACE("%p %s %s\n", hSCManager,
1271 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
1273 hscm = sc_handle_get_handle_data( hSCManager, SC_HTYPE_MANAGER );
1276 SetLastError( ERROR_INVALID_HANDLE );
1280 r = RegCreateKeyExW(hscm->hkey, lpServiceName, 0, NULL,
1281 REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dp);
1282 if (r!=ERROR_SUCCESS)
1285 if (dp != REG_CREATED_NEW_KEY)
1287 SetLastError(ERROR_SERVICE_EXISTS);
1292 service_set_string( &val[n++], szDisplayName, lpDisplayName );
1294 service_set_dword( &val[n++], szType, &dwServiceType );
1295 service_set_dword( &val[n++], szStart, &dwStartType );
1296 service_set_dword( &val[n++], szError, &dwErrorControl );
1298 if( lpBinaryPathName )
1299 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
1301 if( lpLoadOrderGroup )
1302 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
1304 if( lpDependencies )
1305 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
1308 FIXME("Don't know how to add a Password for a service.\n");
1310 if( lpServiceStartName )
1311 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
1313 r = service_write_values( hKey, val, n );
1314 if( r != ERROR_SUCCESS )
1317 len = strlenW(lpServiceName)+1;
1318 len = sizeof (struct sc_service) + len*sizeof(WCHAR);
1319 hsvc = sc_handle_alloc( SC_HTYPE_SERVICE, len, sc_handle_destroy_service );
1322 lstrcpyW( hsvc->name, lpServiceName );
1325 hscm->hdr.ref_count++;
1327 return (SC_HANDLE) &hsvc->hdr;
1330 RegCloseKey( hKey );
1335 /******************************************************************************
1336 * CreateServiceA [ADVAPI32.@]
1339 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1340 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
1341 DWORD dwServiceType, DWORD dwStartType,
1342 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1343 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
1344 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
1347 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1348 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1351 TRACE("%p %s %s\n", hSCManager,
1352 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1354 lpServiceNameW = SERV_dup( lpServiceName );
1355 lpDisplayNameW = SERV_dup( lpDisplayName );
1356 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1357 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1358 lpDependenciesW = SERV_dupmulti( lpDependencies );
1359 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1360 lpPasswordW = SERV_dup( lpPassword );
1362 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1363 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1364 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1365 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1367 SERV_free( lpServiceNameW );
1368 SERV_free( lpDisplayNameW );
1369 SERV_free( lpBinaryPathNameW );
1370 SERV_free( lpLoadOrderGroupW );
1371 SERV_free( lpDependenciesW );
1372 SERV_free( lpServiceStartNameW );
1373 SERV_free( lpPasswordW );
1379 /******************************************************************************
1380 * DeleteService [ADVAPI32.@]
1382 * Delete a service from the service control manager database.
1385 * hService [I] Handle of the service to delete
1391 BOOL WINAPI DeleteService( SC_HANDLE hService )
1393 struct sc_service *hsvc;
1395 WCHAR valname[MAX_PATH+1];
1400 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1403 SetLastError( ERROR_INVALID_HANDLE );
1409 /* Clean out the values */
1410 rc = RegEnumValueW(hKey, index, valname,&size,0,0,0,0);
1411 while (rc == ERROR_SUCCESS)
1413 RegDeleteValueW(hKey,valname);
1416 rc = RegEnumValueW(hKey, index, valname, &size,0,0,0,0);
1422 /* delete the key */
1423 RegDeleteKeyW(hsvc->scm->hkey, hsvc->name);
1429 /******************************************************************************
1430 * StartServiceA [ADVAPI32.@]
1435 * hService [I] Handle of service
1436 * dwNumServiceArgs [I] Number of arguments
1437 * lpServiceArgVectors [I] Address of array of argument strings
1440 * - NT implements this function using an obscure RPC call.
1441 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1442 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1443 * - This will only work for shared address space. How should the service
1444 * args be transferred when address spaces are separated?
1445 * - Can only start one service at a time.
1446 * - Has no concept of privilege.
1452 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1453 LPCSTR *lpServiceArgVectors )
1455 LPWSTR *lpwstr=NULL;
1459 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1461 if (dwNumServiceArgs)
1462 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1463 dwNumServiceArgs*sizeof(LPWSTR) );
1465 for(i=0; i<dwNumServiceArgs; i++)
1466 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1468 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1470 if (dwNumServiceArgs)
1472 for(i=0; i<dwNumServiceArgs; i++)
1473 SERV_free(lpwstr[i]);
1474 HeapFree(GetProcessHeap(), 0, lpwstr);
1480 /******************************************************************************
1481 * service_start_process [INTERNAL]
1483 static DWORD service_start_process(struct sc_service *hsvc, LPDWORD ppid)
1485 static const WCHAR _ImagePathW[] = {'I','m','a','g','e','P','a','t','h',0};
1486 PROCESS_INFORMATION pi;
1488 LPWSTR path = NULL, str;
1489 DWORD type, size, ret, svc_type;
1493 size = sizeof(svc_type);
1494 if (RegQueryValueExW(hsvc->hkey, szType, NULL, &type, (LPBYTE)&svc_type, &size) || type != REG_DWORD)
1497 if (svc_type == SERVICE_KERNEL_DRIVER)
1499 static const WCHAR winedeviceW[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1500 DWORD len = GetSystemDirectoryW( NULL, 0 ) + sizeof(winedeviceW)/sizeof(WCHAR) + strlenW(hsvc->name);
1502 if (!(path = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) return FALSE;
1503 GetSystemDirectoryW( path, len );
1504 lstrcatW( path, winedeviceW );
1505 lstrcatW( path, hsvc->name );
1509 /* read the executable path from the registry */
1511 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1512 if (ret!=ERROR_SUCCESS)
1514 str = HeapAlloc(GetProcessHeap(),0,size);
1515 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1516 if (ret==ERROR_SUCCESS)
1518 size = ExpandEnvironmentStringsW(str,NULL,0);
1519 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1520 ExpandEnvironmentStringsW(str,path,size);
1522 HeapFree(GetProcessHeap(),0,str);
1527 /* wait for the process to start and set an event or terminate */
1528 handles[0] = service_get_event_handle( hsvc->name );
1529 ZeroMemory(&si, sizeof(STARTUPINFOW));
1530 si.cb = sizeof(STARTUPINFOW);
1531 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1534 if (ppid) *ppid = pi.dwProcessId;
1536 handles[1] = pi.hProcess;
1537 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1538 if(ret != WAIT_OBJECT_0)
1540 SetLastError(ERROR_IO_PENDING);
1544 CloseHandle( pi.hThread );
1545 CloseHandle( pi.hProcess );
1547 CloseHandle( handles[0] );
1548 HeapFree(GetProcessHeap(),0,path);
1552 static BOOL service_wait_for_startup(SC_HANDLE hService)
1555 SERVICE_STATUS status;
1558 TRACE("%p\n", hService);
1560 for (i=0; i<30; i++)
1562 status.dwCurrentState = 0;
1563 r = QueryServiceStatus(hService, &status);
1566 if (status.dwCurrentState == SERVICE_RUNNING)
1568 TRACE("Service started successfully\n");
1577 /******************************************************************************
1578 * StartServiceW [ADVAPI32.@]
1580 * See StartServiceA.
1582 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1583 LPCWSTR *lpServiceArgVectors)
1585 struct sc_service *hsvc;
1587 DWORD dwResult, dwProcessId = 0;
1589 HANDLE handle = INVALID_HANDLE_VALUE;
1591 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1593 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1596 SetLastError(ERROR_INVALID_HANDLE);
1600 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1604 handle = service_open_pipe(hsvc->name);
1605 if (handle==INVALID_HANDLE_VALUE)
1607 /* start the service process */
1608 if (service_start_process(hsvc, &dwProcessId))
1609 handle = service_open_pipe(hsvc->name);
1612 if (handle != INVALID_HANDLE_VALUE)
1614 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1615 CloseHandle(handle);
1618 handle = service_open_pipe(hsvc->name);
1619 if (handle != INVALID_HANDLE_VALUE)
1621 service_set_processID(handle, dwProcessId, &dwResult);
1622 CloseHandle(handle);
1625 UnlockServiceDatabase( hLock );
1627 TRACE("returning %d\n", r);
1630 service_wait_for_startup(hService);
1635 /******************************************************************************
1636 * QueryServiceStatus [ADVAPI32.@]
1639 * hService [I] Handle to service to get information about
1640 * lpservicestatus [O] buffer to receive the status information for the service
1643 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1644 LPSERVICE_STATUS lpservicestatus)
1646 SERVICE_STATUS_PROCESS SvcStatusData;
1649 TRACE("%p %p\n", hService, lpservicestatus);
1651 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1652 sizeof(SERVICE_STATUS_PROCESS), NULL);
1653 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1658 /******************************************************************************
1659 * QueryServiceStatusEx [ADVAPI32.@]
1661 * Get information about a service.
1664 * hService [I] Handle to service to get information about
1665 * InfoLevel [I] Level of information to get
1666 * lpBuffer [O] Destination for requested information
1667 * cbBufSize [I] Size of lpBuffer in bytes
1668 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1674 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1675 LPBYTE lpBuffer, DWORD cbBufSize,
1676 LPDWORD pcbBytesNeeded)
1678 struct sc_service *hsvc;
1679 DWORD size, type, val;
1682 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1684 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1686 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1688 SetLastError( ERROR_INVALID_LEVEL);
1692 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1693 if (pSvcStatusData == NULL)
1695 SetLastError( ERROR_INVALID_PARAMETER);
1699 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1701 if( pcbBytesNeeded != NULL)
1702 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1704 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1708 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1711 SetLastError( ERROR_INVALID_HANDLE );
1715 pipe = service_open_pipe(hsvc->name);
1716 if (pipe != INVALID_HANDLE_VALUE)
1718 r = service_get_status(pipe, pSvcStatusData);
1724 TRACE("Failed to read service status\n");
1726 /* read the service type from the registry */
1728 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1729 if (r != ERROR_SUCCESS || type != REG_DWORD)
1732 pSvcStatusData->dwServiceType = val;
1733 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1734 pSvcStatusData->dwControlsAccepted = 0;
1735 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1736 pSvcStatusData->dwServiceSpecificExitCode = 0;
1737 pSvcStatusData->dwCheckPoint = 0;
1738 pSvcStatusData->dwWaitHint = 0;
1743 /******************************************************************************
1744 * QueryServiceConfigA [ADVAPI32.@]
1746 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1747 DWORD size, LPDWORD needed )
1752 QUERY_SERVICE_CONFIGW *configW;
1754 TRACE("%p %p %d %p\n", hService, config, size, needed);
1756 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1758 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1761 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1762 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1763 if (!ret) goto done;
1765 config->dwServiceType = configW->dwServiceType;
1766 config->dwStartType = configW->dwStartType;
1767 config->dwErrorControl = configW->dwErrorControl;
1768 config->lpBinaryPathName = NULL;
1769 config->lpLoadOrderGroup = NULL;
1770 config->dwTagId = configW->dwTagId;
1771 config->lpDependencies = NULL;
1772 config->lpServiceStartName = NULL;
1773 config->lpDisplayName = NULL;
1775 p = (LPSTR)(config + 1);
1776 n = size - sizeof(*config);
1779 #define MAP_STR(str) \
1783 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1784 if (!sz) goto done; \
1791 MAP_STR( lpBinaryPathName );
1792 MAP_STR( lpLoadOrderGroup );
1793 MAP_STR( lpDependencies );
1794 MAP_STR( lpServiceStartName );
1795 MAP_STR( lpDisplayName );
1798 *needed = p - buffer;
1802 HeapFree( GetProcessHeap(), 0, buffer );
1806 /******************************************************************************
1807 * QueryServiceConfigW [ADVAPI32.@]
1810 QueryServiceConfigW( SC_HANDLE hService,
1811 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1812 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1814 WCHAR str_buffer[ MAX_PATH ];
1816 DWORD type, val, sz, total, n;
1819 struct sc_service *hsvc;
1821 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1822 cbBufSize, pcbBytesNeeded);
1824 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1827 SetLastError( ERROR_INVALID_HANDLE );
1832 /* calculate the size required first */
1833 total = sizeof (QUERY_SERVICE_CONFIGW);
1835 sz = sizeof(str_buffer);
1836 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1837 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1839 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1840 if( 0 == sz ) return FALSE;
1842 total += sizeof(WCHAR) * sz;
1846 /* FIXME: set last error */
1851 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1852 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1856 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1857 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1860 total += sizeof(WCHAR);
1863 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1864 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1868 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1869 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1872 *pcbBytesNeeded = total;
1874 /* if there's not enough memory, return an error */
1875 if( total > cbBufSize )
1877 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1881 ZeroMemory( lpServiceConfig, total );
1884 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1885 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1886 lpServiceConfig->dwServiceType = val;
1889 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1890 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1891 lpServiceConfig->dwStartType = val;
1894 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1895 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1896 lpServiceConfig->dwErrorControl = val;
1898 /* now do the strings */
1899 p = (LPBYTE) &lpServiceConfig[1];
1900 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1902 sz = sizeof(str_buffer);
1903 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1904 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1906 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1907 sz *= sizeof(WCHAR);
1908 if( 0 == sz || sz > n ) return FALSE;
1910 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1916 /* FIXME: set last error */
1921 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1922 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1924 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1930 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1931 lpServiceConfig->lpDependencies = (LPWSTR) p;
1932 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1945 ERR("Buffer overflow!\n");
1947 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1948 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1953 /******************************************************************************
1954 * EnumServicesStatusA [ADVAPI32.@]
1957 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1958 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1959 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1960 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1962 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1963 dwServiceType, dwServiceState, lpServices, cbBufSize,
1964 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1965 SetLastError (ERROR_ACCESS_DENIED);
1969 /******************************************************************************
1970 * EnumServicesStatusW [ADVAPI32.@]
1973 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1974 DWORD dwServiceState, LPENUM_SERVICE_STATUSW 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 * EnumServicesStatusExA [ADVAPI32.@]
1989 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1990 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1991 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1993 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1994 dwServiceType, dwServiceState, lpServices, cbBufSize,
1995 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1996 SetLastError (ERROR_ACCESS_DENIED);
2000 /******************************************************************************
2001 * EnumServicesStatusExW [ADVAPI32.@]
2004 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
2005 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
2006 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
2008 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
2009 dwServiceType, dwServiceState, lpServices, cbBufSize,
2010 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
2011 SetLastError (ERROR_ACCESS_DENIED);
2015 /******************************************************************************
2016 * GetServiceKeyNameA [ADVAPI32.@]
2018 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2019 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2021 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2025 /******************************************************************************
2026 * GetServiceKeyNameW [ADVAPI32.@]
2028 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2029 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2031 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2035 /******************************************************************************
2036 * QueryServiceLockStatusA [ADVAPI32.@]
2038 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2039 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2040 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2042 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2047 /******************************************************************************
2048 * QueryServiceLockStatusW [ADVAPI32.@]
2050 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2051 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2052 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2054 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2059 /******************************************************************************
2060 * GetServiceDisplayNameA [ADVAPI32.@]
2062 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2063 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2065 struct sc_manager *hscm;
2069 TRACE("%p %s %p %p\n", hSCManager,
2070 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2072 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2075 SetLastError(ERROR_INVALID_HANDLE);
2079 size = *lpcchBuffer;
2080 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2081 if (!ret && !lpDisplayName && size)
2082 ret = ERROR_MORE_DATA;
2086 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2088 if (ret == ERROR_MORE_DATA)
2090 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2091 *lpcchBuffer = size - 1;
2100 /******************************************************************************
2101 * GetServiceDisplayNameW [ADVAPI32.@]
2103 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2104 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2106 struct sc_manager *hscm;
2110 TRACE("%p %s %p %p\n", hSCManager,
2111 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2113 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2116 SetLastError(ERROR_INVALID_HANDLE);
2120 size = *lpcchBuffer * sizeof(WCHAR);
2121 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2122 if (!ret && !lpDisplayName && size)
2123 ret = ERROR_MORE_DATA;
2127 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2129 if (ret == ERROR_MORE_DATA)
2131 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2132 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2141 /******************************************************************************
2142 * ChangeServiceConfigW [ADVAPI32.@]
2144 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2145 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2146 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2147 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2149 struct reg_value val[10];
2150 struct sc_service *hsvc;
2151 DWORD r = ERROR_SUCCESS;
2155 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2156 hService, dwServiceType, dwStartType, dwErrorControl,
2157 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2158 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2159 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2161 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2164 SetLastError( ERROR_INVALID_HANDLE );
2169 if( dwServiceType != SERVICE_NO_CHANGE )
2170 service_set_dword( &val[n++], szType, &dwServiceType );
2172 if( dwStartType != SERVICE_NO_CHANGE )
2173 service_set_dword( &val[n++], szStart, &dwStartType );
2175 if( dwErrorControl != SERVICE_NO_CHANGE )
2176 service_set_dword( &val[n++], szError, &dwErrorControl );
2178 if( lpBinaryPathName )
2179 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2181 if( lpLoadOrderGroup )
2182 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2184 if( lpDependencies )
2185 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2188 FIXME("ignoring password\n");
2190 if( lpServiceStartName )
2191 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2193 r = service_write_values( hsvc->hkey, val, n );
2195 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2198 /******************************************************************************
2199 * ChangeServiceConfigA [ADVAPI32.@]
2201 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2202 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2203 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2204 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2206 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2207 LPWSTR wServiceStartName, wPassword, wDisplayName;
2210 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2211 hService, dwServiceType, dwStartType, dwErrorControl,
2212 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2213 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2214 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2216 wBinaryPathName = SERV_dup( lpBinaryPathName );
2217 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2218 wDependencies = SERV_dupmulti( lpDependencies );
2219 wServiceStartName = SERV_dup( lpServiceStartName );
2220 wPassword = SERV_dup( lpPassword );
2221 wDisplayName = SERV_dup( lpDisplayName );
2223 r = ChangeServiceConfigW( hService, dwServiceType,
2224 dwStartType, dwErrorControl, wBinaryPathName,
2225 wLoadOrderGroup, lpdwTagId, wDependencies,
2226 wServiceStartName, wPassword, wDisplayName);
2228 SERV_free( wBinaryPathName );
2229 SERV_free( wLoadOrderGroup );
2230 SERV_free( wDependencies );
2231 SERV_free( wServiceStartName );
2232 SERV_free( wPassword );
2233 SERV_free( wDisplayName );
2238 /******************************************************************************
2239 * ChangeServiceConfig2A [ADVAPI32.@]
2241 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2246 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2248 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2250 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2251 SERVICE_DESCRIPTIONW sdw;
2253 sdw.lpDescription = SERV_dup( sd->lpDescription );
2255 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2257 SERV_free( sdw.lpDescription );
2259 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2261 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2262 SERVICE_FAILURE_ACTIONSW faw;
2264 faw.dwResetPeriod = fa->dwResetPeriod;
2265 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2266 faw.lpCommand = SERV_dup( fa->lpCommand );
2267 faw.cActions = fa->cActions;
2268 faw.lpsaActions = fa->lpsaActions;
2270 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2272 SERV_free( faw.lpRebootMsg );
2273 SERV_free( faw.lpCommand );
2276 SetLastError( ERROR_INVALID_PARAMETER );
2281 /******************************************************************************
2282 * ChangeServiceConfig2W [ADVAPI32.@]
2284 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2288 struct sc_service *hsvc;
2290 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2293 SetLastError( ERROR_INVALID_HANDLE );
2298 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2300 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2301 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2302 if (sd->lpDescription)
2304 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2305 if (sd->lpDescription[0] == 0)
2306 RegDeleteValueW(hKey,szDescription);
2308 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2309 (LPVOID)sd->lpDescription,
2310 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2314 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2318 /******************************************************************************
2319 * QueryServiceObjectSecurity [ADVAPI32.@]
2321 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2322 SECURITY_INFORMATION dwSecurityInformation,
2323 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2324 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2328 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2329 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2331 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2333 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2334 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2335 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2339 /******************************************************************************
2340 * SetServiceObjectSecurity [ADVAPI32.@]
2342 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2343 SECURITY_INFORMATION dwSecurityInformation,
2344 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2346 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2350 /******************************************************************************
2351 * SetServiceBits [ADVAPI32.@]
2353 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2354 DWORD dwServiceBits,
2356 BOOL bUpdateImmediately)
2358 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2359 bSetBitsOn, bUpdateImmediately);
2363 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2364 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2366 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2370 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2371 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2373 service_data *service;
2375 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2377 EnterCriticalSection( &service_cs );
2378 for(service = service_list; service; service = service->next)
2379 if(!strcmpW(lpServiceName, service->name))
2383 service->handler.handler_ex = lpHandlerProc;
2384 service->context = lpContext;
2385 service->extended = TRUE;
2387 LeaveCriticalSection( &service_cs );
2389 return (SERVICE_STATUS_HANDLE)service;