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
24 #include "wine/port.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
44 #include "advapi32_misc.h"
46 #include "wine/exception.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(service);
50 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
52 return HeapAlloc(GetProcessHeap(), 0, len);
55 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
57 HeapFree(GetProcessHeap(), 0, ptr);
60 typedef struct service_data_t
62 LPHANDLER_FUNCTION_EX handler;
66 SC_HANDLE full_access_handle;
69 LPSERVICE_MAIN_FUNCTIONA a;
70 LPSERVICE_MAIN_FUNCTIONW w;
76 static CRITICAL_SECTION service_cs;
77 static CRITICAL_SECTION_DEBUG service_cs_debug =
80 { &service_cs_debug.ProcessLocksList,
81 &service_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
84 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
86 static service_data **services;
87 static unsigned int nb_services;
88 static HANDLE service_event;
90 extern HANDLE CDECL __wine_make_process_system(void);
92 /******************************************************************************
93 * String management functions (same behaviour as strdup)
94 * NOTE: the caller of those functions is responsible for calling HeapFree
95 * in order to release the memory allocated by those functions.
97 LPWSTR SERV_dup( LPCSTR str )
104 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
105 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
106 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
110 static inline LPWSTR SERV_dupmulti(LPCSTR str)
118 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
119 n += (strlen( &str[n] ) + 1);
124 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
125 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
129 static inline DWORD multisz_cb(LPCWSTR wmultisz)
131 const WCHAR *wptr = wmultisz;
133 if (wmultisz == NULL)
137 wptr += lstrlenW(wptr)+1;
138 return (wptr - wmultisz + 1)*sizeof(WCHAR);
141 /******************************************************************************
142 * RPC connection with services.exe
145 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
147 WCHAR transport[] = SVCCTL_TRANSPORT;
148 WCHAR endpoint[] = SVCCTL_ENDPOINT;
149 RPC_WSTR binding_str;
153 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
154 if (status != RPC_S_OK)
156 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
160 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
161 RpcStringFreeW(&binding_str);
163 if (status != RPC_S_OK)
165 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
172 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
177 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
179 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
182 static DWORD map_exception_code(DWORD exception_code)
184 switch (exception_code)
186 case RPC_X_NULL_REF_POINTER:
187 return ERROR_INVALID_ADDRESS;
188 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
189 case RPC_X_BYTE_COUNT_TOO_SMALL:
190 return ERROR_INVALID_PARAMETER;
191 case RPC_S_INVALID_BINDING:
192 case RPC_X_SS_IN_NULL_CONTEXT:
193 return ERROR_INVALID_HANDLE;
195 return exception_code;
199 /******************************************************************************
200 * Service IPC functions
202 static LPWSTR service_get_pipe_name(void)
204 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
205 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
206 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
207 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
208 'C','o','n','t','r','o','l','\\',
209 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
212 HKEY service_current_key;
213 DWORD service_current;
217 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
218 KEY_QUERY_VALUE, &service_current_key);
219 if (ret != ERROR_SUCCESS)
221 len = sizeof(service_current);
222 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
223 (BYTE *)&service_current, &len);
224 RegCloseKey(service_current_key);
225 if (ret != ERROR_SUCCESS || type != REG_DWORD)
227 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
228 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
231 snprintfW(name, len, format, service_current);
235 static HANDLE service_open_pipe(void)
237 LPWSTR szPipe = service_get_pipe_name();
238 HANDLE handle = INVALID_HANDLE_VALUE;
241 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
242 0, NULL, OPEN_ALWAYS, 0, NULL);
243 if (handle != INVALID_HANDLE_VALUE)
245 if (GetLastError() != ERROR_PIPE_BUSY)
247 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
248 HeapFree(GetProcessHeap(), 0, szPipe);
253 static service_data *find_service_by_name( const WCHAR *name )
257 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
259 for (i = 0; i < nb_services; i++)
260 if (!strcmpiW( name, services[i]->name )) return services[i];
264 /******************************************************************************
267 * Call into the main service routine provided by StartServiceCtrlDispatcher.
269 static DWORD WINAPI service_thread(LPVOID arg)
271 service_data *info = arg;
272 LPWSTR str = info->args;
273 DWORD argc = 0, len = 0;
279 len += strlenW(&str[len]) + 1;
288 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
289 for (argc=0, p=str; *p; p += strlenW(p) + 1)
293 info->proc.w(argc, argv);
294 HeapFree(GetProcessHeap(), 0, argv);
298 LPSTR strA, *argv, p;
301 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
302 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
303 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
305 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
306 for (argc=0, p=strA; *p; p += strlen(p) + 1)
310 info->proc.a(argc, argv);
311 HeapFree(GetProcessHeap(), 0, argv);
312 HeapFree(GetProcessHeap(), 0, strA);
317 /******************************************************************************
318 * service_handle_start
320 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
322 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
326 WARN("service is not stopped\n");
327 return ERROR_SERVICE_ALREADY_RUNNING;
330 HeapFree(GetProcessHeap(), 0, service->args);
331 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
332 memcpy( service->args, data, count * sizeof(WCHAR) );
333 service->thread = CreateThread( NULL, 0, service_thread,
335 SetEvent( service_event ); /* notify the main loop */
339 /******************************************************************************
340 * service_handle_control
342 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
344 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
346 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
348 if (service->handler)
349 ret = service->handler(dwControl, 0, NULL, service->context);
353 /******************************************************************************
354 * service_control_dispatcher
356 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
361 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
363 ERR("failed to open service manager error %u\n", GetLastError());
367 pipe = service_open_pipe();
369 if (pipe==INVALID_HANDLE_VALUE)
371 WARN("failed to create control pipe error = %d\n", GetLastError());
375 /* dispatcher loop */
378 service_data *service;
379 service_start_info info;
382 DWORD data_size = 0, count, result;
384 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
387 if (GetLastError() != ERROR_BROKEN_PIPE)
388 ERR( "pipe read failed error %u\n", GetLastError() );
391 if (count != FIELD_OFFSET(service_start_info,data))
393 ERR( "partial pipe read %u\n", count );
396 if (count < info.total_size)
398 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
399 data = HeapAlloc( GetProcessHeap(), 0, data_size );
400 r = ReadFile( pipe, data, data_size, &count, NULL );
403 if (GetLastError() != ERROR_BROKEN_PIPE)
404 ERR( "pipe read failed error %u\n", GetLastError() );
407 if (count != data_size)
409 ERR( "partial pipe read %u/%u\n", count, data_size );
414 /* find the service */
416 if (!(service = find_service_by_name( data )))
418 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
419 result = ERROR_INVALID_PARAMETER;
423 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
425 /* handle the request */
428 case WINESERV_STARTINFO:
429 if (!service->handle)
431 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )) ||
432 !(service->full_access_handle = OpenServiceW( manager, data, GENERIC_READ|GENERIC_WRITE )))
433 FIXME( "failed to open service %s\n", debugstr_w(data) );
435 result = service_handle_start(service, data, data_size / sizeof(WCHAR));
437 case WINESERV_SENDCONTROL:
438 result = service_handle_control(service, info.control);
441 ERR("received invalid command %u\n", info.cmd);
442 result = ERROR_INVALID_PARAMETER;
447 WriteFile(pipe, &result, sizeof(result), &count, NULL);
448 HeapFree( GetProcessHeap(), 0, data );
452 CloseServiceHandle( manager );
456 /******************************************************************************
457 * service_run_main_thread
459 static BOOL service_run_main_thread(void)
462 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
463 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
465 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
467 /* FIXME: service_control_dispatcher should be merged into the main thread */
468 wait_handles[0] = __wine_make_process_system();
469 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
470 wait_handles[2] = service_event;
472 TRACE("Starting %d services running as process %d\n",
473 nb_services, GetCurrentProcessId());
475 /* wait for all the threads to pack up and exit */
478 EnterCriticalSection( &service_cs );
479 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
481 if (!services[i]->thread) continue;
482 wait_services[n] = i;
483 wait_handles[n++] = services[i]->thread;
485 LeaveCriticalSection( &service_cs );
487 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
488 if (!ret) /* system process event */
491 SERVICE_PRESHUTDOWN_INFO spi;
492 DWORD timeout = 5000;
495 EnterCriticalSection( &service_cs );
497 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
499 if (!services[i]->thread) continue;
501 res = QueryServiceStatus(services[i]->full_access_handle, &st);
503 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
505 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
506 (LPBYTE)&spi, sizeof(spi), &i );
509 FIXME("service should be able to delay shutdown\n");
510 timeout += spi.dwPreshutdownTimeout;
511 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN );
512 wait_handles[n++] = services[i]->thread;
515 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
517 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN );
518 wait_handles[n++] = services[i]->thread;
521 LeaveCriticalSection( &service_cs );
523 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
524 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
529 TRACE( "control dispatcher exited, shutting down\n" );
530 /* FIXME: we should maybe send a shutdown control to running services */
535 continue; /* rebuild the list */
539 services[wait_services[ret]]->thread = 0;
540 CloseHandle( wait_handles[ret] );
541 if (n == 4) return TRUE; /* it was the last running thread */
547 /******************************************************************************
548 * StartServiceCtrlDispatcherA [ADVAPI32.@]
550 * See StartServiceCtrlDispatcherW.
552 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
558 TRACE("%p\n", servent);
562 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
565 while (servent[nb_services].lpServiceName) nb_services++;
566 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
568 for (i = 0; i < nb_services; i++)
570 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
571 DWORD sz = FIELD_OFFSET( service_data, name[len] );
572 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
573 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
574 info->proc.a = servent[i].lpServiceProc;
575 info->unicode = FALSE;
579 service_run_main_thread();
584 /******************************************************************************
585 * StartServiceCtrlDispatcherW [ADVAPI32.@]
587 * Connects a process containing one or more services to the service control
591 * servent [I] A list of the service names and service procedures
597 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
603 TRACE("%p\n", servent);
607 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
610 while (servent[nb_services].lpServiceName) nb_services++;
611 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
613 for (i = 0; i < nb_services; i++)
615 DWORD len = strlenW(servent[i].lpServiceName) + 1;
616 DWORD sz = FIELD_OFFSET( service_data, name[len] );
617 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
618 strcpyW(info->name, servent[i].lpServiceName);
619 info->proc.w = servent[i].lpServiceProc;
620 info->unicode = TRUE;
624 service_run_main_thread();
629 /******************************************************************************
630 * LockServiceDatabase [ADVAPI32.@]
632 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
634 SC_RPC_LOCK hLock = NULL;
637 TRACE("%p\n",hSCManager);
641 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
645 err = map_exception_code(GetExceptionCode());
648 if (err != ERROR_SUCCESS)
656 /******************************************************************************
657 * UnlockServiceDatabase [ADVAPI32.@]
659 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
662 SC_RPC_LOCK hRpcLock = ScLock;
664 TRACE("%p\n",ScLock);
668 err = svcctl_UnlockServiceDatabase(&hRpcLock);
672 err = map_exception_code(GetExceptionCode());
675 if (err != ERROR_SUCCESS)
683 /******************************************************************************
684 * SetServiceStatus [ADVAPI32.@]
691 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
695 TRACE("%p %x %x %x %x %x %x %x\n", hService,
696 lpStatus->dwServiceType, lpStatus->dwCurrentState,
697 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
698 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
699 lpStatus->dwWaitHint);
703 err = svcctl_SetServiceStatus( hService, lpStatus );
707 err = map_exception_code(GetExceptionCode());
710 if (err != ERROR_SUCCESS)
716 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
717 CloseServiceHandle((SC_HANDLE)hService);
723 /******************************************************************************
724 * OpenSCManagerA [ADVAPI32.@]
726 * Establish a connection to the service control manager and open its database.
729 * lpMachineName [I] Pointer to machine name string
730 * lpDatabaseName [I] Pointer to database name string
731 * dwDesiredAccess [I] Type of access
734 * Success: A Handle to the service control manager database
737 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
738 DWORD dwDesiredAccess )
740 LPWSTR lpMachineNameW, lpDatabaseNameW;
743 lpMachineNameW = SERV_dup(lpMachineName);
744 lpDatabaseNameW = SERV_dup(lpDatabaseName);
745 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
746 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
747 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
751 /******************************************************************************
752 * OpenSCManagerW [ADVAPI32.@]
754 * See OpenSCManagerA.
756 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
757 DWORD dwDesiredAccess )
759 SC_HANDLE handle = 0;
762 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
763 debugstr_w(lpDatabaseName), dwDesiredAccess);
767 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
771 r = map_exception_code(GetExceptionCode());
775 if (r!=ERROR_SUCCESS)
781 TRACE("returning %p\n", handle);
785 /******************************************************************************
786 * ControlService [ADVAPI32.@]
788 * Send a control code to a service.
791 * hService [I] Handle of the service control manager database
792 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
793 * lpServiceStatus [O] Destination for the status of the service, if available
800 * Unlike M$' implementation, control requests are not serialized and may be
801 * processed asynchronously.
803 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
804 LPSERVICE_STATUS lpServiceStatus )
808 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
812 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
816 err = map_exception_code(GetExceptionCode());
819 if (err != ERROR_SUCCESS)
828 /******************************************************************************
829 * CloseServiceHandle [ADVAPI32.@]
831 * Close a handle to a service or the service control manager database.
834 * hSCObject [I] Handle to service or service control manager database
841 CloseServiceHandle( SC_HANDLE hSCObject )
845 TRACE("%p\n", hSCObject);
849 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
853 err = map_exception_code(GetExceptionCode());
857 if (err != ERROR_SUCCESS)
866 /******************************************************************************
867 * OpenServiceA [ADVAPI32.@]
869 * Open a handle to a service.
872 * hSCManager [I] Handle of the service control manager database
873 * lpServiceName [I] Name of the service to open
874 * dwDesiredAccess [I] Access required to the service
877 * Success: Handle to the service
880 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
881 DWORD dwDesiredAccess )
883 LPWSTR lpServiceNameW;
886 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
888 lpServiceNameW = SERV_dup(lpServiceName);
889 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
890 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
895 /******************************************************************************
896 * OpenServiceW [ADVAPI32.@]
900 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
901 DWORD dwDesiredAccess)
903 SC_HANDLE handle = 0;
906 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
910 SetLastError( ERROR_INVALID_HANDLE );
916 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
920 err = map_exception_code(GetExceptionCode());
924 if (err != ERROR_SUCCESS)
930 TRACE("returning %p\n",handle);
934 /******************************************************************************
935 * CreateServiceW [ADVAPI32.@]
938 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
939 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
940 DWORD dwServiceType, DWORD dwStartType,
941 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
942 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
943 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
946 SC_HANDLE handle = 0;
950 TRACE("%p %s %s\n", hSCManager,
951 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
955 SetLastError( ERROR_INVALID_HANDLE );
960 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
966 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
967 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
968 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
969 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
970 (SC_RPC_HANDLE *)&handle);
974 err = map_exception_code(GetExceptionCode());
978 if (err != ERROR_SUCCESS)
987 /******************************************************************************
988 * CreateServiceA [ADVAPI32.@]
991 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
992 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
993 DWORD dwServiceType, DWORD dwStartType,
994 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
995 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
996 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
999 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1000 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1003 TRACE("%p %s %s\n", hSCManager,
1004 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1006 lpServiceNameW = SERV_dup( lpServiceName );
1007 lpDisplayNameW = SERV_dup( lpDisplayName );
1008 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1009 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1010 lpDependenciesW = SERV_dupmulti( lpDependencies );
1011 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1012 lpPasswordW = SERV_dup( lpPassword );
1014 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1015 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1016 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1017 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1019 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1020 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1021 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1022 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1023 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1024 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1025 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1031 /******************************************************************************
1032 * DeleteService [ADVAPI32.@]
1034 * Delete a service from the service control manager database.
1037 * hService [I] Handle of the service to delete
1043 BOOL WINAPI DeleteService( SC_HANDLE hService )
1049 err = svcctl_DeleteService(hService);
1051 __EXCEPT(rpc_filter)
1053 err = map_exception_code(GetExceptionCode());
1066 /******************************************************************************
1067 * StartServiceA [ADVAPI32.@]
1072 * hService [I] Handle of service
1073 * dwNumServiceArgs [I] Number of arguments
1074 * lpServiceArgVectors [I] Address of array of argument strings
1077 * - NT implements this function using an obscure RPC call.
1078 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1079 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1080 * - This will only work for shared address space. How should the service
1081 * args be transferred when address spaces are separated?
1082 * - Can only start one service at a time.
1083 * - Has no concept of privilege.
1089 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1090 LPCSTR *lpServiceArgVectors )
1092 LPWSTR *lpwstr=NULL;
1096 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1098 if (dwNumServiceArgs)
1099 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1100 dwNumServiceArgs*sizeof(LPWSTR) );
1102 for(i=0; i<dwNumServiceArgs; i++)
1103 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1105 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1107 if (dwNumServiceArgs)
1109 for(i=0; i<dwNumServiceArgs; i++)
1110 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1111 HeapFree(GetProcessHeap(), 0, lpwstr);
1118 /******************************************************************************
1119 * StartServiceW [ADVAPI32.@]
1121 * See StartServiceA.
1123 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1124 LPCWSTR *lpServiceArgVectors)
1128 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1132 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1134 __EXCEPT(rpc_filter)
1136 err = map_exception_code(GetExceptionCode());
1139 if (err != ERROR_SUCCESS)
1148 /******************************************************************************
1149 * QueryServiceStatus [ADVAPI32.@]
1152 * hService [I] Handle to service to get information about
1153 * lpservicestatus [O] buffer to receive the status information for the service
1156 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1157 LPSERVICE_STATUS lpservicestatus)
1159 SERVICE_STATUS_PROCESS SvcStatusData;
1163 TRACE("%p %p\n", hService, lpservicestatus);
1167 SetLastError(ERROR_INVALID_HANDLE);
1170 if (!lpservicestatus)
1172 SetLastError(ERROR_INVALID_ADDRESS);
1176 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1177 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1178 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1183 /******************************************************************************
1184 * QueryServiceStatusEx [ADVAPI32.@]
1186 * Get information about a service.
1189 * hService [I] Handle to service to get information about
1190 * InfoLevel [I] Level of information to get
1191 * lpBuffer [O] Destination for requested information
1192 * cbBufSize [I] Size of lpBuffer in bytes
1193 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1199 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1200 LPBYTE lpBuffer, DWORD cbBufSize,
1201 LPDWORD pcbBytesNeeded)
1205 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1207 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1209 err = ERROR_INVALID_LEVEL;
1211 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1213 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1214 err = ERROR_INSUFFICIENT_BUFFER;
1220 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1222 __EXCEPT(rpc_filter)
1224 err = map_exception_code(GetExceptionCode());
1228 if (err != ERROR_SUCCESS)
1236 /******************************************************************************
1237 * QueryServiceConfigA [ADVAPI32.@]
1239 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1240 DWORD size, LPDWORD needed )
1245 QUERY_SERVICE_CONFIGW *configW;
1247 TRACE("%p %p %d %p\n", hService, config, size, needed);
1249 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1251 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1254 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1255 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1256 if (!ret) goto done;
1258 config->dwServiceType = configW->dwServiceType;
1259 config->dwStartType = configW->dwStartType;
1260 config->dwErrorControl = configW->dwErrorControl;
1261 config->lpBinaryPathName = NULL;
1262 config->lpLoadOrderGroup = NULL;
1263 config->dwTagId = configW->dwTagId;
1264 config->lpDependencies = NULL;
1265 config->lpServiceStartName = NULL;
1266 config->lpDisplayName = NULL;
1268 p = (LPSTR)(config + 1);
1269 n = size - sizeof(*config);
1272 #define MAP_STR(str) \
1276 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1277 if (!sz) goto done; \
1284 MAP_STR( lpBinaryPathName );
1285 MAP_STR( lpLoadOrderGroup );
1286 MAP_STR( lpDependencies );
1287 MAP_STR( lpServiceStartName );
1288 MAP_STR( lpDisplayName );
1291 *needed = p - (LPSTR)config;
1295 HeapFree( GetProcessHeap(), 0, buffer );
1299 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1306 memset(*buf, 0, cb);
1310 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1311 memcpy(*buf, *string_ptr, cb);
1312 MIDL_user_free(*string_ptr);
1315 *string_ptr = (LPWSTR)*buf;
1321 static DWORD size_string(LPCWSTR string)
1323 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1326 /******************************************************************************
1327 * QueryServiceConfigW [ADVAPI32.@]
1330 QueryServiceConfigW( SC_HANDLE hService,
1331 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1332 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1334 QUERY_SERVICE_CONFIGW config;
1339 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1340 cbBufSize, pcbBytesNeeded);
1342 memset(&config, 0, sizeof(config));
1346 err = svcctl_QueryServiceConfigW(hService, &config);
1348 __EXCEPT(rpc_filter)
1350 err = map_exception_code(GetExceptionCode());
1354 if (err != ERROR_SUCCESS)
1356 TRACE("services.exe: error %u\n", err);
1361 /* calculate the size required first */
1362 total = sizeof (QUERY_SERVICE_CONFIGW);
1363 total += size_string(config.lpBinaryPathName);
1364 total += size_string(config.lpLoadOrderGroup);
1365 total += size_string(config.lpDependencies);
1366 total += size_string(config.lpServiceStartName);
1367 total += size_string(config.lpDisplayName);
1369 *pcbBytesNeeded = total;
1371 /* if there's not enough memory, return an error */
1372 if( total > cbBufSize )
1374 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1375 MIDL_user_free(config.lpBinaryPathName);
1376 MIDL_user_free(config.lpLoadOrderGroup);
1377 MIDL_user_free(config.lpDependencies);
1378 MIDL_user_free(config.lpServiceStartName);
1379 MIDL_user_free(config.lpDisplayName);
1383 *lpServiceConfig = config;
1384 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1385 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1386 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1387 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1388 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1389 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1391 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1392 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1393 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1394 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1395 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1400 /******************************************************************************
1401 * QueryServiceConfig2A [ADVAPI32.@]
1404 * observed under win2k:
1405 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1406 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1408 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1409 DWORD size, LPDWORD needed)
1412 LPBYTE bufferW = NULL;
1415 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1417 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1418 if(!ret) goto cleanup;
1421 case SERVICE_CONFIG_DESCRIPTION:
1422 if (buffer && bufferW) {
1423 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1424 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1425 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1427 configA->lpDescription = (LPSTR)(configA + 1);
1428 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1429 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1431 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1433 configA->lpDescription = NULL;
1436 else configA->lpDescription = NULL;
1439 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1440 if (buffer && bufferW && *needed<=size)
1441 memcpy(buffer, bufferW, *needed);
1444 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1450 HeapFree( GetProcessHeap(), 0, bufferW);
1454 /******************************************************************************
1455 * QueryServiceConfig2W [ADVAPI32.@]
1457 * See QueryServiceConfig2A.
1459 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1460 DWORD size, LPDWORD needed)
1464 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1465 FIXME("Level %d not implemented\n", dwLevel);
1466 SetLastError(ERROR_INVALID_LEVEL);
1470 if(!buffer && size) {
1471 SetLastError(ERROR_INVALID_ADDRESS);
1475 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1479 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1481 __EXCEPT(rpc_filter)
1483 err = map_exception_code(GetExceptionCode());
1487 if (err != ERROR_SUCCESS)
1489 SetLastError( err );
1495 case SERVICE_CONFIG_DESCRIPTION:
1498 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1499 if (descr->lpDescription) /* make it an absolute pointer */
1500 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1508 /******************************************************************************
1509 * EnumServicesStatusA [ADVAPI32.@]
1512 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1513 services, DWORD size, LPDWORD needed, LPDWORD returned,
1514 LPDWORD resume_handle )
1518 ENUM_SERVICE_STATUSW *servicesW = NULL;
1522 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1523 returned, resume_handle);
1525 sz = max( 2 * size, sizeof(*servicesW) );
1526 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1528 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1532 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1533 if (!ret) goto done;
1535 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1536 n = size - (p - (char *)services);
1538 for (i = 0; i < *returned; i++)
1540 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1542 services[i].lpServiceName = p;
1545 if (servicesW[i].lpDisplayName)
1547 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1549 services[i].lpDisplayName = p;
1553 else services[i].lpDisplayName = NULL;
1554 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1560 HeapFree( GetProcessHeap(), 0, servicesW );
1564 /******************************************************************************
1565 * EnumServicesStatusW [ADVAPI32.@]
1568 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1569 services, DWORD size, LPDWORD needed, LPDWORD returned,
1570 LPDWORD resume_handle )
1573 ENUM_SERVICE_STATUSW dummy_status;
1575 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1576 returned, resume_handle);
1579 FIXME("resume handle not supported\n");
1583 SetLastError( ERROR_INVALID_HANDLE );
1587 /* make sure we pass a valid pointer */
1588 if (!services || size < sizeof(*services))
1590 services = &dummy_status;
1591 size = sizeof(dummy_status);
1596 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1598 __EXCEPT(rpc_filter)
1600 err = map_exception_code( GetExceptionCode() );
1604 if (err != ERROR_SUCCESS)
1606 SetLastError( err );
1610 for (i = 0; i < *returned; i++)
1612 /* convert buffer offsets into pointers */
1613 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1614 if (services[i].lpDisplayName)
1615 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1621 /******************************************************************************
1622 * EnumServicesStatusExA [ADVAPI32.@]
1625 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1626 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1627 LPDWORD resume_handle, LPCSTR group )
1631 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1632 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1633 WCHAR *groupW = NULL;
1637 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1638 size, needed, returned, resume_handle, debugstr_a(group));
1640 sz = max( 2 * size, sizeof(*servicesW) );
1641 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1643 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1648 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1649 if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1651 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1652 HeapFree( GetProcessHeap(), 0, servicesW );
1655 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1658 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1659 needed, returned, resume_handle, groupW );
1660 if (!ret) goto done;
1662 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1663 n = size - (p - (char *)services);
1665 for (i = 0; i < *returned; i++)
1667 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1669 services[i].lpServiceName = p;
1672 if (servicesW[i].lpDisplayName)
1674 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1676 services[i].lpDisplayName = p;
1680 else services[i].lpDisplayName = NULL;
1681 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1687 HeapFree( GetProcessHeap(), 0, servicesW );
1688 HeapFree( GetProcessHeap(), 0, groupW );
1692 /******************************************************************************
1693 * EnumServicesStatusExW [ADVAPI32.@]
1696 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1697 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1698 LPDWORD resume_handle, LPCWSTR group )
1701 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1702 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1704 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1705 size, needed, returned, resume_handle, debugstr_w(group));
1708 FIXME("resume handle not supported\n");
1710 if (level != SC_ENUM_PROCESS_INFO)
1712 SetLastError( ERROR_INVALID_LEVEL );
1717 SetLastError( ERROR_INVALID_HANDLE );
1721 /* make sure we pass a valid buffer pointer */
1722 if (!services || size < sizeof(*services))
1724 buffer = (BYTE *)&dummy_status;
1725 size = sizeof(dummy_status);
1730 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1733 __EXCEPT(rpc_filter)
1735 err = map_exception_code( GetExceptionCode() );
1739 if (err != ERROR_SUCCESS)
1741 SetLastError( err );
1745 for (i = 0; i < *returned; i++)
1747 /* convert buffer offsets into pointers */
1748 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1749 if (services[i].lpDisplayName)
1750 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1756 /******************************************************************************
1757 * GetServiceKeyNameA [ADVAPI32.@]
1759 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1760 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1762 LPWSTR lpDisplayNameW, lpServiceNameW;
1766 TRACE("%p %s %p %p\n", hSCManager,
1767 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1769 lpDisplayNameW = SERV_dup(lpDisplayName);
1771 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1773 lpServiceNameW = NULL;
1775 sizeW = *lpcchBuffer;
1776 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1778 if (lpServiceName && *lpcchBuffer)
1779 lpServiceName[0] = 0;
1780 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1784 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1785 *lpcchBuffer, NULL, NULL ))
1787 if (*lpcchBuffer && lpServiceName)
1788 lpServiceName[0] = 0;
1789 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1793 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1797 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1798 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1802 /******************************************************************************
1803 * GetServiceKeyNameW [ADVAPI32.@]
1805 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1806 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1812 TRACE("%p %s %p %p\n", hSCManager,
1813 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1817 SetLastError( ERROR_INVALID_HANDLE );
1821 /* provide a buffer if the caller didn't */
1822 if (!lpServiceName || *lpcchBuffer < 2)
1824 lpServiceName = buffer;
1825 /* A size of 1 would be enough, but tests show that Windows returns 2,
1826 * probably because of a WCHAR/bytes mismatch in their code.
1831 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1832 * includes the nul-terminator on input. */
1833 size = *lpcchBuffer - 1;
1837 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1840 __EXCEPT(rpc_filter)
1842 err = map_exception_code(GetExceptionCode());
1846 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1847 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1848 *lpcchBuffer = size;
1852 return err == ERROR_SUCCESS;
1855 /******************************************************************************
1856 * QueryServiceLockStatusA [ADVAPI32.@]
1858 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1859 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1860 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1862 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1867 /******************************************************************************
1868 * QueryServiceLockStatusW [ADVAPI32.@]
1870 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1871 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1872 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1874 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1879 /******************************************************************************
1880 * GetServiceDisplayNameA [ADVAPI32.@]
1882 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1883 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1885 LPWSTR lpServiceNameW, lpDisplayNameW;
1889 TRACE("%p %s %p %p\n", hSCManager,
1890 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1892 lpServiceNameW = SERV_dup(lpServiceName);
1894 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1896 lpDisplayNameW = NULL;
1898 sizeW = *lpcchBuffer;
1899 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1901 if (lpDisplayName && *lpcchBuffer)
1902 lpDisplayName[0] = 0;
1903 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1907 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1908 *lpcchBuffer, NULL, NULL ))
1910 if (*lpcchBuffer && lpDisplayName)
1911 lpDisplayName[0] = 0;
1912 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1916 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1917 * (but if the function succeeded it means that is a good upper estimation of the size) */
1921 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1922 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1926 /******************************************************************************
1927 * GetServiceDisplayNameW [ADVAPI32.@]
1929 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1930 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1936 TRACE("%p %s %p %p\n", hSCManager,
1937 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1941 SetLastError( ERROR_INVALID_HANDLE );
1945 /* provide a buffer if the caller didn't */
1946 if (!lpDisplayName || *lpcchBuffer < 2)
1948 lpDisplayName = buffer;
1949 /* A size of 1 would be enough, but tests show that Windows returns 2,
1950 * probably because of a WCHAR/bytes mismatch in their code.
1955 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1956 * includes the nul-terminator on input. */
1957 size = *lpcchBuffer - 1;
1961 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
1964 __EXCEPT(rpc_filter)
1966 err = map_exception_code(GetExceptionCode());
1970 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1971 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1972 *lpcchBuffer = size;
1976 return err == ERROR_SUCCESS;
1979 /******************************************************************************
1980 * ChangeServiceConfigW [ADVAPI32.@]
1982 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1983 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1984 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1985 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1990 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1991 hService, dwServiceType, dwStartType, dwErrorControl,
1992 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1993 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1994 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1996 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
2000 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2001 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2002 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2003 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2005 __EXCEPT(rpc_filter)
2007 err = map_exception_code(GetExceptionCode());
2011 if (err != ERROR_SUCCESS)
2014 return err == ERROR_SUCCESS;
2017 /******************************************************************************
2018 * ChangeServiceConfigA [ADVAPI32.@]
2020 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2021 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2022 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2023 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2025 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2026 LPWSTR wServiceStartName, wPassword, wDisplayName;
2029 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2030 hService, dwServiceType, dwStartType, dwErrorControl,
2031 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2032 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2033 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2035 wBinaryPathName = SERV_dup( lpBinaryPathName );
2036 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2037 wDependencies = SERV_dupmulti( lpDependencies );
2038 wServiceStartName = SERV_dup( lpServiceStartName );
2039 wPassword = SERV_dup( lpPassword );
2040 wDisplayName = SERV_dup( lpDisplayName );
2042 r = ChangeServiceConfigW( hService, dwServiceType,
2043 dwStartType, dwErrorControl, wBinaryPathName,
2044 wLoadOrderGroup, lpdwTagId, wDependencies,
2045 wServiceStartName, wPassword, wDisplayName);
2047 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2048 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2049 HeapFree( GetProcessHeap(), 0, wDependencies );
2050 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2051 HeapFree( GetProcessHeap(), 0, wPassword );
2052 HeapFree( GetProcessHeap(), 0, wDisplayName );
2057 /******************************************************************************
2058 * ChangeServiceConfig2A [ADVAPI32.@]
2060 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2065 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2067 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2069 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2070 SERVICE_DESCRIPTIONW sdw;
2072 sdw.lpDescription = SERV_dup( sd->lpDescription );
2074 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2076 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2078 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2080 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2081 SERVICE_FAILURE_ACTIONSW faw;
2083 faw.dwResetPeriod = fa->dwResetPeriod;
2084 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2085 faw.lpCommand = SERV_dup( fa->lpCommand );
2086 faw.cActions = fa->cActions;
2087 faw.lpsaActions = fa->lpsaActions;
2089 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2091 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2092 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2094 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2096 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2099 SetLastError( ERROR_INVALID_PARAMETER );
2104 /******************************************************************************
2105 * ChangeServiceConfig2W [ADVAPI32.@]
2107 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2114 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2116 __EXCEPT(rpc_filter)
2118 err = map_exception_code(GetExceptionCode());
2122 if (err != ERROR_SUCCESS)
2125 return err == ERROR_SUCCESS;
2128 /******************************************************************************
2129 * QueryServiceObjectSecurity [ADVAPI32.@]
2131 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2132 SECURITY_INFORMATION dwSecurityInformation,
2133 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2134 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2136 SECURITY_DESCRIPTOR descriptor;
2141 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2142 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2144 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2145 FIXME("information %d not supported\n", dwSecurityInformation);
2147 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2149 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2150 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2153 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2154 *pcbBytesNeeded = size;
2158 /******************************************************************************
2159 * SetServiceObjectSecurity [ADVAPI32.@]
2161 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2162 SECURITY_INFORMATION dwSecurityInformation,
2163 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2165 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2169 /******************************************************************************
2170 * SetServiceBits [ADVAPI32.@]
2172 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2173 DWORD dwServiceBits,
2175 BOOL bUpdateImmediately)
2177 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2178 bSetBitsOn, bUpdateImmediately);
2182 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2183 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2185 LPHANDLER_FUNCTION func = context;
2188 return ERROR_SUCCESS;
2191 /******************************************************************************
2192 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2194 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2196 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2199 /******************************************************************************
2200 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2202 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2204 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2207 /******************************************************************************
2208 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2210 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2213 SERVICE_STATUS_HANDLE ret;
2215 nameW = SERV_dup(name);
2216 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2217 HeapFree( GetProcessHeap(), 0, nameW );
2221 /******************************************************************************
2222 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2224 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2225 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2227 service_data *service;
2228 SC_HANDLE hService = 0;
2231 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2233 EnterCriticalSection( &service_cs );
2234 if ((service = find_service_by_name( lpServiceName )))
2236 service->handler = lpHandlerProc;
2237 service->context = lpContext;
2238 hService = service->handle;
2241 LeaveCriticalSection( &service_cs );
2243 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2245 return (SERVICE_STATUS_HANDLE)hService;
2248 /******************************************************************************
2249 * EnumDependentServicesA [ADVAPI32.@]
2251 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2252 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2253 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2255 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2256 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2258 *lpServicesReturned = 0;
2262 /******************************************************************************
2263 * EnumDependentServicesW [ADVAPI32.@]
2265 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2266 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2267 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2269 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2270 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2272 *lpServicesReturned = 0;