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
33 #include "wine/unicode.h"
34 #include "wine/debug.h"
38 #include "wine/list.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(advapi
);
42 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
43 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
44 'S','e','r','v','i','c','e','s',0 };
45 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
48 typedef struct service_start_info_t
55 #define WINESERV_STARTINFO 1
56 #define WINESERV_GETSTATUS 2
57 #define WINESERV_SENDCONTROL 3
58 #define WINESERV_SETPID 4
60 typedef struct service_data_t
64 LPHANDLER_FUNCTION handler
;
65 LPHANDLER_FUNCTION_EX handler_ex
;
68 SERVICE_STATUS_PROCESS status
;
71 BOOL extended
: 1; /* uses handler_ex instead of handler? */
73 LPSERVICE_MAIN_FUNCTIONA a
;
74 LPSERVICE_MAIN_FUNCTIONW w
;
80 static CRITICAL_SECTION service_cs
;
81 static CRITICAL_SECTION_DEBUG service_cs_debug
=
84 { &service_cs_debug
.ProcessLocksList
,
85 &service_cs_debug
.ProcessLocksList
},
86 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
88 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
90 static struct list service_list
= LIST_INIT(service_list
);
92 extern HANDLE
__wine_make_process_system(void);
94 /******************************************************************************
98 #define MAX_SERVICE_NAME 256
100 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
103 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
107 SC_HANDLE_TYPE htype
;
109 sc_handle_destructor destroy
;
112 struct sc_manager
/* service control manager handle */
114 struct sc_handle hdr
;
115 HKEY hkey
; /* handle to services database in the registry */
119 struct sc_service
/* service handle */
121 struct sc_handle hdr
;
122 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
124 struct sc_manager
*scm
; /* pointer to SCM handle */
128 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
129 sc_handle_destructor destroy
)
131 struct sc_handle
*hdr
;
133 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
138 hdr
->destroy
= destroy
;
140 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
144 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
146 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
150 if (hdr
->htype
!= htype
)
155 static void sc_handle_free(struct sc_handle
* hdr
)
159 if (--hdr
->ref_count
)
162 HeapFree(GetProcessHeap(), 0, hdr
);
165 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
167 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
169 TRACE("destroying SC Manager %p\n", mgr
);
171 RegCloseKey(mgr
->hkey
);
174 static void sc_handle_destroy_service(struct sc_handle
*handle
)
176 struct sc_service
*svc
= (struct sc_service
*) handle
;
178 TRACE("destroying service %p\n", svc
);
180 RegCloseKey(svc
->hkey
);
182 sc_handle_free(&svc
->scm
->hdr
);
186 /******************************************************************************
187 * String management functions
189 static inline LPWSTR
SERV_dup( LPCSTR str
)
196 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
197 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
198 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
202 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
210 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
211 n
+= (strlen( &str
[n
] ) + 1);
216 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
217 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
221 static inline VOID
SERV_free( LPWSTR wstr
)
223 HeapFree( GetProcessHeap(), 0, wstr
);
226 /******************************************************************************
227 * registry access functions and data
229 static const WCHAR szDisplayName
[] = {
230 'D','i','s','p','l','a','y','N','a','m','e', 0 };
231 static const WCHAR szType
[] = {'T','y','p','e',0};
232 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
233 static const WCHAR szError
[] = {
234 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
235 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
236 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
237 static const WCHAR szDependencies
[] = {
238 'D','e','p','e','n','d','e','n','c','i','e','s',0};
239 static const WCHAR szDependOnService
[] = {
240 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
241 static const WCHAR szObjectName
[] = {
242 'O','b','j','e','c','t','N','a','m','e',0};
243 static const WCHAR szTag
[] = {
253 static inline void service_set_value( struct reg_value
*val
,
254 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
262 static inline void service_set_dword( struct reg_value
*val
,
263 LPCWSTR name
, const DWORD
*data
)
265 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
268 static inline void service_set_string( struct reg_value
*val
,
269 LPCWSTR name
, LPCWSTR string
)
271 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
272 service_set_value( val
, REG_SZ
, name
, string
, len
);
275 static inline void service_set_multi_string( struct reg_value
*val
,
276 LPCWSTR name
, LPCWSTR string
)
280 /* determine the length of a double null terminated multi string */
282 len
+= (lstrlenW( &string
[ len
] )+1);
283 } while ( string
[ len
++ ] );
285 len
*= sizeof (WCHAR
);
286 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
289 static inline LONG
service_write_values( HKEY hKey
,
290 const struct reg_value
*val
, int n
)
292 LONG r
= ERROR_SUCCESS
;
297 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
298 (const BYTE
*)val
[i
].data
, val
[i
].size
);
299 if( r
!= ERROR_SUCCESS
)
305 /******************************************************************************
306 * Service IPC functions
308 static LPWSTR
service_get_pipe_name(LPCWSTR service
)
310 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
311 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
315 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
316 name
= HeapAlloc(GetProcessHeap(), 0, len
);
317 strcpyW(name
, prefix
);
318 strcatW(name
, service
);
322 static HANDLE
service_open_pipe(LPCWSTR service
)
324 LPWSTR szPipe
= service_get_pipe_name( service
);
325 HANDLE handle
= INVALID_HANDLE_VALUE
;
328 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
329 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
330 if (handle
!= INVALID_HANDLE_VALUE
)
332 if (GetLastError() != ERROR_PIPE_BUSY
)
334 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
340 /******************************************************************************
341 * service_get_event_handle
343 static HANDLE
service_get_event_handle(LPCWSTR service
)
345 static const WCHAR prefix
[] = {
346 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
351 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
352 name
= HeapAlloc(GetProcessHeap(), 0, len
);
353 strcpyW(name
, prefix
);
354 strcatW(name
, service
);
355 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
360 /******************************************************************************
363 * Call into the main service routine provided by StartServiceCtrlDispatcher.
365 static DWORD WINAPI
service_thread(LPVOID arg
)
367 service_data
*info
= arg
;
368 LPWSTR str
= info
->args
;
369 DWORD argc
= 0, len
= 0;
375 len
+= strlenW(&str
[len
]) + 1;
382 info
->proc
.w(0, NULL
);
384 info
->proc
.a(0, NULL
);
392 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
393 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
397 info
->proc
.w(argc
, argv
);
398 HeapFree(GetProcessHeap(), 0, argv
);
402 LPSTR strA
, *argv
, p
;
405 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
406 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
407 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
409 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
410 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
414 info
->proc
.a(argc
, argv
);
415 HeapFree(GetProcessHeap(), 0, argv
);
416 HeapFree(GetProcessHeap(), 0, strA
);
421 /******************************************************************************
422 * service_handle_start
424 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
426 DWORD read
= 0, result
= 0;
430 TRACE("%p %p %d\n", pipe
, service
, count
);
432 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
433 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
434 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
436 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
437 r
, count
, read
, debugstr_wn(args
, count
));
443 ERR("service is not stopped\n");
447 SERV_free(service
->args
);
448 service
->args
= args
;
450 service
->thread
= CreateThread( NULL
, 0, service_thread
,
454 HeapFree(GetProcessHeap(), 0, args
);
455 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
460 /******************************************************************************
461 * service_send_start_message
463 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
465 DWORD i
, len
, count
, result
;
466 service_start_info
*ssi
;
470 TRACE("%p %p %d\n", pipe
, argv
, argc
);
472 /* calculate how much space do we need to send the startup info */
474 for (i
=0; i
<argc
; i
++)
475 len
+= strlenW(argv
[i
])+1;
477 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
478 ssi
->cmd
= WINESERV_STARTINFO
;
481 /* copy service args into a single buffer*/
483 for (i
=0; i
<argc
; i
++)
490 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
492 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
494 HeapFree(GetProcessHeap(),0,ssi
);
499 /******************************************************************************
500 * service_handle_get_status
502 static BOOL
service_handle_get_status(HANDLE pipe
, const service_data
*service
)
506 return WriteFile(pipe
, &service
->status
,
507 sizeof service
->status
, &count
, NULL
);
510 /******************************************************************************
513 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS_PROCESS status
)
515 DWORD cmd
[2], count
= 0;
518 cmd
[0] = WINESERV_GETSTATUS
;
520 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
521 if (!r
|| count
!= sizeof cmd
)
523 ERR("service protocol error - failed to write pipe!\n");
526 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
527 if (!r
|| count
!= sizeof *status
)
528 ERR("service protocol error - failed to read pipe "
529 "r = %d count = %d!\n", r
, count
);
533 /******************************************************************************
534 * service_handle_set_processID
536 static BOOL
service_handle_set_processID(HANDLE pipe
, service_data
*service
, DWORD dwProcessId
)
538 DWORD count
, ret
= ERROR_SUCCESS
;
540 TRACE("received control %d\n", dwProcessId
);
541 service
->status
.dwProcessId
= dwProcessId
;
542 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
545 /******************************************************************************
546 * service_set_processID
548 static BOOL
service_set_processID(HANDLE pipe
, DWORD dwprocessId
, LPDWORD dwResult
)
550 DWORD cmd
[2], count
= 0;
553 cmd
[0] = WINESERV_SETPID
;
554 cmd
[1] = dwprocessId
;
555 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
556 if (!r
|| count
!= sizeof cmd
)
558 ERR("service protocol error - failed to write pipe!\n");
561 r
= ReadFile( pipe
, dwResult
, sizeof *dwResult
, &count
, NULL
);
562 if (!r
|| count
!= sizeof *dwResult
)
563 ERR("service protocol error - failed to read pipe "
564 "r = %d count = %d!\n", r
, count
);
568 /******************************************************************************
569 * service_send_control
571 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
573 DWORD cmd
[2], count
= 0;
576 cmd
[0] = WINESERV_SENDCONTROL
;
578 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
579 if (!r
|| count
!= sizeof cmd
)
581 ERR("service protocol error - failed to write pipe!\n");
584 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
585 if (!r
|| count
!= sizeof *result
)
586 ERR("service protocol error - failed to read pipe "
587 "r = %d count = %d!\n", r
, count
);
591 /******************************************************************************
592 * service_accepts_control
594 static BOOL
service_accepts_control(const service_data
*service
, DWORD dwControl
)
596 DWORD a
= service
->status
.dwControlsAccepted
;
600 case SERVICE_CONTROL_INTERROGATE
:
602 case SERVICE_CONTROL_STOP
:
603 if (a
&SERVICE_ACCEPT_STOP
)
606 case SERVICE_CONTROL_SHUTDOWN
:
607 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
610 case SERVICE_CONTROL_PAUSE
:
611 case SERVICE_CONTROL_CONTINUE
:
612 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
615 case SERVICE_CONTROL_PARAMCHANGE
:
616 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
619 case SERVICE_CONTROL_NETBINDADD
:
620 case SERVICE_CONTROL_NETBINDREMOVE
:
621 case SERVICE_CONTROL_NETBINDENABLE
:
622 case SERVICE_CONTROL_NETBINDDISABLE
:
623 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
626 if (!service
->extended
)
630 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
631 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
634 case SERVICE_CONTROL_POWEREVENT
:
635 if (a
&SERVICE_ACCEPT_POWEREVENT
)
638 case SERVICE_CONTROL_SESSIONCHANGE
:
639 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
646 /******************************************************************************
647 * service_handle_control
649 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
652 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
654 TRACE("received control %d\n", dwControl
);
656 if (service_accepts_control(service
, dwControl
))
658 if (service
->extended
&& service
->handler
.handler_ex
)
660 service
->handler
.handler_ex(dwControl
, 0, NULL
, service
->context
);
663 else if (service
->handler
.handler
)
665 service
->handler
.handler(dwControl
);
669 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
672 /******************************************************************************
673 * service_reap_thread
675 static DWORD
service_reap_thread(service_data
*service
)
679 if (!service
->thread
)
681 GetExitCodeThread(service
->thread
, &exitcode
);
682 if (exitcode
!=STILL_ACTIVE
)
684 CloseHandle(service
->thread
);
690 /******************************************************************************
691 * service_control_dispatcher
693 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
695 service_data
*service
= arg
;
699 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
701 /* create a pipe to talk to the rest of the world with */
702 name
= service_get_pipe_name(service
->name
);
703 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
704 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
707 /* let the process who started us know we've tried to create a pipe */
708 event
= service_get_event_handle(service
->name
);
712 if (pipe
==INVALID_HANDLE_VALUE
)
714 ERR("failed to create pipe for %s, error = %d\n",
715 debugstr_w(service
->name
), GetLastError());
719 /* dispatcher loop */
723 DWORD count
, req
[2] = {0,0};
725 r
= ConnectNamedPipe(pipe
, NULL
);
726 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
728 ERR("pipe connect failed\n");
732 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
733 if (!r
|| count
!=sizeof req
)
735 ERR("pipe read failed\n");
739 service_reap_thread(service
);
741 /* handle the request */
744 case WINESERV_STARTINFO
:
745 service_handle_start(pipe
, service
, req
[1]);
747 case WINESERV_GETSTATUS
:
748 service_handle_get_status(pipe
, service
);
750 case WINESERV_SENDCONTROL
:
751 service_handle_control(pipe
, service
, req
[1]);
753 case WINESERV_SETPID
:
754 service_handle_set_processID(pipe
, service
, req
[1]);
757 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
760 FlushFileBuffers(pipe
);
761 DisconnectNamedPipe(pipe
);
768 /******************************************************************************
769 * service_run_threads
771 static BOOL
service_run_threads(void)
773 service_data
*service
;
777 EnterCriticalSection( &service_cs
);
779 count
= list_count( &service_list
);
781 TRACE("starting %d pipe listener threads\n", count
);
783 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
) * (count
+ 1));
785 handles
[n
++] = __wine_make_process_system();
787 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
788 handles
[n
++] = CreateThread( NULL
, 0, service_control_dispatcher
,
790 assert(n
== count
+ 1);
792 LeaveCriticalSection( &service_cs
);
794 /* wait for all the threads to pack up and exit */
797 DWORD ret
= WaitForMultipleObjects( min(n
,MAXIMUM_WAIT_OBJECTS
), handles
, FALSE
, INFINITE
);
798 if (!ret
) /* system process event */
800 TRACE( "last user process exited, shutting down\n" );
801 /* FIXME: we should maybe send a shutdown control to running services */
804 if (ret
< MAXIMUM_WAIT_OBJECTS
)
806 CloseHandle( handles
[ret
] );
807 memmove( &handles
[ret
], &handles
[ret
+1], (n
- ret
- 1) * sizeof(HANDLE
) );
813 while (n
) CloseHandle( handles
[--n
] );
814 HeapFree(GetProcessHeap(), 0, handles
);
819 /******************************************************************************
820 * StartServiceCtrlDispatcherA [ADVAPI32.@]
822 * See StartServiceCtrlDispatcherW.
824 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
830 TRACE("%p\n", servent
);
832 EnterCriticalSection( &service_cs
);
833 while (servent
->lpServiceName
)
835 LPSTR name
= servent
->lpServiceName
;
837 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
838 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
839 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
840 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
841 info
->proc
.a
= servent
->lpServiceProc
;
842 info
->unicode
= FALSE
;
843 list_add_head( &service_list
, &info
->entry
);
846 LeaveCriticalSection( &service_cs
);
848 service_run_threads();
853 /******************************************************************************
854 * StartServiceCtrlDispatcherW [ADVAPI32.@]
856 * Connects a process containing one or more services to the service control
860 * servent [I] A list of the service names and service procedures
866 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
872 TRACE("%p\n", servent
);
874 EnterCriticalSection( &service_cs
);
875 while (servent
->lpServiceName
)
877 LPWSTR name
= servent
->lpServiceName
;
880 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
881 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
882 strcpyW(info
->name
, name
);
883 info
->proc
.w
= servent
->lpServiceProc
;
884 info
->unicode
= TRUE
;
885 list_add_head( &service_list
, &info
->entry
);
888 LeaveCriticalSection( &service_cs
);
890 service_run_threads();
895 /******************************************************************************
896 * LockServiceDatabase [ADVAPI32.@]
898 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
902 TRACE("%p\n",hSCManager
);
904 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
905 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
909 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
912 TRACE("returning %p\n", ret
);
917 /******************************************************************************
918 * UnlockServiceDatabase [ADVAPI32.@]
920 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
922 TRACE("%p\n",ScLock
);
924 return CloseHandle( ScLock
);
927 /******************************************************************************
928 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
930 SERVICE_STATUS_HANDLE WINAPI
931 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
933 LPWSTR lpServiceNameW
;
934 SERVICE_STATUS_HANDLE ret
;
936 lpServiceNameW
= SERV_dup(lpServiceName
);
937 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
938 SERV_free(lpServiceNameW
);
942 /******************************************************************************
943 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
949 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
950 LPHANDLER_FUNCTION lpfHandler
)
952 service_data
*service
;
953 SERVICE_STATUS_HANDLE handle
= 0;
955 EnterCriticalSection( &service_cs
);
956 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
958 if(!strcmpW(lpServiceName
, service
->name
))
960 service
->handler
.handler
= lpfHandler
;
961 handle
= (SERVICE_STATUS_HANDLE
)service
;
965 LeaveCriticalSection( &service_cs
);
969 /******************************************************************************
970 * SetServiceStatus [ADVAPI32.@]
977 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
979 service_data
*service
;
982 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
983 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
984 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
985 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
986 lpStatus
->dwWaitHint
);
988 EnterCriticalSection( &service_cs
);
989 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
991 if(service
== (service_data
*)hService
)
993 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
994 TRACE("Set service status to %d\n",service
->status
.dwCurrentState
);
999 LeaveCriticalSection( &service_cs
);
1005 /******************************************************************************
1006 * OpenSCManagerA [ADVAPI32.@]
1008 * Establish a connection to the service control manager and open its database.
1011 * lpMachineName [I] Pointer to machine name string
1012 * lpDatabaseName [I] Pointer to database name string
1013 * dwDesiredAccess [I] Type of access
1016 * Success: A Handle to the service control manager database
1019 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
1020 DWORD dwDesiredAccess
)
1022 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
1025 lpMachineNameW
= SERV_dup(lpMachineName
);
1026 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
1027 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
1028 SERV_free(lpDatabaseNameW
);
1029 SERV_free(lpMachineNameW
);
1033 /******************************************************************************
1034 * OpenSCManagerW [ADVAPI32.@]
1036 * See OpenSCManagerA.
1038 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
1039 DWORD dwDesiredAccess
)
1041 struct sc_manager
*manager
;
1045 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
1046 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
1048 if( lpDatabaseName
&& lpDatabaseName
[0] )
1050 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
1052 /* noop, all right */
1054 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
1056 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
1061 SetLastError( ERROR_INVALID_NAME
);
1066 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
1067 sc_handle_destroy_manager
);
1071 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
1072 if (r
!=ERROR_SUCCESS
)
1075 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
1076 RegCloseKey( hReg
);
1077 if (r
!=ERROR_SUCCESS
)
1080 manager
->dwAccess
= dwDesiredAccess
;
1081 TRACE("returning %p\n", manager
);
1083 return (SC_HANDLE
) &manager
->hdr
;
1086 sc_handle_free( &manager
->hdr
);
1091 /******************************************************************************
1092 * ControlService [ADVAPI32.@]
1094 * Send a control code to a service.
1097 * hService [I] Handle of the service control manager database
1098 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1099 * lpServiceStatus [O] Destination for the status of the service, if available
1106 * Unlike M$' implementation, control requests are not serialized and may be
1107 * processed asynchronously.
1109 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1110 LPSERVICE_STATUS lpServiceStatus
)
1112 struct sc_service
*hsvc
;
1116 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1118 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1121 SetLastError( ERROR_INVALID_HANDLE
);
1125 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1128 ERR("failed to query service status\n");
1129 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1133 switch (lpServiceStatus
->dwCurrentState
)
1135 case SERVICE_STOPPED
:
1136 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1138 case SERVICE_START_PENDING
:
1139 if (dwControl
==SERVICE_CONTROL_STOP
)
1142 case SERVICE_STOP_PENDING
:
1143 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1147 handle
= service_open_pipe(hsvc
->name
);
1148 if (handle
!=INVALID_HANDLE_VALUE
)
1150 DWORD result
= ERROR_SUCCESS
;
1151 ret
= service_send_control(handle
, dwControl
, &result
);
1152 CloseHandle(handle
);
1153 if (result
!=ERROR_SUCCESS
)
1155 SetLastError(result
);
1163 /******************************************************************************
1164 * CloseServiceHandle [ADVAPI32.@]
1166 * Close a handle to a service or the service control manager database.
1169 * hSCObject [I] Handle to service or service control manager database
1176 CloseServiceHandle( SC_HANDLE hSCObject
)
1178 TRACE("%p\n", hSCObject
);
1180 sc_handle_free( (struct sc_handle
*) hSCObject
);
1186 /******************************************************************************
1187 * OpenServiceA [ADVAPI32.@]
1189 * Open a handle to a service.
1192 * hSCManager [I] Handle of the service control manager database
1193 * lpServiceName [I] Name of the service to open
1194 * dwDesiredAccess [I] Access required to the service
1197 * Success: Handle to the service
1200 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1201 DWORD dwDesiredAccess
)
1203 LPWSTR lpServiceNameW
;
1206 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1208 lpServiceNameW
= SERV_dup(lpServiceName
);
1209 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1210 SERV_free(lpServiceNameW
);
1215 /******************************************************************************
1216 * OpenServiceW [ADVAPI32.@]
1220 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1221 DWORD dwDesiredAccess
)
1223 struct sc_manager
*hscm
;
1224 struct sc_service
*hsvc
;
1229 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1233 SetLastError(ERROR_INVALID_ADDRESS
);
1237 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1240 SetLastError( ERROR_INVALID_HANDLE
);
1244 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1245 if (r
!=ERROR_SUCCESS
)
1247 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1251 len
= strlenW(lpServiceName
)+1;
1252 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1253 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1254 sc_handle_destroy_service
);
1257 strcpyW( hsvc
->name
, lpServiceName
);
1259 hsvc
->dwAccess
= dwDesiredAccess
;
1261 /* add reference to SCM handle */
1262 hscm
->hdr
.ref_count
++;
1265 TRACE("returning %p\n",hsvc
);
1267 return (SC_HANDLE
) &hsvc
->hdr
;
1270 /******************************************************************************
1271 * CreateServiceW [ADVAPI32.@]
1274 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1275 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1276 DWORD dwServiceType
, DWORD dwStartType
,
1277 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1278 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1279 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1280 LPCWSTR lpPassword
)
1282 struct sc_manager
*hscm
;
1283 struct sc_service
*hsvc
= NULL
;
1287 struct reg_value val
[10];
1290 TRACE("%p %s %s\n", hSCManager
,
1291 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1293 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1296 SetLastError( ERROR_INVALID_HANDLE
);
1300 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1301 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1302 if (r
!=ERROR_SUCCESS
)
1305 if (dp
!= REG_CREATED_NEW_KEY
)
1307 SetLastError(ERROR_SERVICE_EXISTS
);
1312 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1314 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1315 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1316 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1318 if( lpBinaryPathName
)
1319 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1321 if( lpLoadOrderGroup
)
1322 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1324 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1325 * There is no such key as what szDependencies refers to */
1326 if( lpDependencies
)
1327 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1330 FIXME("Don't know how to add a Password for a service.\n");
1332 if( lpServiceStartName
)
1333 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
1335 r
= service_write_values( hKey
, val
, n
);
1336 if( r
!= ERROR_SUCCESS
)
1339 len
= strlenW(lpServiceName
)+1;
1340 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1341 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1344 lstrcpyW( hsvc
->name
, lpServiceName
);
1347 hscm
->hdr
.ref_count
++;
1349 return (SC_HANDLE
) &hsvc
->hdr
;
1352 RegCloseKey( hKey
);
1357 /******************************************************************************
1358 * CreateServiceA [ADVAPI32.@]
1361 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1362 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1363 DWORD dwServiceType
, DWORD dwStartType
,
1364 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1365 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1366 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1369 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1370 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1373 TRACE("%p %s %s\n", hSCManager
,
1374 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1376 lpServiceNameW
= SERV_dup( lpServiceName
);
1377 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1378 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1379 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1380 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1381 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1382 lpPasswordW
= SERV_dup( lpPassword
);
1384 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1385 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1386 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1387 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1389 SERV_free( lpServiceNameW
);
1390 SERV_free( lpDisplayNameW
);
1391 SERV_free( lpBinaryPathNameW
);
1392 SERV_free( lpLoadOrderGroupW
);
1393 SERV_free( lpDependenciesW
);
1394 SERV_free( lpServiceStartNameW
);
1395 SERV_free( lpPasswordW
);
1401 /******************************************************************************
1402 * DeleteService [ADVAPI32.@]
1404 * Delete a service from the service control manager database.
1407 * hService [I] Handle of the service to delete
1413 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1415 struct sc_service
*hsvc
;
1417 WCHAR valname
[MAX_PATH
+1];
1422 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1425 SetLastError( ERROR_INVALID_HANDLE
);
1431 /* Clean out the values */
1432 rc
= RegEnumValueW(hKey
, index
, valname
,&size
,0,0,0,0);
1433 while (rc
== ERROR_SUCCESS
)
1435 RegDeleteValueW(hKey
,valname
);
1438 rc
= RegEnumValueW(hKey
, index
, valname
, &size
,0,0,0,0);
1444 /* delete the key */
1445 RegDeleteKeyW(hsvc
->scm
->hkey
, hsvc
->name
);
1451 /******************************************************************************
1452 * StartServiceA [ADVAPI32.@]
1457 * hService [I] Handle of service
1458 * dwNumServiceArgs [I] Number of arguments
1459 * lpServiceArgVectors [I] Address of array of argument strings
1462 * - NT implements this function using an obscure RPC call.
1463 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1464 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1465 * - This will only work for shared address space. How should the service
1466 * args be transferred when address spaces are separated?
1467 * - Can only start one service at a time.
1468 * - Has no concept of privilege.
1474 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1475 LPCSTR
*lpServiceArgVectors
)
1477 LPWSTR
*lpwstr
=NULL
;
1481 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1483 if (dwNumServiceArgs
)
1484 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1485 dwNumServiceArgs
*sizeof(LPWSTR
) );
1487 for(i
=0; i
<dwNumServiceArgs
; i
++)
1488 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1490 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1492 if (dwNumServiceArgs
)
1494 for(i
=0; i
<dwNumServiceArgs
; i
++)
1495 SERV_free(lpwstr
[i
]);
1496 HeapFree(GetProcessHeap(), 0, lpwstr
);
1502 /******************************************************************************
1503 * service_start_process [INTERNAL]
1505 static DWORD
service_start_process(struct sc_service
*hsvc
, LPDWORD ppid
)
1507 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1508 PROCESS_INFORMATION pi
;
1510 LPWSTR path
= NULL
, str
;
1511 DWORD type
, size
, ret
, svc_type
;
1515 size
= sizeof(svc_type
);
1516 if (RegQueryValueExW(hsvc
->hkey
, szType
, NULL
, &type
, (LPBYTE
)&svc_type
, &size
) || type
!= REG_DWORD
)
1519 if (svc_type
== SERVICE_KERNEL_DRIVER
)
1521 static const WCHAR winedeviceW
[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1522 DWORD len
= GetSystemDirectoryW( NULL
, 0 ) + sizeof(winedeviceW
)/sizeof(WCHAR
) + strlenW(hsvc
->name
);
1524 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1525 GetSystemDirectoryW( path
, len
);
1526 lstrcatW( path
, winedeviceW
);
1527 lstrcatW( path
, hsvc
->name
);
1531 /* read the executable path from the registry */
1533 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1534 if (ret
!=ERROR_SUCCESS
)
1536 str
= HeapAlloc(GetProcessHeap(),0,size
);
1537 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1538 if (ret
==ERROR_SUCCESS
)
1540 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1541 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1542 ExpandEnvironmentStringsW(str
,path
,size
);
1544 HeapFree(GetProcessHeap(),0,str
);
1549 /* wait for the process to start and set an event or terminate */
1550 handles
[0] = service_get_event_handle( hsvc
->name
);
1551 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1552 si
.cb
= sizeof(STARTUPINFOW
);
1553 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1556 if (ppid
) *ppid
= pi
.dwProcessId
;
1558 handles
[1] = pi
.hProcess
;
1559 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1560 if(ret
!= WAIT_OBJECT_0
)
1562 SetLastError(ERROR_IO_PENDING
);
1566 CloseHandle( pi
.hThread
);
1567 CloseHandle( pi
.hProcess
);
1569 CloseHandle( handles
[0] );
1570 HeapFree(GetProcessHeap(),0,path
);
1574 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1577 SERVICE_STATUS status
;
1580 TRACE("%p\n", hService
);
1582 for (i
=0; i
<30; i
++)
1584 status
.dwCurrentState
= 0;
1585 r
= QueryServiceStatus(hService
, &status
);
1588 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1590 TRACE("Service started successfully\n");
1599 /******************************************************************************
1600 * StartServiceW [ADVAPI32.@]
1602 * See StartServiceA.
1604 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1605 LPCWSTR
*lpServiceArgVectors
)
1607 struct sc_service
*hsvc
;
1609 DWORD dwResult
, dwProcessId
= 0;
1611 HANDLE handle
= INVALID_HANDLE_VALUE
;
1613 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1615 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1618 SetLastError(ERROR_INVALID_HANDLE
);
1622 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1626 handle
= service_open_pipe(hsvc
->name
);
1627 if (handle
==INVALID_HANDLE_VALUE
)
1629 /* start the service process */
1630 if (service_start_process(hsvc
, &dwProcessId
))
1631 handle
= service_open_pipe(hsvc
->name
);
1634 if (handle
!= INVALID_HANDLE_VALUE
)
1636 r
= service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1637 CloseHandle(handle
);
1640 handle
= service_open_pipe(hsvc
->name
);
1641 if (handle
!= INVALID_HANDLE_VALUE
)
1643 service_set_processID(handle
, dwProcessId
, &dwResult
);
1644 CloseHandle(handle
);
1647 UnlockServiceDatabase( hLock
);
1649 TRACE("returning %d\n", r
);
1652 service_wait_for_startup(hService
);
1657 /******************************************************************************
1658 * QueryServiceStatus [ADVAPI32.@]
1661 * hService [I] Handle to service to get information about
1662 * lpservicestatus [O] buffer to receive the status information for the service
1665 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1666 LPSERVICE_STATUS lpservicestatus
)
1668 SERVICE_STATUS_PROCESS SvcStatusData
;
1671 TRACE("%p %p\n", hService
, lpservicestatus
);
1673 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1674 sizeof(SERVICE_STATUS_PROCESS
), NULL
);
1675 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1680 /******************************************************************************
1681 * QueryServiceStatusEx [ADVAPI32.@]
1683 * Get information about a service.
1686 * hService [I] Handle to service to get information about
1687 * InfoLevel [I] Level of information to get
1688 * lpBuffer [O] Destination for requested information
1689 * cbBufSize [I] Size of lpBuffer in bytes
1690 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1696 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1697 LPBYTE lpBuffer
, DWORD cbBufSize
,
1698 LPDWORD pcbBytesNeeded
)
1700 struct sc_service
*hsvc
;
1701 DWORD size
, type
, val
;
1704 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
1706 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1708 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1710 SetLastError( ERROR_INVALID_LEVEL
);
1714 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
1715 if (pSvcStatusData
== NULL
)
1717 SetLastError( ERROR_INVALID_PARAMETER
);
1721 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1723 if( pcbBytesNeeded
!= NULL
)
1724 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1726 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1730 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1733 SetLastError( ERROR_INVALID_HANDLE
);
1737 pipe
= service_open_pipe(hsvc
->name
);
1738 if (pipe
!= INVALID_HANDLE_VALUE
)
1740 r
= service_get_status(pipe
, pSvcStatusData
);
1746 TRACE("Failed to read service status\n");
1748 /* read the service type from the registry */
1750 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1751 if (r
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
1754 pSvcStatusData
->dwServiceType
= val
;
1755 pSvcStatusData
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1756 pSvcStatusData
->dwControlsAccepted
= 0;
1757 pSvcStatusData
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1758 pSvcStatusData
->dwServiceSpecificExitCode
= 0;
1759 pSvcStatusData
->dwCheckPoint
= 0;
1760 pSvcStatusData
->dwWaitHint
= 0;
1765 /******************************************************************************
1766 * QueryServiceConfigA [ADVAPI32.@]
1768 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1769 DWORD size
, LPDWORD needed
)
1774 QUERY_SERVICE_CONFIGW
*configW
;
1776 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1778 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1780 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1783 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1784 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1785 if (!ret
) goto done
;
1787 config
->dwServiceType
= configW
->dwServiceType
;
1788 config
->dwStartType
= configW
->dwStartType
;
1789 config
->dwErrorControl
= configW
->dwErrorControl
;
1790 config
->lpBinaryPathName
= NULL
;
1791 config
->lpLoadOrderGroup
= NULL
;
1792 config
->dwTagId
= configW
->dwTagId
;
1793 config
->lpDependencies
= NULL
;
1794 config
->lpServiceStartName
= NULL
;
1795 config
->lpDisplayName
= NULL
;
1797 p
= (LPSTR
)(config
+ 1);
1798 n
= size
- sizeof(*config
);
1801 #define MAP_STR(str) \
1805 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1806 if (!sz) goto done; \
1813 MAP_STR( lpBinaryPathName
);
1814 MAP_STR( lpLoadOrderGroup
);
1815 MAP_STR( lpDependencies
);
1816 MAP_STR( lpServiceStartName
);
1817 MAP_STR( lpDisplayName
);
1820 *needed
= p
- (LPSTR
)config
;
1824 HeapFree( GetProcessHeap(), 0, buffer
);
1828 /******************************************************************************
1829 * QueryServiceConfigW [ADVAPI32.@]
1832 QueryServiceConfigW( SC_HANDLE hService
,
1833 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1834 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1836 WCHAR str_buffer
[ MAX_PATH
];
1838 DWORD type
, val
, sz
, total
, n
;
1841 struct sc_service
*hsvc
;
1843 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1844 cbBufSize
, pcbBytesNeeded
);
1846 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1849 SetLastError( ERROR_INVALID_HANDLE
);
1854 /* TODO: Check which members are mandatory and what the registry types
1855 * should be. This should of course also be tested when a service is
1859 /* calculate the size required first */
1860 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1862 sz
= sizeof(str_buffer
);
1863 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1864 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1866 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1867 if( 0 == sz
) return FALSE
;
1869 total
+= sizeof(WCHAR
) * sz
;
1873 /* FIXME: set last error */
1878 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1879 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1882 total
+= sizeof(WCHAR
);
1885 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1886 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1889 total
+= sizeof(WCHAR
);
1892 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, NULL
, &sz
);
1893 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1896 total
+= sizeof(WCHAR
);
1899 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1900 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1903 total
+= sizeof(WCHAR
);
1905 *pcbBytesNeeded
= total
;
1907 /* if there's not enough memory, return an error */
1908 if( total
> cbBufSize
)
1910 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1914 ZeroMemory( lpServiceConfig
, total
);
1917 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1918 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1919 lpServiceConfig
->dwServiceType
= val
;
1922 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1923 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1924 lpServiceConfig
->dwStartType
= val
;
1927 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1928 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1929 lpServiceConfig
->dwErrorControl
= val
;
1932 r
= RegQueryValueExW( hKey
, szTag
, 0, &type
, (LPBYTE
)&val
, &sz
);
1933 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1934 lpServiceConfig
->dwTagId
= val
;
1936 /* now do the strings */
1937 p
= (LPBYTE
) &lpServiceConfig
[1];
1938 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1940 sz
= sizeof(str_buffer
);
1941 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1942 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1944 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1945 sz
*= sizeof(WCHAR
);
1946 if( 0 == sz
|| sz
> n
) return FALSE
;
1948 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1954 /* FIXME: set last error */
1959 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1960 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1961 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1974 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
1975 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
1976 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1989 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, p
, &sz
);
1990 lpServiceConfig
->lpServiceStartName
= (LPWSTR
) p
;
1991 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2004 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, p
, &sz
);
2005 lpServiceConfig
->lpDisplayName
= (LPWSTR
) p
;
2006 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2019 ERR("Buffer overflow!\n");
2021 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
2022 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
2023 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
2024 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
2025 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
2030 /******************************************************************************
2031 * EnumServicesStatusA [ADVAPI32.@]
2034 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2035 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
2036 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2037 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2039 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2040 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2041 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2042 SetLastError (ERROR_ACCESS_DENIED
);
2046 /******************************************************************************
2047 * EnumServicesStatusW [ADVAPI32.@]
2050 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2051 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
2052 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2053 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2055 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2056 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2057 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2058 SetLastError (ERROR_ACCESS_DENIED
);
2062 /******************************************************************************
2063 * EnumServicesStatusExA [ADVAPI32.@]
2066 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2067 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2068 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
2070 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2071 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2072 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
2073 SetLastError (ERROR_ACCESS_DENIED
);
2077 /******************************************************************************
2078 * EnumServicesStatusExW [ADVAPI32.@]
2081 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2082 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2083 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
2085 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2086 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2087 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
2088 SetLastError (ERROR_ACCESS_DENIED
);
2092 /******************************************************************************
2093 * GetServiceKeyNameA [ADVAPI32.@]
2095 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2096 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2098 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2102 /******************************************************************************
2103 * GetServiceKeyNameW [ADVAPI32.@]
2105 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2106 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2108 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2112 /******************************************************************************
2113 * QueryServiceLockStatusA [ADVAPI32.@]
2115 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2116 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2117 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2119 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2124 /******************************************************************************
2125 * QueryServiceLockStatusW [ADVAPI32.@]
2127 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2128 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2129 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2131 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2136 /******************************************************************************
2137 * GetServiceDisplayNameA [ADVAPI32.@]
2139 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2140 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2142 struct sc_manager
*hscm
;
2146 TRACE("%p %s %p %p\n", hSCManager
,
2147 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2151 SetLastError(ERROR_INVALID_PARAMETER
);
2155 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2158 SetLastError(ERROR_INVALID_HANDLE
);
2162 size
= *lpcchBuffer
;
2163 ret
= RegGetValueA(hscm
->hkey
, lpServiceName
, "DisplayName", RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2164 if (!ret
&& !lpDisplayName
&& size
)
2165 ret
= ERROR_MORE_DATA
;
2169 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2171 if (ret
== ERROR_MORE_DATA
)
2173 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2174 *lpcchBuffer
= size
- 1;
2183 /******************************************************************************
2184 * GetServiceDisplayNameW [ADVAPI32.@]
2186 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2187 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2189 struct sc_manager
*hscm
;
2193 TRACE("%p %s %p %p\n", hSCManager
,
2194 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2198 SetLastError(ERROR_INVALID_PARAMETER
);
2202 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2205 SetLastError(ERROR_INVALID_HANDLE
);
2209 size
= *lpcchBuffer
* sizeof(WCHAR
);
2210 ret
= RegGetValueW(hscm
->hkey
, lpServiceName
, szDisplayName
, RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2211 if (!ret
&& !lpDisplayName
&& size
)
2212 ret
= ERROR_MORE_DATA
;
2216 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2218 if (ret
== ERROR_MORE_DATA
)
2220 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2221 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2230 /******************************************************************************
2231 * ChangeServiceConfigW [ADVAPI32.@]
2233 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2234 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2235 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2236 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2238 struct reg_value val
[10];
2239 struct sc_service
*hsvc
;
2240 DWORD r
= ERROR_SUCCESS
;
2244 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2245 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2246 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2247 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2248 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2250 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2253 SetLastError( ERROR_INVALID_HANDLE
);
2258 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2259 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2261 if( dwStartType
!= SERVICE_NO_CHANGE
)
2262 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2264 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2265 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2267 if( lpBinaryPathName
)
2268 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2270 if( lpLoadOrderGroup
)
2271 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2273 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2274 * There is no such key as what szDependencies refers to */
2275 if( lpDependencies
)
2276 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2279 FIXME("ignoring password\n");
2281 if( lpServiceStartName
)
2282 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
2284 r
= service_write_values( hsvc
->hkey
, val
, n
);
2286 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2289 /******************************************************************************
2290 * ChangeServiceConfigA [ADVAPI32.@]
2292 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2293 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2294 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2295 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2297 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2298 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2301 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2302 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2303 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2304 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2305 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2307 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2308 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2309 wDependencies
= SERV_dupmulti( lpDependencies
);
2310 wServiceStartName
= SERV_dup( lpServiceStartName
);
2311 wPassword
= SERV_dup( lpPassword
);
2312 wDisplayName
= SERV_dup( lpDisplayName
);
2314 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2315 dwStartType
, dwErrorControl
, wBinaryPathName
,
2316 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2317 wServiceStartName
, wPassword
, wDisplayName
);
2319 SERV_free( wBinaryPathName
);
2320 SERV_free( wLoadOrderGroup
);
2321 SERV_free( wDependencies
);
2322 SERV_free( wServiceStartName
);
2323 SERV_free( wPassword
);
2324 SERV_free( wDisplayName
);
2329 /******************************************************************************
2330 * ChangeServiceConfig2A [ADVAPI32.@]
2332 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2337 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2339 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2341 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2342 SERVICE_DESCRIPTIONW sdw
;
2344 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2346 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2348 SERV_free( sdw
.lpDescription
);
2350 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2352 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2353 SERVICE_FAILURE_ACTIONSW faw
;
2355 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2356 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2357 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2358 faw
.cActions
= fa
->cActions
;
2359 faw
.lpsaActions
= fa
->lpsaActions
;
2361 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2363 SERV_free( faw
.lpRebootMsg
);
2364 SERV_free( faw
.lpCommand
);
2367 SetLastError( ERROR_INVALID_PARAMETER
);
2372 /******************************************************************************
2373 * ChangeServiceConfig2W [ADVAPI32.@]
2375 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2379 struct sc_service
*hsvc
;
2381 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2384 SetLastError( ERROR_INVALID_HANDLE
);
2389 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2391 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2392 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2393 if (sd
->lpDescription
)
2395 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2396 if (sd
->lpDescription
[0] == 0)
2397 RegDeleteValueW(hKey
,szDescription
);
2399 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2400 (LPVOID
)sd
->lpDescription
,
2401 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2405 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2409 /******************************************************************************
2410 * QueryServiceObjectSecurity [ADVAPI32.@]
2412 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2413 SECURITY_INFORMATION dwSecurityInformation
,
2414 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2415 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2419 FIXME("%p %d %p %u %p\n", hService
, dwSecurityInformation
,
2420 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2422 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2424 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2425 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2426 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2430 /******************************************************************************
2431 * SetServiceObjectSecurity [ADVAPI32.@]
2433 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2434 SECURITY_INFORMATION dwSecurityInformation
,
2435 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2437 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2441 /******************************************************************************
2442 * SetServiceBits [ADVAPI32.@]
2444 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2445 DWORD dwServiceBits
,
2447 BOOL bUpdateImmediately
)
2449 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2450 bSetBitsOn
, bUpdateImmediately
);
2454 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName
,
2455 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2457 FIXME("%s %p %p\n", debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
2461 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2462 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2464 service_data
*service
;
2465 SERVICE_STATUS_HANDLE handle
= 0;
2467 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2469 EnterCriticalSection( &service_cs
);
2470 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
2472 if(!strcmpW(lpServiceName
, service
->name
))
2474 service
->handler
.handler_ex
= lpHandlerProc
;
2475 service
->context
= lpContext
;
2476 service
->extended
= TRUE
;
2477 handle
= (SERVICE_STATUS_HANDLE
)service
;
2481 LeaveCriticalSection( &service_cs
);