usp10: Some unicode code points will force us into bidi mode.
[wine.git] / dlls / advapi32 / service.c
blobbb5e49ca204ec155a6c37960259d42c03edb955d
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 "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;
61 LPVOID context;
62 HANDLE thread;
63 SC_HANDLE handle;
64 BOOL unicode : 1;
65 union {
66 LPSERVICE_MAIN_FUNCTIONA a;
67 LPSERVICE_MAIN_FUNCTIONW w;
68 } proc;
69 LPWSTR args;
70 WCHAR name[1];
71 } service_data;
73 static CRITICAL_SECTION service_cs;
74 static CRITICAL_SECTION_DEBUG service_cs_debug =
76 0, 0, &service_cs,
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 )
96 UINT len;
97 LPWSTR wstr;
99 if( !str )
100 return NULL;
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 );
104 return wstr;
107 static inline LPWSTR SERV_dupmulti(LPCSTR str)
109 UINT len = 0, n = 0;
110 LPWSTR wstr;
112 if( !str )
113 return NULL;
114 do {
115 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
116 n += (strlen( &str[n] ) + 1);
117 } while (str[n]);
118 len++;
119 n++;
121 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
122 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
123 return wstr;
126 static inline DWORD multisz_cb(LPCWSTR wmultisz)
128 const WCHAR *wptr = wmultisz;
130 if (wmultisz == NULL)
131 return 0;
133 while (*wptr)
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;
147 RPC_STATUS status;
148 handle_t rpc_handle;
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);
154 return NULL;
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);
163 return NULL;
166 return rpc_handle;
169 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
171 RpcBindingFree(&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;
191 default:
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};
207 LPWSTR name;
208 DWORD len;
209 HKEY service_current_key;
210 DWORD service_current;
211 LONG ret;
212 DWORD type;
214 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
215 KEY_QUERY_VALUE, &service_current_key);
216 if (ret != ERROR_SUCCESS)
217 return NULL;
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)
223 return NULL;
224 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
225 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
226 if (!name)
227 return NULL;
228 snprintfW(name, len, format, service_current);
229 return name;
232 static HANDLE service_open_pipe(void)
234 LPWSTR szPipe = service_get_pipe_name();
235 HANDLE handle = INVALID_HANDLE_VALUE;
237 do {
238 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
239 0, NULL, OPEN_ALWAYS, 0, NULL);
240 if (handle != INVALID_HANDLE_VALUE)
241 break;
242 if (GetLastError() != ERROR_PIPE_BUSY)
243 break;
244 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
245 HeapFree(GetProcessHeap(), 0, szPipe);
247 return handle;
250 static service_data *find_service_by_name( const WCHAR *name )
252 unsigned int i;
254 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
255 return services[0];
256 for (i = 0; i < nb_services; i++)
257 if (!strcmpiW( name, services[i]->name )) return services[i];
258 return NULL;
261 /******************************************************************************
262 * service_thread
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;
272 TRACE("%p\n", arg);
274 while (str[len])
276 len += strlenW(&str[len]) + 1;
277 argc++;
279 len++;
281 if (info->unicode)
283 LPWSTR *argv, p;
285 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
286 for (argc=0, p=str; *p; p += strlenW(p) + 1)
287 argv[argc++] = p;
288 argv[argc] = NULL;
290 info->proc.w(argc, argv);
291 HeapFree(GetProcessHeap(), 0, argv);
293 else
295 LPSTR strA, *argv, p;
296 DWORD lenA;
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)
304 argv[argc++] = p;
305 argv[argc] = NULL;
307 info->proc.a(argc, argv);
308 HeapFree(GetProcessHeap(), 0, argv);
309 HeapFree(GetProcessHeap(), 0, strA);
311 return 0;
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);
321 if (service->thread)
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,
331 service, 0, NULL );
332 SetEvent( service_event ); /* notify the main loop */
333 return 0;
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);
347 return ret;
350 /******************************************************************************
351 * service_control_dispatcher
353 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
355 SC_HANDLE manager;
356 HANDLE pipe;
358 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
360 ERR("failed to open service manager error %u\n", GetLastError());
361 return 0;
364 pipe = service_open_pipe();
366 if (pipe==INVALID_HANDLE_VALUE)
368 ERR("failed to create control pipe error = %d\n", GetLastError());
369 return 0;
372 /* dispatcher loop */
373 while (1)
375 service_data *service;
376 service_start_info info;
377 WCHAR *data = NULL;
378 BOOL r;
379 DWORD data_size = 0, count, result;
381 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
382 if (!r)
384 if (GetLastError() != ERROR_BROKEN_PIPE)
385 ERR( "pipe read failed error %u\n", GetLastError() );
386 break;
388 if (count != FIELD_OFFSET(service_start_info,data))
390 ERR( "partial pipe read %u\n", count );
391 break;
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 );
398 if (!r)
400 if (GetLastError() != ERROR_BROKEN_PIPE)
401 ERR( "pipe read failed error %u\n", GetLastError() );
402 break;
404 if (count != data_size)
406 ERR( "partial pipe read %u/%u\n", count, data_size );
407 break;
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;
417 goto done;
420 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
422 /* handle the request */
423 switch (info.cmd)
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 );
433 break;
434 case WINESERV_SENDCONTROL:
435 result = service_handle_control(service, info.control);
436 break;
437 default:
438 ERR("received invalid command %u\n", info.cmd);
439 result = ERROR_INVALID_PARAMETER;
440 break;
443 done:
444 WriteFile(pipe, &result, sizeof(result), &count, NULL);
445 HeapFree( GetProcessHeap(), 0, data );
448 CloseHandle(pipe);
449 CloseServiceHandle( manager );
450 return 1;
453 /******************************************************************************
454 * service_run_main_thread
456 static BOOL service_run_main_thread(void)
458 DWORD i, n, ret;
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 */
473 for (;;)
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 */
489 ExitProcess(0);
491 else if (ret == 1)
493 TRACE( "control dispatcher exited, shutting down\n" );
494 /* FIXME: we should maybe send a shutdown control to running services */
495 ExitProcess(0);
497 else if (ret == 2)
499 continue; /* rebuild the list */
501 else if (ret < n)
503 services[wait_services[ret]]->thread = 0;
504 CloseHandle( wait_handles[ret] );
505 if (n == 4) return TRUE; /* it was the last running thread */
507 else return FALSE;
511 /******************************************************************************
512 * StartServiceCtrlDispatcherA [ADVAPI32.@]
514 * See StartServiceCtrlDispatcherW.
516 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
518 service_data *info;
519 unsigned int i;
520 BOOL ret = TRUE;
522 TRACE("%p\n", servent);
524 if (nb_services)
526 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
527 return FALSE;
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;
540 services[i] = info;
543 service_run_main_thread();
545 return ret;
548 /******************************************************************************
549 * StartServiceCtrlDispatcherW [ADVAPI32.@]
551 * Connects a process containing one or more services to the service control
552 * manager.
554 * PARAMS
555 * servent [I] A list of the service names and service procedures
557 * RETURNS
558 * Success: TRUE.
559 * Failure: FALSE.
561 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
563 service_data *info;
564 unsigned int i;
565 BOOL ret = TRUE;
567 TRACE("%p\n", servent);
569 if (nb_services)
571 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
572 return FALSE;
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;
585 services[i] = info;
588 service_run_main_thread();
590 return ret;
593 /******************************************************************************
594 * LockServiceDatabase [ADVAPI32.@]
596 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
598 SC_RPC_LOCK hLock = NULL;
599 DWORD err;
601 TRACE("%p\n",hSCManager);
603 __TRY
605 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
607 __EXCEPT(rpc_filter)
609 err = map_exception_code(GetExceptionCode());
611 __ENDTRY
612 if (err != ERROR_SUCCESS)
614 SetLastError(err);
615 return NULL;
617 return hLock;
620 /******************************************************************************
621 * UnlockServiceDatabase [ADVAPI32.@]
623 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
625 DWORD err;
626 SC_RPC_LOCK hRpcLock = ScLock;
628 TRACE("%p\n",ScLock);
630 __TRY
632 err = svcctl_UnlockServiceDatabase(&hRpcLock);
634 __EXCEPT(rpc_filter)
636 err = map_exception_code(GetExceptionCode());
638 __ENDTRY
639 if (err != ERROR_SUCCESS)
641 SetLastError(err);
642 return FALSE;
644 return TRUE;
647 /******************************************************************************
648 * SetServiceStatus [ADVAPI32.@]
650 * PARAMS
651 * hService []
652 * lpStatus []
654 BOOL WINAPI
655 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
657 DWORD err;
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);
665 __TRY
667 err = svcctl_SetServiceStatus( hService, lpStatus );
669 __EXCEPT(rpc_filter)
671 err = map_exception_code(GetExceptionCode());
673 __ENDTRY
674 if (err != ERROR_SUCCESS)
676 SetLastError(err);
677 return FALSE;
680 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
681 CloseServiceHandle((SC_HANDLE)hService);
683 return TRUE;
687 /******************************************************************************
688 * OpenSCManagerA [ADVAPI32.@]
690 * Establish a connection to the service control manager and open its database.
692 * PARAMS
693 * lpMachineName [I] Pointer to machine name string
694 * lpDatabaseName [I] Pointer to database name string
695 * dwDesiredAccess [I] Type of access
697 * RETURNS
698 * Success: A Handle to the service control manager database
699 * Failure: NULL
701 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
702 DWORD dwDesiredAccess )
704 LPWSTR lpMachineNameW, lpDatabaseNameW;
705 SC_HANDLE ret;
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);
712 return ret;
715 /******************************************************************************
716 * OpenSCManagerW [ADVAPI32.@]
718 * See OpenSCManagerA.
720 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
721 DWORD dwDesiredAccess )
723 SC_HANDLE handle;
724 LONG r;
726 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
727 debugstr_w(lpDatabaseName), dwDesiredAccess);
729 __TRY
731 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
733 __EXCEPT(rpc_filter)
735 r = map_exception_code(GetExceptionCode());
737 __ENDTRY
739 if (r!=ERROR_SUCCESS)
741 SetLastError( r );
742 handle = 0;
745 TRACE("returning %p\n", handle);
746 return handle;
749 /******************************************************************************
750 * ControlService [ADVAPI32.@]
752 * Send a control code to a service.
754 * PARAMS
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
759 * RETURNS
760 * Success: TRUE.
761 * Failure: FALSE.
763 * BUGS
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 )
770 DWORD err;
772 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
774 __TRY
776 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
778 __EXCEPT(rpc_filter)
780 err = map_exception_code(GetExceptionCode());
782 __ENDTRY
783 if (err != ERROR_SUCCESS)
785 SetLastError(err);
786 return FALSE;
789 return TRUE;
792 /******************************************************************************
793 * CloseServiceHandle [ADVAPI32.@]
795 * Close a handle to a service or the service control manager database.
797 * PARAMS
798 * hSCObject [I] Handle to service or service control manager database
800 * RETURNS
801 * Success: TRUE
802 * Failure: FALSE
804 BOOL WINAPI
805 CloseServiceHandle( SC_HANDLE hSCObject )
807 DWORD err;
809 TRACE("%p\n", hSCObject);
811 __TRY
813 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
815 __EXCEPT(rpc_filter)
817 err = map_exception_code(GetExceptionCode());
819 __ENDTRY
821 if (err != ERROR_SUCCESS)
823 SetLastError(err);
824 return FALSE;
826 return TRUE;
830 /******************************************************************************
831 * OpenServiceA [ADVAPI32.@]
833 * Open a handle to a service.
835 * PARAMS
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
840 * RETURNS
841 * Success: Handle to the service
842 * Failure: NULL
844 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
845 DWORD dwDesiredAccess )
847 LPWSTR lpServiceNameW;
848 SC_HANDLE ret;
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);
855 return ret;
859 /******************************************************************************
860 * OpenServiceW [ADVAPI32.@]
862 * See OpenServiceA.
864 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
865 DWORD dwDesiredAccess)
867 SC_HANDLE handle;
868 DWORD err;
870 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
872 if (!hSCManager)
874 SetLastError( ERROR_INVALID_HANDLE );
875 return 0;
878 __TRY
880 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
882 __EXCEPT(rpc_filter)
884 err = map_exception_code(GetExceptionCode());
886 __ENDTRY
888 if (err != ERROR_SUCCESS)
890 SetLastError(err);
891 handle = 0;
894 TRACE("returning %p\n",handle);
895 return handle;
898 /******************************************************************************
899 * CreateServiceW [ADVAPI32.@]
901 SC_HANDLE WINAPI
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,
908 LPCWSTR lpPassword )
910 SC_HANDLE handle;
911 DWORD err;
912 SIZE_T passwdlen;
914 TRACE("%p %s %s\n", hSCManager,
915 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
917 if (!hSCManager)
919 SetLastError( ERROR_INVALID_HANDLE );
920 return 0;
923 if (lpPassword)
924 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
925 else
926 passwdlen = 0;
928 __TRY
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);
936 __EXCEPT(rpc_filter)
938 err = map_exception_code(GetExceptionCode());
940 __ENDTRY
942 if (err != ERROR_SUCCESS)
944 SetLastError(err);
945 handle = 0;
947 return handle;
951 /******************************************************************************
952 * CreateServiceA [ADVAPI32.@]
954 SC_HANDLE WINAPI
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,
961 LPCSTR lpPassword )
963 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
964 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
965 SC_HANDLE r;
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 );
991 return r;
995 /******************************************************************************
996 * DeleteService [ADVAPI32.@]
998 * Delete a service from the service control manager database.
1000 * PARAMS
1001 * hService [I] Handle of the service to delete
1003 * RETURNS
1004 * Success: TRUE
1005 * Failure: FALSE
1007 BOOL WINAPI DeleteService( SC_HANDLE hService )
1009 DWORD err;
1011 __TRY
1013 err = svcctl_DeleteService(hService);
1015 __EXCEPT(rpc_filter)
1017 err = map_exception_code(GetExceptionCode());
1019 __ENDTRY
1020 if (err != 0)
1022 SetLastError(err);
1023 return FALSE;
1026 return TRUE;
1030 /******************************************************************************
1031 * StartServiceA [ADVAPI32.@]
1033 * Start a service
1035 * PARAMS
1036 * hService [I] Handle of service
1037 * dwNumServiceArgs [I] Number of arguments
1038 * lpServiceArgVectors [I] Address of array of argument strings
1040 * NOTES
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.
1049 * RETURNS
1050 * Success: TRUE.
1051 * Failure: FALSE
1053 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1054 LPCSTR *lpServiceArgVectors )
1056 LPWSTR *lpwstr=NULL;
1057 unsigned int i;
1058 BOOL r;
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);
1078 return r;
1082 /******************************************************************************
1083 * StartServiceW [ADVAPI32.@]
1085 * See StartServiceA.
1087 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1088 LPCWSTR *lpServiceArgVectors)
1090 DWORD err;
1092 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1094 __TRY
1096 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1098 __EXCEPT(rpc_filter)
1100 err = map_exception_code(GetExceptionCode());
1102 __ENDTRY
1103 if (err != ERROR_SUCCESS)
1105 SetLastError(err);
1106 return FALSE;
1109 return TRUE;
1112 /******************************************************************************
1113 * QueryServiceStatus [ADVAPI32.@]
1115 * PARAMS
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;
1124 BOOL ret;
1125 DWORD dummy;
1127 TRACE("%p %p\n", hService, lpservicestatus);
1129 if (!hService)
1131 SetLastError(ERROR_INVALID_HANDLE);
1132 return FALSE;
1134 if (!lpservicestatus)
1136 SetLastError(ERROR_INVALID_ADDRESS);
1137 return FALSE;
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)) ;
1143 return ret;
1147 /******************************************************************************
1148 * QueryServiceStatusEx [ADVAPI32.@]
1150 * Get information about a service.
1152 * PARAMS
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
1159 * RETURNS
1160 * Success: TRUE
1161 * FAILURE: FALSE
1163 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1164 LPBYTE lpBuffer, DWORD cbBufSize,
1165 LPDWORD pcbBytesNeeded)
1167 DWORD err;
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;
1180 else
1182 __TRY
1184 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1186 __EXCEPT(rpc_filter)
1188 err = map_exception_code(GetExceptionCode());
1190 __ENDTRY
1192 if (err != ERROR_SUCCESS)
1194 SetLastError(err);
1195 return FALSE;
1197 return TRUE;
1200 /******************************************************************************
1201 * QueryServiceConfigA [ADVAPI32.@]
1203 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1204 DWORD size, LPDWORD needed )
1206 DWORD n;
1207 LPSTR p, buffer;
1208 BOOL ret;
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 );
1216 return FALSE;
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);
1234 ret = FALSE;
1236 #define MAP_STR(str) \
1237 do { \
1238 if (configW->str) \
1240 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1241 if (!sz) goto done; \
1242 config->str = p; \
1243 p += sz; \
1244 n -= sz; \
1246 } while (0)
1248 MAP_STR( lpBinaryPathName );
1249 MAP_STR( lpLoadOrderGroup );
1250 MAP_STR( lpDependencies );
1251 MAP_STR( lpServiceStartName );
1252 MAP_STR( lpDisplayName );
1253 #undef MAP_STR
1255 *needed = p - (LPSTR)config;
1256 ret = TRUE;
1258 done:
1259 HeapFree( GetProcessHeap(), 0, buffer );
1260 return ret;
1263 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1265 DWORD cb;
1267 if (!*string_ptr)
1269 cb = sizeof(WCHAR);
1270 memset(*buf, 0, cb);
1272 else
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;
1280 *buf += cb;
1282 return cb;
1285 static DWORD size_string(LPCWSTR string)
1287 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1290 /******************************************************************************
1291 * QueryServiceConfigW [ADVAPI32.@]
1293 BOOL WINAPI
1294 QueryServiceConfigW( SC_HANDLE hService,
1295 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1296 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1298 QUERY_SERVICE_CONFIGW config;
1299 DWORD total;
1300 DWORD err;
1301 BYTE *bufpos;
1303 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1304 cbBufSize, pcbBytesNeeded);
1306 memset(&config, 0, sizeof(config));
1308 __TRY
1310 err = svcctl_QueryServiceConfigW(hService, &config);
1312 __EXCEPT(rpc_filter)
1314 err = map_exception_code(GetExceptionCode());
1316 __ENDTRY
1318 if (err != ERROR_SUCCESS)
1320 TRACE("services.exe: error %u\n", err);
1321 SetLastError(err);
1322 return FALSE;
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);
1344 return FALSE;
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) );
1361 return TRUE;
1364 /******************************************************************************
1365 * QueryServiceConfig2A [ADVAPI32.@]
1367 * Note
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)
1375 BOOL ret;
1376 LPBYTE bufferW = NULL;
1378 if(buffer && size)
1379 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1381 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1382 if(!ret) goto cleanup;
1384 switch(dwLevel) {
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))) {
1390 DWORD sz;
1391 configA->lpDescription = (LPSTR)(configA + 1);
1392 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1393 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1394 if (!sz) {
1395 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1396 ret = FALSE;
1397 configA->lpDescription = NULL;
1400 else configA->lpDescription = NULL;
1402 break;
1403 default:
1404 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1405 ret = FALSE;
1406 break;
1409 cleanup:
1410 HeapFree( GetProcessHeap(), 0, bufferW);
1411 return ret;
1414 /******************************************************************************
1415 * QueryServiceConfig2W [ADVAPI32.@]
1417 * See QueryServiceConfig2A.
1419 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1420 DWORD size, LPDWORD needed)
1422 DWORD err;
1424 if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1425 FIXME("Level %d not implemented\n", dwLevel);
1426 SetLastError(ERROR_INVALID_LEVEL);
1427 return FALSE;
1430 if(!buffer && size) {
1431 SetLastError(ERROR_INVALID_ADDRESS);
1432 return FALSE;
1435 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1437 __TRY
1439 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1441 __EXCEPT(rpc_filter)
1443 err = map_exception_code(GetExceptionCode());
1445 __ENDTRY
1447 if (err != ERROR_SUCCESS)
1449 SetLastError( err );
1450 return FALSE;
1453 switch (dwLevel)
1455 case SERVICE_CONFIG_DESCRIPTION:
1456 if (buffer)
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);
1461 break;
1465 return TRUE;
1468 /******************************************************************************
1469 * EnumServicesStatusA [ADVAPI32.@]
1471 BOOL WINAPI
1472 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1473 services, DWORD size, LPDWORD needed, LPDWORD returned,
1474 LPDWORD resume_handle )
1476 BOOL ret;
1477 unsigned int i;
1478 ENUM_SERVICE_STATUSW *servicesW = NULL;
1479 DWORD sz, n;
1480 char *p;
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 );
1489 return FALSE;
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);
1497 ret = FALSE;
1498 for (i = 0; i < *returned; i++)
1500 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1501 if (!sz) goto done;
1502 services[i].lpServiceName = p;
1503 p += sz;
1504 n -= sz;
1505 if (servicesW[i].lpDisplayName)
1507 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1508 if (!sz) goto done;
1509 services[i].lpDisplayName = p;
1510 p += sz;
1511 n -= sz;
1513 else services[i].lpDisplayName = NULL;
1514 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1517 ret = TRUE;
1519 done:
1520 HeapFree( GetProcessHeap(), 0, servicesW );
1521 return ret;
1524 /******************************************************************************
1525 * EnumServicesStatusW [ADVAPI32.@]
1527 BOOL WINAPI
1528 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1529 services, DWORD size, LPDWORD needed, LPDWORD returned,
1530 LPDWORD resume_handle )
1532 DWORD err, i;
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);
1538 if (resume_handle)
1539 FIXME("resume handle not supported\n");
1541 if (!hmngr)
1543 SetLastError( ERROR_INVALID_HANDLE );
1544 return FALSE;
1547 /* make sure we pass a valid pointer */
1548 if (!services || size < sizeof(*services))
1550 services = &dummy_status;
1551 size = sizeof(dummy_status);
1554 __TRY
1556 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1558 __EXCEPT(rpc_filter)
1560 err = map_exception_code( GetExceptionCode() );
1562 __ENDTRY
1564 if (err != ERROR_SUCCESS)
1566 SetLastError( err );
1567 return FALSE;
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);
1578 return TRUE;
1581 /******************************************************************************
1582 * EnumServicesStatusExA [ADVAPI32.@]
1584 BOOL WINAPI
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 )
1589 BOOL ret;
1590 unsigned int i;
1591 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1592 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1593 WCHAR *groupW = NULL;
1594 DWORD sz, n;
1595 char *p;
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 );
1604 return FALSE;
1606 if (group)
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 );
1613 return FALSE;
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);
1624 ret = FALSE;
1625 for (i = 0; i < *returned; i++)
1627 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1628 if (!sz) goto done;
1629 services[i].lpServiceName = p;
1630 p += sz;
1631 n -= sz;
1632 if (servicesW[i].lpDisplayName)
1634 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1635 if (!sz) goto done;
1636 services[i].lpDisplayName = p;
1637 p += sz;
1638 n -= sz;
1640 else services[i].lpDisplayName = NULL;
1641 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1644 ret = TRUE;
1646 done:
1647 HeapFree( GetProcessHeap(), 0, servicesW );
1648 HeapFree( GetProcessHeap(), 0, groupW );
1649 return ret;
1652 /******************************************************************************
1653 * EnumServicesStatusExW [ADVAPI32.@]
1655 BOOL WINAPI
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 )
1660 DWORD err, i;
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));
1667 if (resume_handle)
1668 FIXME("resume handle not supported\n");
1670 if (level != SC_ENUM_PROCESS_INFO)
1672 SetLastError( ERROR_INVALID_LEVEL );
1673 return FALSE;
1675 if (!hmngr)
1677 SetLastError( ERROR_INVALID_HANDLE );
1678 return FALSE;
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);
1688 __TRY
1690 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1691 returned, group );
1693 __EXCEPT(rpc_filter)
1695 err = map_exception_code( GetExceptionCode() );
1697 __ENDTRY
1699 if (err != ERROR_SUCCESS)
1701 SetLastError( err );
1702 return FALSE;
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);
1713 return TRUE;
1716 /******************************************************************************
1717 * GetServiceKeyNameA [ADVAPI32.@]
1719 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1720 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1722 LPWSTR lpDisplayNameW, lpServiceNameW;
1723 DWORD sizeW;
1724 BOOL ret = FALSE;
1726 TRACE("%p %s %p %p\n", hSCManager,
1727 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1729 lpDisplayNameW = SERV_dup(lpDisplayName);
1730 if (lpServiceName)
1731 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1732 else
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 */
1741 goto cleanup;
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);
1750 goto cleanup;
1753 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1754 ret = TRUE;
1756 cleanup:
1757 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1758 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1759 return ret;
1762 /******************************************************************************
1763 * GetServiceKeyNameW [ADVAPI32.@]
1765 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1766 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1768 DWORD err;
1769 WCHAR buffer[2];
1770 DWORD size;
1772 TRACE("%p %s %p %p\n", hSCManager,
1773 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1775 if (!hSCManager)
1777 SetLastError( ERROR_INVALID_HANDLE );
1778 return 0;
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.
1788 *lpcchBuffer = 2;
1791 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1792 * includes the nul-terminator on input. */
1793 size = *lpcchBuffer - 1;
1795 __TRY
1797 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1798 &size);
1800 __EXCEPT(rpc_filter)
1802 err = map_exception_code(GetExceptionCode());
1804 __ENDTRY
1806 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1807 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1808 *lpcchBuffer = size;
1810 if (err)
1811 SetLastError(err);
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);
1824 return FALSE;
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);
1836 return FALSE;
1839 /******************************************************************************
1840 * GetServiceDisplayNameA [ADVAPI32.@]
1842 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1843 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1845 LPWSTR lpServiceNameW, lpDisplayNameW;
1846 DWORD sizeW;
1847 BOOL ret = FALSE;
1849 TRACE("%p %s %p %p\n", hSCManager,
1850 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1852 lpServiceNameW = SERV_dup(lpServiceName);
1853 if (lpDisplayName)
1854 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1855 else
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 */
1864 goto cleanup;
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);
1873 goto cleanup;
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) */
1878 ret = TRUE;
1880 cleanup:
1881 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1882 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1883 return ret;
1886 /******************************************************************************
1887 * GetServiceDisplayNameW [ADVAPI32.@]
1889 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1890 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1892 DWORD err;
1893 DWORD size;
1894 WCHAR buffer[2];
1896 TRACE("%p %s %p %p\n", hSCManager,
1897 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1899 if (!hSCManager)
1901 SetLastError( ERROR_INVALID_HANDLE );
1902 return 0;
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.
1912 *lpcchBuffer = 2;
1915 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1916 * includes the nul-terminator on input. */
1917 size = *lpcchBuffer - 1;
1919 __TRY
1921 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
1922 &size);
1924 __EXCEPT(rpc_filter)
1926 err = map_exception_code(GetExceptionCode());
1928 __ENDTRY
1930 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1931 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1932 *lpcchBuffer = size;
1934 if (err)
1935 SetLastError(err);
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)
1947 DWORD cb_pwd;
1948 DWORD err;
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;
1958 __TRY
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());
1969 __ENDTRY
1971 if (err != ERROR_SUCCESS)
1972 SetLastError(err);
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;
1987 BOOL r;
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 );
2014 return r;
2017 /******************************************************************************
2018 * ChangeServiceConfig2A [ADVAPI32.@]
2020 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2021 LPVOID lpInfo)
2023 BOOL r = FALSE;
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 );
2054 else
2055 SetLastError( ERROR_INVALID_PARAMETER );
2057 return r;
2060 /******************************************************************************
2061 * ChangeServiceConfig2W [ADVAPI32.@]
2063 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2064 LPVOID lpInfo)
2066 DWORD err;
2068 __TRY
2070 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2072 __EXCEPT(rpc_filter)
2074 err = map_exception_code(GetExceptionCode());
2076 __ENDTRY
2078 if (err != ERROR_SUCCESS)
2079 SetLastError(err);
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;
2093 DWORD size;
2094 BOOL succ;
2095 ACL acl;
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);
2108 size = cbBufSize;
2109 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2110 *pcbBytesNeeded = size;
2111 return succ;
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);
2122 return TRUE;
2125 /******************************************************************************
2126 * SetServiceBits [ADVAPI32.@]
2128 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2129 DWORD dwServiceBits,
2130 BOOL bSetBitsOn,
2131 BOOL bUpdateImmediately)
2133 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2134 bSetBitsOn, bUpdateImmediately);
2135 return TRUE;
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;
2143 func( control );
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 )
2168 LPWSTR nameW;
2169 SERVICE_STATUS_HANDLE ret;
2171 nameW = SERV_dup(name);
2172 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2173 HeapFree( GetProcessHeap(), 0, nameW );
2174 return ret;
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;
2185 BOOL found = FALSE;
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;
2195 found = TRUE;
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;
2215 return TRUE;
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;
2229 return TRUE;