mlang: Added IMLangConvertCharset stub.
[wine.git] / dlls / advapi32 / service.c
blobf69e78f2943a2f4d5013287aa7cac958dfc01942
1 /*
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
23 #include "config.h"
24 #include "wine/port.h"
26 #include <stdarg.h>
27 #include <string.h>
28 #include <time.h>
29 #include <assert.h>
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winsvc.h"
34 #include "winerror.h"
35 #include "winreg.h"
36 #include "wine/unicode.h"
37 #include "wine/debug.h"
38 #include "winternl.h"
39 #include "lmcons.h"
40 #include "lmserver.h"
42 #include "svcctl.h"
44 #include "advapi32_misc.h"
46 #include "wine/exception.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(service);
50 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
52 return HeapAlloc(GetProcessHeap(), 0, len);
55 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
57 HeapFree(GetProcessHeap(), 0, ptr);
60 typedef struct service_data_t
62 LPHANDLER_FUNCTION_EX handler;
63 LPVOID context;
64 HANDLE thread;
65 SC_HANDLE handle;
66 SC_HANDLE full_access_handle;
67 BOOL unicode : 1;
68 union {
69 LPSERVICE_MAIN_FUNCTIONA a;
70 LPSERVICE_MAIN_FUNCTIONW w;
71 } proc;
72 LPWSTR args;
73 WCHAR name[1];
74 } service_data;
76 static CRITICAL_SECTION service_cs;
77 static CRITICAL_SECTION_DEBUG service_cs_debug =
79 0, 0, &service_cs,
80 { &service_cs_debug.ProcessLocksList,
81 &service_cs_debug.ProcessLocksList },
82 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
84 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
86 static service_data **services;
87 static unsigned int nb_services;
88 static HANDLE service_event;
90 extern HANDLE CDECL __wine_make_process_system(void);
92 /******************************************************************************
93 * String management functions (same behaviour as strdup)
94 * NOTE: the caller of those functions is responsible for calling HeapFree
95 * in order to release the memory allocated by those functions.
97 LPWSTR SERV_dup( LPCSTR str )
99 UINT len;
100 LPWSTR wstr;
102 if( !str )
103 return NULL;
104 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
105 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
106 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
107 return wstr;
110 static inline LPWSTR SERV_dupmulti(LPCSTR str)
112 UINT len = 0, n = 0;
113 LPWSTR wstr;
115 if( !str )
116 return NULL;
117 do {
118 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
119 n += (strlen( &str[n] ) + 1);
120 } while (str[n]);
121 len++;
122 n++;
124 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
125 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
126 return wstr;
129 static inline DWORD multisz_cb(LPCWSTR wmultisz)
131 const WCHAR *wptr = wmultisz;
133 if (wmultisz == NULL)
134 return 0;
136 while (*wptr)
137 wptr += lstrlenW(wptr)+1;
138 return (wptr - wmultisz + 1)*sizeof(WCHAR);
141 /******************************************************************************
142 * RPC connection with services.exe
145 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
147 WCHAR transport[] = SVCCTL_TRANSPORT;
148 WCHAR endpoint[] = SVCCTL_ENDPOINT;
149 RPC_WSTR binding_str;
150 RPC_STATUS status;
151 handle_t rpc_handle;
153 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
154 if (status != RPC_S_OK)
156 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
157 return NULL;
160 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
161 RpcStringFreeW(&binding_str);
163 if (status != RPC_S_OK)
165 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
166 return NULL;
169 return rpc_handle;
172 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
174 RpcBindingFree(&h);
177 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
179 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
182 static DWORD map_exception_code(DWORD exception_code)
184 switch (exception_code)
186 case RPC_X_NULL_REF_POINTER:
187 return ERROR_INVALID_ADDRESS;
188 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
189 case RPC_X_BYTE_COUNT_TOO_SMALL:
190 return ERROR_INVALID_PARAMETER;
191 case RPC_S_INVALID_BINDING:
192 case RPC_X_SS_IN_NULL_CONTEXT:
193 return ERROR_INVALID_HANDLE;
194 default:
195 return exception_code;
199 /******************************************************************************
200 * Service IPC functions
202 static LPWSTR service_get_pipe_name(void)
204 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
205 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
206 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
207 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
208 'C','o','n','t','r','o','l','\\',
209 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
210 LPWSTR name;
211 DWORD len;
212 HKEY service_current_key;
213 DWORD service_current;
214 LONG ret;
215 DWORD type;
217 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
218 KEY_QUERY_VALUE, &service_current_key);
219 if (ret != ERROR_SUCCESS)
220 return NULL;
221 len = sizeof(service_current);
222 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
223 (BYTE *)&service_current, &len);
224 RegCloseKey(service_current_key);
225 if (ret != ERROR_SUCCESS || type != REG_DWORD)
226 return NULL;
227 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
228 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
229 if (!name)
230 return NULL;
231 snprintfW(name, len, format, service_current);
232 return name;
235 static HANDLE service_open_pipe(void)
237 LPWSTR szPipe = service_get_pipe_name();
238 HANDLE handle = INVALID_HANDLE_VALUE;
240 do {
241 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
242 0, NULL, OPEN_ALWAYS, 0, NULL);
243 if (handle != INVALID_HANDLE_VALUE)
244 break;
245 if (GetLastError() != ERROR_PIPE_BUSY)
246 break;
247 } while (WaitNamedPipeW(szPipe, NMPWAIT_USE_DEFAULT_WAIT));
248 HeapFree(GetProcessHeap(), 0, szPipe);
250 return handle;
253 static service_data *find_service_by_name( const WCHAR *name )
255 unsigned int i;
257 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
258 return services[0];
259 for (i = 0; i < nb_services; i++)
260 if (!strcmpiW( name, services[i]->name )) return services[i];
261 return NULL;
264 /******************************************************************************
265 * service_thread
267 * Call into the main service routine provided by StartServiceCtrlDispatcher.
269 static DWORD WINAPI service_thread(LPVOID arg)
271 service_data *info = arg;
272 LPWSTR str = info->args;
273 DWORD argc = 0, len = 0;
275 TRACE("%p\n", arg);
277 while (str[len])
279 len += strlenW(&str[len]) + 1;
280 argc++;
282 len++;
284 if (info->unicode)
286 LPWSTR *argv, p;
288 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
289 for (argc=0, p=str; *p; p += strlenW(p) + 1)
290 argv[argc++] = p;
291 argv[argc] = NULL;
293 info->proc.w(argc, argv);
294 HeapFree(GetProcessHeap(), 0, argv);
296 else
298 LPSTR strA, *argv, p;
299 DWORD lenA;
301 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
302 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
303 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
305 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
306 for (argc=0, p=strA; *p; p += strlen(p) + 1)
307 argv[argc++] = p;
308 argv[argc] = NULL;
310 info->proc.a(argc, argv);
311 HeapFree(GetProcessHeap(), 0, argv);
312 HeapFree(GetProcessHeap(), 0, strA);
314 return 0;
317 /******************************************************************************
318 * service_handle_start
320 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
322 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
324 if (service->thread)
326 WARN("service is not stopped\n");
327 return ERROR_SERVICE_ALREADY_RUNNING;
330 HeapFree(GetProcessHeap(), 0, service->args);
331 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
332 memcpy( service->args, data, count * sizeof(WCHAR) );
333 service->thread = CreateThread( NULL, 0, service_thread,
334 service, 0, NULL );
335 SetEvent( service_event ); /* notify the main loop */
336 return 0;
339 /******************************************************************************
340 * service_handle_control
342 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
344 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
346 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
348 if (service->handler)
349 ret = service->handler(dwControl, 0, NULL, service->context);
350 return ret;
353 /******************************************************************************
354 * service_control_dispatcher
356 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
358 SC_HANDLE manager;
359 HANDLE pipe;
361 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
363 ERR("failed to open service manager error %u\n", GetLastError());
364 return 0;
367 pipe = service_open_pipe();
369 if (pipe==INVALID_HANDLE_VALUE)
371 WARN("failed to create control pipe error = %d\n", GetLastError());
372 return 0;
375 /* dispatcher loop */
376 while (1)
378 service_data *service;
379 service_start_info info;
380 WCHAR *data = NULL;
381 BOOL r;
382 DWORD data_size = 0, count, result;
384 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
385 if (!r)
387 if (GetLastError() != ERROR_BROKEN_PIPE)
388 ERR( "pipe read failed error %u\n", GetLastError() );
389 break;
391 if (count != FIELD_OFFSET(service_start_info,data))
393 ERR( "partial pipe read %u\n", count );
394 break;
396 if (count < info.total_size)
398 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
399 data = HeapAlloc( GetProcessHeap(), 0, data_size );
400 r = ReadFile( pipe, data, data_size, &count, NULL );
401 if (!r)
403 if (GetLastError() != ERROR_BROKEN_PIPE)
404 ERR( "pipe read failed error %u\n", GetLastError() );
405 break;
407 if (count != data_size)
409 ERR( "partial pipe read %u/%u\n", count, data_size );
410 break;
414 /* find the service */
416 if (!(service = find_service_by_name( data )))
418 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
419 result = ERROR_INVALID_PARAMETER;
420 goto done;
423 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
425 /* handle the request */
426 switch (info.cmd)
428 case WINESERV_STARTINFO:
429 if (!service->handle)
431 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )) ||
432 !(service->full_access_handle = OpenServiceW( manager, data, GENERIC_READ|GENERIC_WRITE )))
433 FIXME( "failed to open service %s\n", debugstr_w(data) );
435 result = service_handle_start(service, data, data_size / sizeof(WCHAR));
436 break;
437 case WINESERV_SENDCONTROL:
438 result = service_handle_control(service, info.control);
439 break;
440 default:
441 ERR("received invalid command %u\n", info.cmd);
442 result = ERROR_INVALID_PARAMETER;
443 break;
446 done:
447 WriteFile(pipe, &result, sizeof(result), &count, NULL);
448 HeapFree( GetProcessHeap(), 0, data );
451 CloseHandle(pipe);
452 CloseServiceHandle( manager );
453 return 1;
456 /******************************************************************************
457 * service_run_main_thread
459 static BOOL service_run_main_thread(void)
461 DWORD i, n, ret;
462 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
463 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
465 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
467 /* FIXME: service_control_dispatcher should be merged into the main thread */
468 wait_handles[0] = __wine_make_process_system();
469 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
470 wait_handles[2] = service_event;
472 TRACE("Starting %d services running as process %d\n",
473 nb_services, GetCurrentProcessId());
475 /* wait for all the threads to pack up and exit */
476 for (;;)
478 EnterCriticalSection( &service_cs );
479 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
481 if (!services[i]->thread) continue;
482 wait_services[n] = i;
483 wait_handles[n++] = services[i]->thread;
485 LeaveCriticalSection( &service_cs );
487 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
488 if (!ret) /* system process event */
490 SERVICE_STATUS st;
491 SERVICE_PRESHUTDOWN_INFO spi;
492 DWORD timeout = 5000;
493 BOOL res;
495 EnterCriticalSection( &service_cs );
496 n = 0;
497 for (i = 0; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
499 if (!services[i]->thread) continue;
501 res = QueryServiceStatus(services[i]->full_access_handle, &st);
502 ret = ERROR_SUCCESS;
503 if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_PRESHUTDOWN))
505 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
506 (LPBYTE)&spi, sizeof(spi), &i );
507 if (res)
509 FIXME("service should be able to delay shutdown\n");
510 timeout += spi.dwPreshutdownTimeout;
511 ret = service_handle_control( services[i], SERVICE_CONTROL_PRESHUTDOWN );
512 wait_handles[n++] = services[i]->thread;
515 else if (res && (st.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN))
517 ret = service_handle_control( services[i], SERVICE_CONTROL_SHUTDOWN );
518 wait_handles[n++] = services[i]->thread;
521 LeaveCriticalSection( &service_cs );
523 TRACE("last user process exited, shutting down (timeout: %d)\n", timeout);
524 WaitForMultipleObjects( n, wait_handles, TRUE, timeout );
525 ExitProcess(0);
527 else if (ret == 1)
529 TRACE( "control dispatcher exited, shutting down\n" );
530 /* FIXME: we should maybe send a shutdown control to running services */
531 ExitProcess(0);
533 else if (ret == 2)
535 continue; /* rebuild the list */
537 else if (ret < n)
539 services[wait_services[ret]]->thread = 0;
540 CloseHandle( wait_handles[ret] );
541 if (n == 4) return TRUE; /* it was the last running thread */
543 else return FALSE;
547 /******************************************************************************
548 * StartServiceCtrlDispatcherA [ADVAPI32.@]
550 * See StartServiceCtrlDispatcherW.
552 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
554 service_data *info;
555 unsigned int i;
556 BOOL ret = TRUE;
558 TRACE("%p\n", servent);
560 if (nb_services)
562 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
563 return FALSE;
565 while (servent[nb_services].lpServiceName) nb_services++;
566 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
568 for (i = 0; i < nb_services; i++)
570 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
571 DWORD sz = FIELD_OFFSET( service_data, name[len] );
572 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
573 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
574 info->proc.a = servent[i].lpServiceProc;
575 info->unicode = FALSE;
576 services[i] = info;
579 service_run_main_thread();
581 return ret;
584 /******************************************************************************
585 * StartServiceCtrlDispatcherW [ADVAPI32.@]
587 * Connects a process containing one or more services to the service control
588 * manager.
590 * PARAMS
591 * servent [I] A list of the service names and service procedures
593 * RETURNS
594 * Success: TRUE.
595 * Failure: FALSE.
597 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
599 service_data *info;
600 unsigned int i;
601 BOOL ret = TRUE;
603 TRACE("%p\n", servent);
605 if (nb_services)
607 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
608 return FALSE;
610 while (servent[nb_services].lpServiceName) nb_services++;
611 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
613 for (i = 0; i < nb_services; i++)
615 DWORD len = strlenW(servent[i].lpServiceName) + 1;
616 DWORD sz = FIELD_OFFSET( service_data, name[len] );
617 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
618 strcpyW(info->name, servent[i].lpServiceName);
619 info->proc.w = servent[i].lpServiceProc;
620 info->unicode = TRUE;
621 services[i] = info;
624 service_run_main_thread();
626 return ret;
629 /******************************************************************************
630 * LockServiceDatabase [ADVAPI32.@]
632 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
634 SC_RPC_LOCK hLock = NULL;
635 DWORD err;
637 TRACE("%p\n",hSCManager);
639 __TRY
641 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
643 __EXCEPT(rpc_filter)
645 err = map_exception_code(GetExceptionCode());
647 __ENDTRY
648 if (err != ERROR_SUCCESS)
650 SetLastError(err);
651 return NULL;
653 return hLock;
656 /******************************************************************************
657 * UnlockServiceDatabase [ADVAPI32.@]
659 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
661 DWORD err;
662 SC_RPC_LOCK hRpcLock = ScLock;
664 TRACE("%p\n",ScLock);
666 __TRY
668 err = svcctl_UnlockServiceDatabase(&hRpcLock);
670 __EXCEPT(rpc_filter)
672 err = map_exception_code(GetExceptionCode());
674 __ENDTRY
675 if (err != ERROR_SUCCESS)
677 SetLastError(err);
678 return FALSE;
680 return TRUE;
683 /******************************************************************************
684 * SetServiceStatus [ADVAPI32.@]
686 * PARAMS
687 * hService []
688 * lpStatus []
690 BOOL WINAPI
691 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
693 DWORD err;
695 TRACE("%p %x %x %x %x %x %x %x\n", hService,
696 lpStatus->dwServiceType, lpStatus->dwCurrentState,
697 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
698 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
699 lpStatus->dwWaitHint);
701 __TRY
703 err = svcctl_SetServiceStatus( hService, lpStatus );
705 __EXCEPT(rpc_filter)
707 err = map_exception_code(GetExceptionCode());
709 __ENDTRY
710 if (err != ERROR_SUCCESS)
712 SetLastError(err);
713 return FALSE;
716 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
717 CloseServiceHandle((SC_HANDLE)hService);
719 return TRUE;
723 /******************************************************************************
724 * OpenSCManagerA [ADVAPI32.@]
726 * Establish a connection to the service control manager and open its database.
728 * PARAMS
729 * lpMachineName [I] Pointer to machine name string
730 * lpDatabaseName [I] Pointer to database name string
731 * dwDesiredAccess [I] Type of access
733 * RETURNS
734 * Success: A Handle to the service control manager database
735 * Failure: NULL
737 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
738 DWORD dwDesiredAccess )
740 LPWSTR lpMachineNameW, lpDatabaseNameW;
741 SC_HANDLE ret;
743 lpMachineNameW = SERV_dup(lpMachineName);
744 lpDatabaseNameW = SERV_dup(lpDatabaseName);
745 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
746 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
747 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
748 return ret;
751 /******************************************************************************
752 * OpenSCManagerW [ADVAPI32.@]
754 * See OpenSCManagerA.
756 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
757 DWORD dwDesiredAccess )
759 SC_HANDLE handle = 0;
760 LONG r;
762 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
763 debugstr_w(lpDatabaseName), dwDesiredAccess);
765 __TRY
767 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
769 __EXCEPT(rpc_filter)
771 r = map_exception_code(GetExceptionCode());
773 __ENDTRY
775 if (r!=ERROR_SUCCESS)
777 SetLastError( r );
778 handle = 0;
781 TRACE("returning %p\n", handle);
782 return handle;
785 /******************************************************************************
786 * ControlService [ADVAPI32.@]
788 * Send a control code to a service.
790 * PARAMS
791 * hService [I] Handle of the service control manager database
792 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
793 * lpServiceStatus [O] Destination for the status of the service, if available
795 * RETURNS
796 * Success: TRUE.
797 * Failure: FALSE.
799 * BUGS
800 * Unlike M$' implementation, control requests are not serialized and may be
801 * processed asynchronously.
803 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
804 LPSERVICE_STATUS lpServiceStatus )
806 DWORD err;
808 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
810 __TRY
812 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
814 __EXCEPT(rpc_filter)
816 err = map_exception_code(GetExceptionCode());
818 __ENDTRY
819 if (err != ERROR_SUCCESS)
821 SetLastError(err);
822 return FALSE;
825 return TRUE;
828 /******************************************************************************
829 * CloseServiceHandle [ADVAPI32.@]
831 * Close a handle to a service or the service control manager database.
833 * PARAMS
834 * hSCObject [I] Handle to service or service control manager database
836 * RETURNS
837 * Success: TRUE
838 * Failure: FALSE
840 BOOL WINAPI
841 CloseServiceHandle( SC_HANDLE hSCObject )
843 DWORD err;
845 TRACE("%p\n", hSCObject);
847 __TRY
849 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
851 __EXCEPT(rpc_filter)
853 err = map_exception_code(GetExceptionCode());
855 __ENDTRY
857 if (err != ERROR_SUCCESS)
859 SetLastError(err);
860 return FALSE;
862 return TRUE;
866 /******************************************************************************
867 * OpenServiceA [ADVAPI32.@]
869 * Open a handle to a service.
871 * PARAMS
872 * hSCManager [I] Handle of the service control manager database
873 * lpServiceName [I] Name of the service to open
874 * dwDesiredAccess [I] Access required to the service
876 * RETURNS
877 * Success: Handle to the service
878 * Failure: NULL
880 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
881 DWORD dwDesiredAccess )
883 LPWSTR lpServiceNameW;
884 SC_HANDLE ret;
886 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
888 lpServiceNameW = SERV_dup(lpServiceName);
889 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
890 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
891 return ret;
895 /******************************************************************************
896 * OpenServiceW [ADVAPI32.@]
898 * See OpenServiceA.
900 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
901 DWORD dwDesiredAccess)
903 SC_HANDLE handle = 0;
904 DWORD err;
906 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
908 if (!hSCManager)
910 SetLastError( ERROR_INVALID_HANDLE );
911 return 0;
914 __TRY
916 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
918 __EXCEPT(rpc_filter)
920 err = map_exception_code(GetExceptionCode());
922 __ENDTRY
924 if (err != ERROR_SUCCESS)
926 SetLastError(err);
927 handle = 0;
930 TRACE("returning %p\n",handle);
931 return handle;
934 /******************************************************************************
935 * CreateServiceW [ADVAPI32.@]
937 SC_HANDLE WINAPI
938 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
939 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
940 DWORD dwServiceType, DWORD dwStartType,
941 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
942 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
943 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
944 LPCWSTR lpPassword )
946 SC_HANDLE handle = 0;
947 DWORD err;
948 SIZE_T passwdlen;
950 TRACE("%p %s %s\n", hSCManager,
951 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
953 if (!hSCManager)
955 SetLastError( ERROR_INVALID_HANDLE );
956 return 0;
959 if (lpPassword)
960 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
961 else
962 passwdlen = 0;
964 __TRY
966 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
967 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
968 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
969 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
970 (SC_RPC_HANDLE *)&handle);
972 __EXCEPT(rpc_filter)
974 err = map_exception_code(GetExceptionCode());
976 __ENDTRY
978 if (err != ERROR_SUCCESS)
980 SetLastError(err);
981 handle = 0;
983 return handle;
987 /******************************************************************************
988 * CreateServiceA [ADVAPI32.@]
990 SC_HANDLE WINAPI
991 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
992 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
993 DWORD dwServiceType, DWORD dwStartType,
994 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
995 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
996 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
997 LPCSTR lpPassword )
999 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
1000 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
1001 SC_HANDLE r;
1003 TRACE("%p %s %s\n", hSCManager,
1004 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
1006 lpServiceNameW = SERV_dup( lpServiceName );
1007 lpDisplayNameW = SERV_dup( lpDisplayName );
1008 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
1009 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
1010 lpDependenciesW = SERV_dupmulti( lpDependencies );
1011 lpServiceStartNameW = SERV_dup( lpServiceStartName );
1012 lpPasswordW = SERV_dup( lpPassword );
1014 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
1015 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
1016 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
1017 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
1019 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
1020 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
1021 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
1022 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
1023 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
1024 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
1025 HeapFree( GetProcessHeap(), 0, lpPasswordW );
1027 return r;
1031 /******************************************************************************
1032 * DeleteService [ADVAPI32.@]
1034 * Delete a service from the service control manager database.
1036 * PARAMS
1037 * hService [I] Handle of the service to delete
1039 * RETURNS
1040 * Success: TRUE
1041 * Failure: FALSE
1043 BOOL WINAPI DeleteService( SC_HANDLE hService )
1045 DWORD err;
1047 __TRY
1049 err = svcctl_DeleteService(hService);
1051 __EXCEPT(rpc_filter)
1053 err = map_exception_code(GetExceptionCode());
1055 __ENDTRY
1056 if (err != 0)
1058 SetLastError(err);
1059 return FALSE;
1062 return TRUE;
1066 /******************************************************************************
1067 * StartServiceA [ADVAPI32.@]
1069 * Start a service
1071 * PARAMS
1072 * hService [I] Handle of service
1073 * dwNumServiceArgs [I] Number of arguments
1074 * lpServiceArgVectors [I] Address of array of argument strings
1076 * NOTES
1077 * - NT implements this function using an obscure RPC call.
1078 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1079 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1080 * - This will only work for shared address space. How should the service
1081 * args be transferred when address spaces are separated?
1082 * - Can only start one service at a time.
1083 * - Has no concept of privilege.
1085 * RETURNS
1086 * Success: TRUE.
1087 * Failure: FALSE
1089 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1090 LPCSTR *lpServiceArgVectors )
1092 LPWSTR *lpwstr=NULL;
1093 unsigned int i;
1094 BOOL r;
1096 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1098 if (dwNumServiceArgs)
1099 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1100 dwNumServiceArgs*sizeof(LPWSTR) );
1102 for(i=0; i<dwNumServiceArgs; i++)
1103 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1105 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1107 if (dwNumServiceArgs)
1109 for(i=0; i<dwNumServiceArgs; i++)
1110 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1111 HeapFree(GetProcessHeap(), 0, lpwstr);
1114 return r;
1118 /******************************************************************************
1119 * StartServiceW [ADVAPI32.@]
1121 * See StartServiceA.
1123 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1124 LPCWSTR *lpServiceArgVectors)
1126 DWORD err;
1128 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1130 __TRY
1132 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1134 __EXCEPT(rpc_filter)
1136 err = map_exception_code(GetExceptionCode());
1138 __ENDTRY
1139 if (err != ERROR_SUCCESS)
1141 SetLastError(err);
1142 return FALSE;
1145 return TRUE;
1148 /******************************************************************************
1149 * QueryServiceStatus [ADVAPI32.@]
1151 * PARAMS
1152 * hService [I] Handle to service to get information about
1153 * lpservicestatus [O] buffer to receive the status information for the service
1156 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1157 LPSERVICE_STATUS lpservicestatus)
1159 SERVICE_STATUS_PROCESS SvcStatusData;
1160 BOOL ret;
1161 DWORD dummy;
1163 TRACE("%p %p\n", hService, lpservicestatus);
1165 if (!hService)
1167 SetLastError(ERROR_INVALID_HANDLE);
1168 return FALSE;
1170 if (!lpservicestatus)
1172 SetLastError(ERROR_INVALID_ADDRESS);
1173 return FALSE;
1176 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1177 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1178 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1179 return ret;
1183 /******************************************************************************
1184 * QueryServiceStatusEx [ADVAPI32.@]
1186 * Get information about a service.
1188 * PARAMS
1189 * hService [I] Handle to service to get information about
1190 * InfoLevel [I] Level of information to get
1191 * lpBuffer [O] Destination for requested information
1192 * cbBufSize [I] Size of lpBuffer in bytes
1193 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1195 * RETURNS
1196 * Success: TRUE
1197 * FAILURE: FALSE
1199 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1200 LPBYTE lpBuffer, DWORD cbBufSize,
1201 LPDWORD pcbBytesNeeded)
1203 DWORD err;
1205 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1207 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1209 err = ERROR_INVALID_LEVEL;
1211 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1213 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1214 err = ERROR_INSUFFICIENT_BUFFER;
1216 else
1218 __TRY
1220 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1222 __EXCEPT(rpc_filter)
1224 err = map_exception_code(GetExceptionCode());
1226 __ENDTRY
1228 if (err != ERROR_SUCCESS)
1230 SetLastError(err);
1231 return FALSE;
1233 return TRUE;
1236 /******************************************************************************
1237 * QueryServiceConfigA [ADVAPI32.@]
1239 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1240 DWORD size, LPDWORD needed )
1242 DWORD n;
1243 LPSTR p, buffer;
1244 BOOL ret;
1245 QUERY_SERVICE_CONFIGW *configW;
1247 TRACE("%p %p %d %p\n", hService, config, size, needed);
1249 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1251 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1252 return FALSE;
1254 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1255 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1256 if (!ret) goto done;
1258 config->dwServiceType = configW->dwServiceType;
1259 config->dwStartType = configW->dwStartType;
1260 config->dwErrorControl = configW->dwErrorControl;
1261 config->lpBinaryPathName = NULL;
1262 config->lpLoadOrderGroup = NULL;
1263 config->dwTagId = configW->dwTagId;
1264 config->lpDependencies = NULL;
1265 config->lpServiceStartName = NULL;
1266 config->lpDisplayName = NULL;
1268 p = (LPSTR)(config + 1);
1269 n = size - sizeof(*config);
1270 ret = FALSE;
1272 #define MAP_STR(str) \
1273 do { \
1274 if (configW->str) \
1276 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1277 if (!sz) goto done; \
1278 config->str = p; \
1279 p += sz; \
1280 n -= sz; \
1282 } while (0)
1284 MAP_STR( lpBinaryPathName );
1285 MAP_STR( lpLoadOrderGroup );
1286 MAP_STR( lpDependencies );
1287 MAP_STR( lpServiceStartName );
1288 MAP_STR( lpDisplayName );
1289 #undef MAP_STR
1291 *needed = p - (LPSTR)config;
1292 ret = TRUE;
1294 done:
1295 HeapFree( GetProcessHeap(), 0, buffer );
1296 return ret;
1299 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1301 DWORD cb;
1303 if (!*string_ptr)
1305 cb = sizeof(WCHAR);
1306 memset(*buf, 0, cb);
1308 else
1310 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1311 memcpy(*buf, *string_ptr, cb);
1312 MIDL_user_free(*string_ptr);
1315 *string_ptr = (LPWSTR)*buf;
1316 *buf += cb;
1318 return cb;
1321 static DWORD size_string(LPCWSTR string)
1323 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1326 /******************************************************************************
1327 * QueryServiceConfigW [ADVAPI32.@]
1329 BOOL WINAPI
1330 QueryServiceConfigW( SC_HANDLE hService,
1331 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1332 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1334 QUERY_SERVICE_CONFIGW config;
1335 DWORD total;
1336 DWORD err;
1337 BYTE *bufpos;
1339 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1340 cbBufSize, pcbBytesNeeded);
1342 memset(&config, 0, sizeof(config));
1344 __TRY
1346 err = svcctl_QueryServiceConfigW(hService, &config);
1348 __EXCEPT(rpc_filter)
1350 err = map_exception_code(GetExceptionCode());
1352 __ENDTRY
1354 if (err != ERROR_SUCCESS)
1356 TRACE("services.exe: error %u\n", err);
1357 SetLastError(err);
1358 return FALSE;
1361 /* calculate the size required first */
1362 total = sizeof (QUERY_SERVICE_CONFIGW);
1363 total += size_string(config.lpBinaryPathName);
1364 total += size_string(config.lpLoadOrderGroup);
1365 total += size_string(config.lpDependencies);
1366 total += size_string(config.lpServiceStartName);
1367 total += size_string(config.lpDisplayName);
1369 *pcbBytesNeeded = total;
1371 /* if there's not enough memory, return an error */
1372 if( total > cbBufSize )
1374 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1375 MIDL_user_free(config.lpBinaryPathName);
1376 MIDL_user_free(config.lpLoadOrderGroup);
1377 MIDL_user_free(config.lpDependencies);
1378 MIDL_user_free(config.lpServiceStartName);
1379 MIDL_user_free(config.lpDisplayName);
1380 return FALSE;
1383 *lpServiceConfig = config;
1384 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1385 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1386 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1387 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1388 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1389 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1391 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1392 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1393 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1394 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1395 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1397 return TRUE;
1400 /******************************************************************************
1401 * QueryServiceConfig2A [ADVAPI32.@]
1403 * Note
1404 * observed under win2k:
1405 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1406 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1408 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1409 DWORD size, LPDWORD needed)
1411 BOOL ret;
1412 LPBYTE bufferW = NULL;
1414 if(buffer && size)
1415 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1417 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1418 if(!ret) goto cleanup;
1420 switch(dwLevel) {
1421 case SERVICE_CONFIG_DESCRIPTION:
1422 if (buffer && bufferW) {
1423 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1424 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1425 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1426 DWORD sz;
1427 configA->lpDescription = (LPSTR)(configA + 1);
1428 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1429 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1430 if (!sz) {
1431 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1432 ret = FALSE;
1433 configA->lpDescription = NULL;
1436 else configA->lpDescription = NULL;
1438 break;
1439 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
1440 if (buffer && bufferW && *needed<=size)
1441 memcpy(buffer, bufferW, *needed);
1442 break;
1443 default:
1444 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1445 ret = FALSE;
1446 break;
1449 cleanup:
1450 HeapFree( GetProcessHeap(), 0, bufferW);
1451 return ret;
1454 /******************************************************************************
1455 * QueryServiceConfig2W [ADVAPI32.@]
1457 * See QueryServiceConfig2A.
1459 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1460 DWORD size, LPDWORD needed)
1462 DWORD err;
1464 if(dwLevel!=SERVICE_CONFIG_DESCRIPTION && dwLevel!=SERVICE_CONFIG_PRESHUTDOWN_INFO) {
1465 FIXME("Level %d not implemented\n", dwLevel);
1466 SetLastError(ERROR_INVALID_LEVEL);
1467 return FALSE;
1470 if(!buffer && size) {
1471 SetLastError(ERROR_INVALID_ADDRESS);
1472 return FALSE;
1475 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1477 __TRY
1479 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1481 __EXCEPT(rpc_filter)
1483 err = map_exception_code(GetExceptionCode());
1485 __ENDTRY
1487 if (err != ERROR_SUCCESS)
1489 SetLastError( err );
1490 return FALSE;
1493 switch (dwLevel)
1495 case SERVICE_CONFIG_DESCRIPTION:
1496 if (buffer)
1498 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1499 if (descr->lpDescription) /* make it an absolute pointer */
1500 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1501 break;
1505 return TRUE;
1508 /******************************************************************************
1509 * EnumServicesStatusA [ADVAPI32.@]
1511 BOOL WINAPI
1512 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1513 services, DWORD size, LPDWORD needed, LPDWORD returned,
1514 LPDWORD resume_handle )
1516 BOOL ret;
1517 unsigned int i;
1518 ENUM_SERVICE_STATUSW *servicesW = NULL;
1519 DWORD sz, n;
1520 char *p;
1522 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1523 returned, resume_handle);
1525 sz = max( 2 * size, sizeof(*servicesW) );
1526 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1528 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1529 return FALSE;
1532 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1533 if (!ret) goto done;
1535 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1536 n = size - (p - (char *)services);
1537 ret = FALSE;
1538 for (i = 0; i < *returned; i++)
1540 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1541 if (!sz) goto done;
1542 services[i].lpServiceName = p;
1543 p += sz;
1544 n -= sz;
1545 if (servicesW[i].lpDisplayName)
1547 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1548 if (!sz) goto done;
1549 services[i].lpDisplayName = p;
1550 p += sz;
1551 n -= sz;
1553 else services[i].lpDisplayName = NULL;
1554 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1557 ret = TRUE;
1559 done:
1560 HeapFree( GetProcessHeap(), 0, servicesW );
1561 return ret;
1564 /******************************************************************************
1565 * EnumServicesStatusW [ADVAPI32.@]
1567 BOOL WINAPI
1568 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1569 services, DWORD size, LPDWORD needed, LPDWORD returned,
1570 LPDWORD resume_handle )
1572 DWORD err, i;
1573 ENUM_SERVICE_STATUSW dummy_status;
1575 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1576 returned, resume_handle);
1578 if (resume_handle)
1579 FIXME("resume handle not supported\n");
1581 if (!hmngr)
1583 SetLastError( ERROR_INVALID_HANDLE );
1584 return FALSE;
1587 /* make sure we pass a valid pointer */
1588 if (!services || size < sizeof(*services))
1590 services = &dummy_status;
1591 size = sizeof(dummy_status);
1594 __TRY
1596 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1598 __EXCEPT(rpc_filter)
1600 err = map_exception_code( GetExceptionCode() );
1602 __ENDTRY
1604 if (err != ERROR_SUCCESS)
1606 SetLastError( err );
1607 return FALSE;
1610 for (i = 0; i < *returned; i++)
1612 /* convert buffer offsets into pointers */
1613 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1614 if (services[i].lpDisplayName)
1615 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1618 return TRUE;
1621 /******************************************************************************
1622 * EnumServicesStatusExA [ADVAPI32.@]
1624 BOOL WINAPI
1625 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1626 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1627 LPDWORD resume_handle, LPCSTR group )
1629 BOOL ret;
1630 unsigned int i;
1631 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1632 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1633 WCHAR *groupW = NULL;
1634 DWORD sz, n;
1635 char *p;
1637 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1638 size, needed, returned, resume_handle, debugstr_a(group));
1640 sz = max( 2 * size, sizeof(*servicesW) );
1641 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1643 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1644 return FALSE;
1646 if (group)
1648 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1649 if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1651 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1652 HeapFree( GetProcessHeap(), 0, servicesW );
1653 return FALSE;
1655 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1658 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1659 needed, returned, resume_handle, groupW );
1660 if (!ret) goto done;
1662 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1663 n = size - (p - (char *)services);
1664 ret = FALSE;
1665 for (i = 0; i < *returned; i++)
1667 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1668 if (!sz) goto done;
1669 services[i].lpServiceName = p;
1670 p += sz;
1671 n -= sz;
1672 if (servicesW[i].lpDisplayName)
1674 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1675 if (!sz) goto done;
1676 services[i].lpDisplayName = p;
1677 p += sz;
1678 n -= sz;
1680 else services[i].lpDisplayName = NULL;
1681 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1684 ret = TRUE;
1686 done:
1687 HeapFree( GetProcessHeap(), 0, servicesW );
1688 HeapFree( GetProcessHeap(), 0, groupW );
1689 return ret;
1692 /******************************************************************************
1693 * EnumServicesStatusExW [ADVAPI32.@]
1695 BOOL WINAPI
1696 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1697 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1698 LPDWORD resume_handle, LPCWSTR group )
1700 DWORD err, i;
1701 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1702 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1704 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1705 size, needed, returned, resume_handle, debugstr_w(group));
1707 if (resume_handle)
1708 FIXME("resume handle not supported\n");
1710 if (level != SC_ENUM_PROCESS_INFO)
1712 SetLastError( ERROR_INVALID_LEVEL );
1713 return FALSE;
1715 if (!hmngr)
1717 SetLastError( ERROR_INVALID_HANDLE );
1718 return FALSE;
1721 /* make sure we pass a valid buffer pointer */
1722 if (!services || size < sizeof(*services))
1724 buffer = (BYTE *)&dummy_status;
1725 size = sizeof(dummy_status);
1728 __TRY
1730 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1731 returned, group );
1733 __EXCEPT(rpc_filter)
1735 err = map_exception_code( GetExceptionCode() );
1737 __ENDTRY
1739 if (err != ERROR_SUCCESS)
1741 SetLastError( err );
1742 return FALSE;
1745 for (i = 0; i < *returned; i++)
1747 /* convert buffer offsets into pointers */
1748 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1749 if (services[i].lpDisplayName)
1750 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1753 return TRUE;
1756 /******************************************************************************
1757 * GetServiceKeyNameA [ADVAPI32.@]
1759 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1760 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1762 LPWSTR lpDisplayNameW, lpServiceNameW;
1763 DWORD sizeW;
1764 BOOL ret = FALSE;
1766 TRACE("%p %s %p %p\n", hSCManager,
1767 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1769 lpDisplayNameW = SERV_dup(lpDisplayName);
1770 if (lpServiceName)
1771 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1772 else
1773 lpServiceNameW = NULL;
1775 sizeW = *lpcchBuffer;
1776 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1778 if (lpServiceName && *lpcchBuffer)
1779 lpServiceName[0] = 0;
1780 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1781 goto cleanup;
1784 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1785 *lpcchBuffer, NULL, NULL ))
1787 if (*lpcchBuffer && lpServiceName)
1788 lpServiceName[0] = 0;
1789 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1790 goto cleanup;
1793 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1794 ret = TRUE;
1796 cleanup:
1797 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1798 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1799 return ret;
1802 /******************************************************************************
1803 * GetServiceKeyNameW [ADVAPI32.@]
1805 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1806 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1808 DWORD err;
1809 WCHAR buffer[2];
1810 DWORD size;
1812 TRACE("%p %s %p %p\n", hSCManager,
1813 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1815 if (!hSCManager)
1817 SetLastError( ERROR_INVALID_HANDLE );
1818 return 0;
1821 /* provide a buffer if the caller didn't */
1822 if (!lpServiceName || *lpcchBuffer < 2)
1824 lpServiceName = buffer;
1825 /* A size of 1 would be enough, but tests show that Windows returns 2,
1826 * probably because of a WCHAR/bytes mismatch in their code.
1828 *lpcchBuffer = 2;
1831 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1832 * includes the nul-terminator on input. */
1833 size = *lpcchBuffer - 1;
1835 __TRY
1837 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1838 &size);
1840 __EXCEPT(rpc_filter)
1842 err = map_exception_code(GetExceptionCode());
1844 __ENDTRY
1846 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1847 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1848 *lpcchBuffer = size;
1850 if (err)
1851 SetLastError(err);
1852 return err == ERROR_SUCCESS;
1855 /******************************************************************************
1856 * QueryServiceLockStatusA [ADVAPI32.@]
1858 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1859 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1860 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1862 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1864 return FALSE;
1867 /******************************************************************************
1868 * QueryServiceLockStatusW [ADVAPI32.@]
1870 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1871 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1872 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1874 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1876 return FALSE;
1879 /******************************************************************************
1880 * GetServiceDisplayNameA [ADVAPI32.@]
1882 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1883 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1885 LPWSTR lpServiceNameW, lpDisplayNameW;
1886 DWORD sizeW;
1887 BOOL ret = FALSE;
1889 TRACE("%p %s %p %p\n", hSCManager,
1890 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1892 lpServiceNameW = SERV_dup(lpServiceName);
1893 if (lpDisplayName)
1894 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1895 else
1896 lpDisplayNameW = NULL;
1898 sizeW = *lpcchBuffer;
1899 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1901 if (lpDisplayName && *lpcchBuffer)
1902 lpDisplayName[0] = 0;
1903 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1904 goto cleanup;
1907 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1908 *lpcchBuffer, NULL, NULL ))
1910 if (*lpcchBuffer && lpDisplayName)
1911 lpDisplayName[0] = 0;
1912 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1913 goto cleanup;
1916 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1917 * (but if the function succeeded it means that is a good upper estimation of the size) */
1918 ret = TRUE;
1920 cleanup:
1921 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1922 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1923 return ret;
1926 /******************************************************************************
1927 * GetServiceDisplayNameW [ADVAPI32.@]
1929 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1930 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1932 DWORD err;
1933 DWORD size;
1934 WCHAR buffer[2];
1936 TRACE("%p %s %p %p\n", hSCManager,
1937 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1939 if (!hSCManager)
1941 SetLastError( ERROR_INVALID_HANDLE );
1942 return 0;
1945 /* provide a buffer if the caller didn't */
1946 if (!lpDisplayName || *lpcchBuffer < 2)
1948 lpDisplayName = buffer;
1949 /* A size of 1 would be enough, but tests show that Windows returns 2,
1950 * probably because of a WCHAR/bytes mismatch in their code.
1952 *lpcchBuffer = 2;
1955 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1956 * includes the nul-terminator on input. */
1957 size = *lpcchBuffer - 1;
1959 __TRY
1961 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
1962 &size);
1964 __EXCEPT(rpc_filter)
1966 err = map_exception_code(GetExceptionCode());
1968 __ENDTRY
1970 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1971 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1972 *lpcchBuffer = size;
1974 if (err)
1975 SetLastError(err);
1976 return err == ERROR_SUCCESS;
1979 /******************************************************************************
1980 * ChangeServiceConfigW [ADVAPI32.@]
1982 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1983 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1984 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1985 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1987 DWORD cb_pwd;
1988 DWORD err;
1990 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1991 hService, dwServiceType, dwStartType, dwErrorControl,
1992 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1993 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1994 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1996 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
1998 __TRY
2000 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
2001 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
2002 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
2003 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
2005 __EXCEPT(rpc_filter)
2007 err = map_exception_code(GetExceptionCode());
2009 __ENDTRY
2011 if (err != ERROR_SUCCESS)
2012 SetLastError(err);
2014 return err == ERROR_SUCCESS;
2017 /******************************************************************************
2018 * ChangeServiceConfigA [ADVAPI32.@]
2020 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
2021 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
2022 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
2023 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
2025 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
2026 LPWSTR wServiceStartName, wPassword, wDisplayName;
2027 BOOL r;
2029 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2030 hService, dwServiceType, dwStartType, dwErrorControl,
2031 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
2032 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
2033 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
2035 wBinaryPathName = SERV_dup( lpBinaryPathName );
2036 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2037 wDependencies = SERV_dupmulti( lpDependencies );
2038 wServiceStartName = SERV_dup( lpServiceStartName );
2039 wPassword = SERV_dup( lpPassword );
2040 wDisplayName = SERV_dup( lpDisplayName );
2042 r = ChangeServiceConfigW( hService, dwServiceType,
2043 dwStartType, dwErrorControl, wBinaryPathName,
2044 wLoadOrderGroup, lpdwTagId, wDependencies,
2045 wServiceStartName, wPassword, wDisplayName);
2047 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2048 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2049 HeapFree( GetProcessHeap(), 0, wDependencies );
2050 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2051 HeapFree( GetProcessHeap(), 0, wPassword );
2052 HeapFree( GetProcessHeap(), 0, wDisplayName );
2054 return r;
2057 /******************************************************************************
2058 * ChangeServiceConfig2A [ADVAPI32.@]
2060 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2061 LPVOID lpInfo)
2063 BOOL r = FALSE;
2065 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2067 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2069 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2070 SERVICE_DESCRIPTIONW sdw;
2072 sdw.lpDescription = SERV_dup( sd->lpDescription );
2074 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2076 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2078 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2080 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2081 SERVICE_FAILURE_ACTIONSW faw;
2083 faw.dwResetPeriod = fa->dwResetPeriod;
2084 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2085 faw.lpCommand = SERV_dup( fa->lpCommand );
2086 faw.cActions = fa->cActions;
2087 faw.lpsaActions = fa->lpsaActions;
2089 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2091 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2092 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2094 else if (dwInfoLevel == SERVICE_CONFIG_PRESHUTDOWN_INFO)
2096 r = ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo);
2098 else
2099 SetLastError( ERROR_INVALID_PARAMETER );
2101 return r;
2104 /******************************************************************************
2105 * ChangeServiceConfig2W [ADVAPI32.@]
2107 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2108 LPVOID lpInfo)
2110 DWORD err;
2112 __TRY
2114 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2116 __EXCEPT(rpc_filter)
2118 err = map_exception_code(GetExceptionCode());
2120 __ENDTRY
2122 if (err != ERROR_SUCCESS)
2123 SetLastError(err);
2125 return err == ERROR_SUCCESS;
2128 /******************************************************************************
2129 * QueryServiceObjectSecurity [ADVAPI32.@]
2131 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2132 SECURITY_INFORMATION dwSecurityInformation,
2133 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2134 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2136 SECURITY_DESCRIPTOR descriptor;
2137 DWORD size;
2138 BOOL succ;
2139 ACL acl;
2141 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2142 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2144 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2145 FIXME("information %d not supported\n", dwSecurityInformation);
2147 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2149 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2150 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2152 size = cbBufSize;
2153 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2154 *pcbBytesNeeded = size;
2155 return succ;
2158 /******************************************************************************
2159 * SetServiceObjectSecurity [ADVAPI32.@]
2161 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2162 SECURITY_INFORMATION dwSecurityInformation,
2163 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2165 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2166 return TRUE;
2169 /******************************************************************************
2170 * SetServiceBits [ADVAPI32.@]
2172 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2173 DWORD dwServiceBits,
2174 BOOL bSetBitsOn,
2175 BOOL bUpdateImmediately)
2177 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2178 bSetBitsOn, bUpdateImmediately);
2179 return TRUE;
2182 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2183 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2185 LPHANDLER_FUNCTION func = context;
2187 func( control );
2188 return ERROR_SUCCESS;
2191 /******************************************************************************
2192 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2194 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2196 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2199 /******************************************************************************
2200 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2202 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2204 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2207 /******************************************************************************
2208 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2210 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2212 LPWSTR nameW;
2213 SERVICE_STATUS_HANDLE ret;
2215 nameW = SERV_dup(name);
2216 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2217 HeapFree( GetProcessHeap(), 0, nameW );
2218 return ret;
2221 /******************************************************************************
2222 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2224 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2225 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2227 service_data *service;
2228 SC_HANDLE hService = 0;
2229 BOOL found = FALSE;
2231 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2233 EnterCriticalSection( &service_cs );
2234 if ((service = find_service_by_name( lpServiceName )))
2236 service->handler = lpHandlerProc;
2237 service->context = lpContext;
2238 hService = service->handle;
2239 found = TRUE;
2241 LeaveCriticalSection( &service_cs );
2243 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2245 return (SERVICE_STATUS_HANDLE)hService;
2248 /******************************************************************************
2249 * EnumDependentServicesA [ADVAPI32.@]
2251 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2252 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2253 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2255 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2256 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2258 *lpServicesReturned = 0;
2259 return TRUE;
2262 /******************************************************************************
2263 * EnumDependentServicesW [ADVAPI32.@]
2265 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2266 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2267 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2269 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2270 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2272 *lpServicesReturned = 0;
2273 return TRUE;