user32: Remove _wassert workaround.
[wine.git] / dlls / sechost / service.c
blobe6f4eb75db0c87d32d2f69d62db9edb99976550c
1 /*
2 * Service control API
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 #define NONAMELESSUNION
24 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winsvc.h"
28 #include "winternl.h"
29 #include "winuser.h"
30 #include "dbt.h"
32 #include "wine/debug.h"
33 #include "wine/exception.h"
34 #include "wine/heap.h"
35 #include "wine/list.h"
37 #include "svcctl.h"
38 #include "plugplay.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(service);
42 struct notify_data
44 SC_HANDLE service;
45 SC_RPC_NOTIFY_PARAMS params;
46 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 cparams;
47 SC_NOTIFY_RPC_HANDLE notify_handle;
48 SERVICE_NOTIFYW *notify_buffer;
49 HANDLE calling_thread, ready_evt;
50 struct list entry;
53 static struct list notify_list = LIST_INIT(notify_list);
55 static CRITICAL_SECTION service_cs;
56 static CRITICAL_SECTION_DEBUG service_cs_debug =
58 0, 0, &service_cs,
59 { &service_cs_debug.ProcessLocksList,
60 &service_cs_debug.ProcessLocksList },
61 0, 0, { (DWORD_PTR)(__FILE__ ": service_cs") }
63 static CRITICAL_SECTION service_cs = { &service_cs_debug, -1, 0, 0, 0, 0 };
65 struct service_data
67 LPHANDLER_FUNCTION_EX handler;
68 void *context;
69 HANDLE thread;
70 SC_HANDLE handle;
71 SC_HANDLE full_access_handle;
72 unsigned int unicode : 1;
73 union
75 LPSERVICE_MAIN_FUNCTIONA a;
76 LPSERVICE_MAIN_FUNCTIONW w;
77 } proc;
78 WCHAR *args;
79 WCHAR name[1];
82 struct dispatcher_data
84 SC_HANDLE manager;
85 HANDLE pipe;
88 static struct service_data **services;
89 static unsigned int nb_services;
90 static HANDLE service_event;
91 static BOOL stop_service;
93 static WCHAR *heap_strdupAtoW( const char *src )
95 WCHAR *dst = NULL;
96 if (src)
98 DWORD len = MultiByteToWideChar( CP_ACP, 0, src, -1, NULL, 0 );
99 if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, -1, dst, len );
101 return dst;
104 static WCHAR *heap_strdup_multi_AtoW( const char *src )
106 WCHAR *dst = NULL;
107 const char *p = src;
108 DWORD len;
110 if (!src) return NULL;
112 while (*p) p += strlen(p) + 1;
113 for (p = src; *p; p += strlen(p) + 1);
114 p++; /* final null */
115 len = MultiByteToWideChar( CP_ACP, 0, src, p - src, NULL, 0 );
116 if ((dst = heap_alloc( len * sizeof(WCHAR) ))) MultiByteToWideChar( CP_ACP, 0, src, p - src, dst, len );
117 return dst;
120 static inline DWORD multisz_size( const WCHAR *str )
122 const WCHAR *p = str;
124 if (!str) return 0;
126 while (*p) p += wcslen(p) + 1;
127 return (p - str + 1) * sizeof(WCHAR);
130 void __RPC_FAR * __RPC_USER MIDL_user_allocate( SIZE_T len )
132 return heap_alloc(len);
135 void __RPC_USER MIDL_user_free( void __RPC_FAR *ptr )
137 heap_free(ptr);
140 static LONG WINAPI rpc_filter( EXCEPTION_POINTERS *eptr )
142 return I_RpcExceptionFilter( eptr->ExceptionRecord->ExceptionCode );
145 static DWORD map_exception_code( DWORD exception_code )
147 switch (exception_code)
149 case RPC_X_NULL_REF_POINTER:
150 return ERROR_INVALID_ADDRESS;
151 case RPC_X_ENUM_VALUE_OUT_OF_RANGE:
152 case RPC_X_BYTE_COUNT_TOO_SMALL:
153 return ERROR_INVALID_PARAMETER;
154 case RPC_S_INVALID_BINDING:
155 case RPC_X_SS_IN_NULL_CONTEXT:
156 return ERROR_INVALID_HANDLE;
157 default:
158 return exception_code;
162 static handle_t rpc_wstr_bind( RPC_WSTR str )
164 WCHAR transport[] = SVCCTL_TRANSPORT;
165 WCHAR endpoint[] = SVCCTL_ENDPOINT;
166 RPC_WSTR binding_str;
167 RPC_STATUS status;
168 handle_t rpc_handle;
170 status = RpcStringBindingComposeW( NULL, transport, str, endpoint, NULL, &binding_str );
171 if (status != RPC_S_OK)
173 ERR("RpcStringBindingComposeW failed, error %d\n", status);
174 return NULL;
177 status = RpcBindingFromStringBindingW( binding_str, &rpc_handle );
178 RpcStringFreeW( &binding_str );
180 if (status != RPC_S_OK)
182 ERR("Couldn't connect to services.exe, error %d\n", status);
183 return NULL;
186 return rpc_handle;
189 static handle_t rpc_cstr_bind(RPC_CSTR str)
191 RPC_CSTR transport = (RPC_CSTR)SVCCTL_TRANSPORTA;
192 RPC_CSTR endpoint = (RPC_CSTR)SVCCTL_ENDPOINTA;
193 RPC_CSTR binding_str;
194 RPC_STATUS status;
195 handle_t rpc_handle;
197 status = RpcStringBindingComposeA( NULL, transport, str, endpoint, NULL, &binding_str );
198 if (status != RPC_S_OK)
200 ERR("RpcStringBindingComposeA failed, error %d\n", status);
201 return NULL;
204 status = RpcBindingFromStringBindingA( binding_str, &rpc_handle );
205 RpcStringFreeA( &binding_str );
207 if (status != RPC_S_OK)
209 ERR("Couldn't connect to services.exe, error %d\n", status);
210 return NULL;
213 return rpc_handle;
216 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEA_bind( MACHINE_HANDLEA name )
218 return rpc_cstr_bind( (RPC_CSTR)name );
221 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEA_unbind( MACHINE_HANDLEA name, handle_t h )
223 RpcBindingFree( &h );
226 DECLSPEC_HIDDEN handle_t __RPC_USER MACHINE_HANDLEW_bind( MACHINE_HANDLEW name )
228 return rpc_wstr_bind( (RPC_WSTR)name );
231 DECLSPEC_HIDDEN void __RPC_USER MACHINE_HANDLEW_unbind( MACHINE_HANDLEW name, handle_t h )
233 RpcBindingFree( &h );
236 DECLSPEC_HIDDEN handle_t __RPC_USER SVCCTL_HANDLEW_bind( SVCCTL_HANDLEW name )
238 return rpc_wstr_bind( (RPC_WSTR)name );
241 DECLSPEC_HIDDEN void __RPC_USER SVCCTL_HANDLEW_unbind( SVCCTL_HANDLEW name, handle_t h )
243 RpcBindingFree( &h );
246 static BOOL set_error( DWORD err )
248 if (err) SetLastError( err );
249 return !err;
252 /******************************************************************************
253 * OpenSCManagerA (sechost.@)
255 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerA( const char *machine, const char *database, DWORD access )
257 WCHAR *machineW, *databaseW;
258 SC_HANDLE ret;
260 machineW = heap_strdupAtoW( machine );
261 databaseW = heap_strdupAtoW( database );
262 ret = OpenSCManagerW( machineW, databaseW, access );
263 heap_free( databaseW );
264 heap_free( machineW );
265 return ret;
268 /******************************************************************************
269 * OpenSCManagerW (sechost.@)
271 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenSCManagerW( const WCHAR *machine, const WCHAR *database, DWORD access )
273 SC_RPC_HANDLE handle = NULL;
274 DWORD err;
276 TRACE( "%s %s %#x\n", debugstr_w(machine), debugstr_w(database), access );
278 __TRY
280 err = svcctl_OpenSCManagerW( machine, database, access, &handle );
282 __EXCEPT(rpc_filter)
284 err = map_exception_code( GetExceptionCode() );
286 __ENDTRY
288 if (!err) return handle;
289 SetLastError( err );
290 return NULL;
293 /******************************************************************************
294 * OpenServiceA (sechost.@)
296 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceA( SC_HANDLE manager, const char *name, DWORD access )
298 WCHAR *nameW;
299 SC_HANDLE ret;
301 TRACE( "%p %s %#x\n", manager, debugstr_a(name), access );
303 nameW = heap_strdupAtoW( name );
304 ret = OpenServiceW( manager, nameW, access );
305 heap_free( nameW );
306 return ret;
309 /******************************************************************************
310 * OpenServiceW (sechost.@)
312 SC_HANDLE WINAPI DECLSPEC_HOTPATCH OpenServiceW( SC_HANDLE manager, const WCHAR *name, DWORD access )
314 SC_RPC_HANDLE handle = NULL;
315 DWORD err;
317 TRACE( "%p %s %#x\n", manager, debugstr_w(name), access );
319 if (!manager)
321 SetLastError( ERROR_INVALID_HANDLE );
322 return NULL;
325 __TRY
327 err = svcctl_OpenServiceW( manager, name, access, &handle );
329 __EXCEPT(rpc_filter)
331 err = map_exception_code( GetExceptionCode() );
333 __ENDTRY
335 if (!err) return handle;
336 SetLastError( err );
337 return 0;
340 /******************************************************************************
341 * CreateServiceA (sechost.@)
343 SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceA( SC_HANDLE manager, const char *name, const char *display_name,
344 DWORD access, DWORD service_type, DWORD start_type,
345 DWORD error_control, const char *path, const char *group,
346 DWORD *tag, const char *dependencies, const char *username,
347 const char *password )
349 WCHAR *nameW, *display_nameW, *pathW, *groupW, *dependenciesW, *usernameW, *passwordW;
350 SC_HANDLE handle;
352 TRACE( "%p %s %s\n", manager, debugstr_a(name), debugstr_a(display_name) );
354 nameW = heap_strdupAtoW( name );
355 display_nameW = heap_strdupAtoW( display_name );
356 pathW = heap_strdupAtoW( path );
357 groupW = heap_strdupAtoW( group );
358 dependenciesW = heap_strdupAtoW( dependencies );
359 usernameW = heap_strdupAtoW( username );
360 passwordW = heap_strdupAtoW( password );
362 handle = CreateServiceW( manager, nameW, display_nameW, access, service_type, start_type, error_control,
363 pathW, groupW, tag, dependenciesW, usernameW, passwordW );
365 heap_free( nameW );
366 heap_free( display_nameW );
367 heap_free( pathW );
368 heap_free( groupW );
369 heap_free( dependenciesW );
370 heap_free( usernameW );
371 heap_free( passwordW );
373 return handle;
376 /******************************************************************************
377 * CreateServiceW (sechost.@)
379 SC_HANDLE WINAPI DECLSPEC_HOTPATCH CreateServiceW( SC_HANDLE manager, const WCHAR *name, const WCHAR *display_name,
380 DWORD access, DWORD service_type, DWORD start_type,
381 DWORD error_control, const WCHAR *path, const WCHAR *group,
382 DWORD *tag, const WCHAR *dependencies, const WCHAR *username,
383 const WCHAR *password )
385 SC_RPC_HANDLE handle = NULL;
386 DWORD err;
387 SIZE_T password_size = 0;
389 TRACE( "%p %s %s\n", manager, debugstr_w(name), debugstr_w(display_name) );
391 if (!manager)
393 SetLastError( ERROR_INVALID_HANDLE );
394 return 0;
397 if (password) password_size = (wcslen(password) + 1) * sizeof(WCHAR);
399 __TRY
401 BOOL is_wow64;
403 if (IsWow64Process(GetCurrentProcess(), &is_wow64) && is_wow64)
404 err = svcctl_CreateServiceWOW64W( manager, name, display_name, access, service_type, start_type,
405 error_control, path, group, tag, (const BYTE *)dependencies,
406 multisz_size( dependencies ), username, (const BYTE *)password,
407 password_size, &handle );
408 else
409 err = svcctl_CreateServiceW( manager, name, display_name, access, service_type, start_type,
410 error_control, path, group, tag, (const BYTE *)dependencies,
411 multisz_size( dependencies ), username, (const BYTE *)password,
412 password_size, &handle );
414 __EXCEPT(rpc_filter)
416 err = map_exception_code( GetExceptionCode() );
418 __ENDTRY
420 if (!err) return handle;
421 SetLastError( err );
422 return NULL;
425 /******************************************************************************
426 * DeleteService (sechost.@)
428 BOOL WINAPI DECLSPEC_HOTPATCH DeleteService( SC_HANDLE service )
430 DWORD err;
432 TRACE( "%p\n", service );
434 __TRY
436 err = svcctl_DeleteService( service );
438 __EXCEPT(rpc_filter)
440 err = map_exception_code( GetExceptionCode() );
442 __ENDTRY
444 return set_error( err );
447 /******************************************************************************
448 * CloseServiceHandle (sechost.@)
450 BOOL WINAPI DECLSPEC_HOTPATCH CloseServiceHandle( SC_HANDLE handle )
452 DWORD err;
454 TRACE( "%p\n", handle );
456 __TRY
458 err = svcctl_CloseServiceHandle( (SC_RPC_HANDLE *)&handle );
460 __EXCEPT(rpc_filter)
462 err = map_exception_code( GetExceptionCode() );
464 __ENDTRY
466 return set_error( err );
469 /******************************************************************************
470 * ChangeServiceConfig2A (sechost.@)
472 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2A( SC_HANDLE service, DWORD level, void *info)
474 BOOL r = FALSE;
476 TRACE( "%p %d %p\n", service, level, info );
478 if (level == SERVICE_CONFIG_DESCRIPTION)
480 SERVICE_DESCRIPTIONA *sd = info;
481 SERVICE_DESCRIPTIONW sdw;
483 sdw.lpDescription = heap_strdupAtoW( sd->lpDescription );
485 r = ChangeServiceConfig2W( service, level, &sdw );
487 heap_free( sdw.lpDescription );
489 else if (level == SERVICE_CONFIG_FAILURE_ACTIONS)
491 SERVICE_FAILURE_ACTIONSA *fa = info;
492 SERVICE_FAILURE_ACTIONSW faw;
494 faw.dwResetPeriod = fa->dwResetPeriod;
495 faw.lpRebootMsg = heap_strdupAtoW( fa->lpRebootMsg );
496 faw.lpCommand = heap_strdupAtoW( fa->lpCommand );
497 faw.cActions = fa->cActions;
498 faw.lpsaActions = fa->lpsaActions;
500 r = ChangeServiceConfig2W( service, level, &faw );
502 heap_free( faw.lpRebootMsg );
503 heap_free( faw.lpCommand );
505 else if (level == SERVICE_CONFIG_PRESHUTDOWN_INFO)
507 r = ChangeServiceConfig2W( service, level, info );
509 else
510 SetLastError( ERROR_INVALID_PARAMETER );
512 return r;
515 /******************************************************************************
516 * ChangeServiceConfig2W (sechost.@)
518 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfig2W( SC_HANDLE service, DWORD level, void *info )
520 SERVICE_RPC_REQUIRED_PRIVILEGES_INFO rpc_privinfo;
521 DWORD err;
523 __TRY
525 SC_RPC_CONFIG_INFOW rpc_info;
527 rpc_info.dwInfoLevel = level;
528 if (level == SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO)
530 SERVICE_REQUIRED_PRIVILEGES_INFOW *privinfo = info;
532 rpc_privinfo.cbRequiredPrivileges = multisz_size( privinfo->pmszRequiredPrivileges );
533 rpc_privinfo.pRequiredPrivileges = (BYTE *)privinfo->pmszRequiredPrivileges;
534 rpc_info.privinfo = &rpc_privinfo;
536 else
537 rpc_info.descr = info;
538 err = svcctl_ChangeServiceConfig2W( service, rpc_info );
540 __EXCEPT(rpc_filter)
542 err = map_exception_code( GetExceptionCode() );
544 __ENDTRY
546 return set_error( err );
549 /******************************************************************************
550 * ChangeServiceConfigA (sechost.@)
552 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigA( SC_HANDLE service, DWORD service_type, DWORD start_type,
553 DWORD error_control, const char *path, const char *group,
554 DWORD *tag, const char *dependencies, const char *username,
555 const char *password, const char *display_name )
557 WCHAR *pathW, *groupW, *dependenciesW, *usernameW, *passwordW, *display_nameW;
558 BOOL r;
560 TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service, service_type, start_type,
561 error_control, debugstr_a(path), debugstr_a(group), tag, dependencies,
562 debugstr_a(username), debugstr_a(password), debugstr_a(display_name) );
564 pathW = heap_strdupAtoW( path );
565 groupW = heap_strdupAtoW( group );
566 dependenciesW = heap_strdup_multi_AtoW( dependencies );
567 usernameW = heap_strdupAtoW( username );
568 passwordW = heap_strdupAtoW( password );
569 display_nameW = heap_strdupAtoW( display_name );
571 r = ChangeServiceConfigW( service, service_type, start_type, error_control, pathW,
572 groupW, tag, dependenciesW, usernameW, passwordW, display_nameW );
574 heap_free( pathW );
575 heap_free( groupW );
576 heap_free( dependenciesW );
577 heap_free( usernameW );
578 heap_free( passwordW );
579 heap_free( display_nameW );
581 return r;
584 /******************************************************************************
585 * ChangeServiceConfigW (sechost.@)
587 BOOL WINAPI DECLSPEC_HOTPATCH ChangeServiceConfigW( SC_HANDLE service, DWORD service_type, DWORD start_type,
588 DWORD error_control, const WCHAR *path, const WCHAR *group,
589 DWORD *tag, const WCHAR *dependencies, const WCHAR *username,
590 const WCHAR *password, const WCHAR *display_name )
592 DWORD password_size;
593 DWORD err;
595 TRACE( "%p %d %d %d %s %s %p %p %s %s %s\n", service, service_type, start_type,
596 error_control, debugstr_w(path), debugstr_w(group), tag, dependencies,
597 debugstr_w(username), debugstr_w(password), debugstr_w(display_name) );
599 password_size = password ? (wcslen(password) + 1) * sizeof(WCHAR) : 0;
601 __TRY
603 err = svcctl_ChangeServiceConfigW( service, service_type, start_type, error_control, path, group, tag,
604 (const BYTE *)dependencies, multisz_size(dependencies), username,
605 (const BYTE *)password, password_size, display_name );
607 __EXCEPT(rpc_filter)
609 err = map_exception_code( GetExceptionCode() );
611 __ENDTRY
613 return set_error( err );
616 /******************************************************************************
617 * QueryServiceConfigA (sechost.@)
619 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigA( SC_HANDLE service, QUERY_SERVICE_CONFIGA *config,
620 DWORD size, DWORD *ret_size )
622 DWORD n;
623 char *p, *buffer;
624 BOOL ret;
625 QUERY_SERVICE_CONFIGW *configW;
627 TRACE( "%p %p %d %p\n", service, config, size, ret_size );
629 if (!(buffer = heap_alloc( 2 * size ))) return set_error( ERROR_NOT_ENOUGH_MEMORY );
630 configW = (QUERY_SERVICE_CONFIGW *)buffer;
631 ret = QueryServiceConfigW( service, configW, 2 * size, ret_size );
632 if (!ret) goto done;
634 config->dwServiceType = configW->dwServiceType;
635 config->dwStartType = configW->dwStartType;
636 config->dwErrorControl = configW->dwErrorControl;
637 config->lpBinaryPathName = NULL;
638 config->lpLoadOrderGroup = NULL;
639 config->dwTagId = configW->dwTagId;
640 config->lpDependencies = NULL;
641 config->lpServiceStartName = NULL;
642 config->lpDisplayName = NULL;
644 p = (char *)(config + 1);
645 n = size - sizeof(*config);
646 ret = FALSE;
648 #define MAP_STR(str) \
649 do { \
650 if (configW->str) \
652 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
653 if (!sz) goto done; \
654 config->str = p; \
655 p += sz; \
656 n -= sz; \
658 } while (0)
660 MAP_STR( lpBinaryPathName );
661 MAP_STR( lpLoadOrderGroup );
662 MAP_STR( lpDependencies );
663 MAP_STR( lpServiceStartName );
664 MAP_STR( lpDisplayName );
665 #undef MAP_STR
667 *ret_size = p - (char *)config;
668 ret = TRUE;
670 done:
671 heap_free( buffer );
672 return ret;
675 static DWORD move_string_to_buffer(BYTE **buf, WCHAR **string_ptr)
677 DWORD cb;
679 if (!*string_ptr)
681 cb = sizeof(WCHAR);
682 memset(*buf, 0, cb);
684 else
686 cb = (wcslen( *string_ptr ) + 1) * sizeof(WCHAR);
687 memcpy(*buf, *string_ptr, cb);
688 MIDL_user_free( *string_ptr );
691 *string_ptr = (WCHAR *)*buf;
692 *buf += cb;
694 return cb;
697 static DWORD size_string( const WCHAR *string )
699 return (string ? (wcslen( string ) + 1) * sizeof(WCHAR) : sizeof(WCHAR));
702 /******************************************************************************
703 * QueryServiceConfigW (sechost.@)
705 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfigW( SC_HANDLE service, QUERY_SERVICE_CONFIGW *ret_config,
706 DWORD size, DWORD *ret_size )
708 QUERY_SERVICE_CONFIGW config;
709 DWORD total;
710 DWORD err;
711 BYTE *bufpos;
713 TRACE( "%p %p %d %p\n", service, ret_config, size, ret_size );
715 memset(&config, 0, sizeof(config));
717 __TRY
719 err = svcctl_QueryServiceConfigW( service, &config, size, ret_size );
721 __EXCEPT(rpc_filter)
723 err = map_exception_code( GetExceptionCode() );
725 __ENDTRY
727 if (err) return set_error( err );
729 /* calculate the size required first */
730 total = sizeof(QUERY_SERVICE_CONFIGW);
731 total += size_string( config.lpBinaryPathName );
732 total += size_string( config.lpLoadOrderGroup );
733 total += size_string( config.lpDependencies );
734 total += size_string( config.lpServiceStartName );
735 total += size_string( config.lpDisplayName );
737 *ret_size = total;
739 /* if there's not enough memory, return an error */
740 if (size < total)
742 SetLastError( ERROR_INSUFFICIENT_BUFFER );
743 MIDL_user_free( config.lpBinaryPathName );
744 MIDL_user_free( config.lpLoadOrderGroup );
745 MIDL_user_free( config.lpDependencies );
746 MIDL_user_free( config.lpServiceStartName );
747 MIDL_user_free( config.lpDisplayName );
748 return FALSE;
751 *ret_config = config;
752 bufpos = ((BYTE *)ret_config) + sizeof(QUERY_SERVICE_CONFIGW);
753 move_string_to_buffer( &bufpos, &ret_config->lpBinaryPathName );
754 move_string_to_buffer( &bufpos, &ret_config->lpLoadOrderGroup );
755 move_string_to_buffer( &bufpos, &ret_config->lpDependencies );
756 move_string_to_buffer( &bufpos, &ret_config->lpServiceStartName );
757 move_string_to_buffer( &bufpos, &ret_config->lpDisplayName );
759 TRACE( "Image path = %s\n", debugstr_w( ret_config->lpBinaryPathName ) );
760 TRACE( "Group = %s\n", debugstr_w( ret_config->lpLoadOrderGroup ) );
761 TRACE( "Dependencies = %s\n", debugstr_w( ret_config->lpDependencies ) );
762 TRACE( "Service account name = %s\n", debugstr_w( ret_config->lpServiceStartName ) );
763 TRACE( "Display name = %s\n", debugstr_w( ret_config->lpDisplayName ) );
765 return TRUE;
768 /******************************************************************************
769 * QueryServiceConfig2A (sechost.@)
771 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2A( SC_HANDLE service, DWORD level, BYTE *buffer,
772 DWORD size, DWORD *ret_size )
774 BYTE *bufferW = NULL;
776 TRACE( "%p %u %p %u %p\n", service, level, buffer, size, ret_size );
778 if (buffer && size)
779 bufferW = heap_alloc( size );
781 if (!QueryServiceConfig2W( service, level, bufferW, size, ret_size ))
783 heap_free( bufferW );
784 return FALSE;
787 switch (level)
789 case SERVICE_CONFIG_DESCRIPTION:
790 if (buffer && bufferW) {
791 SERVICE_DESCRIPTIONA *configA = (SERVICE_DESCRIPTIONA *)buffer;
792 SERVICE_DESCRIPTIONW *configW = (SERVICE_DESCRIPTIONW *)bufferW;
793 if (configW->lpDescription && size > sizeof(SERVICE_DESCRIPTIONA))
795 configA->lpDescription = (char *)(configA + 1);
796 WideCharToMultiByte( CP_ACP, 0, configW->lpDescription, -1, configA->lpDescription,
797 size - sizeof(SERVICE_DESCRIPTIONA), NULL, NULL );
799 else configA->lpDescription = NULL;
801 break;
802 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
803 if (buffer && bufferW && *ret_size <= size)
804 memcpy(buffer, bufferW, *ret_size);
805 break;
806 default:
807 FIXME("conversion W->A not implemented for level %d\n", level);
808 heap_free( bufferW );
809 return FALSE;
812 heap_free( bufferW );
813 return TRUE;
816 /******************************************************************************
817 * QueryServiceConfig2W (sechost.@)
819 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceConfig2W( SC_HANDLE service, DWORD level, BYTE *buffer,
820 DWORD size, DWORD *ret_size )
822 BYTE *bufptr;
823 DWORD err;
825 TRACE( "%p %u %p %u %p\n", service, level, buffer, size, ret_size );
827 if (!buffer && size)
829 SetLastError(ERROR_INVALID_ADDRESS);
830 return FALSE;
833 switch (level)
835 case SERVICE_CONFIG_DESCRIPTION:
836 if (!(bufptr = heap_alloc( size )))
838 SetLastError( ERROR_NOT_ENOUGH_MEMORY );
839 return FALSE;
841 break;
843 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
844 bufptr = buffer;
845 break;
847 default:
848 FIXME("Level %d not implemented\n", level);
849 SetLastError(ERROR_INVALID_LEVEL);
850 return FALSE;
853 if (!ret_size)
855 if (level == SERVICE_CONFIG_DESCRIPTION) heap_free( bufptr );
856 SetLastError(ERROR_INVALID_ADDRESS);
857 return FALSE;
860 __TRY
862 err = svcctl_QueryServiceConfig2W( service, level, bufptr, size, ret_size );
864 __EXCEPT(rpc_filter)
866 err = map_exception_code( GetExceptionCode() );
868 __ENDTRY
870 switch (level)
872 case SERVICE_CONFIG_DESCRIPTION:
874 SERVICE_DESCRIPTIONW *desc = (SERVICE_DESCRIPTIONW *)buffer;
875 struct service_description *s = (struct service_description *)bufptr;
877 if (err != ERROR_SUCCESS && err != ERROR_INSUFFICIENT_BUFFER)
879 heap_free( bufptr );
880 SetLastError( err );
881 return FALSE;
884 /* adjust for potentially larger SERVICE_DESCRIPTIONW structure */
885 if (*ret_size == sizeof(*s))
886 *ret_size = sizeof(*desc);
887 else
888 *ret_size = *ret_size - FIELD_OFFSET(struct service_description, description) + sizeof(*desc);
890 if (size < *ret_size)
892 heap_free( bufptr );
893 SetLastError( ERROR_INSUFFICIENT_BUFFER );
894 return FALSE;
896 if (desc)
898 if (!s->size) desc->lpDescription = NULL;
899 else
901 desc->lpDescription = (WCHAR *)(desc + 1);
902 memcpy( desc->lpDescription, s->description, s->size );
905 heap_free( bufptr );
906 break;
908 case SERVICE_CONFIG_PRESHUTDOWN_INFO:
909 return set_error( err );
911 default:
912 break;
915 return TRUE;
918 /******************************************************************************
919 * GetServiceDisplayNameW (sechost.@)
921 BOOL WINAPI DECLSPEC_HOTPATCH GetServiceDisplayNameW( SC_HANDLE manager, const WCHAR *service,
922 WCHAR *display_name, DWORD *len )
924 DWORD err;
925 DWORD size;
926 WCHAR buffer[2];
928 TRACE( "%p %s %p %p\n", manager, debugstr_w(service), display_name, len );
930 if (!manager)
932 SetLastError( ERROR_INVALID_HANDLE );
933 return FALSE;
936 /* provide a buffer if the caller didn't */
937 if (!display_name || *len < sizeof(WCHAR))
939 display_name = buffer;
940 /* A size of 1 would be enough, but tests show that Windows returns 2,
941 * probably because of a WCHAR/bytes mismatch in their code. */
942 *len = 2;
945 /* RPC call takes size excluding nul-terminator, whereas *len
946 * includes the nul-terminator on input. */
947 size = *len - 1;
949 __TRY
951 err = svcctl_GetServiceDisplayNameW( manager, service, display_name, &size );
953 __EXCEPT(rpc_filter)
955 err = map_exception_code( GetExceptionCode() );
957 __ENDTRY
959 /* The value of *len excludes nul-terminator on output. */
960 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
961 *len = size;
962 return set_error( err );
965 /******************************************************************************
966 * GetServiceKeyNameW (sechost.@)
968 BOOL WINAPI DECLSPEC_HOTPATCH GetServiceKeyNameW( SC_HANDLE manager, const WCHAR *display_name,
969 WCHAR *key_name, DWORD *len )
971 DWORD err;
972 WCHAR buffer[2];
973 DWORD size;
975 TRACE( "%p %s %p %p\n", manager, debugstr_w(display_name), key_name, len );
977 if (!manager)
979 SetLastError( ERROR_INVALID_HANDLE );
980 return FALSE;
983 /* provide a buffer if the caller didn't */
984 if (!key_name || *len < 2)
986 key_name = buffer;
987 /* A size of 1 would be enough, but tests show that Windows returns 2,
988 * probably because of a WCHAR/bytes mismatch in their code.
990 *len = 2;
993 /* RPC call takes size excluding nul-terminator, whereas *len
994 * includes the nul-terminator on input. */
995 size = *len - 1;
997 __TRY
999 err = svcctl_GetServiceKeyNameW( manager, display_name, key_name, &size );
1001 __EXCEPT(rpc_filter)
1003 err = map_exception_code( GetExceptionCode() );
1005 __ENDTRY
1007 /* The value of *lpcchBuffer excludes nul-terminator on output. */
1008 if (err == ERROR_SUCCESS || err == ERROR_INSUFFICIENT_BUFFER)
1009 *len = size;
1010 return set_error( err );
1013 /******************************************************************************
1014 * StartServiceA (sechost.@)
1016 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceA( SC_HANDLE service, DWORD argc, const char **argv )
1018 WCHAR **argvW = NULL;
1019 DWORD i;
1020 BOOL r;
1022 if (argc)
1023 argvW = heap_alloc( argc * sizeof(*argvW) );
1025 for (i = 0; i < argc; i++)
1026 argvW[i] = heap_strdupAtoW( argv[i] );
1028 r = StartServiceW( service, argc, (const WCHAR **)argvW );
1030 for (i = 0; i < argc; i++)
1031 heap_free( argvW[i] );
1032 heap_free( argvW );
1033 return r;
1037 /******************************************************************************
1038 * StartServiceW (sechost.@)
1040 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceW( SC_HANDLE service, DWORD argc, const WCHAR **argv )
1042 DWORD err;
1044 TRACE( "%p %u %p\n", service, argc, argv );
1046 __TRY
1048 err = svcctl_StartServiceW( service, argc, argv );
1050 __EXCEPT(rpc_filter)
1052 err = map_exception_code( GetExceptionCode() );
1054 __ENDTRY
1056 return set_error( err );
1059 /******************************************************************************
1060 * ControlService (sechost.@)
1062 BOOL WINAPI DECLSPEC_HOTPATCH ControlService( SC_HANDLE service, DWORD control, SERVICE_STATUS *status )
1064 DWORD err;
1066 TRACE( "%p %d %p\n", service, control, status );
1068 __TRY
1070 err = svcctl_ControlService( service, control, status );
1072 __EXCEPT(rpc_filter)
1074 err = map_exception_code( GetExceptionCode() );
1076 __ENDTRY
1078 return set_error( err );
1081 /******************************************************************************
1082 * QueryServiceStatus (sechost.@)
1084 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatus( SC_HANDLE service, SERVICE_STATUS *status )
1086 SERVICE_STATUS_PROCESS process_status;
1087 BOOL ret;
1088 DWORD size;
1090 TRACE( "%p %p\n", service, status );
1092 if (!service) return set_error( ERROR_INVALID_HANDLE );
1093 if (!status) return set_error( ERROR_INVALID_ADDRESS );
1095 ret = QueryServiceStatusEx( service, SC_STATUS_PROCESS_INFO, (BYTE *)&process_status,
1096 sizeof(SERVICE_STATUS_PROCESS), &size );
1097 if (ret) memcpy(status, &process_status, sizeof(SERVICE_STATUS) );
1098 return ret;
1101 /******************************************************************************
1102 * QueryServiceStatusEx (sechost.@)
1104 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceStatusEx( SC_HANDLE service, SC_STATUS_TYPE level,
1105 BYTE *buffer, DWORD size, DWORD *ret_size )
1107 DWORD err;
1109 TRACE( "%p %d %p %d %p\n", service, level, buffer, size, ret_size );
1111 if (level != SC_STATUS_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL );
1113 if (size < sizeof(SERVICE_STATUS_PROCESS))
1115 *ret_size = sizeof(SERVICE_STATUS_PROCESS);
1116 return set_error( ERROR_INSUFFICIENT_BUFFER );
1119 __TRY
1121 err = svcctl_QueryServiceStatusEx( service, level, buffer, size, ret_size );
1123 __EXCEPT(rpc_filter)
1125 err = map_exception_code( GetExceptionCode() );
1127 __ENDTRY
1129 return set_error( err );
1132 /******************************************************************************
1133 * EnumServicesStatusExW (sechost.@)
1135 BOOL WINAPI DECLSPEC_HOTPATCH EnumServicesStatusExW( SC_HANDLE manager, SC_ENUM_TYPE level, DWORD type, DWORD state,
1136 BYTE *buffer, DWORD size, DWORD *needed, DWORD *returned,
1137 DWORD *resume_handle, const WCHAR *group )
1139 DWORD err, i, offset, buflen, count, total_size = 0;
1140 ENUM_SERVICE_STATUS_PROCESSW *services = (ENUM_SERVICE_STATUS_PROCESSW *)buffer;
1141 struct enum_service_status_process *entry;
1142 const WCHAR *str;
1143 BYTE *buf;
1145 TRACE( "%p %u 0x%x 0x%x %p %u %p %p %p %s\n", manager, level, type, state, buffer,
1146 size, needed, returned, resume_handle, debugstr_w(group) );
1148 if (level != SC_ENUM_PROCESS_INFO) return set_error( ERROR_INVALID_LEVEL );
1149 if (!manager) return set_error( ERROR_INVALID_HANDLE );
1150 if (!needed || !returned) return set_error( ERROR_INVALID_ADDRESS );
1152 /* make sure we pass a valid pointer */
1153 buflen = max( size, sizeof(*services) );
1154 if (!(buf = heap_alloc( buflen ))) return set_error( ERROR_NOT_ENOUGH_MEMORY );
1156 __TRY
1158 err = svcctl_EnumServicesStatusExW( manager, SC_ENUM_PROCESS_INFO, type, state, buf, buflen, needed,
1159 &count, resume_handle, group );
1161 __EXCEPT(rpc_filter)
1163 err = map_exception_code( GetExceptionCode() );
1165 __ENDTRY
1167 *returned = 0;
1168 if (err != ERROR_SUCCESS)
1170 /* double the needed size to fit the potentially larger ENUM_SERVICE_STATUS_PROCESSW */
1171 if (err == ERROR_MORE_DATA) *needed *= 2;
1172 heap_free( buf );
1173 SetLastError( err );
1174 return FALSE;
1177 entry = (struct enum_service_status_process *)buf;
1178 for (i = 0; i < count; i++)
1180 total_size += sizeof(*services);
1181 if (entry->service_name)
1183 str = (const WCHAR *)(buf + entry->service_name);
1184 total_size += (wcslen( str ) + 1) * sizeof(WCHAR);
1186 if (entry->display_name)
1188 str = (const WCHAR *)(buf + entry->display_name);
1189 total_size += (wcslen( str ) + 1) * sizeof(WCHAR);
1191 entry++;
1194 if (total_size > size)
1196 heap_free( buf );
1197 *needed = total_size;
1198 SetLastError( ERROR_MORE_DATA );
1199 return FALSE;
1202 offset = count * sizeof(*services);
1203 entry = (struct enum_service_status_process *)buf;
1204 for (i = 0; i < count; i++)
1206 DWORD str_size;
1207 str = (const WCHAR *)(buf + entry->service_name);
1208 str_size = (wcslen( str ) + 1) * sizeof(WCHAR);
1209 services[i].lpServiceName = (WCHAR *)((char *)services + offset);
1210 memcpy( services[i].lpServiceName, str, str_size );
1211 offset += str_size;
1213 if (!entry->display_name) services[i].lpDisplayName = NULL;
1214 else
1216 str = (const WCHAR *)(buf + entry->display_name);
1217 str_size = (wcslen( str ) + 1) * sizeof(WCHAR);
1218 services[i].lpDisplayName = (WCHAR *)((char *)services + offset);
1219 memcpy( services[i].lpDisplayName, str, str_size );
1220 offset += str_size;
1222 services[i].ServiceStatusProcess = entry->service_status_process;
1223 entry++;
1226 heap_free( buf );
1227 *needed = 0;
1228 *returned = count;
1229 return TRUE;
1232 /******************************************************************************
1233 * EnumDependentServicesW (sechost.@)
1235 BOOL WINAPI EnumDependentServicesW( SC_HANDLE hService, DWORD dwServiceState,
1236 LPENUM_SERVICE_STATUSW lpServices, DWORD cbBufSize,
1237 LPDWORD pcbBytesNeeded, LPDWORD lpServicesReturned )
1239 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService, dwServiceState,
1240 lpServices, cbBufSize, pcbBytesNeeded, lpServicesReturned);
1242 *lpServicesReturned = 0;
1243 return TRUE;
1246 /******************************************************************************
1247 * QueryServiceObjectSecurity (sechost.@)
1249 BOOL WINAPI DECLSPEC_HOTPATCH QueryServiceObjectSecurity( SC_HANDLE service, SECURITY_INFORMATION type,
1250 PSECURITY_DESCRIPTOR ret_descriptor, DWORD size, DWORD *ret_size )
1252 SECURITY_DESCRIPTOR descriptor;
1253 NTSTATUS status;
1254 ACL acl;
1256 FIXME( "%p %d %p %u %p - semi-stub\n", service, type, ret_descriptor, size, ret_size );
1258 if (type != DACL_SECURITY_INFORMATION)
1259 FIXME("information %d not supported\n", type);
1261 InitializeSecurityDescriptor( &descriptor, SECURITY_DESCRIPTOR_REVISION );
1263 InitializeAcl( &acl, sizeof(ACL), ACL_REVISION );
1264 SetSecurityDescriptorDacl( &descriptor, TRUE, &acl, TRUE );
1266 status = RtlMakeSelfRelativeSD( &descriptor, ret_descriptor, &size );
1267 *ret_size = size;
1269 return set_error( RtlNtStatusToDosError( status ) );
1272 /******************************************************************************
1273 * SetServiceObjectSecurity (sechost.@)
1275 BOOL WINAPI SetServiceObjectSecurity(SC_HANDLE hService,
1276 SECURITY_INFORMATION dwSecurityInformation,
1277 PSECURITY_DESCRIPTOR lpSecurityDescriptor)
1279 FIXME("%p %d %p\n", hService, dwSecurityInformation, lpSecurityDescriptor);
1280 return TRUE;
1283 static DWORD WINAPI notify_thread(void *user)
1285 DWORD err;
1286 struct notify_data *data = user;
1287 SC_RPC_NOTIFY_PARAMS_LIST *list = NULL;
1288 SERVICE_NOTIFY_STATUS_CHANGE_PARAMS_2 *cparams;
1289 BOOL dummy;
1291 __TRY
1293 /* GetNotifyResults blocks until there is an event */
1294 err = svcctl_GetNotifyResults(data->notify_handle, &list);
1296 __EXCEPT(rpc_filter)
1298 err = map_exception_code(GetExceptionCode());
1300 __ENDTRY
1302 EnterCriticalSection( &service_cs );
1304 list_remove(&data->entry);
1306 LeaveCriticalSection( &service_cs );
1308 if (err == ERROR_SUCCESS && list)
1310 cparams = list->NotifyParamsArray[0].params;
1312 data->notify_buffer->dwNotificationStatus = cparams->dwNotificationStatus;
1313 memcpy(&data->notify_buffer->ServiceStatus, &cparams->ServiceStatus,
1314 sizeof(SERVICE_STATUS_PROCESS));
1315 data->notify_buffer->dwNotificationTriggered = cparams->dwNotificationTriggered;
1316 data->notify_buffer->pszServiceNames = NULL;
1318 QueueUserAPC((PAPCFUNC)data->notify_buffer->pfnNotifyCallback,
1319 data->calling_thread, (ULONG_PTR)data->notify_buffer);
1321 HeapFree(GetProcessHeap(), 0, list);
1323 else
1324 WARN("GetNotifyResults server call failed: %u\n", err);
1327 __TRY
1329 err = svcctl_CloseNotifyHandle(&data->notify_handle, &dummy);
1331 __EXCEPT(rpc_filter)
1333 err = map_exception_code(GetExceptionCode());
1335 __ENDTRY
1337 if (err != ERROR_SUCCESS)
1338 WARN("CloseNotifyHandle server call failed: %u\n", err);
1340 CloseHandle(data->calling_thread);
1341 HeapFree(GetProcessHeap(), 0, data);
1343 return 0;
1346 /******************************************************************************
1347 * NotifyServiceStatusChangeW (sechost.@)
1349 DWORD WINAPI DECLSPEC_HOTPATCH NotifyServiceStatusChangeW( SC_HANDLE service, DWORD mask,
1350 SERVICE_NOTIFYW *notify_buffer )
1352 DWORD err;
1353 BOOL b_dummy = FALSE;
1354 GUID g_dummy = {0};
1355 struct notify_data *data;
1357 TRACE( "%p 0x%x %p\n", service, mask, notify_buffer );
1359 if (!(data = heap_alloc_zero( sizeof(*data) )))
1360 return ERROR_NOT_ENOUGH_MEMORY;
1362 data->service = service;
1363 data->notify_buffer = notify_buffer;
1364 if (!DuplicateHandle( GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
1365 &data->calling_thread, 0, FALSE, DUPLICATE_SAME_ACCESS ))
1367 ERR("DuplicateHandle failed: %u\n", GetLastError());
1368 heap_free( data );
1369 return ERROR_NOT_ENOUGH_MEMORY;
1372 data->params.dwInfoLevel = 2;
1373 data->params.params = &data->cparams;
1375 data->cparams.dwNotifyMask = mask;
1377 EnterCriticalSection( &service_cs );
1379 __TRY
1381 err = svcctl_NotifyServiceStatusChange( service, data->params, &g_dummy,
1382 &g_dummy, &b_dummy, &data->notify_handle );
1384 __EXCEPT(rpc_filter)
1386 err = map_exception_code( GetExceptionCode() );
1388 __ENDTRY
1390 if (err != ERROR_SUCCESS)
1392 WARN("NotifyServiceStatusChange server call failed: %u\n", err);
1393 LeaveCriticalSection( &service_cs );
1394 CloseHandle( data->calling_thread );
1395 CloseHandle( data->ready_evt );
1396 heap_free( data );
1397 return err;
1400 CloseHandle( CreateThread( NULL, 0, &notify_thread, data, 0, NULL ) );
1402 list_add_tail( &notify_list, &data->entry );
1404 LeaveCriticalSection( &service_cs );
1406 return ERROR_SUCCESS;
1409 /* thunk for calling the RegisterServiceCtrlHandler handler function */
1410 static DWORD WINAPI ctrl_handler_thunk( DWORD control, DWORD type, void *data, void *context )
1412 LPHANDLER_FUNCTION func = context;
1414 func( control );
1415 return ERROR_SUCCESS;
1418 /******************************************************************************
1419 * RegisterServiceCtrlHandlerA (sechost.@)
1421 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerA(
1422 const char *name, LPHANDLER_FUNCTION handler )
1424 return RegisterServiceCtrlHandlerExA( name, ctrl_handler_thunk, handler );
1427 /******************************************************************************
1428 * RegisterServiceCtrlHandlerW (sechost.@)
1430 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerW(
1431 const WCHAR *name, LPHANDLER_FUNCTION handler )
1433 return RegisterServiceCtrlHandlerExW( name, ctrl_handler_thunk, handler );
1436 /******************************************************************************
1437 * RegisterServiceCtrlHandlerExA (sechost.@)
1439 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExA(
1440 const char *name, LPHANDLER_FUNCTION_EX handler, void *context )
1442 WCHAR *nameW;
1443 SERVICE_STATUS_HANDLE ret;
1445 nameW = heap_strdupAtoW( name );
1446 ret = RegisterServiceCtrlHandlerExW( nameW, handler, context );
1447 heap_free( nameW );
1448 return ret;
1451 static struct service_data *find_service_by_name( const WCHAR *name )
1453 unsigned int i;
1455 if (nb_services == 1) /* only one service (FIXME: should depend on OWN_PROCESS etc.) */
1456 return services[0];
1457 for (i = 0; i < nb_services; i++)
1458 if (!wcsicmp( name, services[i]->name )) return services[i];
1459 return NULL;
1462 /******************************************************************************
1463 * RegisterServiceCtrlHandlerExW (sechost.@)
1465 SERVICE_STATUS_HANDLE WINAPI DECLSPEC_HOTPATCH RegisterServiceCtrlHandlerExW(
1466 const WCHAR *name, LPHANDLER_FUNCTION_EX handler, void *context )
1468 struct service_data *service;
1469 SC_HANDLE handle = 0;
1471 TRACE( "%s %p %p\n", debugstr_w(name), handler, context );
1473 EnterCriticalSection( &service_cs );
1474 if ((service = find_service_by_name( name )))
1476 service->handler = handler;
1477 service->context = context;
1478 handle = service->handle;
1480 LeaveCriticalSection( &service_cs );
1482 if (!handle) SetLastError( ERROR_SERVICE_DOES_NOT_EXIST );
1483 return (SERVICE_STATUS_HANDLE)handle;
1486 /******************************************************************************
1487 * SetServiceStatus (sechost.@)
1489 BOOL WINAPI DECLSPEC_HOTPATCH SetServiceStatus( SERVICE_STATUS_HANDLE service, SERVICE_STATUS *status )
1491 DWORD err;
1493 TRACE( "%p %#x %#x %#x %#x %#x %#x %#x\n", service, status->dwServiceType,
1494 status->dwCurrentState, status->dwControlsAccepted, status->dwWin32ExitCode,
1495 status->dwServiceSpecificExitCode, status->dwCheckPoint, status->dwWaitHint );
1497 __TRY
1499 err = svcctl_SetServiceStatus( service, status );
1501 __EXCEPT(rpc_filter)
1503 err = map_exception_code( GetExceptionCode() );
1505 __ENDTRY
1507 if (!set_error( err ))
1508 return FALSE;
1510 if (status->dwCurrentState == SERVICE_STOPPED)
1512 unsigned int i, count = 0;
1513 EnterCriticalSection( &service_cs );
1514 for (i = 0; i < nb_services; i++)
1516 if (services[i]->handle == (SC_HANDLE)service) continue;
1517 if (services[i]->thread) count++;
1519 if (!count)
1521 stop_service = TRUE;
1522 SetEvent( service_event ); /* notify the main loop */
1524 LeaveCriticalSection( &service_cs );
1527 return TRUE;
1530 static WCHAR *service_get_pipe_name(void)
1532 static const WCHAR format[] = L"\\\\.\\pipe\\net\\NtControlPipe%u";
1533 WCHAR *name;
1534 DWORD len;
1535 HKEY service_current_key;
1536 DWORD service_current;
1537 LONG ret;
1538 DWORD type;
1540 ret = RegOpenKeyExW( HKEY_LOCAL_MACHINE,
1541 L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent",
1542 0, KEY_QUERY_VALUE, &service_current_key );
1543 if (ret != ERROR_SUCCESS)
1544 return NULL;
1546 len = sizeof(service_current);
1547 ret = RegQueryValueExW( service_current_key, NULL, NULL, &type,
1548 (BYTE *)&service_current, &len );
1549 RegCloseKey(service_current_key);
1550 if (ret != ERROR_SUCCESS || type != REG_DWORD)
1551 return NULL;
1553 len = ARRAY_SIZE(format) + 10 /* strlenW("4294967295") */;
1554 name = heap_alloc(len * sizeof(WCHAR));
1555 if (!name)
1556 return NULL;
1558 swprintf( name, len, format, service_current );
1559 return name;
1562 static HANDLE service_open_pipe(void)
1564 WCHAR *pipe_name = service_get_pipe_name();
1565 HANDLE handle = INVALID_HANDLE_VALUE;
1569 handle = CreateFileW( pipe_name, GENERIC_READ|GENERIC_WRITE,
1570 0, NULL, OPEN_ALWAYS, 0, NULL );
1571 if (handle != INVALID_HANDLE_VALUE)
1572 break;
1573 if (GetLastError() != ERROR_PIPE_BUSY)
1574 break;
1575 } while (WaitNamedPipeW( pipe_name, NMPWAIT_USE_DEFAULT_WAIT ));
1576 heap_free(pipe_name);
1578 return handle;
1581 static DWORD WINAPI service_thread( void *arg )
1583 struct service_data *info = arg;
1584 WCHAR *str = info->args;
1585 DWORD argc = 0, len = 0;
1587 TRACE("%p\n", arg);
1589 while (str[len])
1591 len += wcslen( &str[len] ) + 1;
1592 argc++;
1594 len++;
1596 if (info->unicode)
1598 WCHAR **argv, *p;
1600 argv = heap_alloc( (argc+1)*sizeof(*argv) );
1601 for (argc = 0, p = str; *p; p += wcslen( p ) + 1)
1602 argv[argc++] = p;
1603 argv[argc] = NULL;
1605 info->proc.w( argc, argv );
1606 heap_free( argv );
1608 else
1610 char *strA, **argv, *p;
1611 DWORD lenA;
1613 lenA = WideCharToMultiByte( CP_ACP,0, str, len, NULL, 0, NULL, NULL );
1614 strA = heap_alloc(lenA);
1615 WideCharToMultiByte(CP_ACP,0, str, len, strA, lenA, NULL, NULL);
1617 argv = heap_alloc( (argc+1)*sizeof(*argv) );
1618 for (argc = 0, p = strA; *p; p += strlen( p ) + 1)
1619 argv[argc++] = p;
1620 argv[argc] = NULL;
1622 info->proc.a( argc, argv );
1623 heap_free( argv );
1624 heap_free( strA );
1626 return 0;
1629 static DWORD service_handle_start( struct service_data *service, const void *data, DWORD data_size )
1631 DWORD count = data_size / sizeof(WCHAR);
1633 if (service->thread)
1635 WARN("service is not stopped\n");
1636 return ERROR_SERVICE_ALREADY_RUNNING;
1639 heap_free( service->args );
1640 service->args = heap_alloc( (count + 2) * sizeof(WCHAR) );
1641 if (count) memcpy( service->args, data, count * sizeof(WCHAR) );
1642 service->args[count++] = 0;
1643 service->args[count++] = 0;
1645 service->thread = CreateThread( NULL, 0, service_thread,
1646 service, 0, NULL );
1647 SetEvent( service_event ); /* notify the main loop */
1648 return 0;
1651 static DWORD service_handle_control( struct service_data *service, DWORD control, const void *data, DWORD data_size )
1653 DWORD ret = ERROR_INVALID_SERVICE_CONTROL;
1655 TRACE( "%s control %u data %p data_size %u\n", debugstr_w(service->name), control, data, data_size );
1657 if (control == SERVICE_CONTROL_START)
1658 ret = service_handle_start( service, data, data_size );
1659 else if (service->handler)
1660 ret = service->handler( control, 0, (void *)data, service->context );
1661 return ret;
1664 static DWORD WINAPI service_control_dispatcher( void *arg )
1666 struct dispatcher_data *disp = arg;
1668 /* dispatcher loop */
1669 while (1)
1671 struct service_data *service;
1672 service_start_info info;
1673 BYTE *data = NULL;
1674 WCHAR *name;
1675 BOOL r;
1676 DWORD data_size = 0, count, result;
1678 r = ReadFile( disp->pipe, &info, FIELD_OFFSET(service_start_info,data), &count, NULL );
1679 if (!r)
1681 if (GetLastError() != ERROR_BROKEN_PIPE)
1682 ERR( "pipe read failed error %u\n", GetLastError() );
1683 break;
1685 if (count != FIELD_OFFSET(service_start_info,data))
1687 ERR( "partial pipe read %u\n", count );
1688 break;
1690 if (count < info.total_size)
1692 data_size = info.total_size - FIELD_OFFSET(service_start_info,data);
1693 data = heap_alloc( data_size );
1694 r = ReadFile( disp->pipe, data, data_size, &count, NULL );
1695 if (!r)
1697 if (GetLastError() != ERROR_BROKEN_PIPE)
1698 ERR( "pipe read failed error %u\n", GetLastError() );
1699 heap_free( data );
1700 break;
1702 if (count != data_size)
1704 ERR( "partial pipe read %u/%u\n", count, data_size );
1705 heap_free( data );
1706 break;
1710 EnterCriticalSection( &service_cs );
1712 /* validate service name */
1713 name = (WCHAR *)data;
1714 if (!info.name_size || data_size < info.name_size * sizeof(WCHAR) || name[info.name_size - 1])
1716 ERR( "got request without valid service name\n" );
1717 result = ERROR_INVALID_PARAMETER;
1718 goto done;
1721 if (info.magic != SERVICE_PROTOCOL_MAGIC)
1723 ERR( "received invalid request for service %s\n", debugstr_w(name) );
1724 result = ERROR_INVALID_PARAMETER;
1725 goto done;
1728 /* find the service */
1729 if (!(service = find_service_by_name( name )))
1731 FIXME( "got request for unknown service %s\n", debugstr_w(name) );
1732 result = ERROR_INVALID_PARAMETER;
1733 goto done;
1736 if (!service->handle)
1738 if (!(service->handle = OpenServiceW( disp->manager, name, SERVICE_SET_STATUS )) ||
1739 !(service->full_access_handle = OpenServiceW( disp->manager, name,
1740 GENERIC_READ|GENERIC_WRITE )))
1741 FIXME( "failed to open service %s\n", debugstr_w(name) );
1744 data_size -= info.name_size * sizeof(WCHAR);
1745 result = service_handle_control(service, info.control, data_size ?
1746 &data[info.name_size * sizeof(WCHAR)] : NULL, data_size);
1748 done:
1749 LeaveCriticalSection( &service_cs );
1750 WriteFile( disp->pipe, &result, sizeof(result), &count, NULL );
1751 heap_free( data );
1754 CloseHandle( disp->pipe );
1755 CloseServiceHandle( disp->manager );
1756 heap_free( disp );
1757 return 1;
1760 /* wait for services which accept this type of message to become STOPPED */
1761 static void handle_shutdown_msg(DWORD msg, DWORD accept)
1763 SERVICE_STATUS st;
1764 SERVICE_PRESHUTDOWN_INFO spi;
1765 DWORD i, n = 0, sz, timeout = 2000;
1766 ULONGLONG stop_time;
1767 BOOL res, done = TRUE;
1768 SC_HANDLE *wait_handles = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(SC_HANDLE) * nb_services );
1770 EnterCriticalSection( &service_cs );
1771 for (i = 0; i < nb_services; i++)
1773 res = QueryServiceStatus( services[i]->full_access_handle, &st );
1774 if (!res || st.dwCurrentState == SERVICE_STOPPED || !(st.dwControlsAccepted & accept))
1775 continue;
1777 done = FALSE;
1779 if (accept == SERVICE_ACCEPT_PRESHUTDOWN)
1781 res = QueryServiceConfig2W( services[i]->full_access_handle, SERVICE_CONFIG_PRESHUTDOWN_INFO,
1782 (BYTE *)&spi, sizeof(spi), &sz );
1783 if (res)
1785 FIXME( "service should be able to delay shutdown\n" );
1786 timeout = max( spi.dwPreshutdownTimeout, timeout );
1790 service_handle_control( services[i], msg, NULL, 0 );
1791 wait_handles[n++] = services[i]->full_access_handle;
1793 LeaveCriticalSection( &service_cs );
1795 /* FIXME: these timeouts should be more generous, but we can't currently delay prefix shutdown */
1796 timeout = min( timeout, 3000 );
1797 stop_time = GetTickCount64() + timeout;
1799 while (!done && GetTickCount64() < stop_time)
1801 done = TRUE;
1802 for (i = 0; i < n; i++)
1804 res = QueryServiceStatus( wait_handles[i], &st );
1805 if (!res || st.dwCurrentState == SERVICE_STOPPED)
1806 continue;
1808 done = FALSE;
1809 Sleep( 100 );
1810 break;
1814 HeapFree( GetProcessHeap(), 0, wait_handles );
1817 static BOOL service_run_main_thread(void)
1819 DWORD i, n, ret;
1820 HANDLE wait_handles[MAXIMUM_WAIT_OBJECTS];
1821 UINT wait_services[MAXIMUM_WAIT_OBJECTS];
1822 struct dispatcher_data *disp = heap_alloc( sizeof(*disp) );
1824 disp->manager = OpenSCManagerW( NULL, NULL, SC_MANAGER_CONNECT );
1825 if (!disp->manager)
1827 ERR("failed to open service manager error %u\n", GetLastError());
1828 heap_free( disp );
1829 return FALSE;
1832 disp->pipe = service_open_pipe();
1833 if (disp->pipe == INVALID_HANDLE_VALUE)
1835 WARN("failed to create control pipe error %u\n", GetLastError());
1836 CloseServiceHandle( disp->manager );
1837 heap_free( disp );
1838 SetLastError( ERROR_FAILED_SERVICE_CONTROLLER_CONNECT );
1839 return FALSE;
1842 service_event = CreateEventW( NULL, FALSE, FALSE, NULL );
1843 stop_service = FALSE;
1845 /* FIXME: service_control_dispatcher should be merged into the main thread */
1846 NtSetInformationProcess( GetCurrentProcess(), ProcessWineMakeProcessSystem,
1847 &wait_handles[0], sizeof(HANDLE *) );
1848 wait_handles[1] = CreateThread( NULL, 0, service_control_dispatcher, disp, 0, NULL );
1849 wait_handles[2] = service_event;
1851 TRACE("Starting %d services running as process %d\n",
1852 nb_services, GetCurrentProcessId());
1854 /* wait for all the threads to pack up and exit */
1855 while (!stop_service)
1857 EnterCriticalSection( &service_cs );
1858 for (i = 0, n = 3; i < nb_services && n < MAXIMUM_WAIT_OBJECTS; i++)
1860 if (!services[i]->thread) continue;
1861 wait_services[n] = i;
1862 wait_handles[n++] = services[i]->thread;
1864 LeaveCriticalSection( &service_cs );
1866 ret = WaitForMultipleObjects( n, wait_handles, FALSE, INFINITE );
1867 if (!ret) /* system process event */
1869 handle_shutdown_msg(SERVICE_CONTROL_PRESHUTDOWN, SERVICE_ACCEPT_PRESHUTDOWN);
1870 handle_shutdown_msg(SERVICE_CONTROL_SHUTDOWN, SERVICE_ACCEPT_SHUTDOWN);
1871 ExitProcess(0);
1873 else if (ret == 1)
1875 TRACE( "control dispatcher exited, shutting down\n" );
1876 /* FIXME: we should maybe send a shutdown control to running services */
1877 ExitProcess(0);
1879 else if (ret == 2)
1881 continue; /* rebuild the list */
1883 else if (ret < n)
1885 i = wait_services[ret];
1886 EnterCriticalSection( &service_cs );
1887 CloseHandle( services[i]->thread );
1888 services[i]->thread = NULL;
1889 LeaveCriticalSection( &service_cs );
1891 else return FALSE;
1894 return TRUE;
1897 /******************************************************************************
1898 * StartServiceCtrlDispatcherA (sechost.@)
1900 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA *servent )
1902 struct service_data *info;
1903 unsigned int i;
1905 TRACE("%p\n", servent);
1907 if (nb_services)
1909 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1910 return FALSE;
1912 while (servent[nb_services].lpServiceName) nb_services++;
1913 if (!nb_services)
1915 SetLastError( ERROR_INVALID_PARAMETER );
1916 return FALSE;
1919 services = heap_alloc( nb_services * sizeof(*services) );
1921 for (i = 0; i < nb_services; i++)
1923 DWORD len = MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, NULL, 0 );
1924 DWORD sz = FIELD_OFFSET( struct service_data, name[len] );
1925 info = heap_alloc_zero( sz );
1926 MultiByteToWideChar( CP_ACP, 0, servent[i].lpServiceName, -1, info->name, len );
1927 info->proc.a = servent[i].lpServiceProc;
1928 info->unicode = FALSE;
1929 services[i] = info;
1932 return service_run_main_thread();
1935 /******************************************************************************
1936 * StartServiceCtrlDispatcherW (sechost.@)
1938 BOOL WINAPI DECLSPEC_HOTPATCH StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW *servent )
1940 struct service_data *info;
1941 unsigned int i;
1943 TRACE("%p\n", servent);
1945 if (nb_services)
1947 SetLastError( ERROR_SERVICE_ALREADY_RUNNING );
1948 return FALSE;
1950 while (servent[nb_services].lpServiceName) nb_services++;
1951 if (!nb_services)
1953 SetLastError( ERROR_INVALID_PARAMETER );
1954 return FALSE;
1957 services = heap_alloc( nb_services * sizeof(*services) );
1959 for (i = 0; i < nb_services; i++)
1961 DWORD len = wcslen( servent[i].lpServiceName ) + 1;
1962 DWORD sz = FIELD_OFFSET( struct service_data, name[len] );
1963 info = heap_alloc_zero( sz );
1964 wcscpy( info->name, servent[i].lpServiceName );
1965 info->proc.w = servent[i].lpServiceProc;
1966 info->unicode = TRUE;
1967 services[i] = info;
1970 return service_run_main_thread();
1973 struct device_notification_details
1975 DWORD (CALLBACK *cb)(HANDLE handle, DWORD flags, DEV_BROADCAST_HDR *header);
1976 HANDLE handle;
1979 static HANDLE device_notify_thread;
1980 static struct list device_notify_list = LIST_INIT(device_notify_list);
1982 struct device_notify_registration
1984 struct list entry;
1985 struct device_notification_details details;
1988 static DWORD WINAPI device_notify_proc( void *arg )
1990 WCHAR endpoint[] = L"\\pipe\\wine_plugplay";
1991 WCHAR protseq[] = L"ncalrpc";
1992 RPC_WSTR binding_str;
1993 DWORD err = ERROR_SUCCESS;
1994 struct device_notify_registration *registration;
1995 struct device_notification_details *details_copy;
1996 unsigned int details_copy_nelems, details_copy_size;
1997 plugplay_rpc_handle handle = NULL;
1998 DWORD code = 0;
1999 unsigned int i, size;
2000 BYTE *buf;
2002 if ((err = RpcStringBindingComposeW( NULL, protseq, NULL, endpoint, NULL, &binding_str )))
2004 ERR("RpcStringBindingCompose() failed, error %#x\n", err);
2005 return err;
2007 err = RpcBindingFromStringBindingW( binding_str, &plugplay_binding_handle );
2008 RpcStringFreeW( &binding_str );
2009 if (err)
2011 ERR("RpcBindingFromStringBinding() failed, error %#x\n", err);
2012 return err;
2015 __TRY
2017 handle = plugplay_register_listener();
2019 __EXCEPT(rpc_filter)
2021 err = map_exception_code( GetExceptionCode() );
2023 __ENDTRY
2025 if (!handle)
2027 ERR("failed to open RPC handle, error %u\n", err);
2028 return 1;
2031 details_copy_size = 8;
2032 details_copy = heap_alloc( details_copy_size * sizeof(*details_copy) );
2034 for (;;)
2036 buf = NULL;
2037 __TRY
2039 code = plugplay_get_event( handle, &buf, &size );
2040 err = ERROR_SUCCESS;
2042 __EXCEPT(rpc_filter)
2044 err = map_exception_code( GetExceptionCode() );
2046 __ENDTRY
2048 if (err)
2050 ERR("failed to get event, error %u\n", err);
2051 break;
2054 /* Make a copy to avoid a hang if a callback tries to register or unregister for notifications. */
2055 i = 0;
2056 details_copy_nelems = 0;
2057 EnterCriticalSection( &service_cs );
2058 LIST_FOR_EACH_ENTRY(registration, &device_notify_list, struct device_notify_registration, entry)
2060 details_copy[i++] = registration->details;
2061 details_copy_nelems++;
2062 if (i == details_copy_size)
2064 details_copy_size *= 2;
2065 details_copy = heap_realloc( details_copy, details_copy_size * sizeof(*details_copy) );
2068 LeaveCriticalSection(&service_cs);
2070 for (i = 0; i < details_copy_nelems; i++)
2072 details_copy[i].cb( details_copy[i].handle, code, (DEV_BROADCAST_HDR *)buf );
2074 MIDL_user_free(buf);
2077 heap_free( details_copy );
2079 __TRY
2081 plugplay_unregister_listener( handle );
2083 __EXCEPT(rpc_filter)
2086 __ENDTRY
2088 RpcBindingFree( &plugplay_binding_handle );
2089 return 0;
2092 /******************************************************************************
2093 * I_ScRegisterDeviceNotification (sechost.@)
2095 HDEVNOTIFY WINAPI I_ScRegisterDeviceNotification( struct device_notification_details *details,
2096 void *filter, DWORD flags )
2098 struct device_notify_registration *registration;
2100 TRACE("callback %p, handle %p, filter %p, flags %#x\n", details->cb, details->handle, filter, flags);
2102 if (filter) FIXME("Notification filters are not yet implemented.\n");
2104 if (!(registration = heap_alloc(sizeof(struct device_notify_registration))))
2106 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
2107 return NULL;
2110 registration->details = *details;
2112 EnterCriticalSection( &service_cs );
2113 list_add_tail( &device_notify_list, &registration->entry );
2115 if (!device_notify_thread)
2116 device_notify_thread = CreateThread( NULL, 0, device_notify_proc, NULL, 0, NULL );
2118 LeaveCriticalSection( &service_cs );
2120 return registration;
2123 /******************************************************************************
2124 * I_ScUnregisterDeviceNotification (sechost.@)
2126 BOOL WINAPI I_ScUnregisterDeviceNotification( HDEVNOTIFY handle )
2128 struct device_notify_registration *registration = handle;
2130 TRACE("%p\n", handle);
2132 if (!handle)
2133 return FALSE;
2135 EnterCriticalSection( &service_cs );
2136 list_remove( &registration->entry );
2137 LeaveCriticalSection(&service_cs);
2138 heap_free( registration );
2139 return TRUE;