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;
1493 /* read the executable path from memory */
1495 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, NULL, &size);
1496 if (ret!=ERROR_SUCCESS)
1498 str = HeapAlloc(GetProcessHeap(),0,size);
1499 ret = RegQueryValueExW(hsvc->hkey, _ImagePathW, NULL, &type, (LPBYTE)str, &size);
1500 if (ret==ERROR_SUCCESS)
1502 size = ExpandEnvironmentStringsW(str,NULL,0);
1503 path = HeapAlloc(GetProcessHeap(),0,size*sizeof(WCHAR));
1504 ExpandEnvironmentStringsW(str,path,size);
1506 HeapFree(GetProcessHeap(),0,str);
1510 /* wait for the process to start and set an event or terminate */
1511 handles[0] = service_get_event_handle( hsvc->name );
1512 ZeroMemory(&si, sizeof(STARTUPINFOW));
1513 si.cb = sizeof(STARTUPINFOW);
1514 r = CreateProcessW(NULL, path, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
1517 if (ppid) *ppid = pi.dwProcessId;
1519 handles[1] = pi.hProcess;
1520 ret = WaitForMultipleObjectsEx(2, handles, FALSE, 30000, FALSE);
1521 if(ret != WAIT_OBJECT_0)
1523 SetLastError(ERROR_IO_PENDING);
1527 CloseHandle( pi.hThread );
1528 CloseHandle( pi.hProcess );
1530 CloseHandle( handles[0] );
1531 HeapFree(GetProcessHeap(),0,path);
1535 static BOOL service_wait_for_startup(SC_HANDLE hService)
1538 SERVICE_STATUS status;
1541 TRACE("%p\n", hService);
1543 for (i=0; i<30; i++)
1545 status.dwCurrentState = 0;
1546 r = QueryServiceStatus(hService, &status);
1549 if (status.dwCurrentState == SERVICE_RUNNING)
1551 TRACE("Service started successfully\n");
1560 /******************************************************************************
1561 * StartServiceW [ADVAPI32.@]
1563 * See StartServiceA.
1565 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1566 LPCWSTR *lpServiceArgVectors)
1568 struct sc_service *hsvc;
1570 DWORD dwResult, dwProcessId = 0;
1572 HANDLE handle = INVALID_HANDLE_VALUE;
1574 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1576 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1579 SetLastError(ERROR_INVALID_HANDLE);
1583 hLock = LockServiceDatabase((SC_HANDLE)hsvc->scm);
1587 handle = service_open_pipe(hsvc->name);
1588 if (handle==INVALID_HANDLE_VALUE)
1590 /* start the service process */
1591 if (service_start_process(hsvc, &dwProcessId))
1592 handle = service_open_pipe(hsvc->name);
1595 if (handle != INVALID_HANDLE_VALUE)
1597 r = service_send_start_message(handle, lpServiceArgVectors, dwNumServiceArgs);
1598 CloseHandle(handle);
1601 handle = service_open_pipe(hsvc->name);
1602 if (handle != INVALID_HANDLE_VALUE)
1604 service_set_processID(handle, dwProcessId, &dwResult);
1605 CloseHandle(handle);
1608 UnlockServiceDatabase( hLock );
1610 TRACE("returning %d\n", r);
1613 service_wait_for_startup(hService);
1618 /******************************************************************************
1619 * QueryServiceStatus [ADVAPI32.@]
1622 * hService [I] Handle to service to get information about
1623 * lpservicestatus [O] buffer to receive the status information for the service
1626 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1627 LPSERVICE_STATUS lpservicestatus)
1629 SERVICE_STATUS_PROCESS SvcStatusData;
1632 TRACE("%p %p\n", hService, lpservicestatus);
1634 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1635 sizeof(SERVICE_STATUS_PROCESS), NULL);
1636 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1641 /******************************************************************************
1642 * QueryServiceStatusEx [ADVAPI32.@]
1644 * Get information about a service.
1647 * hService [I] Handle to service to get information about
1648 * InfoLevel [I] Level of information to get
1649 * lpBuffer [O] Destination for requested information
1650 * cbBufSize [I] Size of lpBuffer in bytes
1651 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1657 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1658 LPBYTE lpBuffer, DWORD cbBufSize,
1659 LPDWORD pcbBytesNeeded)
1661 struct sc_service *hsvc;
1662 DWORD size, type, val;
1665 LPSERVICE_STATUS_PROCESS pSvcStatusData;
1667 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1669 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1671 SetLastError( ERROR_INVALID_LEVEL);
1675 pSvcStatusData = (LPSERVICE_STATUS_PROCESS) lpBuffer;
1676 if (pSvcStatusData == NULL)
1678 SetLastError( ERROR_INVALID_PARAMETER);
1682 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1684 if( pcbBytesNeeded != NULL)
1685 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1687 SetLastError( ERROR_INSUFFICIENT_BUFFER);
1691 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1694 SetLastError( ERROR_INVALID_HANDLE );
1698 pipe = service_open_pipe(hsvc->name);
1699 if (pipe != INVALID_HANDLE_VALUE)
1701 r = service_get_status(pipe, pSvcStatusData);
1707 TRACE("Failed to read service status\n");
1709 /* read the service type from the registry */
1711 r = RegQueryValueExA(hsvc->hkey, "Type", NULL, &type, (LPBYTE)&val, &size);
1712 if (r != ERROR_SUCCESS || type != REG_DWORD)
1715 pSvcStatusData->dwServiceType = val;
1716 pSvcStatusData->dwCurrentState = SERVICE_STOPPED; /* stopped */
1717 pSvcStatusData->dwControlsAccepted = 0;
1718 pSvcStatusData->dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
1719 pSvcStatusData->dwServiceSpecificExitCode = 0;
1720 pSvcStatusData->dwCheckPoint = 0;
1721 pSvcStatusData->dwWaitHint = 0;
1726 /******************************************************************************
1727 * QueryServiceConfigA [ADVAPI32.@]
1729 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1730 DWORD size, LPDWORD needed )
1735 QUERY_SERVICE_CONFIGW *configW;
1737 TRACE("%p %p %d %p\n", hService, config, size, needed);
1739 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1741 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1744 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1745 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1746 if (!ret) goto done;
1748 config->dwServiceType = configW->dwServiceType;
1749 config->dwStartType = configW->dwStartType;
1750 config->dwErrorControl = configW->dwErrorControl;
1751 config->lpBinaryPathName = NULL;
1752 config->lpLoadOrderGroup = NULL;
1753 config->dwTagId = configW->dwTagId;
1754 config->lpDependencies = NULL;
1755 config->lpServiceStartName = NULL;
1756 config->lpDisplayName = NULL;
1758 p = (LPSTR)(config + 1);
1759 n = size - sizeof(*config);
1762 #define MAP_STR(str) \
1766 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1767 if (!sz) goto done; \
1774 MAP_STR( lpBinaryPathName );
1775 MAP_STR( lpLoadOrderGroup );
1776 MAP_STR( lpDependencies );
1777 MAP_STR( lpServiceStartName );
1778 MAP_STR( lpDisplayName );
1781 *needed = p - buffer;
1785 HeapFree( GetProcessHeap(), 0, buffer );
1789 /******************************************************************************
1790 * QueryServiceConfigW [ADVAPI32.@]
1793 QueryServiceConfigW( SC_HANDLE hService,
1794 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1795 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1797 WCHAR str_buffer[ MAX_PATH ];
1799 DWORD type, val, sz, total, n;
1802 struct sc_service *hsvc;
1804 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1805 cbBufSize, pcbBytesNeeded);
1807 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
1810 SetLastError( ERROR_INVALID_HANDLE );
1815 /* calculate the size required first */
1816 total = sizeof (QUERY_SERVICE_CONFIGW);
1818 sz = sizeof(str_buffer);
1819 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1820 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1822 sz = ExpandEnvironmentStringsW(str_buffer,NULL,0);
1823 if( 0 == sz ) return FALSE;
1825 total += sizeof(WCHAR) * sz;
1829 /* FIXME: set last error */
1834 r = RegQueryValueExW( hKey, szGroup, 0, &type, NULL, &sz );
1835 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1839 r = RegQueryValueExW( hKey, szDependencies, 0, &type, NULL, &sz );
1840 if( ( r == ERROR_SUCCESS ) && ( type == REG_MULTI_SZ ) )
1843 total += sizeof(WCHAR);
1846 r = RegQueryValueExW( hKey, szStart, 0, &type, NULL, &sz );
1847 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1851 r = RegQueryValueExW( hKey, szDisplayName, 0, &type, NULL, &sz );
1852 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ ) )
1855 *pcbBytesNeeded = total;
1857 /* if there's not enough memory, return an error */
1858 if( total > cbBufSize )
1860 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1864 ZeroMemory( lpServiceConfig, total );
1867 r = RegQueryValueExW( hKey, szType, 0, &type, (LPBYTE)&val, &sz );
1868 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1869 lpServiceConfig->dwServiceType = val;
1872 r = RegQueryValueExW( hKey, szStart, 0, &type, (LPBYTE)&val, &sz );
1873 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1874 lpServiceConfig->dwStartType = val;
1877 r = RegQueryValueExW( hKey, szError, 0, &type, (LPBYTE)&val, &sz );
1878 if( ( r == ERROR_SUCCESS ) || ( type == REG_DWORD ) )
1879 lpServiceConfig->dwErrorControl = val;
1881 /* now do the strings */
1882 p = (LPBYTE) &lpServiceConfig[1];
1883 n = total - sizeof (QUERY_SERVICE_CONFIGW);
1885 sz = sizeof(str_buffer);
1886 r = RegQueryValueExW( hKey, szImagePath, 0, &type, (LPBYTE) str_buffer, &sz );
1887 if( ( r == ERROR_SUCCESS ) && ( type == REG_SZ || type == REG_EXPAND_SZ ) )
1889 sz = ExpandEnvironmentStringsW(str_buffer, (LPWSTR) p, n);
1890 sz *= sizeof(WCHAR);
1891 if( 0 == sz || sz > n ) return FALSE;
1893 lpServiceConfig->lpBinaryPathName = (LPWSTR) p;
1899 /* FIXME: set last error */
1904 r = RegQueryValueExW( hKey, szGroup, 0, &type, p, &sz );
1905 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1907 lpServiceConfig->lpLoadOrderGroup = (LPWSTR) p;
1913 r = RegQueryValueExW( hKey, szDependencies, 0, &type, p, &sz );
1914 lpServiceConfig->lpDependencies = (LPWSTR) p;
1915 if( ( r == ERROR_SUCCESS ) || ( type == REG_SZ ) )
1928 ERR("Buffer overflow!\n");
1930 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1931 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1936 /******************************************************************************
1937 * EnumServicesStatusA [ADVAPI32.@]
1940 EnumServicesStatusA( SC_HANDLE hSCManager, DWORD dwServiceType,
1941 DWORD dwServiceState, LPENUM_SERVICE_STATUSA lpServices,
1942 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1943 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1945 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1946 dwServiceType, dwServiceState, lpServices, cbBufSize,
1947 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1948 SetLastError (ERROR_ACCESS_DENIED);
1952 /******************************************************************************
1953 * EnumServicesStatusW [ADVAPI32.@]
1956 EnumServicesStatusW( SC_HANDLE hSCManager, DWORD dwServiceType,
1957 DWORD dwServiceState, LPENUM_SERVICE_STATUSW lpServices,
1958 DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1959 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle )
1961 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager,
1962 dwServiceType, dwServiceState, lpServices, cbBufSize,
1963 pcbBytesNeeded, lpServicesReturned, lpResumeHandle);
1964 SetLastError (ERROR_ACCESS_DENIED);
1968 /******************************************************************************
1969 * EnumServicesStatusExA [ADVAPI32.@]
1972 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1973 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1974 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1976 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1977 dwServiceType, dwServiceState, lpServices, cbBufSize,
1978 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1979 SetLastError (ERROR_ACCESS_DENIED);
1983 /******************************************************************************
1984 * EnumServicesStatusExW [ADVAPI32.@]
1987 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1988 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1989 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1991 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1992 dwServiceType, dwServiceState, lpServices, cbBufSize,
1993 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
1994 SetLastError (ERROR_ACCESS_DENIED);
1998 /******************************************************************************
1999 * GetServiceKeyNameA [ADVAPI32.@]
2001 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
2002 LPSTR lpServiceName, LPDWORD lpcchBuffer )
2004 FIXME("%p %s %p %p\n", hSCManager, debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
2008 /******************************************************************************
2009 * GetServiceKeyNameW [ADVAPI32.@]
2011 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
2012 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
2014 FIXME("%p %s %p %p\n", hSCManager, debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
2018 /******************************************************************************
2019 * QueryServiceLockStatusA [ADVAPI32.@]
2021 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
2022 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
2023 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2025 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2030 /******************************************************************************
2031 * QueryServiceLockStatusW [ADVAPI32.@]
2033 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
2034 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2035 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2037 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
2042 /******************************************************************************
2043 * GetServiceDisplayNameA [ADVAPI32.@]
2045 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
2046 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
2048 struct sc_manager *hscm;
2052 TRACE("%p %s %p %p\n", hSCManager,
2053 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
2055 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2058 SetLastError(ERROR_INVALID_HANDLE);
2062 size = *lpcchBuffer;
2063 ret = RegGetValueA(hscm->hkey, lpServiceName, "DisplayName", RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2066 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2068 if (ret == ERROR_MORE_DATA)
2070 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2071 *lpcchBuffer = size - 1;
2080 /******************************************************************************
2081 * GetServiceDisplayNameW [ADVAPI32.@]
2083 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
2084 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
2086 struct sc_manager *hscm;
2090 TRACE("%p %s %p %p\n", hSCManager,
2091 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
2093 hscm = sc_handle_get_handle_data(hSCManager, SC_HTYPE_MANAGER);
2096 SetLastError(ERROR_INVALID_HANDLE);
2100 size = *lpcchBuffer * sizeof(WCHAR);
2101 ret = RegGetValueW(hscm->hkey, lpServiceName, szDisplayName, RRF_RT_REG_SZ, &type, lpDisplayName, &size);
2104 if (lpDisplayName && *lpcchBuffer) *lpDisplayName = 0;
2106 if (ret == ERROR_MORE_DATA)
2108 SetLastError(ERROR_INSUFFICIENT_BUFFER);
2109 *lpcchBuffer = (size / sizeof(WCHAR)) - 1;
2118 /******************************************************************************
2119 * ChangeServiceConfigW [ADVAPI32.@]
2121 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
2122 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
2123 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
2124 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
2126 struct reg_value val[10];
2127 struct sc_service *hsvc;
2128 DWORD r = ERROR_SUCCESS;
2132 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2133 hService, dwServiceType, dwStartType, dwErrorControl,
2134 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
2135 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
2136 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
2138 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2141 SetLastError( ERROR_INVALID_HANDLE );
2146 if( dwServiceType != SERVICE_NO_CHANGE )
2147 service_set_dword( &val[n++], szType, &dwServiceType );
2149 if( dwStartType != SERVICE_NO_CHANGE )
2150 service_set_dword( &val[n++], szStart, &dwStartType );
2152 if( dwErrorControl != SERVICE_NO_CHANGE )
2153 service_set_dword( &val[n++], szError, &dwErrorControl );
2155 if( lpBinaryPathName )
2156 service_set_string( &val[n++], szImagePath, lpBinaryPathName );
2158 if( lpLoadOrderGroup )
2159 service_set_string( &val[n++], szGroup, lpLoadOrderGroup );
2161 if( lpDependencies )
2162 service_set_multi_string( &val[n++], szDependencies, lpDependencies );
2165 FIXME("ignoring password\n");
2167 if( lpServiceStartName )
2168 service_set_string( &val[n++], szDependOnService, lpServiceStartName );
2170 r = service_write_values( hsvc->hkey, val, n );
2172 return (r == ERROR_SUCCESS) ? TRUE : FALSE ;
2175 /******************************************************************************
2176 * ChangeServiceConfigA [ADVAPI32.@]
2178 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2179 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2180 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2181 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2183 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2184 LPWSTR wServiceStartName, wPassword, wDisplayName;
2187 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2188 hService, dwServiceType, dwStartType, dwErrorControl,
2189 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2190 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2191 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2193 wBinaryPathName = SERV_dup( lpBinaryPathName );
2194 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2195 wDependencies = SERV_dupmulti( lpDependencies );
2196 wServiceStartName = SERV_dup( lpServiceStartName );
2197 wPassword = SERV_dup( lpPassword );
2198 wDisplayName = SERV_dup( lpDisplayName );
2200 r = ChangeServiceConfigW( hService, dwServiceType,
2201 dwStartType, dwErrorControl, wBinaryPathName,
2202 wLoadOrderGroup, lpdwTagId, wDependencies,
2203 wServiceStartName, wPassword, wDisplayName);
2205 SERV_free( wBinaryPathName );
2206 SERV_free( wLoadOrderGroup );
2207 SERV_free( wDependencies );
2208 SERV_free( wServiceStartName );
2209 SERV_free( wPassword );
2210 SERV_free( wDisplayName );
2215 /******************************************************************************
2216 * ChangeServiceConfig2A [ADVAPI32.@]
2218 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2223 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2225 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2227 LPSERVICE_DESCRIPTIONA sd = (LPSERVICE_DESCRIPTIONA) lpInfo;
2228 SERVICE_DESCRIPTIONW sdw;
2230 sdw.lpDescription = SERV_dup( sd->lpDescription );
2232 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2234 SERV_free( sdw.lpDescription );
2236 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2238 LPSERVICE_FAILURE_ACTIONSA fa = (LPSERVICE_FAILURE_ACTIONSA) lpInfo;
2239 SERVICE_FAILURE_ACTIONSW faw;
2241 faw.dwResetPeriod = fa->dwResetPeriod;
2242 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2243 faw.lpCommand = SERV_dup( fa->lpCommand );
2244 faw.cActions = fa->cActions;
2245 faw.lpsaActions = fa->lpsaActions;
2247 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2249 SERV_free( faw.lpRebootMsg );
2250 SERV_free( faw.lpCommand );
2253 SetLastError( ERROR_INVALID_PARAMETER );
2258 /******************************************************************************
2259 * ChangeServiceConfig2W [ADVAPI32.@]
2261 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2265 struct sc_service *hsvc;
2267 hsvc = sc_handle_get_handle_data(hService, SC_HTYPE_SERVICE);
2270 SetLastError( ERROR_INVALID_HANDLE );
2275 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2277 static const WCHAR szDescription[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2278 LPSERVICE_DESCRIPTIONW sd = (LPSERVICE_DESCRIPTIONW)lpInfo;
2279 if (sd->lpDescription)
2281 TRACE("Setting Description to %s\n",debugstr_w(sd->lpDescription));
2282 if (sd->lpDescription[0] == 0)
2283 RegDeleteValueW(hKey,szDescription);
2285 RegSetValueExW(hKey, szDescription, 0, REG_SZ,
2286 (LPVOID)sd->lpDescription,
2287 sizeof(WCHAR)*(strlenW(sd->lpDescription)+1));
2291 FIXME("STUB: %p %d %p\n",hService, dwInfoLevel, lpInfo);
2295 /******************************************************************************
2296 * QueryServiceObjectSecurity [ADVAPI32.@]
2298 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2299 SECURITY_INFORMATION dwSecurityInformation,
2300 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2301 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2305 FIXME("%p %d %p %u %p\n", hService, dwSecurityInformation,
2306 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2308 InitializeSecurityDescriptor(lpSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION);
2310 pACL = HeapAlloc( GetProcessHeap(), 0, sizeof(ACL) );
2311 InitializeAcl(pACL, sizeof(ACL), ACL_REVISION);
2312 SetSecurityDescriptorDacl(lpSecurityDescriptor, TRUE, pACL, TRUE);
2316 /******************************************************************************
2317 * SetServiceObjectSecurity [ADVAPI32.@]
2319 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2320 SECURITY_INFORMATION dwSecurityInformation,
2321 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2323 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2327 /******************************************************************************
2328 * SetServiceBits [ADVAPI32.@]
2330 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2331 DWORD dwServiceBits,
2333 BOOL bUpdateImmediately)
2335 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2336 bSetBitsOn, bUpdateImmediately);
2340 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName,
2341 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2343 FIXME("%s %p %p\n", debugstr_a(lpServiceName), lpHandlerProc, lpContext);
2347 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2348 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2350 service_data *service;
2352 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2354 EnterCriticalSection( &service_cs );
2355 for(service = service_list; service; service = service->next)
2356 if(!strcmpW(lpServiceName, service->name))
2360 service->handler.handler_ex = lpHandlerProc;
2361 service->context = lpContext;
2362 service->extended = TRUE;
2364 LeaveCriticalSection( &service_cs );
2366 return (SERVICE_STATUS_HANDLE)service;