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 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
50 return HeapAlloc(GetProcessHeap(), 0, len);
53 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
55 HeapFree(GetProcessHeap(), 0, ptr);
58 typedef struct service_data_t
60 LPHANDLER_FUNCTION_EX handler;
66 LPSERVICE_MAIN_FUNCTIONA a;
67 LPSERVICE_MAIN_FUNCTIONW w;
73 static CRITICAL_SECTION service_cs;
74 static CRITICAL_SECTION_DEBUG service_cs_debug =
77 { &service_cs_debug.ProcessLocksList,
78 &service_cs_debug.ProcessLocksList },
79 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
81 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
83 static service_data **services;
84 static unsigned int nb_services;
85 static HANDLE service_event;
87 extern HANDLE CDECL __wine_make_process_system(void);
89 /******************************************************************************
90 * String management functions (same behaviour as strdup)
91 * NOTE: the caller of those functions is responsible for calling HeapFree
92 * in order to release the memory allocated by those functions.
94 static inline LPWSTR SERV_dup( LPCSTR str )
101 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
102 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
103 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
107 static inline LPWSTR SERV_dupmulti(LPCSTR str)
115 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
116 n += (strlen( &str[n] ) + 1);
121 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
122 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
126 static inline DWORD multisz_cb(LPCWSTR wmultisz)
128 const WCHAR *wptr = wmultisz;
130 if (wmultisz == NULL)
134 wptr += lstrlenW(wptr)+1;
135 return (wptr - wmultisz + 1)*sizeof(WCHAR);
138 /******************************************************************************
139 * RPC connection with services.exe
142 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
144 WCHAR transport[] = SVCCTL_TRANSPORT;
145 WCHAR endpoint[] = SVCCTL_ENDPOINT;
146 RPC_WSTR binding_str;
150 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
151 if (status != RPC_S_OK)
153 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
157 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
158 RpcStringFreeW(&binding_str);
160 if (status != RPC_S_OK)
162 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
169 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
174 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
176 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
179 static DWORD map_exception_code(DWORD exception_code)
181 switch (exception_code)
183 case RPC_X_NULL_REF_POINTER:
184 return ERROR_INVALID_ADDRESS;
185 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
186 case RPC_X_BYTE_COUNT_TOO_SMALL:
187 return ERROR_INVALID_PARAMETER;
188 case RPC_S_INVALID_BINDING:
189 case RPC_X_SS_IN_NULL_CONTEXT:
190 return ERROR_INVALID_HANDLE;
192 return exception_code;
196 /******************************************************************************
197 * Service IPC functions
199 static LPWSTR service_get_pipe_name(void)
201 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
202 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
203 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
204 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
205 'C','o','n','t','r','o','l','\\',
206 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
209 HKEY service_current_key;
210 DWORD service_current;
214 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
215 KEY_QUERY_VALUE, &service_current_key);
216 if (ret != ERROR_SUCCESS)
218 len = sizeof(service_current);
219 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
220 (BYTE *)&service_current, &len);
221 RegCloseKey(service_current_key);
222 if (ret != ERROR_SUCCESS || type != REG_DWORD)
224 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
225 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
228 snprintfW(name, len, format, service_current);
232 static HANDLE service_open_pipe(void)
234 LPWSTR szPipe = service_get_pipe_name();
235 HANDLE handle = INVALID_HANDLE_VALUE;
238 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
239 0, NULL, OPEN_ALWAYS, 0, NULL);
240 if (handle != INVALID_HANDLE_VALUE)
242 if (GetLastError() != ERROR_PIPE_BUSY)
244 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
245 HeapFree(GetProcessHeap(), 0, szPipe);
250 static service_data *find_service_by_name( const WCHAR *name )
254 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
256 for (i = 0; i < nb_services; i++)
257 if (!strcmpiW( name, services[i]->name )) return services[i];
261 /******************************************************************************
264 * Call into the main service routine provided by StartServiceCtrlDispatcher.
266 static DWORD WINAPI service_thread(LPVOID arg)
268 service_data *info = arg;
269 LPWSTR str = info->args;
270 DWORD argc = 0, len = 0;
276 len += strlenW(&str[len]) + 1;
285 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
286 for (argc=0, p=str; *p; p += strlenW(p) + 1)
290 info->proc.w(argc, argv);
291 HeapFree(GetProcessHeap(), 0, argv);
295 LPSTR strA, *argv, p;
298 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
299 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
300 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
302 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
303 for (argc=0, p=strA; *p; p += strlen(p) + 1)
307 info->proc.a(argc, argv);
308 HeapFree(GetProcessHeap(), 0, argv);
309 HeapFree(GetProcessHeap(), 0, strA);
314 /******************************************************************************
315 * service_handle_start
317 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
319 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
323 WARN("service is not stopped\n");
324 return ERROR_SERVICE_ALREADY_RUNNING;
327 HeapFree(GetProcessHeap(), 0, service->args);
328 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
329 memcpy( service->args, data, count * sizeof(WCHAR) );
330 service->thread = CreateThread( NULL, 0, service_thread,
332 SetEvent( service_event ); /* notify the main loop */
336 /******************************************************************************
337 * service_handle_control
339 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
341 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
343 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
345 if (service->handler)
346 ret = service->handler(dwControl, 0, NULL, service->context);
350 /******************************************************************************
351 * service_control_dispatcher
353 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
358 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
360 ERR("failed to open service manager error %u\n", GetLastError());
364 pipe = service_open_pipe();
366 if (pipe==INVALID_HANDLE_VALUE)
368 ERR("failed to create control pipe error = %d\n", GetLastError());
372 /* dispatcher loop */
375 service_data *service;
376 service_start_info info;
379 DWORD data_size = 0, count, result;
381 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
384 if (GetLastError() != ERROR_BROKEN_PIPE)
385 ERR( "pipe read failed error %u\n", GetLastError() );
388 if (count != FIELD_OFFSET(service_start_info,data))
390 ERR( "partial pipe read %u\n", count );
393 if (count < info.total_size)
395 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
396 data = HeapAlloc( GetProcessHeap(), 0, data_size );
397 r = ReadFile( pipe, data, data_size, &count, NULL );
400 if (GetLastError() != ERROR_BROKEN_PIPE)
401 ERR( "pipe read failed error %u\n", GetLastError() );
404 if (count != data_size)
406 ERR( "partial pipe read %u/%u\n", count, data_size );
411 /* find the service */
413 if (!(service = find_service_by_name( data )))
415 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
416 result = ERROR_INVALID_PARAMETER;
420 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
422 /* handle the request */
425 case WINESERV_STARTINFO:
426 if (!service->handle)
428 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )))
429 FIXME( "failed to open service %s\n", debugstr_w(data) );
431 result = service_handle_start(service, data + info.name_size,
432 data_size / sizeof(WCHAR) - info.name_size );
434 case WINESERV_SENDCONTROL:
435 result = service_handle_control(service, info.control);
438 ERR("received invalid command %u\n", info.cmd);
439 result = ERROR_INVALID_PARAMETER;
444 WriteFile(pipe, &result, sizeof(result), &count, NULL);
445 HeapFree( GetProcessHeap(), 0, data );
449 CloseServiceHandle( manager );
453 /******************************************************************************
454 * service_run_main_thread
456 static BOOL service_run_main_thread(void)
459 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
460 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
462 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
464 /* FIXME: service_control_dispatcher should be merged into the main thread */
465 wait_handles[0] = __wine_make_process_system();
466 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
467 wait_handles[2] = service_event;
469 TRACE("Starting %d services running as process %d\n",
470 nb_services, GetCurrentProcessId());
472 /* wait for all the threads to pack up and exit */
475 EnterCriticalSection( &service_cs );
476 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
478 if (!services[i]->thread) continue;
479 wait_services[n] = i;
480 wait_handles[n++] = services[i]->thread;
482 LeaveCriticalSection( &service_cs );
484 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
485 if (!ret) /* system process event */
487 TRACE( "last user process exited, shutting down\n" );
488 /* FIXME: we should maybe send a shutdown control to running services */
493 TRACE( "control dispatcher exited, shutting down\n" );
494 /* FIXME: we should maybe send a shutdown control to running services */
499 continue; /* rebuild the list */
503 services[wait_services[ret]]->thread = 0;
504 CloseHandle( wait_handles[ret] );
505 if (n == 4) return TRUE; /* it was the last running thread */
511 /******************************************************************************
512 * StartServiceCtrlDispatcherA [ADVAPI32.@]
514 * See StartServiceCtrlDispatcherW.
516 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
522 TRACE("%p\n", servent);
526 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
529 while (servent[nb_services].lpServiceName) nb_services++;
530 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
532 for (i = 0; i < nb_services; i++)
534 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
535 DWORD sz = FIELD_OFFSET( service_data, name[len] );
536 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
537 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
538 info->proc.a = servent[i].lpServiceProc;
539 info->unicode = FALSE;
543 service_run_main_thread();
548 /******************************************************************************
549 * StartServiceCtrlDispatcherW [ADVAPI32.@]
551 * Connects a process containing one or more services to the service control
555 * servent [I] A list of the service names and service procedures
561 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
567 TRACE("%p\n", servent);
571 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
574 while (servent[nb_services].lpServiceName) nb_services++;
575 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
577 for (i = 0; i < nb_services; i++)
579 DWORD len = strlenW(servent[i].lpServiceName) + 1;
580 DWORD sz = FIELD_OFFSET( service_data, name[len] );
581 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
582 strcpyW(info->name, servent[i].lpServiceName);
583 info->proc.w = servent[i].lpServiceProc;
584 info->unicode = TRUE;
588 service_run_main_thread();
593 /******************************************************************************
594 * LockServiceDatabase [ADVAPI32.@]
596 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
598 SC_RPC_LOCK hLock = NULL;
601 TRACE("%p\n",hSCManager);
605 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
609 err = map_exception_code(GetExceptionCode());
612 if (err != ERROR_SUCCESS)
620 /******************************************************************************
621 * UnlockServiceDatabase [ADVAPI32.@]
623 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
626 SC_RPC_LOCK hRpcLock = ScLock;
628 TRACE("%p\n",ScLock);
632 err = svcctl_UnlockServiceDatabase(&hRpcLock);
636 err = map_exception_code(GetExceptionCode());
639 if (err != ERROR_SUCCESS)
647 /******************************************************************************
648 * SetServiceStatus [ADVAPI32.@]
655 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
659 TRACE("%p %x %x %x %x %x %x %x\n", hService,
660 lpStatus->dwServiceType, lpStatus->dwCurrentState,
661 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
662 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
663 lpStatus->dwWaitHint);
667 err = svcctl_SetServiceStatus( hService, lpStatus );
671 err = map_exception_code(GetExceptionCode());
674 if (err != ERROR_SUCCESS)
680 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
681 CloseServiceHandle((SC_HANDLE)hService);
687 /******************************************************************************
688 * OpenSCManagerA [ADVAPI32.@]
690 * Establish a connection to the service control manager and open its database.
693 * lpMachineName [I] Pointer to machine name string
694 * lpDatabaseName [I] Pointer to database name string
695 * dwDesiredAccess [I] Type of access
698 * Success: A Handle to the service control manager database
701 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
702 DWORD dwDesiredAccess )
704 LPWSTR lpMachineNameW, lpDatabaseNameW;
707 lpMachineNameW = SERV_dup(lpMachineName);
708 lpDatabaseNameW = SERV_dup(lpDatabaseName);
709 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
710 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
711 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
715 /******************************************************************************
716 * OpenSCManagerW [ADVAPI32.@]
718 * See OpenSCManagerA.
720 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
721 DWORD dwDesiredAccess )
726 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
727 debugstr_w(lpDatabaseName), dwDesiredAccess);
731 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
735 r = map_exception_code(GetExceptionCode());
739 if (r!=ERROR_SUCCESS)
745 TRACE("returning %p\n", handle);
749 /******************************************************************************
750 * ControlService [ADVAPI32.@]
752 * Send a control code to a service.
755 * hService [I] Handle of the service control manager database
756 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
757 * lpServiceStatus [O] Destination for the status of the service, if available
764 * Unlike M$' implementation, control requests are not serialized and may be
765 * processed asynchronously.
767 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
768 LPSERVICE_STATUS lpServiceStatus )
772 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
776 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
780 err = map_exception_code(GetExceptionCode());
783 if (err != ERROR_SUCCESS)
792 /******************************************************************************
793 * CloseServiceHandle [ADVAPI32.@]
795 * Close a handle to a service or the service control manager database.
798 * hSCObject [I] Handle to service or service control manager database
805 CloseServiceHandle( SC_HANDLE hSCObject )
809 TRACE("%p\n", hSCObject);
813 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
817 err = map_exception_code(GetExceptionCode());
821 if (err != ERROR_SUCCESS)
830 /******************************************************************************
831 * OpenServiceA [ADVAPI32.@]
833 * Open a handle to a service.
836 * hSCManager [I] Handle of the service control manager database
837 * lpServiceName [I] Name of the service to open
838 * dwDesiredAccess [I] Access required to the service
841 * Success: Handle to the service
844 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
845 DWORD dwDesiredAccess )
847 LPWSTR lpServiceNameW;
850 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
852 lpServiceNameW = SERV_dup(lpServiceName);
853 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
854 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
859 /******************************************************************************
860 * OpenServiceW [ADVAPI32.@]
864 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
865 DWORD dwDesiredAccess)
870 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
874 SetLastError( ERROR_INVALID_HANDLE );
880 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
884 err = map_exception_code(GetExceptionCode());
888 if (err != ERROR_SUCCESS)
894 TRACE("returning %p\n",handle);
898 /******************************************************************************
899 * CreateServiceW [ADVAPI32.@]
902 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
903 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
904 DWORD dwServiceType, DWORD dwStartType,
905 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
906 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
907 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
914 TRACE("%p %s %s\n", hSCManager,
915 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
919 SetLastError( ERROR_INVALID_HANDLE );
924 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
930 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
931 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
932 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
933 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
934 (SC_RPC_HANDLE *)&handle);
938 err = map_exception_code(GetExceptionCode());
942 if (err != ERROR_SUCCESS)
951 /******************************************************************************
952 * CreateServiceA [ADVAPI32.@]
955 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
956 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
957 DWORD dwServiceType, DWORD dwStartType,
958 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
959 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
960 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
963 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
964 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
967 TRACE("%p %s %s\n", hSCManager,
968 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
970 lpServiceNameW = SERV_dup( lpServiceName );
971 lpDisplayNameW = SERV_dup( lpDisplayName );
972 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
973 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
974 lpDependenciesW = SERV_dupmulti( lpDependencies );
975 lpServiceStartNameW = SERV_dup( lpServiceStartName );
976 lpPasswordW = SERV_dup( lpPassword );
978 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
979 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
980 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
981 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
983 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
984 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
985 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
986 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
987 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
988 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
989 HeapFree( GetProcessHeap(), 0, lpPasswordW );
995 /******************************************************************************
996 * DeleteService [ADVAPI32.@]
998 * Delete a service from the service control manager database.
1001 * hService [I] Handle of the service to delete
1007 BOOL WINAPI DeleteService( SC_HANDLE hService )
1013 err = svcctl_DeleteService(hService);
1015 __EXCEPT(rpc_filter)
1017 err = map_exception_code(GetExceptionCode());
1030 /******************************************************************************
1031 * StartServiceA [ADVAPI32.@]
1036 * hService [I] Handle of service
1037 * dwNumServiceArgs [I] Number of arguments
1038 * lpServiceArgVectors [I] Address of array of argument strings
1041 * - NT implements this function using an obscure RPC call.
1042 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1043 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1044 * - This will only work for shared address space. How should the service
1045 * args be transferred when address spaces are separated?
1046 * - Can only start one service at a time.
1047 * - Has no concept of privilege.
1053 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1054 LPCSTR *lpServiceArgVectors )
1056 LPWSTR *lpwstr=NULL;
1060 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1062 if (dwNumServiceArgs)
1063 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1064 dwNumServiceArgs*sizeof(LPWSTR) );
1066 for(i=0; i<dwNumServiceArgs; i++)
1067 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1069 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1071 if (dwNumServiceArgs)
1073 for(i=0; i<dwNumServiceArgs; i++)
1074 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1075 HeapFree(GetProcessHeap(), 0, lpwstr);
1082 /******************************************************************************
1083 * StartServiceW [ADVAPI32.@]
1085 * See StartServiceA.
1087 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1088 LPCWSTR *lpServiceArgVectors)
1092 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1096 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1098 __EXCEPT(rpc_filter)
1100 err = map_exception_code(GetExceptionCode());
1103 if (err != ERROR_SUCCESS)
1112 /******************************************************************************
1113 * QueryServiceStatus [ADVAPI32.@]
1116 * hService [I] Handle to service to get information about
1117 * lpservicestatus [O] buffer to receive the status information for the service
1120 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1121 LPSERVICE_STATUS lpservicestatus)
1123 SERVICE_STATUS_PROCESS SvcStatusData;
1127 TRACE("%p %p\n", hService, lpservicestatus);
1131 SetLastError(ERROR_INVALID_HANDLE);
1134 if (!lpservicestatus)
1136 SetLastError(ERROR_INVALID_ADDRESS);
1140 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1141 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1142 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1147 /******************************************************************************
1148 * QueryServiceStatusEx [ADVAPI32.@]
1150 * Get information about a service.
1153 * hService [I] Handle to service to get information about
1154 * InfoLevel [I] Level of information to get
1155 * lpBuffer [O] Destination for requested information
1156 * cbBufSize [I] Size of lpBuffer in bytes
1157 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1163 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1164 LPBYTE lpBuffer, DWORD cbBufSize,
1165 LPDWORD pcbBytesNeeded)
1169 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1171 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1173 err = ERROR_INVALID_LEVEL;
1175 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1177 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1178 err = ERROR_INSUFFICIENT_BUFFER;
1184 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1186 __EXCEPT(rpc_filter)
1188 err = map_exception_code(GetExceptionCode());
1192 if (err != ERROR_SUCCESS)
1200 /******************************************************************************
1201 * QueryServiceConfigA [ADVAPI32.@]
1203 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1204 DWORD size, LPDWORD needed )
1209 QUERY_SERVICE_CONFIGW *configW;
1211 TRACE("%p %p %d %p\n", hService, config, size, needed);
1213 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1215 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1218 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1219 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1220 if (!ret) goto done;
1222 config->dwServiceType = configW->dwServiceType;
1223 config->dwStartType = configW->dwStartType;
1224 config->dwErrorControl = configW->dwErrorControl;
1225 config->lpBinaryPathName = NULL;
1226 config->lpLoadOrderGroup = NULL;
1227 config->dwTagId = configW->dwTagId;
1228 config->lpDependencies = NULL;
1229 config->lpServiceStartName = NULL;
1230 config->lpDisplayName = NULL;
1232 p = (LPSTR)(config + 1);
1233 n = size - sizeof(*config);
1236 #define MAP_STR(str) \
1240 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1241 if (!sz) goto done; \
1248 MAP_STR( lpBinaryPathName );
1249 MAP_STR( lpLoadOrderGroup );
1250 MAP_STR( lpDependencies );
1251 MAP_STR( lpServiceStartName );
1252 MAP_STR( lpDisplayName );
1255 *needed = p - (LPSTR)config;
1259 HeapFree( GetProcessHeap(), 0, buffer );
1263 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1270 memset(*buf, 0, cb);
1274 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1275 memcpy(*buf, *string_ptr, cb);
1276 MIDL_user_free(*string_ptr);
1279 *string_ptr = (LPWSTR)*buf;
1285 static DWORD size_string(LPCWSTR string)
1287 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1290 /******************************************************************************
1291 * QueryServiceConfigW [ADVAPI32.@]
1294 QueryServiceConfigW( SC_HANDLE hService,
1295 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1296 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1298 QUERY_SERVICE_CONFIGW config;
1303 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1304 cbBufSize, pcbBytesNeeded);
1306 memset(&config, 0, sizeof(config));
1310 err = svcctl_QueryServiceConfigW(hService, &config);
1312 __EXCEPT(rpc_filter)
1314 err = map_exception_code(GetExceptionCode());
1318 if (err != ERROR_SUCCESS)
1320 TRACE("services.exe: error %u\n", err);
1325 /* calculate the size required first */
1326 total = sizeof (QUERY_SERVICE_CONFIGW);
1327 total += size_string(config.lpBinaryPathName);
1328 total += size_string(config.lpLoadOrderGroup);
1329 total += size_string(config.lpDependencies);
1330 total += size_string(config.lpServiceStartName);
1331 total += size_string(config.lpDisplayName);
1333 *pcbBytesNeeded = total;
1335 /* if there's not enough memory, return an error */
1336 if( total > cbBufSize )
1338 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1339 MIDL_user_free(config.lpBinaryPathName);
1340 MIDL_user_free(config.lpLoadOrderGroup);
1341 MIDL_user_free(config.lpDependencies);
1342 MIDL_user_free(config.lpServiceStartName);
1343 MIDL_user_free(config.lpDisplayName);
1347 *lpServiceConfig = config;
1348 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1349 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1350 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1351 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1352 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1353 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1355 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1356 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1357 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1358 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1359 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1364 /******************************************************************************
1365 * QueryServiceConfig2A [ADVAPI32.@]
1368 * observed under win2k:
1369 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1370 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1372 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1373 DWORD size, LPDWORD needed)
1376 LPBYTE bufferW = NULL;
1379 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1381 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1382 if(!ret) goto cleanup;
1385 case SERVICE_CONFIG_DESCRIPTION:
1386 if (buffer && bufferW) {
1387 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1388 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1389 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1391 configA->lpDescription = (LPSTR)(configA + 1);
1392 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1393 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1395 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1397 configA->lpDescription = NULL;
1400 else configA->lpDescription = NULL;
1404 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1410 HeapFree( GetProcessHeap(), 0, bufferW);
1414 /******************************************************************************
1415 * QueryServiceConfig2W [ADVAPI32.@]
1417 * See QueryServiceConfig2A.
1419 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1420 DWORD size, LPDWORD needed)
1424 if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1425 FIXME("Level %d not implemented\n", dwLevel);
1426 SetLastError(ERROR_INVALID_LEVEL);
1430 if(!buffer && size) {
1431 SetLastError(ERROR_INVALID_ADDRESS);
1435 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1439 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1441 __EXCEPT(rpc_filter)
1443 err = map_exception_code(GetExceptionCode());
1447 if (err != ERROR_SUCCESS)
1449 SetLastError( err );
1455 case SERVICE_CONFIG_DESCRIPTION:
1458 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1459 if (descr->lpDescription) /* make it an absolute pointer */
1460 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1468 /******************************************************************************
1469 * EnumServicesStatusA [ADVAPI32.@]
1472 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1473 services, DWORD size, LPDWORD needed, LPDWORD returned,
1474 LPDWORD resume_handle )
1478 ENUM_SERVICE_STATUSW *servicesW = NULL;
1482 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1483 returned, resume_handle);
1485 sz = max( 2 * size, sizeof(*servicesW) );
1486 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1488 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1492 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1493 if (!ret) goto done;
1495 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1496 n = size - (p - (char *)services);
1498 for (i = 0; i < *returned; i++)
1500 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1502 services[i].lpServiceName = p;
1505 if (servicesW[i].lpDisplayName)
1507 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1509 services[i].lpDisplayName = p;
1513 else services[i].lpDisplayName = NULL;
1514 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1520 HeapFree( GetProcessHeap(), 0, servicesW );
1524 /******************************************************************************
1525 * EnumServicesStatusW [ADVAPI32.@]
1528 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1529 services, DWORD size, LPDWORD needed, LPDWORD returned,
1530 LPDWORD resume_handle )
1533 ENUM_SERVICE_STATUSW dummy_status;
1535 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1536 returned, resume_handle);
1539 FIXME("resume handle not supported\n");
1543 SetLastError( ERROR_INVALID_HANDLE );
1547 /* make sure we pass a valid pointer */
1548 if (!services || size < sizeof(*services))
1550 services = &dummy_status;
1551 size = sizeof(dummy_status);
1556 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1558 __EXCEPT(rpc_filter)
1560 err = map_exception_code( GetExceptionCode() );
1564 if (err != ERROR_SUCCESS)
1566 SetLastError( err );
1570 for (i = 0; i < *returned; i++)
1572 /* convert buffer offsets into pointers */
1573 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1574 if (services[i].lpDisplayName)
1575 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1581 /******************************************************************************
1582 * EnumServicesStatusExA [ADVAPI32.@]
1585 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1586 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1587 LPDWORD resume_handle, LPCSTR group )
1591 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1592 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1593 WCHAR *groupW = NULL;
1597 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1598 size, needed, returned, resume_handle, debugstr_a(group));
1600 sz = max( 2 * size, sizeof(*servicesW) );
1601 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1603 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1608 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1609 if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1611 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1612 HeapFree( GetProcessHeap(), 0, servicesW );
1615 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1618 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1619 needed, returned, resume_handle, groupW );
1620 if (!ret) goto done;
1622 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1623 n = size - (p - (char *)services);
1625 for (i = 0; i < *returned; i++)
1627 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1629 services[i].lpServiceName = p;
1632 if (servicesW[i].lpDisplayName)
1634 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1636 services[i].lpDisplayName = p;
1640 else services[i].lpDisplayName = NULL;
1641 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1647 HeapFree( GetProcessHeap(), 0, servicesW );
1648 HeapFree( GetProcessHeap(), 0, groupW );
1652 /******************************************************************************
1653 * EnumServicesStatusExW [ADVAPI32.@]
1656 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1657 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1658 LPDWORD resume_handle, LPCWSTR group )
1661 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1662 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1664 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1665 size, needed, returned, resume_handle, debugstr_w(group));
1668 FIXME("resume handle not supported\n");
1670 if (level != SC_ENUM_PROCESS_INFO)
1672 SetLastError( ERROR_INVALID_LEVEL );
1677 SetLastError( ERROR_INVALID_HANDLE );
1681 /* make sure we pass a valid buffer pointer */
1682 if (!services || size < sizeof(*services))
1684 buffer = (BYTE *)&dummy_status;
1685 size = sizeof(dummy_status);
1690 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1693 __EXCEPT(rpc_filter)
1695 err = map_exception_code( GetExceptionCode() );
1699 if (err != ERROR_SUCCESS)
1701 SetLastError( err );
1705 for (i = 0; i < *returned; i++)
1707 /* convert buffer offsets into pointers */
1708 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1709 if (services[i].lpDisplayName)
1710 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1716 /******************************************************************************
1717 * GetServiceKeyNameA [ADVAPI32.@]
1719 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1720 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1722 LPWSTR lpDisplayNameW, lpServiceNameW;
1726 TRACE("%p %s %p %p\n", hSCManager,
1727 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1729 lpDisplayNameW = SERV_dup(lpDisplayName);
1731 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1733 lpServiceNameW = NULL;
1735 sizeW = *lpcchBuffer;
1736 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1738 if (lpServiceName && *lpcchBuffer)
1739 lpServiceName[0] = 0;
1740 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1744 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1745 *lpcchBuffer, NULL, NULL ))
1747 if (*lpcchBuffer && lpServiceName)
1748 lpServiceName[0] = 0;
1749 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1753 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1757 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1758 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1762 /******************************************************************************
1763 * GetServiceKeyNameW [ADVAPI32.@]
1765 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1766 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1772 TRACE("%p %s %p %p\n", hSCManager,
1773 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1777 SetLastError( ERROR_INVALID_HANDLE );
1781 /* provide a buffer if the caller didn't */
1782 if (!lpServiceName || *lpcchBuffer < 2)
1784 lpServiceName = buffer;
1785 /* A size of 1 would be enough, but tests show that Windows returns 2,
1786 * probably because of a WCHAR/bytes mismatch in their code.
1791 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1792 * includes the nul-terminator on input. */
1793 size = *lpcchBuffer - 1;
1797 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1800 __EXCEPT(rpc_filter)
1802 err = map_exception_code(GetExceptionCode());
1806 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1807 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1808 *lpcchBuffer = size;
1812 return err == ERROR_SUCCESS;
1815 /******************************************************************************
1816 * QueryServiceLockStatusA [ADVAPI32.@]
1818 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1819 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1820 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1822 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1827 /******************************************************************************
1828 * QueryServiceLockStatusW [ADVAPI32.@]
1830 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1831 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1832 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1834 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1839 /******************************************************************************
1840 * GetServiceDisplayNameA [ADVAPI32.@]
1842 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1843 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1845 LPWSTR lpServiceNameW, lpDisplayNameW;
1849 TRACE("%p %s %p %p\n", hSCManager,
1850 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1852 lpServiceNameW = SERV_dup(lpServiceName);
1854 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1856 lpDisplayNameW = NULL;
1858 sizeW = *lpcchBuffer;
1859 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1861 if (lpDisplayName && *lpcchBuffer)
1862 lpDisplayName[0] = 0;
1863 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1867 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1868 *lpcchBuffer, NULL, NULL ))
1870 if (*lpcchBuffer && lpDisplayName)
1871 lpDisplayName[0] = 0;
1872 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1876 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1877 * (but if the function succeeded it means that is a good upper estimation of the size) */
1881 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1882 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1886 /******************************************************************************
1887 * GetServiceDisplayNameW [ADVAPI32.@]
1889 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1890 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1896 TRACE("%p %s %p %p\n", hSCManager,
1897 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1901 SetLastError( ERROR_INVALID_HANDLE );
1905 /* provide a buffer if the caller didn't */
1906 if (!lpDisplayName || *lpcchBuffer < 2)
1908 lpDisplayName = buffer;
1909 /* A size of 1 would be enough, but tests show that Windows returns 2,
1910 * probably because of a WCHAR/bytes mismatch in their code.
1915 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1916 * includes the nul-terminator on input. */
1917 size = *lpcchBuffer - 1;
1921 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
1924 __EXCEPT(rpc_filter)
1926 err = map_exception_code(GetExceptionCode());
1930 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1931 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1932 *lpcchBuffer = size;
1936 return err == ERROR_SUCCESS;
1939 /******************************************************************************
1940 * ChangeServiceConfigW [ADVAPI32.@]
1942 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1943 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1944 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1945 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1950 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1951 hService, dwServiceType, dwStartType, dwErrorControl,
1952 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1953 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1954 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1956 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
1960 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
1961 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
1962 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
1963 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
1965 __EXCEPT(rpc_filter)
1967 err = map_exception_code(GetExceptionCode());
1971 if (err != ERROR_SUCCESS)
1974 return err == ERROR_SUCCESS;
1977 /******************************************************************************
1978 * ChangeServiceConfigA [ADVAPI32.@]
1980 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1981 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1982 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1983 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1985 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1986 LPWSTR wServiceStartName, wPassword, wDisplayName;
1989 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1990 hService, dwServiceType, dwStartType, dwErrorControl,
1991 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1992 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1993 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1995 wBinaryPathName = SERV_dup( lpBinaryPathName );
1996 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
1997 wDependencies = SERV_dupmulti( lpDependencies );
1998 wServiceStartName = SERV_dup( lpServiceStartName );
1999 wPassword = SERV_dup( lpPassword );
2000 wDisplayName = SERV_dup( lpDisplayName );
2002 r = ChangeServiceConfigW( hService, dwServiceType,
2003 dwStartType, dwErrorControl, wBinaryPathName,
2004 wLoadOrderGroup, lpdwTagId, wDependencies,
2005 wServiceStartName, wPassword, wDisplayName);
2007 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2008 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2009 HeapFree( GetProcessHeap(), 0, wDependencies );
2010 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2011 HeapFree( GetProcessHeap(), 0, wPassword );
2012 HeapFree( GetProcessHeap(), 0, wDisplayName );
2017 /******************************************************************************
2018 * ChangeServiceConfig2A [ADVAPI32.@]
2020 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2025 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2027 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2029 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2030 SERVICE_DESCRIPTIONW sdw;
2032 sdw.lpDescription = SERV_dup( sd->lpDescription );
2034 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2036 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2038 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2040 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2041 SERVICE_FAILURE_ACTIONSW faw;
2043 faw.dwResetPeriod = fa->dwResetPeriod;
2044 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2045 faw.lpCommand = SERV_dup( fa->lpCommand );
2046 faw.cActions = fa->cActions;
2047 faw.lpsaActions = fa->lpsaActions;
2049 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2051 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2052 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2055 SetLastError( ERROR_INVALID_PARAMETER );
2060 /******************************************************************************
2061 * ChangeServiceConfig2W [ADVAPI32.@]
2063 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2070 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2072 __EXCEPT(rpc_filter)
2074 err = map_exception_code(GetExceptionCode());
2078 if (err != ERROR_SUCCESS)
2081 return err == ERROR_SUCCESS;
2084 /******************************************************************************
2085 * QueryServiceObjectSecurity [ADVAPI32.@]
2087 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2088 SECURITY_INFORMATION dwSecurityInformation,
2089 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2090 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2092 SECURITY_DESCRIPTOR descriptor;
2097 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2098 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2100 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2101 FIXME("information %d not supported\n", dwSecurityInformation);
2103 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2105 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2106 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2109 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2110 *pcbBytesNeeded = size;
2114 /******************************************************************************
2115 * SetServiceObjectSecurity [ADVAPI32.@]
2117 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2118 SECURITY_INFORMATION dwSecurityInformation,
2119 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2121 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2125 /******************************************************************************
2126 * SetServiceBits [ADVAPI32.@]
2128 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2129 DWORD dwServiceBits,
2131 BOOL bUpdateImmediately)
2133 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2134 bSetBitsOn, bUpdateImmediately);
2138 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2139 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2141 LPHANDLER_FUNCTION func = context;
2144 return ERROR_SUCCESS;
2147 /******************************************************************************
2148 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2150 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2152 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2155 /******************************************************************************
2156 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2158 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2160 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2163 /******************************************************************************
2164 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2166 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2169 SERVICE_STATUS_HANDLE ret;
2171 nameW = SERV_dup(name);
2172 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2173 HeapFree( GetProcessHeap(), 0, nameW );
2177 /******************************************************************************
2178 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2180 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2181 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2183 service_data *service;
2184 SC_HANDLE hService = 0;
2187 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2189 EnterCriticalSection( &service_cs );
2190 if ((service = find_service_by_name( lpServiceName )))
2192 service->handler = lpHandlerProc;
2193 service->context = lpContext;
2194 hService = service->handle;
2197 LeaveCriticalSection( &service_cs );
2199 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2201 return (SERVICE_STATUS_HANDLE)hService;
2204 /******************************************************************************
2205 * EnumDependentServicesA [ADVAPI32.@]
2207 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2208 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2209 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2211 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2212 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2214 *lpServicesReturned = 0;
2218 /******************************************************************************
2219 * EnumDependentServicesW [ADVAPI32.@]
2221 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2222 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2223 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2225 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2226 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2228 *lpServicesReturned = 0;