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 "wine/exception.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(service);
48 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
49 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
50 'S','e','r','v','i','c','e','s',0 };
52 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
54 return HeapAlloc(GetProcessHeap(), 0, len);
57 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
59 HeapFree(GetProcessHeap(), 0, ptr);
62 typedef struct service_data_t
64 LPHANDLER_FUNCTION_EX handler;
70 LPSERVICE_MAIN_FUNCTIONA a;
71 LPSERVICE_MAIN_FUNCTIONW w;
77 static CRITICAL_SECTION service_cs;
78 static CRITICAL_SECTION_DEBUG service_cs_debug =
81 { &service_cs_debug.ProcessLocksList,
82 &service_cs_debug.ProcessLocksList },
83 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
85 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
87 static service_data **services;
88 static unsigned int nb_services;
89 static HANDLE service_event;
91 extern HANDLE CDECL __wine_make_process_system(void);
93 /******************************************************************************
94 * String management functions (same behaviour as strdup)
95 * NOTE: the caller of those functions is responsible for calling HeapFree
96 * in order to release the memory allocated by those functions.
98 static inline LPWSTR SERV_dup( LPCSTR str )
105 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
106 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
107 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
111 static inline LPWSTR SERV_dupmulti(LPCSTR str)
119 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
120 n += (strlen( &str[n] ) + 1);
125 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
126 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
130 static inline DWORD multisz_cb(LPCWSTR wmultisz)
132 const WCHAR *wptr = wmultisz;
134 if (wmultisz == NULL)
138 wptr += lstrlenW(wptr)+1;
139 return (wptr - wmultisz + 1)*sizeof(WCHAR);
142 /******************************************************************************
143 * RPC connection with services.exe
146 handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
148 WCHAR transport[] = SVCCTL_TRANSPORT;
149 WCHAR endpoint[] = SVCCTL_ENDPOINT;
150 RPC_WSTR binding_str;
154 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
155 if (status != RPC_S_OK)
157 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
161 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
162 RpcStringFreeW(&binding_str);
164 if (status != RPC_S_OK)
166 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
173 void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
178 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
180 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
183 static DWORD map_exception_code(DWORD exception_code)
185 switch (exception_code)
187 case RPC_X_NULL_REF_POINTER:
188 return ERROR_INVALID_ADDRESS;
189 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
190 case RPC_X_BYTE_COUNT_TOO_SMALL:
191 return ERROR_INVALID_PARAMETER;
192 case RPC_S_INVALID_BINDING:
193 case RPC_X_SS_IN_NULL_CONTEXT:
194 return ERROR_INVALID_HANDLE;
196 return exception_code;
200 /******************************************************************************
201 * Service IPC functions
203 static LPWSTR service_get_pipe_name(void)
205 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
206 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
207 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
208 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
209 'C','o','n','t','r','o','l','\\',
210 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
213 HKEY service_current_key;
214 DWORD service_current;
218 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
219 KEY_QUERY_VALUE, &service_current_key);
220 if (ret != ERROR_SUCCESS)
222 len = sizeof(service_current);
223 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
224 (BYTE *)&service_current, &len);
225 RegCloseKey(service_current_key);
226 if (ret != ERROR_SUCCESS || type != REG_DWORD)
228 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
229 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
232 snprintfW(name, len, format, service_current);
236 static HANDLE service_open_pipe(void)
238 LPWSTR szPipe = service_get_pipe_name();
239 HANDLE handle = INVALID_HANDLE_VALUE;
242 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
243 0, NULL, OPEN_ALWAYS, 0, NULL);
244 if (handle != INVALID_HANDLE_VALUE)
246 if (GetLastError() != ERROR_PIPE_BUSY)
248 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
249 HeapFree(GetProcessHeap(), 0, szPipe);
254 static service_data *find_service_by_name( const WCHAR *name )
258 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
260 for (i = 0; i < nb_services; i++)
261 if (!strcmpiW( name, services[i]->name )) return services[i];
265 /******************************************************************************
268 * Call into the main service routine provided by StartServiceCtrlDispatcher.
270 static DWORD WINAPI service_thread(LPVOID arg)
272 service_data *info = arg;
273 LPWSTR str = info->args;
274 DWORD argc = 0, len = 0;
280 len += strlenW(&str[len]) + 1;
289 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
290 for (argc=0, p=str; *p; p += strlenW(p) + 1)
294 info->proc.w(argc, argv);
295 HeapFree(GetProcessHeap(), 0, argv);
299 LPSTR strA, *argv, p;
302 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
303 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
304 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
306 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
307 for (argc=0, p=strA; *p; p += strlen(p) + 1)
311 info->proc.a(argc, argv);
312 HeapFree(GetProcessHeap(), 0, argv);
313 HeapFree(GetProcessHeap(), 0, strA);
318 /******************************************************************************
319 * service_handle_start
321 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
323 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
327 WARN("service is not stopped\n");
328 return ERROR_SERVICE_ALREADY_RUNNING;
331 HeapFree(GetProcessHeap(), 0, service->args);
332 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
333 memcpy( service->args, data, count * sizeof(WCHAR) );
334 service->thread = CreateThread( NULL, 0, service_thread,
336 SetEvent( service_event ); /* notify the main loop */
340 /******************************************************************************
341 * service_handle_control
343 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
345 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
347 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
349 if (service->handler)
350 ret = service->handler(dwControl, 0, NULL, service->context);
354 /******************************************************************************
355 * service_control_dispatcher
357 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
362 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
364 ERR("failed to open service manager error %u\n", GetLastError());
368 pipe = service_open_pipe();
370 if (pipe==INVALID_HANDLE_VALUE)
372 ERR("failed to create control pipe error = %d\n", GetLastError());
376 /* dispatcher loop */
379 service_data *service;
380 service_start_info info;
383 DWORD data_size = 0, count, result;
385 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
388 if (GetLastError() != ERROR_BROKEN_PIPE)
389 ERR( "pipe read failed error %u\n", GetLastError() );
392 if (count != FIELD_OFFSET(service_start_info,data))
394 ERR( "partial pipe read %u\n", count );
397 if (count < info.total_size)
399 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
400 data = HeapAlloc( GetProcessHeap(), 0, data_size );
401 r = ReadFile( pipe, data, data_size, &count, NULL );
404 if (GetLastError() != ERROR_BROKEN_PIPE)
405 ERR( "pipe read failed error %u\n", GetLastError() );
408 if (count != data_size)
410 ERR( "partial pipe read %u/%u\n", count, data_size );
415 /* find the service */
417 if (!(service = find_service_by_name( data )))
419 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
420 result = ERROR_INVALID_PARAMETER;
424 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
426 /* handle the request */
429 case WINESERV_STARTINFO:
430 if (!service->handle)
432 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )))
433 FIXME( "failed to open service %s\n", debugstr_w(data) );
435 result = service_handle_start(service, data + info.name_size,
436 data_size / sizeof(WCHAR) - info.name_size );
438 case WINESERV_SENDCONTROL:
439 result = service_handle_control(service, info.control);
442 ERR("received invalid command %u\n", info.cmd);
443 result = ERROR_INVALID_PARAMETER;
448 WriteFile(pipe, &result, sizeof(result), &count, NULL);
449 HeapFree( GetProcessHeap(), 0, data );
453 CloseServiceHandle( manager );
457 /******************************************************************************
458 * service_run_main_thread
460 static BOOL service_run_main_thread(void)
463 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
464 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
466 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
468 /* FIXME: service_control_dispatcher should be merged into the main thread */
469 wait_handles[0] = __wine_make_process_system();
470 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
471 wait_handles[2] = service_event;
473 TRACE("Starting %d services running as process %d\n",
474 nb_services, GetCurrentProcessId());
476 /* wait for all the threads to pack up and exit */
479 EnterCriticalSection( &service_cs );
480 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
482 if (!services[i]->thread) continue;
483 wait_services[n] = i;
484 wait_handles[n++] = services[i]->thread;
486 LeaveCriticalSection( &service_cs );
488 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
489 if (!ret) /* system process event */
491 TRACE( "last user process exited, shutting down\n" );
492 /* FIXME: we should maybe send a shutdown control to running services */
497 TRACE( "control dispatcher exited, shutting down\n" );
498 /* FIXME: we should maybe send a shutdown control to running services */
503 continue; /* rebuild the list */
507 services[wait_services[ret]]->thread = 0;
508 CloseHandle( wait_handles[ret] );
509 if (n == 4) return TRUE; /* it was the last running thread */
515 /******************************************************************************
516 * StartServiceCtrlDispatcherA [ADVAPI32.@]
518 * See StartServiceCtrlDispatcherW.
520 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
526 TRACE("%p\n", servent);
530 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
533 while (servent[nb_services].lpServiceName) nb_services++;
534 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
536 for (i = 0; i < nb_services; i++)
538 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
539 DWORD sz = FIELD_OFFSET( service_data, name[len] );
540 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
541 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
542 info->proc.a = servent[i].lpServiceProc;
543 info->unicode = FALSE;
547 service_run_main_thread();
552 /******************************************************************************
553 * StartServiceCtrlDispatcherW [ADVAPI32.@]
555 * Connects a process containing one or more services to the service control
559 * servent [I] A list of the service names and service procedures
565 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
571 TRACE("%p\n", servent);
575 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
578 while (servent[nb_services].lpServiceName) nb_services++;
579 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
581 for (i = 0; i < nb_services; i++)
583 DWORD len = strlenW(servent[i].lpServiceName) + 1;
584 DWORD sz = FIELD_OFFSET( service_data, name[len] );
585 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
586 strcpyW(info->name, servent[i].lpServiceName);
587 info->proc.w = servent[i].lpServiceProc;
588 info->unicode = TRUE;
592 service_run_main_thread();
597 /******************************************************************************
598 * LockServiceDatabase [ADVAPI32.@]
600 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
602 SC_RPC_LOCK hLock = NULL;
605 TRACE("%p\n",hSCManager);
609 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
613 err = map_exception_code(GetExceptionCode());
616 if (err != ERROR_SUCCESS)
624 /******************************************************************************
625 * UnlockServiceDatabase [ADVAPI32.@]
627 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
630 SC_RPC_LOCK hRpcLock = ScLock;
632 TRACE("%p\n",ScLock);
636 err = svcctl_UnlockServiceDatabase(&hRpcLock);
640 err = map_exception_code(GetExceptionCode());
643 if (err != ERROR_SUCCESS)
651 /******************************************************************************
652 * SetServiceStatus [ADVAPI32.@]
659 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
663 TRACE("%p %x %x %x %x %x %x %x\n", hService,
664 lpStatus->dwServiceType, lpStatus->dwCurrentState,
665 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
666 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
667 lpStatus->dwWaitHint);
671 err = svcctl_SetServiceStatus( hService, lpStatus );
675 err = map_exception_code(GetExceptionCode());
678 if (err != ERROR_SUCCESS)
684 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
685 CloseServiceHandle((SC_HANDLE)hService);
691 /******************************************************************************
692 * OpenSCManagerA [ADVAPI32.@]
694 * Establish a connection to the service control manager and open its database.
697 * lpMachineName [I] Pointer to machine name string
698 * lpDatabaseName [I] Pointer to database name string
699 * dwDesiredAccess [I] Type of access
702 * Success: A Handle to the service control manager database
705 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
706 DWORD dwDesiredAccess )
708 LPWSTR lpMachineNameW, lpDatabaseNameW;
711 lpMachineNameW = SERV_dup(lpMachineName);
712 lpDatabaseNameW = SERV_dup(lpDatabaseName);
713 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
714 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
715 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
719 /******************************************************************************
720 * OpenSCManagerW [ADVAPI32.@]
722 * See OpenSCManagerA.
724 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
725 DWORD dwDesiredAccess )
730 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
731 debugstr_w(lpDatabaseName), dwDesiredAccess);
735 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
739 r = map_exception_code(GetExceptionCode());
743 if (r!=ERROR_SUCCESS)
749 TRACE("returning %p\n", handle);
753 /******************************************************************************
754 * ControlService [ADVAPI32.@]
756 * Send a control code to a service.
759 * hService [I] Handle of the service control manager database
760 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
761 * lpServiceStatus [O] Destination for the status of the service, if available
768 * Unlike M$' implementation, control requests are not serialized and may be
769 * processed asynchronously.
771 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
772 LPSERVICE_STATUS lpServiceStatus )
776 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
780 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
784 err = map_exception_code(GetExceptionCode());
787 if (err != ERROR_SUCCESS)
796 /******************************************************************************
797 * CloseServiceHandle [ADVAPI32.@]
799 * Close a handle to a service or the service control manager database.
802 * hSCObject [I] Handle to service or service control manager database
809 CloseServiceHandle( SC_HANDLE hSCObject )
813 TRACE("%p\n", hSCObject);
817 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
821 err = map_exception_code(GetExceptionCode());
825 if (err != ERROR_SUCCESS)
834 /******************************************************************************
835 * OpenServiceA [ADVAPI32.@]
837 * Open a handle to a service.
840 * hSCManager [I] Handle of the service control manager database
841 * lpServiceName [I] Name of the service to open
842 * dwDesiredAccess [I] Access required to the service
845 * Success: Handle to the service
848 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
849 DWORD dwDesiredAccess )
851 LPWSTR lpServiceNameW;
854 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
856 lpServiceNameW = SERV_dup(lpServiceName);
857 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
858 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
863 /******************************************************************************
864 * OpenServiceW [ADVAPI32.@]
868 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
869 DWORD dwDesiredAccess)
874 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
878 SetLastError( ERROR_INVALID_HANDLE );
884 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
888 err = map_exception_code(GetExceptionCode());
892 if (err != ERROR_SUCCESS)
898 TRACE("returning %p\n",handle);
902 /******************************************************************************
903 * CreateServiceW [ADVAPI32.@]
906 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
907 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
908 DWORD dwServiceType, DWORD dwStartType,
909 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
910 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
911 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
918 TRACE("%p %s %s\n", hSCManager,
919 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
923 SetLastError( ERROR_INVALID_HANDLE );
928 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
934 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
935 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
936 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
937 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
938 (SC_RPC_HANDLE *)&handle);
942 err = map_exception_code(GetExceptionCode());
946 if (err != ERROR_SUCCESS)
955 /******************************************************************************
956 * CreateServiceA [ADVAPI32.@]
959 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
960 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
961 DWORD dwServiceType, DWORD dwStartType,
962 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
963 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
964 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
967 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
968 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
971 TRACE("%p %s %s\n", hSCManager,
972 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
974 lpServiceNameW = SERV_dup( lpServiceName );
975 lpDisplayNameW = SERV_dup( lpDisplayName );
976 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
977 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
978 lpDependenciesW = SERV_dupmulti( lpDependencies );
979 lpServiceStartNameW = SERV_dup( lpServiceStartName );
980 lpPasswordW = SERV_dup( lpPassword );
982 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
983 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
984 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
985 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
987 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
988 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
989 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
990 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
991 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
992 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
993 HeapFree( GetProcessHeap(), 0, lpPasswordW );
999 /******************************************************************************
1000 * DeleteService [ADVAPI32.@]
1002 * Delete a service from the service control manager database.
1005 * hService [I] Handle of the service to delete
1011 BOOL WINAPI DeleteService( SC_HANDLE hService )
1017 err = svcctl_DeleteService(hService);
1019 __EXCEPT(rpc_filter)
1021 err = map_exception_code(GetExceptionCode());
1034 /******************************************************************************
1035 * StartServiceA [ADVAPI32.@]
1040 * hService [I] Handle of service
1041 * dwNumServiceArgs [I] Number of arguments
1042 * lpServiceArgVectors [I] Address of array of argument strings
1045 * - NT implements this function using an obscure RPC call.
1046 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1047 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1048 * - This will only work for shared address space. How should the service
1049 * args be transferred when address spaces are separated?
1050 * - Can only start one service at a time.
1051 * - Has no concept of privilege.
1057 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1058 LPCSTR *lpServiceArgVectors )
1060 LPWSTR *lpwstr=NULL;
1064 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1066 if (dwNumServiceArgs)
1067 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1068 dwNumServiceArgs*sizeof(LPWSTR) );
1070 for(i=0; i<dwNumServiceArgs; i++)
1071 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1073 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1075 if (dwNumServiceArgs)
1077 for(i=0; i<dwNumServiceArgs; i++)
1078 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1079 HeapFree(GetProcessHeap(), 0, lpwstr);
1086 /******************************************************************************
1087 * StartServiceW [ADVAPI32.@]
1089 * See StartServiceA.
1091 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1092 LPCWSTR *lpServiceArgVectors)
1096 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1100 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1102 __EXCEPT(rpc_filter)
1104 err = map_exception_code(GetExceptionCode());
1107 if (err != ERROR_SUCCESS)
1116 /******************************************************************************
1117 * QueryServiceStatus [ADVAPI32.@]
1120 * hService [I] Handle to service to get information about
1121 * lpservicestatus [O] buffer to receive the status information for the service
1124 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1125 LPSERVICE_STATUS lpservicestatus)
1127 SERVICE_STATUS_PROCESS SvcStatusData;
1131 TRACE("%p %p\n", hService, lpservicestatus);
1133 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1134 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1135 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1140 /******************************************************************************
1141 * QueryServiceStatusEx [ADVAPI32.@]
1143 * Get information about a service.
1146 * hService [I] Handle to service to get information about
1147 * InfoLevel [I] Level of information to get
1148 * lpBuffer [O] Destination for requested information
1149 * cbBufSize [I] Size of lpBuffer in bytes
1150 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1156 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1157 LPBYTE lpBuffer, DWORD cbBufSize,
1158 LPDWORD pcbBytesNeeded)
1162 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1166 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1168 __EXCEPT(rpc_filter)
1170 err = map_exception_code(GetExceptionCode());
1173 if (err != ERROR_SUCCESS)
1182 /******************************************************************************
1183 * QueryServiceConfigA [ADVAPI32.@]
1185 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1186 DWORD size, LPDWORD needed )
1191 QUERY_SERVICE_CONFIGW *configW;
1193 TRACE("%p %p %d %p\n", hService, config, size, needed);
1195 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1197 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1200 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1201 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1202 if (!ret) goto done;
1204 config->dwServiceType = configW->dwServiceType;
1205 config->dwStartType = configW->dwStartType;
1206 config->dwErrorControl = configW->dwErrorControl;
1207 config->lpBinaryPathName = NULL;
1208 config->lpLoadOrderGroup = NULL;
1209 config->dwTagId = configW->dwTagId;
1210 config->lpDependencies = NULL;
1211 config->lpServiceStartName = NULL;
1212 config->lpDisplayName = NULL;
1214 p = (LPSTR)(config + 1);
1215 n = size - sizeof(*config);
1218 #define MAP_STR(str) \
1222 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1223 if (!sz) goto done; \
1230 MAP_STR( lpBinaryPathName );
1231 MAP_STR( lpLoadOrderGroup );
1232 MAP_STR( lpDependencies );
1233 MAP_STR( lpServiceStartName );
1234 MAP_STR( lpDisplayName );
1237 *needed = p - (LPSTR)config;
1241 HeapFree( GetProcessHeap(), 0, buffer );
1245 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1252 memset(*buf, 0, cb);
1256 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1257 memcpy(*buf, *string_ptr, cb);
1258 MIDL_user_free(*string_ptr);
1261 *string_ptr = (LPWSTR)*buf;
1267 static DWORD size_string(LPCWSTR string)
1269 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1272 /******************************************************************************
1273 * QueryServiceConfigW [ADVAPI32.@]
1276 QueryServiceConfigW( SC_HANDLE hService,
1277 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1278 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1280 QUERY_SERVICE_CONFIGW config;
1285 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1286 cbBufSize, pcbBytesNeeded);
1288 memset(&config, 0, sizeof(config));
1292 err = svcctl_QueryServiceConfigW(hService, &config);
1294 __EXCEPT(rpc_filter)
1296 err = map_exception_code(GetExceptionCode());
1300 if (err != ERROR_SUCCESS)
1302 TRACE("services.exe: error %u\n", err);
1307 /* calculate the size required first */
1308 total = sizeof (QUERY_SERVICE_CONFIGW);
1309 total += size_string(config.lpBinaryPathName);
1310 total += size_string(config.lpLoadOrderGroup);
1311 total += size_string(config.lpDependencies);
1312 total += size_string(config.lpServiceStartName);
1313 total += size_string(config.lpDisplayName);
1315 *pcbBytesNeeded = total;
1317 /* if there's not enough memory, return an error */
1318 if( total > cbBufSize )
1320 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1321 MIDL_user_free(config.lpBinaryPathName);
1322 MIDL_user_free(config.lpLoadOrderGroup);
1323 MIDL_user_free(config.lpDependencies);
1324 MIDL_user_free(config.lpServiceStartName);
1325 MIDL_user_free(config.lpDisplayName);
1329 *lpServiceConfig = config;
1330 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1331 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1332 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1333 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1334 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1335 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1337 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1338 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1339 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1340 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1341 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1346 /******************************************************************************
1347 * QueryServiceConfig2A [ADVAPI32.@]
1350 * observed under win2k:
1351 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1352 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1354 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1355 DWORD size, LPDWORD needed)
1358 LPBYTE bufferW = NULL;
1361 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1363 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1364 if(!ret) goto cleanup;
1367 case SERVICE_CONFIG_DESCRIPTION:
1368 if (buffer && bufferW) {
1369 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1370 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1371 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1373 configA->lpDescription = (LPSTR)(configA + 1);
1374 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1375 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1377 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1379 configA->lpDescription = NULL;
1382 else configA->lpDescription = NULL;
1386 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1392 HeapFree( GetProcessHeap(), 0, bufferW);
1396 /******************************************************************************
1397 * QueryServiceConfig2W [ADVAPI32.@]
1399 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1400 DWORD size, LPDWORD needed)
1404 if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1405 if((dwLevel == SERVICE_CONFIG_DELAYED_AUTO_START_INFO) ||
1406 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS) ||
1407 (dwLevel == SERVICE_CONFIG_FAILURE_ACTIONS_FLAG) ||
1408 (dwLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO) ||
1409 (dwLevel == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO) ||
1410 (dwLevel == SERVICE_CONFIG_SERVICE_SID_INFO))
1411 FIXME("Level %d not implemented\n", dwLevel);
1412 SetLastError(ERROR_INVALID_LEVEL);
1416 if(!buffer && size) {
1417 SetLastError(ERROR_INVALID_ADDRESS);
1421 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1425 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1427 __EXCEPT(rpc_filter)
1429 err = map_exception_code(GetExceptionCode());
1433 if (err != ERROR_SUCCESS)
1435 SetLastError( err );
1441 case SERVICE_CONFIG_DESCRIPTION:
1444 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1445 if (descr->lpDescription) /* make it an absolute pointer */
1446 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1454 /******************************************************************************
1455 * EnumServicesStatusA [ADVAPI32.@]
1458 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1459 services, DWORD size, LPDWORD needed, LPDWORD returned,
1460 LPDWORD resume_handle )
1464 ENUM_SERVICE_STATUSW *servicesW = NULL;
1468 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1469 returned, resume_handle);
1471 if (size && !(servicesW = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1473 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1477 ret = EnumServicesStatusW( hmngr, type, state, servicesW, 2 * size, needed, returned, resume_handle );
1478 if (!ret) goto done;
1480 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1481 n = size - (p - (char *)services);
1483 for (i = 0; i < *returned; i++)
1485 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1487 services[i].lpServiceName = p;
1490 if (servicesW[i].lpDisplayName)
1492 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1494 services[i].lpDisplayName = p;
1498 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1504 HeapFree( GetProcessHeap(), 0, servicesW );
1508 /******************************************************************************
1509 * EnumServicesStatusW [ADVAPI32.@]
1512 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1513 services, DWORD size, LPDWORD needed, LPDWORD returned,
1514 LPDWORD resume_handle )
1518 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1519 returned, resume_handle);
1522 FIXME("resume handle not supported\n");
1526 SetLastError( ERROR_INVALID_HANDLE );
1532 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1534 __EXCEPT(rpc_filter)
1536 err = map_exception_code( GetExceptionCode() );
1540 if (err != ERROR_SUCCESS)
1542 SetLastError( err );
1546 for (i = 0; i < *returned; i++)
1548 /* convert buffer offsets into pointers */
1549 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1550 if (services[i].lpDisplayName)
1551 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1557 /******************************************************************************
1558 * EnumServicesStatusExA [ADVAPI32.@]
1561 EnumServicesStatusExA(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1562 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1563 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCSTR pszGroupName)
1565 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1566 dwServiceType, dwServiceState, lpServices, cbBufSize,
1567 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_a(pszGroupName));
1568 if (lpServicesReturned) *lpServicesReturned = 0;
1569 SetLastError (ERROR_ACCESS_DENIED);
1573 /******************************************************************************
1574 * EnumServicesStatusExW [ADVAPI32.@]
1577 EnumServicesStatusExW(SC_HANDLE hSCManager, SC_ENUM_TYPE InfoLevel, DWORD dwServiceType,
1578 DWORD dwServiceState, LPBYTE lpServices, DWORD cbBufSize, LPDWORD pcbBytesNeeded,
1579 LPDWORD lpServicesReturned, LPDWORD lpResumeHandle, LPCWSTR pszGroupName)
1581 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager, InfoLevel,
1582 dwServiceType, dwServiceState, lpServices, cbBufSize,
1583 pcbBytesNeeded, lpServicesReturned, lpResumeHandle, debugstr_w(pszGroupName));
1584 SetLastError (ERROR_ACCESS_DENIED);
1588 /******************************************************************************
1589 * GetServiceKeyNameA [ADVAPI32.@]
1591 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1592 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1594 LPWSTR lpDisplayNameW, lpServiceNameW;
1598 TRACE("%p %s %p %p\n", hSCManager,
1599 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1601 lpDisplayNameW = SERV_dup(lpDisplayName);
1603 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1605 lpServiceNameW = NULL;
1607 sizeW = *lpcchBuffer;
1608 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1610 if (lpServiceName && *lpcchBuffer)
1611 lpServiceName[0] = 0;
1612 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1616 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1617 *lpcchBuffer, NULL, NULL ))
1619 if (*lpcchBuffer && lpServiceName)
1620 lpServiceName[0] = 0;
1621 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1625 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1629 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1630 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1634 /******************************************************************************
1635 * GetServiceKeyNameW [ADVAPI32.@]
1637 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1638 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1644 TRACE("%p %s %p %p\n", hSCManager,
1645 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1649 SetLastError( ERROR_INVALID_HANDLE );
1653 /* provide a buffer if the caller didn't */
1654 if (!lpServiceName || *lpcchBuffer < 2)
1656 lpServiceName = buffer;
1657 /* A size of 1 would be enough, but tests show that Windows returns 2,
1658 * probably because of a WCHAR/bytes mismatch in their code.
1663 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1664 * includes the nul-terminator on input. */
1665 size = *lpcchBuffer - 1;
1669 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1672 __EXCEPT(rpc_filter)
1674 err = map_exception_code(GetExceptionCode());
1678 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1679 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1680 *lpcchBuffer = size;
1684 return err == ERROR_SUCCESS;
1687 /******************************************************************************
1688 * QueryServiceLockStatusA [ADVAPI32.@]
1690 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1691 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1692 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1694 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1699 /******************************************************************************
1700 * QueryServiceLockStatusW [ADVAPI32.@]
1702 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1703 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1704 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1706 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1711 /******************************************************************************
1712 * GetServiceDisplayNameA [ADVAPI32.@]
1714 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1715 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1717 LPWSTR lpServiceNameW, lpDisplayNameW;
1721 TRACE("%p %s %p %p\n", hSCManager,
1722 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1724 lpServiceNameW = SERV_dup(lpServiceName);
1726 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1728 lpDisplayNameW = NULL;
1730 sizeW = *lpcchBuffer;
1731 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1733 if (lpDisplayName && *lpcchBuffer)
1734 lpDisplayName[0] = 0;
1735 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1739 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1740 *lpcchBuffer, NULL, NULL ))
1742 if (*lpcchBuffer && lpDisplayName)
1743 lpDisplayName[0] = 0;
1744 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1748 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1749 * (but if the function succeeded it means that is a good upper estimation of the size) */
1753 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1754 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1758 /******************************************************************************
1759 * GetServiceDisplayNameW [ADVAPI32.@]
1761 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1762 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1768 TRACE("%p %s %p %p\n", hSCManager,
1769 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1773 SetLastError( ERROR_INVALID_HANDLE );
1777 /* provide a buffer if the caller didn't */
1778 if (!lpDisplayName || *lpcchBuffer < 2)
1780 lpDisplayName = buffer;
1781 /* A size of 1 would be enough, but tests show that Windows returns 2,
1782 * probably because of a WCHAR/bytes mismatch in their code.
1787 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1788 * includes the nul-terminator on input. */
1789 size = *lpcchBuffer - 1;
1793 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
1796 __EXCEPT(rpc_filter)
1798 err = map_exception_code(GetExceptionCode());
1802 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1803 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1804 *lpcchBuffer = size;
1808 return err == ERROR_SUCCESS;
1811 /******************************************************************************
1812 * ChangeServiceConfigW [ADVAPI32.@]
1814 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1815 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1816 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1817 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1822 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1823 hService, dwServiceType, dwStartType, dwErrorControl,
1824 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1825 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1826 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1828 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
1832 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
1833 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
1834 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
1835 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
1837 __EXCEPT(rpc_filter)
1839 err = map_exception_code(GetExceptionCode());
1843 if (err != ERROR_SUCCESS)
1846 return err == ERROR_SUCCESS;
1849 /******************************************************************************
1850 * ChangeServiceConfigA [ADVAPI32.@]
1852 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1853 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1854 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1855 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1857 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1858 LPWSTR wServiceStartName, wPassword, wDisplayName;
1861 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1862 hService, dwServiceType, dwStartType, dwErrorControl,
1863 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1864 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1865 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1867 wBinaryPathName = SERV_dup( lpBinaryPathName );
1868 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1869 wDependencies = SERV_dupmulti( lpDependencies );
1870 wServiceStartName = SERV_dup( lpServiceStartName );
1871 wPassword = SERV_dup( lpPassword );
1872 wDisplayName = SERV_dup( lpDisplayName );
1874 r = ChangeServiceConfigW( hService, dwServiceType,
1875 dwStartType, dwErrorControl, wBinaryPathName,
1876 wLoadOrderGroup, lpdwTagId, wDependencies,
1877 wServiceStartName, wPassword, wDisplayName);
1879 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
1880 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
1881 HeapFree( GetProcessHeap(), 0, wDependencies );
1882 HeapFree( GetProcessHeap(), 0, wServiceStartName );
1883 HeapFree( GetProcessHeap(), 0, wPassword );
1884 HeapFree( GetProcessHeap(), 0, wDisplayName );
1889 /******************************************************************************
1890 * ChangeServiceConfig2A [ADVAPI32.@]
1892 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
1897 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
1899 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
1901 LPSERVICE_DESCRIPTIONA sd = lpInfo;
1902 SERVICE_DESCRIPTIONW sdw;
1904 sdw.lpDescription = SERV_dup( sd->lpDescription );
1906 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
1908 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
1910 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
1912 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
1913 SERVICE_FAILURE_ACTIONSW faw;
1915 faw.dwResetPeriod = fa->dwResetPeriod;
1916 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
1917 faw.lpCommand = SERV_dup( fa->lpCommand );
1918 faw.cActions = fa->cActions;
1919 faw.lpsaActions = fa->lpsaActions;
1921 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
1923 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
1924 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
1927 SetLastError( ERROR_INVALID_PARAMETER );
1932 /******************************************************************************
1933 * ChangeServiceConfig2W [ADVAPI32.@]
1935 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
1942 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
1944 __EXCEPT(rpc_filter)
1946 err = map_exception_code(GetExceptionCode());
1950 if (err != ERROR_SUCCESS)
1953 return err == ERROR_SUCCESS;
1956 /******************************************************************************
1957 * QueryServiceObjectSecurity [ADVAPI32.@]
1959 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
1960 SECURITY_INFORMATION dwSecurityInformation,
1961 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
1962 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1964 SECURITY_DESCRIPTOR descriptor;
1969 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
1970 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
1972 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
1973 FIXME("information %d not supported\n", dwSecurityInformation);
1975 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
1977 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
1978 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
1981 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
1982 *pcbBytesNeeded = size;
1986 /******************************************************************************
1987 * SetServiceObjectSecurity [ADVAPI32.@]
1989 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1990 SECURITY_INFORMATION dwSecurityInformation,
1991 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1993 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1997 /******************************************************************************
1998 * SetServiceBits [ADVAPI32.@]
2000 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2001 DWORD dwServiceBits,
2003 BOOL bUpdateImmediately)
2005 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2006 bSetBitsOn, bUpdateImmediately);
2010 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2011 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2013 LPHANDLER_FUNCTION func = context;
2016 return ERROR_SUCCESS;
2019 /******************************************************************************
2020 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2022 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2024 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2027 /******************************************************************************
2028 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2030 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2032 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2035 /******************************************************************************
2036 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2038 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2041 SERVICE_STATUS_HANDLE ret;
2043 nameW = SERV_dup(name);
2044 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2045 HeapFree( GetProcessHeap(), 0, nameW );
2049 /******************************************************************************
2050 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2052 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2053 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2055 service_data *service;
2056 SC_HANDLE hService = 0;
2059 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2061 EnterCriticalSection( &service_cs );
2062 if ((service = find_service_by_name( lpServiceName )))
2064 service->handler = lpHandlerProc;
2065 service->context = lpContext;
2066 hService = service->handle;
2069 LeaveCriticalSection( &service_cs );
2071 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2073 return (SERVICE_STATUS_HANDLE)hService;
2076 /******************************************************************************
2077 * EnumDependentServicesA [ADVAPI32.@]
2079 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2080 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2081 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2083 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2084 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2086 *lpServicesReturned = 0;
2090 /******************************************************************************
2091 * EnumDependentServicesW [ADVAPI32.@]
2093 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2094 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2095 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2097 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2098 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2100 *lpServicesReturned = 0;