user32: Add a test to find the queue containing hotkey messages.
[wine.git] / dlls / advapi32 / service.c
blob2fc3d71e59bf5338dbe58306cfba0c5e19796660
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 static const WCHAR szServiceManagerKey[] = { 'S','y','s','t','e','m','\\',
49 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
50 'S','e','r','v','i','c','e','s',0 };
52 void __RPC_FAR * __RPC_USER MIDL_user_allocate(SIZE_T len)
54 return HeapAlloc(GetProcessHeap(), 0, len);
57 void __RPC_USER MIDL_user_free(void __RPC_FAR * ptr)
59 HeapFree(GetProcessHeap(), 0, ptr);
62 typedef struct service_data_t
64 LPHANDLER_FUNCTION_EX handler;
65 LPVOID context;
66 HANDLE thread;
67 SC_HANDLE handle;
68 BOOL unicode : 1;
69 union {
70 LPSERVICE_MAIN_FUNCTIONA a;
71 LPSERVICE_MAIN_FUNCTIONW w;
72 } proc;
73 LPWSTR args;
74 WCHAR name[1];
75 } service_data;
77 static CRITICAL_SECTION service_cs;
78 static CRITICAL_SECTION_DEBUG service_cs_debug =
80 0, 0, &service_cs,
81 { &service_cs_debug.ProcessLocksList,
82 &service_cs_debug.ProcessLocksList },
83 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
85 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
87 static service_data **services;
88 static unsigned int nb_services;
89 static HANDLE service_event;
91 extern HANDLE CDECL __wine_make_process_system(void);
93 /******************************************************************************
94 * String management functions (same behaviour as strdup)
95 * NOTE: the caller of those functions is responsible for calling HeapFree
96 * in order to release the memory allocated by those functions.
98 static inline LPWSTR SERV_dup( LPCSTR str )
100 UINT len;
101 LPWSTR wstr;
103 if( !str )
104 return NULL;
105 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
106 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
107 MultiByteToWideChar( CP_ACP, 0, str, -1, wstr, len );
108 return wstr;
111 static inline LPWSTR SERV_dupmulti(LPCSTR str)
113 UINT len = 0, n = 0;
114 LPWSTR wstr;
116 if( !str )
117 return NULL;
118 do {
119 len += MultiByteToWideChar( CP_ACP, 0, &str[n], -1, NULL, 0 );
120 n += (strlen( &str[n] ) + 1);
121 } while (str[n]);
122 len++;
123 n++;
125 wstr = HeapAlloc( GetProcessHeap(), 0, len*sizeof (WCHAR) );
126 MultiByteToWideChar( CP_ACP, 0, str, n, wstr, len );
127 return wstr;
130 static inline DWORD multisz_cb(LPCWSTR wmultisz)
132 const WCHAR *wptr = wmultisz;
134 if (wmultisz == NULL)
135 return 0;
137 while (*wptr)
138 wptr += lstrlenW(wptr)+1;
139 return (wptr - wmultisz + 1)*sizeof(WCHAR);
142 /******************************************************************************
143 * RPC connection with services.exe
146 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName)
148 WCHAR transport[] = SVCCTL_TRANSPORT;
149 WCHAR endpoint[] = SVCCTL_ENDPOINT;
150 RPC_WSTR binding_str;
151 RPC_STATUS status;
152 handle_t rpc_handle;
154 status = RpcStringBindingComposeW(NULL, transport, (RPC_WSTR)MachineName, endpoint, NULL, &binding_str);
155 if (status != RPC_S_OK)
157 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD)status);
158 return NULL;
161 status = RpcBindingFromStringBindingW(binding_str, &rpc_handle);
162 RpcStringFreeW(&binding_str);
164 if (status != RPC_S_OK)
166 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD)status);
167 return NULL;
170 return rpc_handle;
173 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName, handle_t h)
175 RpcBindingFree(&h);
178 static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
180 return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
183 static DWORD map_exception_code(DWORD exception_code)
185 switch (exception_code)
187 case RPC_X_NULL_REF_POINTER:
188 return ERROR_INVALID_ADDRESS;
189 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
190 case RPC_X_BYTE_COUNT_TOO_SMALL:
191 return ERROR_INVALID_PARAMETER;
192 case RPC_S_INVALID_BINDING:
193 case RPC_X_SS_IN_NULL_CONTEXT:
194 return ERROR_INVALID_HANDLE;
195 default:
196 return exception_code;
200 /******************************************************************************
201 * Service IPC functions
203 static LPWSTR service_get_pipe_name(void)
205 static const WCHAR format[] = { '\\','\\','.','\\','p','i','p','e','\\',
206 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
207 static const WCHAR service_current_key_str[] = { 'S','Y','S','T','E','M','\\',
208 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
209 'C','o','n','t','r','o','l','\\',
210 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
211 LPWSTR name;
212 DWORD len;
213 HKEY service_current_key;
214 DWORD service_current;
215 LONG ret;
216 DWORD type;
218 ret = RegOpenKeyExW(HKEY_LOCAL_MACHINE, service_current_key_str, 0,
219 KEY_QUERY_VALUE, &service_current_key);
220 if (ret != ERROR_SUCCESS)
221 return NULL;
222 len = sizeof(service_current);
223 ret = RegQueryValueExW(service_current_key, NULL, NULL, &type,
224 (BYTE *)&service_current, &len);
225 RegCloseKey(service_current_key);
226 if (ret != ERROR_SUCCESS || type != REG_DWORD)
227 return NULL;
228 len = sizeof(format)/sizeof(WCHAR) + 10 /* strlenW("4294967295") */;
229 name = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
230 if (!name)
231 return NULL;
232 snprintfW(name, len, format, service_current);
233 return name;
236 static HANDLE service_open_pipe(void)
238 LPWSTR szPipe = service_get_pipe_name();
239 HANDLE handle = INVALID_HANDLE_VALUE;
241 do {
242 handle = CreateFileW(szPipe, GENERIC_READ|GENERIC_WRITE,
243 0, NULL, OPEN_ALWAYS, 0, NULL);
244 if (handle != INVALID_HANDLE_VALUE)
245 break;
246 if (GetLastError() != ERROR_PIPE_BUSY)
247 break;
248 } while (WaitNamedPipeW(szPipe, NMPWAIT_WAIT_FOREVER));
249 HeapFree(GetProcessHeap(), 0, szPipe);
251 return handle;
254 static service_data *find_service_by_name( const WCHAR *name )
256 unsigned int i;
258 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
259 return services[0];
260 for (i = 0; i < nb_services; i++)
261 if (!strcmpiW( name, services[i]->name )) return services[i];
262 return NULL;
265 /******************************************************************************
266 * service_thread
268 * Call into the main service routine provided by StartServiceCtrlDispatcher.
270 static DWORD WINAPI service_thread(LPVOID arg)
272 service_data *info = arg;
273 LPWSTR str = info->args;
274 DWORD argc = 0, len = 0;
276 TRACE("%p\n", arg);
278 while (str[len])
280 len += strlenW(&str[len]) + 1;
281 argc++;
283 len++;
285 if (info->unicode)
287 LPWSTR *argv, p;
289 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPWSTR));
290 for (argc=0, p=str; *p; p += strlenW(p) + 1)
291 argv[argc++] = p;
292 argv[argc] = NULL;
294 info->proc.w(argc, argv);
295 HeapFree(GetProcessHeap(), 0, argv);
297 else
299 LPSTR strA, *argv, p;
300 DWORD lenA;
302 lenA = WideCharToMultiByte(CP_ACP,0, str, len, NULL, 0, NULL, NULL);
303 strA = HeapAlloc(GetProcessHeap(), 0, lenA);
304 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
306 argv = HeapAlloc(GetProcessHeap(), 0, (argc+1)*sizeof(LPSTR));
307 for (argc=0, p=strA; *p; p += strlen(p) + 1)
308 argv[argc++] = p;
309 argv[argc] = NULL;
311 info->proc.a(argc, argv);
312 HeapFree(GetProcessHeap(), 0, argv);
313 HeapFree(GetProcessHeap(), 0, strA);
315 return 0;
318 /******************************************************************************
319 * service_handle_start
321 static DWORD service_handle_start(service_data *service, const WCHAR *data, DWORD count)
323 TRACE("%s argsize %u\n", debugstr_w(service->name), count);
325 if (service->thread)
327 WARN("service is not stopped\n");
328 return ERROR_SERVICE_ALREADY_RUNNING;
331 HeapFree(GetProcessHeap(), 0, service->args);
332 service->args = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR));
333 memcpy( service->args, data, count * sizeof(WCHAR) );
334 service->thread = CreateThread( NULL, 0, service_thread,
335 service, 0, NULL );
336 SetEvent( service_event ); /* notify the main loop */
337 return 0;
340 /******************************************************************************
341 * service_handle_control
343 static DWORD service_handle_control(const service_data *service, DWORD dwControl)
345 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
347 TRACE("%s control %u\n", debugstr_w(service->name), dwControl);
349 if (service->handler)
350 ret = service->handler(dwControl, 0, NULL, service->context);
351 return ret;
354 /******************************************************************************
355 * service_control_dispatcher
357 static DWORD WINAPI service_control_dispatcher(LPVOID arg)
359 SC_HANDLE manager;
360 HANDLE pipe;
362 if (!(manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT )))
364 ERR("failed to open service manager error %u\n", GetLastError());
365 return 0;
368 pipe = service_open_pipe();
370 if (pipe==INVALID_HANDLE_VALUE)
372 ERR("failed to create control pipe error = %d\n", GetLastError());
373 return 0;
376 /* dispatcher loop */
377 while (1)
379 service_data *service;
380 service_start_info info;
381 WCHAR *data = NULL;
382 BOOL r;
383 DWORD data_size = 0, count, result;
385 r = ReadFile( pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
386 if (!r)
388 if (GetLastError() != ERROR_BROKEN_PIPE)
389 ERR( "pipe read failed error %u\n", GetLastError() );
390 break;
392 if (count != FIELD_OFFSET(service_start_info,data))
394 ERR( "partial pipe read %u\n", count );
395 break;
397 if (count < info.total_size)
399 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
400 data = HeapAlloc( GetProcessHeap(), 0, data_size );
401 r = ReadFile( pipe, data, data_size, &count, NULL );
402 if (!r)
404 if (GetLastError() != ERROR_BROKEN_PIPE)
405 ERR( "pipe read failed error %u\n", GetLastError() );
406 break;
408 if (count != data_size)
410 ERR( "partial pipe read %u/%u\n", count, data_size );
411 break;
415 /* find the service */
417 if (!(service = find_service_by_name( data )))
419 FIXME( "got request %u for unknown service %s\n", info.cmd, debugstr_w(data));
420 result = ERROR_INVALID_PARAMETER;
421 goto done;
424 TRACE( "got request %u for service %s\n", info.cmd, debugstr_w(data) );
426 /* handle the request */
427 switch (info.cmd)
429 case WINESERV_STARTINFO:
430 if (!service->handle)
432 if (!(service->handle = OpenServiceW( manager, data, SERVICE_SET_STATUS )))
433 FIXME( "failed to open service %s\n", debugstr_w(data) );
435 result = service_handle_start(service, data + info.name_size,
436 data_size / sizeof(WCHAR) - info.name_size );
437 break;
438 case WINESERV_SENDCONTROL:
439 result = service_handle_control(service, info.control);
440 break;
441 default:
442 ERR("received invalid command %u\n", info.cmd);
443 result = ERROR_INVALID_PARAMETER;
444 break;
447 done:
448 WriteFile(pipe, &result, sizeof(result), &count, NULL);
449 HeapFree( GetProcessHeap(), 0, data );
452 CloseHandle(pipe);
453 CloseServiceHandle( manager );
454 return 1;
457 /******************************************************************************
458 * service_run_main_thread
460 static BOOL service_run_main_thread(void)
462 DWORD i, n, ret;
463 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
464 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
466 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
468 /* FIXME: service_control_dispatcher should be merged into the main thread */
469 wait_handles[0] = __wine_make_process_system();
470 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, NULL, 0, NULL );
471 wait_handles[2] = service_event;
473 TRACE("Starting %d services running as process %d\n",
474 nb_services, GetCurrentProcessId());
476 /* wait for all the threads to pack up and exit */
477 for (;;)
479 EnterCriticalSection( &service_cs );
480 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
482 if (!services[i]->thread) continue;
483 wait_services[n] = i;
484 wait_handles[n++] = services[i]->thread;
486 LeaveCriticalSection( &service_cs );
488 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
489 if (!ret) /* system process event */
491 TRACE( "last user process exited, shutting down\n" );
492 /* FIXME: we should maybe send a shutdown control to running services */
493 ExitProcess(0);
495 else if (ret == 1)
497 TRACE( "control dispatcher exited, shutting down\n" );
498 /* FIXME: we should maybe send a shutdown control to running services */
499 ExitProcess(0);
501 else if (ret == 2)
503 continue; /* rebuild the list */
505 else if (ret < n)
507 services[wait_services[ret]]->thread = 0;
508 CloseHandle( wait_handles[ret] );
509 if (n == 4) return TRUE; /* it was the last running thread */
511 else return FALSE;
515 /******************************************************************************
516 * StartServiceCtrlDispatcherA [ADVAPI32.@]
518 * See StartServiceCtrlDispatcherW.
520 BOOL WINAPI StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
522 service_data *info;
523 unsigned int i;
524 BOOL ret = TRUE;
526 TRACE("%p\n", servent);
528 if (nb_services)
530 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
531 return FALSE;
533 while (servent[nb_services].lpServiceName) nb_services++;
534 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
536 for (i = 0; i < nb_services; i++)
538 DWORD len = MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0);
539 DWORD sz = FIELD_OFFSET( service_data, name[len] );
540 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
541 MultiByteToWideChar(CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len);
542 info->proc.a = servent[i].lpServiceProc;
543 info->unicode = FALSE;
544 services[i] = info;
547 service_run_main_thread();
549 return ret;
552 /******************************************************************************
553 * StartServiceCtrlDispatcherW [ADVAPI32.@]
555 * Connects a process containing one or more services to the service control
556 * manager.
558 * PARAMS
559 * servent [I] A list of the service names and service procedures
561 * RETURNS
562 * Success: TRUE.
563 * Failure: FALSE.
565 BOOL WINAPI StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
567 service_data *info;
568 unsigned int i;
569 BOOL ret = TRUE;
571 TRACE("%p\n", servent);
573 if (nb_services)
575 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
576 return FALSE;
578 while (servent[nb_services].lpServiceName) nb_services++;
579 services = HeapAlloc( GetProcessHeap(), 0, nb_services * sizeof(*services) );
581 for (i = 0; i < nb_services; i++)
583 DWORD len = strlenW(servent[i].lpServiceName) + 1;
584 DWORD sz = FIELD_OFFSET( service_data, name[len] );
585 info = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sz );
586 strcpyW(info->name, servent[i].lpServiceName);
587 info->proc.w = servent[i].lpServiceProc;
588 info->unicode = TRUE;
589 services[i] = info;
592 service_run_main_thread();
594 return ret;
597 /******************************************************************************
598 * LockServiceDatabase [ADVAPI32.@]
600 SC_LOCK WINAPI LockServiceDatabase (SC_HANDLE hSCManager)
602 SC_RPC_LOCK hLock = NULL;
603 DWORD err;
605 TRACE("%p\n",hSCManager);
607 __TRY
609 err = svcctl_LockServiceDatabase(hSCManager, &hLock);
611 __EXCEPT(rpc_filter)
613 err = map_exception_code(GetExceptionCode());
615 __ENDTRY
616 if (err != ERROR_SUCCESS)
618 SetLastError(err);
619 return NULL;
621 return hLock;
624 /******************************************************************************
625 * UnlockServiceDatabase [ADVAPI32.@]
627 BOOL WINAPI UnlockServiceDatabase (SC_LOCK ScLock)
629 DWORD err;
630 SC_RPC_LOCK hRpcLock = ScLock;
632 TRACE("%p\n",ScLock);
634 __TRY
636 err = svcctl_UnlockServiceDatabase(&hRpcLock);
638 __EXCEPT(rpc_filter)
640 err = map_exception_code(GetExceptionCode());
642 __ENDTRY
643 if (err != ERROR_SUCCESS)
645 SetLastError(err);
646 return FALSE;
648 return TRUE;
651 /******************************************************************************
652 * SetServiceStatus [ADVAPI32.@]
654 * PARAMS
655 * hService []
656 * lpStatus []
658 BOOL WINAPI
659 SetServiceStatus( SERVICE_STATUS_HANDLE hService, LPSERVICE_STATUS lpStatus )
661 DWORD err;
663 TRACE("%p %x %x %x %x %x %x %x\n", hService,
664 lpStatus->dwServiceType, lpStatus->dwCurrentState,
665 lpStatus->dwControlsAccepted, lpStatus->dwWin32ExitCode,
666 lpStatus->dwServiceSpecificExitCode, lpStatus->dwCheckPoint,
667 lpStatus->dwWaitHint);
669 __TRY
671 err = svcctl_SetServiceStatus( hService, lpStatus );
673 __EXCEPT(rpc_filter)
675 err = map_exception_code(GetExceptionCode());
677 __ENDTRY
678 if (err != ERROR_SUCCESS)
680 SetLastError(err);
681 return FALSE;
684 if (lpStatus->dwCurrentState == SERVICE_STOPPED)
685 CloseServiceHandle((SC_HANDLE)hService);
687 return TRUE;
691 /******************************************************************************
692 * OpenSCManagerA [ADVAPI32.@]
694 * Establish a connection to the service control manager and open its database.
696 * PARAMS
697 * lpMachineName [I] Pointer to machine name string
698 * lpDatabaseName [I] Pointer to database name string
699 * dwDesiredAccess [I] Type of access
701 * RETURNS
702 * Success: A Handle to the service control manager database
703 * Failure: NULL
705 SC_HANDLE WINAPI OpenSCManagerA( LPCSTR lpMachineName, LPCSTR lpDatabaseName,
706 DWORD dwDesiredAccess )
708 LPWSTR lpMachineNameW, lpDatabaseNameW;
709 SC_HANDLE ret;
711 lpMachineNameW = SERV_dup(lpMachineName);
712 lpDatabaseNameW = SERV_dup(lpDatabaseName);
713 ret = OpenSCManagerW(lpMachineNameW, lpDatabaseNameW, dwDesiredAccess);
714 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW);
715 HeapFree(GetProcessHeap(), 0, lpMachineNameW);
716 return ret;
719 /******************************************************************************
720 * OpenSCManagerW [ADVAPI32.@]
722 * See OpenSCManagerA.
724 SC_HANDLE WINAPI OpenSCManagerW( LPCWSTR lpMachineName, LPCWSTR lpDatabaseName,
725 DWORD dwDesiredAccess )
727 SC_HANDLE handle;
728 LONG r;
730 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName),
731 debugstr_w(lpDatabaseName), dwDesiredAccess);
733 __TRY
735 r = svcctl_OpenSCManagerW(lpMachineName, lpDatabaseName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
737 __EXCEPT(rpc_filter)
739 r = map_exception_code(GetExceptionCode());
741 __ENDTRY
743 if (r!=ERROR_SUCCESS)
745 SetLastError( r );
746 handle = 0;
749 TRACE("returning %p\n", handle);
750 return handle;
753 /******************************************************************************
754 * ControlService [ADVAPI32.@]
756 * Send a control code to a service.
758 * PARAMS
759 * hService [I] Handle of the service control manager database
760 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
761 * lpServiceStatus [O] Destination for the status of the service, if available
763 * RETURNS
764 * Success: TRUE.
765 * Failure: FALSE.
767 * BUGS
768 * Unlike M$' implementation, control requests are not serialized and may be
769 * processed asynchronously.
771 BOOL WINAPI ControlService( SC_HANDLE hService, DWORD dwControl,
772 LPSERVICE_STATUS lpServiceStatus )
774 DWORD err;
776 TRACE("%p %d %p\n", hService, dwControl, lpServiceStatus);
778 __TRY
780 err = svcctl_ControlService(hService, dwControl, lpServiceStatus);
782 __EXCEPT(rpc_filter)
784 err = map_exception_code(GetExceptionCode());
786 __ENDTRY
787 if (err != ERROR_SUCCESS)
789 SetLastError(err);
790 return FALSE;
793 return TRUE;
796 /******************************************************************************
797 * CloseServiceHandle [ADVAPI32.@]
799 * Close a handle to a service or the service control manager database.
801 * PARAMS
802 * hSCObject [I] Handle to service or service control manager database
804 * RETURNS
805 * Success: TRUE
806 * Failure: FALSE
808 BOOL WINAPI
809 CloseServiceHandle( SC_HANDLE hSCObject )
811 DWORD err;
813 TRACE("%p\n", hSCObject);
815 __TRY
817 err = svcctl_CloseServiceHandle((SC_RPC_HANDLE *)&hSCObject);
819 __EXCEPT(rpc_filter)
821 err = map_exception_code(GetExceptionCode());
823 __ENDTRY
825 if (err != ERROR_SUCCESS)
827 SetLastError(err);
828 return FALSE;
830 return TRUE;
834 /******************************************************************************
835 * OpenServiceA [ADVAPI32.@]
837 * Open a handle to a service.
839 * PARAMS
840 * hSCManager [I] Handle of the service control manager database
841 * lpServiceName [I] Name of the service to open
842 * dwDesiredAccess [I] Access required to the service
844 * RETURNS
845 * Success: Handle to the service
846 * Failure: NULL
848 SC_HANDLE WINAPI OpenServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
849 DWORD dwDesiredAccess )
851 LPWSTR lpServiceNameW;
852 SC_HANDLE ret;
854 TRACE("%p %s %d\n", hSCManager, debugstr_a(lpServiceName), dwDesiredAccess);
856 lpServiceNameW = SERV_dup(lpServiceName);
857 ret = OpenServiceW( hSCManager, lpServiceNameW, dwDesiredAccess);
858 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
859 return ret;
863 /******************************************************************************
864 * OpenServiceW [ADVAPI32.@]
866 * See OpenServiceA.
868 SC_HANDLE WINAPI OpenServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
869 DWORD dwDesiredAccess)
871 SC_HANDLE handle;
872 DWORD err;
874 TRACE("%p %s %d\n", hSCManager, debugstr_w(lpServiceName), dwDesiredAccess);
876 if (!hSCManager)
878 SetLastError( ERROR_INVALID_HANDLE );
879 return 0;
882 __TRY
884 err = svcctl_OpenServiceW(hSCManager, lpServiceName, dwDesiredAccess, (SC_RPC_HANDLE *)&handle);
886 __EXCEPT(rpc_filter)
888 err = map_exception_code(GetExceptionCode());
890 __ENDTRY
892 if (err != ERROR_SUCCESS)
894 SetLastError(err);
895 handle = 0;
898 TRACE("returning %p\n",handle);
899 return handle;
902 /******************************************************************************
903 * CreateServiceW [ADVAPI32.@]
905 SC_HANDLE WINAPI
906 CreateServiceW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
907 LPCWSTR lpDisplayName, DWORD dwDesiredAccess,
908 DWORD dwServiceType, DWORD dwStartType,
909 DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
910 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
911 LPCWSTR lpDependencies, LPCWSTR lpServiceStartName,
912 LPCWSTR lpPassword )
914 SC_HANDLE handle;
915 DWORD err;
916 SIZE_T passwdlen;
918 TRACE("%p %s %s\n", hSCManager,
919 debugstr_w(lpServiceName), debugstr_w(lpDisplayName));
921 if (!hSCManager)
923 SetLastError( ERROR_INVALID_HANDLE );
924 return 0;
927 if (lpPassword)
928 passwdlen = (strlenW(lpPassword) + 1) * sizeof(WCHAR);
929 else
930 passwdlen = 0;
932 __TRY
934 err = svcctl_CreateServiceW(hSCManager, lpServiceName,
935 lpDisplayName, dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
936 lpBinaryPathName, lpLoadOrderGroup, lpdwTagId, (const BYTE*)lpDependencies,
937 multisz_cb(lpDependencies), lpServiceStartName, (const BYTE*)lpPassword, passwdlen,
938 (SC_RPC_HANDLE *)&handle);
940 __EXCEPT(rpc_filter)
942 err = map_exception_code(GetExceptionCode());
944 __ENDTRY
946 if (err != ERROR_SUCCESS)
948 SetLastError(err);
949 handle = 0;
951 return handle;
955 /******************************************************************************
956 * CreateServiceA [ADVAPI32.@]
958 SC_HANDLE WINAPI
959 CreateServiceA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
960 LPCSTR lpDisplayName, DWORD dwDesiredAccess,
961 DWORD dwServiceType, DWORD dwStartType,
962 DWORD dwErrorControl, LPCSTR lpBinaryPathName,
963 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId,
964 LPCSTR lpDependencies, LPCSTR lpServiceStartName,
965 LPCSTR lpPassword )
967 LPWSTR lpServiceNameW, lpDisplayNameW, lpBinaryPathNameW,
968 lpLoadOrderGroupW, lpDependenciesW, lpServiceStartNameW, lpPasswordW;
969 SC_HANDLE r;
971 TRACE("%p %s %s\n", hSCManager,
972 debugstr_a(lpServiceName), debugstr_a(lpDisplayName));
974 lpServiceNameW = SERV_dup( lpServiceName );
975 lpDisplayNameW = SERV_dup( lpDisplayName );
976 lpBinaryPathNameW = SERV_dup( lpBinaryPathName );
977 lpLoadOrderGroupW = SERV_dup( lpLoadOrderGroup );
978 lpDependenciesW = SERV_dupmulti( lpDependencies );
979 lpServiceStartNameW = SERV_dup( lpServiceStartName );
980 lpPasswordW = SERV_dup( lpPassword );
982 r = CreateServiceW( hSCManager, lpServiceNameW, lpDisplayNameW,
983 dwDesiredAccess, dwServiceType, dwStartType, dwErrorControl,
984 lpBinaryPathNameW, lpLoadOrderGroupW, lpdwTagId,
985 lpDependenciesW, lpServiceStartNameW, lpPasswordW );
987 HeapFree( GetProcessHeap(), 0, lpServiceNameW );
988 HeapFree( GetProcessHeap(), 0, lpDisplayNameW );
989 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW );
990 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW );
991 HeapFree( GetProcessHeap(), 0, lpDependenciesW );
992 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW );
993 HeapFree( GetProcessHeap(), 0, lpPasswordW );
995 return r;
999 /******************************************************************************
1000 * DeleteService [ADVAPI32.@]
1002 * Delete a service from the service control manager database.
1004 * PARAMS
1005 * hService [I] Handle of the service to delete
1007 * RETURNS
1008 * Success: TRUE
1009 * Failure: FALSE
1011 BOOL WINAPI DeleteService( SC_HANDLE hService )
1013 DWORD err;
1015 __TRY
1017 err = svcctl_DeleteService(hService);
1019 __EXCEPT(rpc_filter)
1021 err = map_exception_code(GetExceptionCode());
1023 __ENDTRY
1024 if (err != 0)
1026 SetLastError(err);
1027 return FALSE;
1030 return TRUE;
1034 /******************************************************************************
1035 * StartServiceA [ADVAPI32.@]
1037 * Start a service
1039 * PARAMS
1040 * hService [I] Handle of service
1041 * dwNumServiceArgs [I] Number of arguments
1042 * lpServiceArgVectors [I] Address of array of argument strings
1044 * NOTES
1045 * - NT implements this function using an obscure RPC call.
1046 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1047 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1048 * - This will only work for shared address space. How should the service
1049 * args be transferred when address spaces are separated?
1050 * - Can only start one service at a time.
1051 * - Has no concept of privilege.
1053 * RETURNS
1054 * Success: TRUE.
1055 * Failure: FALSE
1057 BOOL WINAPI StartServiceA( SC_HANDLE hService, DWORD dwNumServiceArgs,
1058 LPCSTR *lpServiceArgVectors )
1060 LPWSTR *lpwstr=NULL;
1061 unsigned int i;
1062 BOOL r;
1064 TRACE("(%p,%d,%p)\n",hService,dwNumServiceArgs,lpServiceArgVectors);
1066 if (dwNumServiceArgs)
1067 lpwstr = HeapAlloc( GetProcessHeap(), 0,
1068 dwNumServiceArgs*sizeof(LPWSTR) );
1070 for(i=0; i<dwNumServiceArgs; i++)
1071 lpwstr[i]=SERV_dup(lpServiceArgVectors[i]);
1073 r = StartServiceW(hService, dwNumServiceArgs, (LPCWSTR *)lpwstr);
1075 if (dwNumServiceArgs)
1077 for(i=0; i<dwNumServiceArgs; i++)
1078 HeapFree(GetProcessHeap(), 0, lpwstr[i]);
1079 HeapFree(GetProcessHeap(), 0, lpwstr);
1082 return r;
1086 /******************************************************************************
1087 * StartServiceW [ADVAPI32.@]
1089 * See StartServiceA.
1091 BOOL WINAPI StartServiceW(SC_HANDLE hService, DWORD dwNumServiceArgs,
1092 LPCWSTR *lpServiceArgVectors)
1094 DWORD err;
1096 TRACE("%p %d %p\n", hService, dwNumServiceArgs, lpServiceArgVectors);
1098 __TRY
1100 err = svcctl_StartServiceW(hService, dwNumServiceArgs, lpServiceArgVectors);
1102 __EXCEPT(rpc_filter)
1104 err = map_exception_code(GetExceptionCode());
1106 __ENDTRY
1107 if (err != ERROR_SUCCESS)
1109 SetLastError(err);
1110 return FALSE;
1113 return TRUE;
1116 /******************************************************************************
1117 * QueryServiceStatus [ADVAPI32.@]
1119 * PARAMS
1120 * hService [I] Handle to service to get information about
1121 * lpservicestatus [O] buffer to receive the status information for the service
1124 BOOL WINAPI QueryServiceStatus(SC_HANDLE hService,
1125 LPSERVICE_STATUS lpservicestatus)
1127 SERVICE_STATUS_PROCESS SvcStatusData;
1128 BOOL ret;
1129 DWORD dummy;
1131 TRACE("%p %p\n", hService, lpservicestatus);
1133 if (!hService)
1135 SetLastError(ERROR_INVALID_HANDLE);
1136 return FALSE;
1138 if (!lpservicestatus)
1140 SetLastError(ERROR_INVALID_ADDRESS);
1141 return FALSE;
1144 ret = QueryServiceStatusEx(hService, SC_STATUS_PROCESS_INFO, (LPBYTE)&SvcStatusData,
1145 sizeof(SERVICE_STATUS_PROCESS), &dummy);
1146 if (ret) memcpy(lpservicestatus, &SvcStatusData, sizeof(SERVICE_STATUS)) ;
1147 return ret;
1151 /******************************************************************************
1152 * QueryServiceStatusEx [ADVAPI32.@]
1154 * Get information about a service.
1156 * PARAMS
1157 * hService [I] Handle to service to get information about
1158 * InfoLevel [I] Level of information to get
1159 * lpBuffer [O] Destination for requested information
1160 * cbBufSize [I] Size of lpBuffer in bytes
1161 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1163 * RETURNS
1164 * Success: TRUE
1165 * FAILURE: FALSE
1167 BOOL WINAPI QueryServiceStatusEx(SC_HANDLE hService, SC_STATUS_TYPE InfoLevel,
1168 LPBYTE lpBuffer, DWORD cbBufSize,
1169 LPDWORD pcbBytesNeeded)
1171 DWORD err;
1173 TRACE("%p %d %p %d %p\n", hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1175 if (InfoLevel != SC_STATUS_PROCESS_INFO)
1177 err = ERROR_INVALID_LEVEL;
1179 else if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
1181 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
1182 err = ERROR_INSUFFICIENT_BUFFER;
1184 else
1186 __TRY
1188 err = svcctl_QueryServiceStatusEx(hService, InfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
1190 __EXCEPT(rpc_filter)
1192 err = map_exception_code(GetExceptionCode());
1194 __ENDTRY
1196 if (err != ERROR_SUCCESS)
1198 SetLastError(err);
1199 return FALSE;
1201 return TRUE;
1204 /******************************************************************************
1205 * QueryServiceConfigA [ADVAPI32.@]
1207 BOOL WINAPI QueryServiceConfigA( SC_HANDLE hService, LPQUERY_SERVICE_CONFIGA config,
1208 DWORD size, LPDWORD needed )
1210 DWORD n;
1211 LPSTR p, buffer;
1212 BOOL ret;
1213 QUERY_SERVICE_CONFIGW *configW;
1215 TRACE("%p %p %d %p\n", hService, config, size, needed);
1217 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, 2 * size )))
1219 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1220 return FALSE;
1222 configW = (QUERY_SERVICE_CONFIGW *)buffer;
1223 ret = QueryServiceConfigW( hService, configW, 2 * size, needed );
1224 if (!ret) goto done;
1226 config->dwServiceType = configW->dwServiceType;
1227 config->dwStartType = configW->dwStartType;
1228 config->dwErrorControl = configW->dwErrorControl;
1229 config->lpBinaryPathName = NULL;
1230 config->lpLoadOrderGroup = NULL;
1231 config->dwTagId = configW->dwTagId;
1232 config->lpDependencies = NULL;
1233 config->lpServiceStartName = NULL;
1234 config->lpDisplayName = NULL;
1236 p = (LPSTR)(config + 1);
1237 n = size - sizeof(*config);
1238 ret = FALSE;
1240 #define MAP_STR(str) \
1241 do { \
1242 if (configW->str) \
1244 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1245 if (!sz) goto done; \
1246 config->str = p; \
1247 p += sz; \
1248 n -= sz; \
1250 } while (0)
1252 MAP_STR( lpBinaryPathName );
1253 MAP_STR( lpLoadOrderGroup );
1254 MAP_STR( lpDependencies );
1255 MAP_STR( lpServiceStartName );
1256 MAP_STR( lpDisplayName );
1257 #undef MAP_STR
1259 *needed = p - (LPSTR)config;
1260 ret = TRUE;
1262 done:
1263 HeapFree( GetProcessHeap(), 0, buffer );
1264 return ret;
1267 static DWORD move_string_to_buffer(BYTE **buf, LPWSTR *string_ptr)
1269 DWORD cb;
1271 if (!*string_ptr)
1273 cb = sizeof(WCHAR);
1274 memset(*buf, 0, cb);
1276 else
1278 cb = (strlenW(*string_ptr) + 1)*sizeof(WCHAR);
1279 memcpy(*buf, *string_ptr, cb);
1280 MIDL_user_free(*string_ptr);
1283 *string_ptr = (LPWSTR)*buf;
1284 *buf += cb;
1286 return cb;
1289 static DWORD size_string(LPCWSTR string)
1291 return (string ? (strlenW(string) + 1)*sizeof(WCHAR) : sizeof(WCHAR));
1294 /******************************************************************************
1295 * QueryServiceConfigW [ADVAPI32.@]
1297 BOOL WINAPI
1298 QueryServiceConfigW( SC_HANDLE hService,
1299 LPQUERY_SERVICE_CONFIGW lpServiceConfig,
1300 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1302 QUERY_SERVICE_CONFIGW config;
1303 DWORD total;
1304 DWORD err;
1305 BYTE *bufpos;
1307 TRACE("%p %p %d %p\n", hService, lpServiceConfig,
1308 cbBufSize, pcbBytesNeeded);
1310 memset(&config, 0, sizeof(config));
1312 __TRY
1314 err = svcctl_QueryServiceConfigW(hService, &config);
1316 __EXCEPT(rpc_filter)
1318 err = map_exception_code(GetExceptionCode());
1320 __ENDTRY
1322 if (err != ERROR_SUCCESS)
1324 TRACE("services.exe: error %u\n", err);
1325 SetLastError(err);
1326 return FALSE;
1329 /* calculate the size required first */
1330 total = sizeof (QUERY_SERVICE_CONFIGW);
1331 total += size_string(config.lpBinaryPathName);
1332 total += size_string(config.lpLoadOrderGroup);
1333 total += size_string(config.lpDependencies);
1334 total += size_string(config.lpServiceStartName);
1335 total += size_string(config.lpDisplayName);
1337 *pcbBytesNeeded = total;
1339 /* if there's not enough memory, return an error */
1340 if( total > cbBufSize )
1342 SetLastError( ERROR_INSUFFICIENT_BUFFER );
1343 MIDL_user_free(config.lpBinaryPathName);
1344 MIDL_user_free(config.lpLoadOrderGroup);
1345 MIDL_user_free(config.lpDependencies);
1346 MIDL_user_free(config.lpServiceStartName);
1347 MIDL_user_free(config.lpDisplayName);
1348 return FALSE;
1351 *lpServiceConfig = config;
1352 bufpos = ((BYTE *)lpServiceConfig) + sizeof(QUERY_SERVICE_CONFIGW);
1353 move_string_to_buffer(&bufpos, &lpServiceConfig->lpBinaryPathName);
1354 move_string_to_buffer(&bufpos, &lpServiceConfig->lpLoadOrderGroup);
1355 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDependencies);
1356 move_string_to_buffer(&bufpos, &lpServiceConfig->lpServiceStartName);
1357 move_string_to_buffer(&bufpos, &lpServiceConfig->lpDisplayName);
1359 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig->lpBinaryPathName) );
1360 TRACE("Group = %s\n", debugstr_w(lpServiceConfig->lpLoadOrderGroup) );
1361 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig->lpDependencies) );
1362 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig->lpServiceStartName) );
1363 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig->lpDisplayName) );
1365 return TRUE;
1368 /******************************************************************************
1369 * QueryServiceConfig2A [ADVAPI32.@]
1371 * Note
1372 * observed under win2k:
1373 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1374 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1376 BOOL WINAPI QueryServiceConfig2A(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1377 DWORD size, LPDWORD needed)
1379 BOOL ret;
1380 LPBYTE bufferW = NULL;
1382 if(buffer && size)
1383 bufferW = HeapAlloc( GetProcessHeap(), 0, size);
1385 ret = QueryServiceConfig2W(hService, dwLevel, bufferW, size, needed);
1386 if(!ret) goto cleanup;
1388 switch(dwLevel) {
1389 case SERVICE_CONFIG_DESCRIPTION:
1390 if (buffer && bufferW) {
1391 LPSERVICE_DESCRIPTIONA configA = (LPSERVICE_DESCRIPTIONA) buffer;
1392 LPSERVICE_DESCRIPTIONW configW = (LPSERVICE_DESCRIPTIONW) bufferW;
1393 if (configW->lpDescription && (size > sizeof(SERVICE_DESCRIPTIONA))) {
1394 DWORD sz;
1395 configA->lpDescription = (LPSTR)(configA + 1);
1396 sz = WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1,
1397 configA->lpDescription, size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
1398 if (!sz) {
1399 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1400 ret = FALSE;
1401 configA->lpDescription = NULL;
1404 else configA->lpDescription = NULL;
1406 break;
1407 default:
1408 FIXME("conversation W->A not implemented for level %d\n", dwLevel);
1409 ret = FALSE;
1410 break;
1413 cleanup:
1414 HeapFree( GetProcessHeap(), 0, bufferW);
1415 return ret;
1418 /******************************************************************************
1419 * QueryServiceConfig2W [ADVAPI32.@]
1421 * See QueryServiceConfig2A.
1423 BOOL WINAPI QueryServiceConfig2W(SC_HANDLE hService, DWORD dwLevel, LPBYTE buffer,
1424 DWORD size, LPDWORD needed)
1426 DWORD err;
1428 if(dwLevel != SERVICE_CONFIG_DESCRIPTION) {
1429 FIXME("Level %d not implemented\n", dwLevel);
1430 SetLastError(ERROR_INVALID_LEVEL);
1431 return FALSE;
1434 if(!buffer && size) {
1435 SetLastError(ERROR_INVALID_ADDRESS);
1436 return FALSE;
1439 TRACE("%p 0x%d %p 0x%d %p\n", hService, dwLevel, buffer, size, needed);
1441 __TRY
1443 err = svcctl_QueryServiceConfig2W(hService, dwLevel, buffer, size, needed);
1445 __EXCEPT(rpc_filter)
1447 err = map_exception_code(GetExceptionCode());
1449 __ENDTRY
1451 if (err != ERROR_SUCCESS)
1453 SetLastError( err );
1454 return FALSE;
1457 switch (dwLevel)
1459 case SERVICE_CONFIG_DESCRIPTION:
1460 if (buffer)
1462 SERVICE_DESCRIPTIONW *descr = (SERVICE_DESCRIPTIONW *)buffer;
1463 if (descr->lpDescription) /* make it an absolute pointer */
1464 descr->lpDescription = (WCHAR *)(buffer + (ULONG_PTR)descr->lpDescription);
1465 break;
1469 return TRUE;
1472 /******************************************************************************
1473 * EnumServicesStatusA [ADVAPI32.@]
1475 BOOL WINAPI
1476 EnumServicesStatusA( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSA
1477 services, DWORD size, LPDWORD needed, LPDWORD returned,
1478 LPDWORD resume_handle )
1480 BOOL ret;
1481 unsigned int i;
1482 ENUM_SERVICE_STATUSW *servicesW = NULL;
1483 DWORD sz, n;
1484 char *p;
1486 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1487 returned, resume_handle);
1489 sz = max( 2 * size, sizeof(*servicesW) );
1490 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1492 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1493 return FALSE;
1496 ret = EnumServicesStatusW( hmngr, type, state, servicesW, sz, needed, returned, resume_handle );
1497 if (!ret) goto done;
1499 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUSA);
1500 n = size - (p - (char *)services);
1501 ret = FALSE;
1502 for (i = 0; i < *returned; i++)
1504 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1505 if (!sz) goto done;
1506 services[i].lpServiceName = p;
1507 p += sz;
1508 n -= sz;
1509 if (servicesW[i].lpDisplayName)
1511 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1512 if (!sz) goto done;
1513 services[i].lpDisplayName = p;
1514 p += sz;
1515 n -= sz;
1517 else services[i].lpDisplayName = NULL;
1518 services[i].ServiceStatus = servicesW[i].ServiceStatus;
1521 ret = TRUE;
1523 done:
1524 HeapFree( GetProcessHeap(), 0, servicesW );
1525 return ret;
1528 /******************************************************************************
1529 * EnumServicesStatusW [ADVAPI32.@]
1531 BOOL WINAPI
1532 EnumServicesStatusW( SC_HANDLE hmngr, DWORD type, DWORD state, LPENUM_SERVICE_STATUSW
1533 services, DWORD size, LPDWORD needed, LPDWORD returned,
1534 LPDWORD resume_handle )
1536 DWORD err, i;
1537 ENUM_SERVICE_STATUSW dummy_status;
1539 TRACE("%p 0x%x 0x%x %p %u %p %p %p\n", hmngr, type, state, services, size, needed,
1540 returned, resume_handle);
1542 if (resume_handle)
1543 FIXME("resume handle not supported\n");
1545 if (!hmngr)
1547 SetLastError( ERROR_INVALID_HANDLE );
1548 return FALSE;
1551 /* make sure we pass a valid pointer */
1552 if (!services || size < sizeof(*services))
1554 services = &dummy_status;
1555 size = sizeof(dummy_status);
1558 __TRY
1560 err = svcctl_EnumServicesStatusW( hmngr, type, state, (BYTE *)services, size, needed, returned );
1562 __EXCEPT(rpc_filter)
1564 err = map_exception_code( GetExceptionCode() );
1566 __ENDTRY
1568 if (err != ERROR_SUCCESS)
1570 SetLastError( err );
1571 return FALSE;
1574 for (i = 0; i < *returned; i++)
1576 /* convert buffer offsets into pointers */
1577 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1578 if (services[i].lpDisplayName)
1579 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1582 return TRUE;
1585 /******************************************************************************
1586 * EnumServicesStatusExA [ADVAPI32.@]
1588 BOOL WINAPI
1589 EnumServicesStatusExA( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1590 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1591 LPDWORD resume_handle, LPCSTR group )
1593 BOOL ret;
1594 unsigned int i;
1595 ENUM_SERVICE_STATUS_PROCESSA *services = (ENUM_SERVICE_STATUS_PROCESSA *)buffer;
1596 ENUM_SERVICE_STATUS_PROCESSW *servicesW = NULL;
1597 WCHAR *groupW = NULL;
1598 DWORD sz, n;
1599 char *p;
1601 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1602 size, needed, returned, resume_handle, debugstr_a(group));
1604 sz = max( 2 * size, sizeof(*servicesW) );
1605 if (!(servicesW = HeapAlloc( GetProcessHeap(), 0, sz )))
1607 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1608 return FALSE;
1610 if (group)
1612 int len = MultiByteToWideChar( CP_ACP, 0, group, -1, NULL, 0 );
1613 if (!(groupW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
1615 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
1616 HeapFree( GetProcessHeap(), 0, servicesW );
1617 return FALSE;
1619 MultiByteToWideChar( CP_ACP, 0, group, -1, groupW, len * sizeof(WCHAR) );
1622 ret = EnumServicesStatusExW( hmngr, level, type, state, (BYTE *)servicesW, sz,
1623 needed, returned, resume_handle, groupW );
1624 if (!ret) goto done;
1626 p = (char *)services + *returned * sizeof(ENUM_SERVICE_STATUS_PROCESSA);
1627 n = size - (p - (char *)services);
1628 ret = FALSE;
1629 for (i = 0; i < *returned; i++)
1631 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpServiceName, -1, p, n, NULL, NULL );
1632 if (!sz) goto done;
1633 services[i].lpServiceName = p;
1634 p += sz;
1635 n -= sz;
1636 if (servicesW[i].lpDisplayName)
1638 sz = WideCharToMultiByte( CP_ACP, 0, servicesW[i].lpDisplayName, -1, p, n, NULL, NULL );
1639 if (!sz) goto done;
1640 services[i].lpDisplayName = p;
1641 p += sz;
1642 n -= sz;
1644 else services[i].lpDisplayName = NULL;
1645 services[i].ServiceStatusProcess = servicesW[i].ServiceStatusProcess;
1648 ret = TRUE;
1650 done:
1651 HeapFree( GetProcessHeap(), 0, servicesW );
1652 HeapFree( GetProcessHeap(), 0, groupW );
1653 return ret;
1656 /******************************************************************************
1657 * EnumServicesStatusExW [ADVAPI32.@]
1659 BOOL WINAPI
1660 EnumServicesStatusExW( SC_HANDLE hmngr, SC_ENUM_TYPE level, DWORD type, DWORD state,
1661 LPBYTE buffer, DWORD size, LPDWORD needed, LPDWORD returned,
1662 LPDWORD resume_handle, LPCWSTR group )
1664 DWORD err, i;
1665 ENUM_SERVICE_STATUS_PROCESSW dummy_status;
1666 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1668 TRACE("%p %u 0x%x 0x%x %p %u %p %p %p %s\n", hmngr, level, type, state, buffer,
1669 size, needed, returned, resume_handle, debugstr_w(group));
1671 if (resume_handle)
1672 FIXME("resume handle not supported\n");
1674 if (level != SC_ENUM_PROCESS_INFO)
1676 SetLastError( ERROR_INVALID_LEVEL );
1677 return FALSE;
1679 if (!hmngr)
1681 SetLastError( ERROR_INVALID_HANDLE );
1682 return FALSE;
1685 /* make sure we pass a valid buffer pointer */
1686 if (!services || size < sizeof(*services))
1688 buffer = (BYTE *)&dummy_status;
1689 size = sizeof(dummy_status);
1692 __TRY
1694 err = svcctl_EnumServicesStatusExW( hmngr, type, state, buffer, size, needed,
1695 returned, group );
1697 __EXCEPT(rpc_filter)
1699 err = map_exception_code( GetExceptionCode() );
1701 __ENDTRY
1703 if (err != ERROR_SUCCESS)
1705 SetLastError( err );
1706 return FALSE;
1709 for (i = 0; i < *returned; i++)
1711 /* convert buffer offsets into pointers */
1712 services[i].lpServiceName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpServiceName);
1713 if (services[i].lpDisplayName)
1714 services[i].lpDisplayName = (WCHAR *)((char *)services + (DWORD_PTR)services[i].lpDisplayName);
1717 return TRUE;
1720 /******************************************************************************
1721 * GetServiceKeyNameA [ADVAPI32.@]
1723 BOOL WINAPI GetServiceKeyNameA( SC_HANDLE hSCManager, LPCSTR lpDisplayName,
1724 LPSTR lpServiceName, LPDWORD lpcchBuffer )
1726 LPWSTR lpDisplayNameW, lpServiceNameW;
1727 DWORD sizeW;
1728 BOOL ret = FALSE;
1730 TRACE("%p %s %p %p\n", hSCManager,
1731 debugstr_a(lpDisplayName), lpServiceName, lpcchBuffer);
1733 lpDisplayNameW = SERV_dup(lpDisplayName);
1734 if (lpServiceName)
1735 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1736 else
1737 lpServiceNameW = NULL;
1739 sizeW = *lpcchBuffer;
1740 if (!GetServiceKeyNameW(hSCManager, lpDisplayNameW, lpServiceNameW, &sizeW))
1742 if (lpServiceName && *lpcchBuffer)
1743 lpServiceName[0] = 0;
1744 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1745 goto cleanup;
1748 if (!WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, (sizeW + 1), lpServiceName,
1749 *lpcchBuffer, NULL, NULL ))
1751 if (*lpcchBuffer && lpServiceName)
1752 lpServiceName[0] = 0;
1753 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpServiceNameW, -1, NULL, 0, NULL, NULL);
1754 goto cleanup;
1757 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
1758 ret = TRUE;
1760 cleanup:
1761 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1762 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1763 return ret;
1766 /******************************************************************************
1767 * GetServiceKeyNameW [ADVAPI32.@]
1769 BOOL WINAPI GetServiceKeyNameW( SC_HANDLE hSCManager, LPCWSTR lpDisplayName,
1770 LPWSTR lpServiceName, LPDWORD lpcchBuffer )
1772 DWORD err;
1773 WCHAR buffer[2];
1774 DWORD size;
1776 TRACE("%p %s %p %p\n", hSCManager,
1777 debugstr_w(lpDisplayName), lpServiceName, lpcchBuffer);
1779 if (!hSCManager)
1781 SetLastError( ERROR_INVALID_HANDLE );
1782 return 0;
1785 /* provide a buffer if the caller didn't */
1786 if (!lpServiceName || *lpcchBuffer < 2)
1788 lpServiceName = buffer;
1789 /* A size of 1 would be enough, but tests show that Windows returns 2,
1790 * probably because of a WCHAR/bytes mismatch in their code.
1792 *lpcchBuffer = 2;
1795 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1796 * includes the nul-terminator on input. */
1797 size = *lpcchBuffer - 1;
1799 __TRY
1801 err = svcctl_GetServiceKeyNameW(hSCManager, lpDisplayName, lpServiceName,
1802 &size);
1804 __EXCEPT(rpc_filter)
1806 err = map_exception_code(GetExceptionCode());
1808 __ENDTRY
1810 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1811 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1812 *lpcchBuffer = size;
1814 if (err)
1815 SetLastError(err);
1816 return err == ERROR_SUCCESS;
1819 /******************************************************************************
1820 * QueryServiceLockStatusA [ADVAPI32.@]
1822 BOOL WINAPI QueryServiceLockStatusA( SC_HANDLE hSCManager,
1823 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
1824 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1826 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1828 return FALSE;
1831 /******************************************************************************
1832 * QueryServiceLockStatusW [ADVAPI32.@]
1834 BOOL WINAPI QueryServiceLockStatusW( SC_HANDLE hSCManager,
1835 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
1836 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
1838 FIXME("%p %p %08x %p\n", hSCManager, lpLockStatus, cbBufSize, pcbBytesNeeded);
1840 return FALSE;
1843 /******************************************************************************
1844 * GetServiceDisplayNameA [ADVAPI32.@]
1846 BOOL WINAPI GetServiceDisplayNameA( SC_HANDLE hSCManager, LPCSTR lpServiceName,
1847 LPSTR lpDisplayName, LPDWORD lpcchBuffer)
1849 LPWSTR lpServiceNameW, lpDisplayNameW;
1850 DWORD sizeW;
1851 BOOL ret = FALSE;
1853 TRACE("%p %s %p %p\n", hSCManager,
1854 debugstr_a(lpServiceName), lpDisplayName, lpcchBuffer);
1856 lpServiceNameW = SERV_dup(lpServiceName);
1857 if (lpDisplayName)
1858 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer * sizeof(WCHAR));
1859 else
1860 lpDisplayNameW = NULL;
1862 sizeW = *lpcchBuffer;
1863 if (!GetServiceDisplayNameW(hSCManager, lpServiceNameW, lpDisplayNameW, &sizeW))
1865 if (lpDisplayName && *lpcchBuffer)
1866 lpDisplayName[0] = 0;
1867 *lpcchBuffer = sizeW*2; /* we can only provide an upper estimation of string length */
1868 goto cleanup;
1871 if (!WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, (sizeW + 1), lpDisplayName,
1872 *lpcchBuffer, NULL, NULL ))
1874 if (*lpcchBuffer && lpDisplayName)
1875 lpDisplayName[0] = 0;
1876 *lpcchBuffer = WideCharToMultiByte(CP_ACP, 0, lpDisplayNameW, -1, NULL, 0, NULL, NULL);
1877 goto cleanup;
1880 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
1881 * (but if the function succeeded it means that is a good upper estimation of the size) */
1882 ret = TRUE;
1884 cleanup:
1885 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
1886 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
1887 return ret;
1890 /******************************************************************************
1891 * GetServiceDisplayNameW [ADVAPI32.@]
1893 BOOL WINAPI GetServiceDisplayNameW( SC_HANDLE hSCManager, LPCWSTR lpServiceName,
1894 LPWSTR lpDisplayName, LPDWORD lpcchBuffer)
1896 DWORD err;
1897 DWORD size;
1898 WCHAR buffer[2];
1900 TRACE("%p %s %p %p\n", hSCManager,
1901 debugstr_w(lpServiceName), lpDisplayName, lpcchBuffer);
1903 if (!hSCManager)
1905 SetLastError( ERROR_INVALID_HANDLE );
1906 return 0;
1909 /* provide a buffer if the caller didn't */
1910 if (!lpDisplayName || *lpcchBuffer < 2)
1912 lpDisplayName = buffer;
1913 /* A size of 1 would be enough, but tests show that Windows returns 2,
1914 * probably because of a WCHAR/bytes mismatch in their code.
1916 *lpcchBuffer = 2;
1919 /* RPC call takes size excluding nul-terminator, whereas *lpcchBuffer
1920 * includes the nul-terminator on input. */
1921 size = *lpcchBuffer - 1;
1923 __TRY
1925 err = svcctl_GetServiceDisplayNameW(hSCManager, lpServiceName, lpDisplayName,
1926 &size);
1928 __EXCEPT(rpc_filter)
1930 err = map_exception_code(GetExceptionCode());
1932 __ENDTRY
1934 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1935 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1936 *lpcchBuffer = size;
1938 if (err)
1939 SetLastError(err);
1940 return err == ERROR_SUCCESS;
1943 /******************************************************************************
1944 * ChangeServiceConfigW [ADVAPI32.@]
1946 BOOL WINAPI ChangeServiceConfigW( SC_HANDLE hService, DWORD dwServiceType,
1947 DWORD dwStartType, DWORD dwErrorControl, LPCWSTR lpBinaryPathName,
1948 LPCWSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCWSTR lpDependencies,
1949 LPCWSTR lpServiceStartName, LPCWSTR lpPassword, LPCWSTR lpDisplayName)
1951 DWORD cb_pwd;
1952 DWORD err;
1954 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1955 hService, dwServiceType, dwStartType, dwErrorControl,
1956 debugstr_w(lpBinaryPathName), debugstr_w(lpLoadOrderGroup),
1957 lpdwTagId, lpDependencies, debugstr_w(lpServiceStartName),
1958 debugstr_w(lpPassword), debugstr_w(lpDisplayName) );
1960 cb_pwd = lpPassword ? (strlenW(lpPassword) + 1)*sizeof(WCHAR) : 0;
1962 __TRY
1964 err = svcctl_ChangeServiceConfigW(hService, dwServiceType,
1965 dwStartType, dwErrorControl, lpBinaryPathName, lpLoadOrderGroup, lpdwTagId,
1966 (const BYTE *)lpDependencies, multisz_cb(lpDependencies), lpServiceStartName,
1967 (const BYTE *)lpPassword, cb_pwd, lpDisplayName);
1969 __EXCEPT(rpc_filter)
1971 err = map_exception_code(GetExceptionCode());
1973 __ENDTRY
1975 if (err != ERROR_SUCCESS)
1976 SetLastError(err);
1978 return err == ERROR_SUCCESS;
1981 /******************************************************************************
1982 * ChangeServiceConfigA [ADVAPI32.@]
1984 BOOL WINAPI ChangeServiceConfigA( SC_HANDLE hService, DWORD dwServiceType,
1985 DWORD dwStartType, DWORD dwErrorControl, LPCSTR lpBinaryPathName,
1986 LPCSTR lpLoadOrderGroup, LPDWORD lpdwTagId, LPCSTR lpDependencies,
1987 LPCSTR lpServiceStartName, LPCSTR lpPassword, LPCSTR lpDisplayName)
1989 LPWSTR wBinaryPathName, wLoadOrderGroup, wDependencies;
1990 LPWSTR wServiceStartName, wPassword, wDisplayName;
1991 BOOL r;
1993 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
1994 hService, dwServiceType, dwStartType, dwErrorControl,
1995 debugstr_a(lpBinaryPathName), debugstr_a(lpLoadOrderGroup),
1996 lpdwTagId, lpDependencies, debugstr_a(lpServiceStartName),
1997 debugstr_a(lpPassword), debugstr_a(lpDisplayName) );
1999 wBinaryPathName = SERV_dup( lpBinaryPathName );
2000 wLoadOrderGroup = SERV_dup( lpLoadOrderGroup );
2001 wDependencies = SERV_dupmulti( lpDependencies );
2002 wServiceStartName = SERV_dup( lpServiceStartName );
2003 wPassword = SERV_dup( lpPassword );
2004 wDisplayName = SERV_dup( lpDisplayName );
2006 r = ChangeServiceConfigW( hService, dwServiceType,
2007 dwStartType, dwErrorControl, wBinaryPathName,
2008 wLoadOrderGroup, lpdwTagId, wDependencies,
2009 wServiceStartName, wPassword, wDisplayName);
2011 HeapFree( GetProcessHeap(), 0, wBinaryPathName );
2012 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup );
2013 HeapFree( GetProcessHeap(), 0, wDependencies );
2014 HeapFree( GetProcessHeap(), 0, wServiceStartName );
2015 HeapFree( GetProcessHeap(), 0, wPassword );
2016 HeapFree( GetProcessHeap(), 0, wDisplayName );
2018 return r;
2021 /******************************************************************************
2022 * ChangeServiceConfig2A [ADVAPI32.@]
2024 BOOL WINAPI ChangeServiceConfig2A( SC_HANDLE hService, DWORD dwInfoLevel,
2025 LPVOID lpInfo)
2027 BOOL r = FALSE;
2029 TRACE("%p %d %p\n",hService, dwInfoLevel, lpInfo);
2031 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
2033 LPSERVICE_DESCRIPTIONA sd = lpInfo;
2034 SERVICE_DESCRIPTIONW sdw;
2036 sdw.lpDescription = SERV_dup( sd->lpDescription );
2038 r = ChangeServiceConfig2W( hService, dwInfoLevel, &sdw );
2040 HeapFree( GetProcessHeap(), 0, sdw.lpDescription );
2042 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
2044 LPSERVICE_FAILURE_ACTIONSA fa = lpInfo;
2045 SERVICE_FAILURE_ACTIONSW faw;
2047 faw.dwResetPeriod = fa->dwResetPeriod;
2048 faw.lpRebootMsg = SERV_dup( fa->lpRebootMsg );
2049 faw.lpCommand = SERV_dup( fa->lpCommand );
2050 faw.cActions = fa->cActions;
2051 faw.lpsaActions = fa->lpsaActions;
2053 r = ChangeServiceConfig2W( hService, dwInfoLevel, &faw );
2055 HeapFree( GetProcessHeap(), 0, faw.lpRebootMsg );
2056 HeapFree( GetProcessHeap(), 0, faw.lpCommand );
2058 else
2059 SetLastError( ERROR_INVALID_PARAMETER );
2061 return r;
2064 /******************************************************************************
2065 * ChangeServiceConfig2W [ADVAPI32.@]
2067 BOOL WINAPI ChangeServiceConfig2W( SC_HANDLE hService, DWORD dwInfoLevel,
2068 LPVOID lpInfo)
2070 DWORD err;
2072 __TRY
2074 err = svcctl_ChangeServiceConfig2W( hService, dwInfoLevel, lpInfo );
2076 __EXCEPT(rpc_filter)
2078 err = map_exception_code(GetExceptionCode());
2080 __ENDTRY
2082 if (err != ERROR_SUCCESS)
2083 SetLastError(err);
2085 return err == ERROR_SUCCESS;
2088 /******************************************************************************
2089 * QueryServiceObjectSecurity [ADVAPI32.@]
2091 BOOL WINAPI QueryServiceObjectSecurity(SC_HANDLE hService,
2092 SECURITY_INFORMATION dwSecurityInformation,
2093 PSECURITY_DESCRIPTOR lpSecurityDescriptor,
2094 DWORD cbBufSize, LPDWORD pcbBytesNeeded)
2096 SECURITY_DESCRIPTOR descriptor;
2097 DWORD size;
2098 BOOL succ;
2099 ACL acl;
2101 FIXME("%p %d %p %u %p - semi-stub\n", hService, dwSecurityInformation,
2102 lpSecurityDescriptor, cbBufSize, pcbBytesNeeded);
2104 if (dwSecurityInformation != DACL_SECURITY_INFORMATION)
2105 FIXME("information %d not supported\n", dwSecurityInformation);
2107 InitializeSecurityDescriptor(&descriptor, SECURITY_DESCRIPTOR_REVISION);
2109 InitializeAcl(&acl, sizeof(ACL), ACL_REVISION);
2110 SetSecurityDescriptorDacl(&descriptor, TRUE, &acl, TRUE);
2112 size = cbBufSize;
2113 succ = MakeSelfRelativeSD(&descriptor, lpSecurityDescriptor, &size);
2114 *pcbBytesNeeded = size;
2115 return succ;
2118 /******************************************************************************
2119 * SetServiceObjectSecurity [ADVAPI32.@]
2121 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
2122 SECURITY_INFORMATION dwSecurityInformation,
2123 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
2125 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
2126 return TRUE;
2129 /******************************************************************************
2130 * SetServiceBits [ADVAPI32.@]
2132 BOOL WINAPI SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus,
2133 DWORD dwServiceBits,
2134 BOOL bSetBitsOn,
2135 BOOL bUpdateImmediately)
2137 FIXME("%p %08x %x %x\n", hServiceStatus, dwServiceBits,
2138 bSetBitsOn, bUpdateImmediately);
2139 return TRUE;
2142 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2143 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
2145 LPHANDLER_FUNCTION func = context;
2147 func( control );
2148 return ERROR_SUCCESS;
2151 /******************************************************************************
2152 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2154 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerA( LPCSTR name, LPHANDLER_FUNCTION handler )
2156 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
2159 /******************************************************************************
2160 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2162 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerW( LPCWSTR name, LPHANDLER_FUNCTION handler )
2164 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
2167 /******************************************************************************
2168 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2170 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExA( LPCSTR name, LPHANDLER_FUNCTION_EX handler, LPVOID context )
2172 LPWSTR nameW;
2173 SERVICE_STATUS_HANDLE ret;
2175 nameW = SERV_dup(name);
2176 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
2177 HeapFree( GetProcessHeap(), 0, nameW );
2178 return ret;
2181 /******************************************************************************
2182 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2184 SERVICE_STATUS_HANDLE WINAPI RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName,
2185 LPHANDLER_FUNCTION_EX lpHandlerProc, LPVOID lpContext )
2187 service_data *service;
2188 SC_HANDLE hService = 0;
2189 BOOL found = FALSE;
2191 TRACE("%s %p %p\n", debugstr_w(lpServiceName), lpHandlerProc, lpContext);
2193 EnterCriticalSection( &service_cs );
2194 if ((service = find_service_by_name( lpServiceName )))
2196 service->handler = lpHandlerProc;
2197 service->context = lpContext;
2198 hService = service->handle;
2199 found = TRUE;
2201 LeaveCriticalSection( &service_cs );
2203 if (!found) SetLastError(ERROR_SERVICE_DOES_NOT_EXIST);
2205 return (SERVICE_STATUS_HANDLE)hService;
2208 /******************************************************************************
2209 * EnumDependentServicesA [ADVAPI32.@]
2211 BOOL WINAPI EnumDependentServicesA( SC_HANDLE hService, DWORD dwServiceState,
2212 LPENUM_SERVICE_STATUSA lpServices, DWORD cbBufSize,
2213 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2215 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2216 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2218 *lpServicesReturned = 0;
2219 return TRUE;
2222 /******************************************************************************
2223 * EnumDependentServicesW [ADVAPI32.@]
2225 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
2226 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
2227 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
2229 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
2230 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
2232 *lpServicesReturned = 0;
2233 return TRUE;