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 static const GENERIC_MAPPING scm_generic
= {
49 (STANDARD_RIGHTS_READ
| SC_MANAGER_ENUMERATE_SERVICE
| SC_MANAGER_QUERY_LOCK_STATUS
),
50 (STANDARD_RIGHTS_WRITE
| SC_MANAGER_CREATE_SERVICE
| SC_MANAGER_MODIFY_BOOT_CONFIG
),
51 (STANDARD_RIGHTS_EXECUTE
| SC_MANAGER_CONNECT
| SC_MANAGER_LOCK
),
55 static const GENERIC_MAPPING svc_generic
= {
56 (STANDARD_RIGHTS_READ
| SERVICE_QUERY_CONFIG
| SERVICE_QUERY_STATUS
| SERVICE_INTERROGATE
| SERVICE_ENUMERATE_DEPENDENTS
),
57 (STANDARD_RIGHTS_WRITE
| SERVICE_CHANGE_CONFIG
),
58 (STANDARD_RIGHTS_EXECUTE
| SERVICE_START
| SERVICE_STOP
| SERVICE_PAUSE_CONTINUE
| SERVICE_USER_DEFINED_CONTROL
),
62 typedef struct service_start_info_t
69 #define WINESERV_STARTINFO 1
70 #define WINESERV_GETSTATUS 2
71 #define WINESERV_SENDCONTROL 3
73 typedef struct service_data_t
77 LPHANDLER_FUNCTION handler
;
78 LPHANDLER_FUNCTION_EX handler_ex
;
81 SERVICE_STATUS_PROCESS status
;
84 BOOL extended
: 1; /* uses handler_ex instead of handler? */
86 LPSERVICE_MAIN_FUNCTIONA a
;
87 LPSERVICE_MAIN_FUNCTIONW w
;
93 static CRITICAL_SECTION service_cs
;
94 static CRITICAL_SECTION_DEBUG service_cs_debug
=
97 { &service_cs_debug
.ProcessLocksList
,
98 &service_cs_debug
.ProcessLocksList
},
99 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
101 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
103 static struct list service_list
= LIST_INIT(service_list
);
105 extern HANDLE
__wine_make_process_system(void);
107 /******************************************************************************
111 #define MAX_SERVICE_NAME 256
113 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
116 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
120 SC_HANDLE_TYPE htype
;
122 sc_handle_destructor destroy
;
125 struct sc_manager
/* service control manager handle */
127 struct sc_handle hdr
;
128 HKEY hkey
; /* handle to services database in the registry */
132 struct sc_service
/* service handle */
134 struct sc_handle hdr
;
135 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
137 struct sc_manager
*scm
; /* pointer to SCM handle */
141 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
142 sc_handle_destructor destroy
)
144 struct sc_handle
*hdr
;
146 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
151 hdr
->destroy
= destroy
;
153 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
157 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
159 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
163 if (hdr
->htype
!= htype
)
168 static void sc_handle_free(struct sc_handle
* hdr
)
172 if (--hdr
->ref_count
)
175 HeapFree(GetProcessHeap(), 0, hdr
);
178 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
180 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
182 TRACE("destroying SC Manager %p\n", mgr
);
184 RegCloseKey(mgr
->hkey
);
187 static void sc_handle_destroy_service(struct sc_handle
*handle
)
189 struct sc_service
*svc
= (struct sc_service
*) handle
;
191 TRACE("destroying service %p\n", svc
);
193 RegCloseKey(svc
->hkey
);
195 sc_handle_free(&svc
->scm
->hdr
);
199 /******************************************************************************
200 * String management functions (same behaviour as strdup)
201 * NOTE: the caller of those functions is responsible for calling HeapFree
202 * in order to release the memory allocated by those functions.
204 static inline LPWSTR
SERV_dup( LPCSTR str
)
211 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
212 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
213 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
217 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
225 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
226 n
+= (strlen( &str
[n
] ) + 1);
231 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
232 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
236 /******************************************************************************
237 * registry access functions and data
239 static const WCHAR szDisplayName
[] = {
240 'D','i','s','p','l','a','y','N','a','m','e', 0 };
241 static const WCHAR szType
[] = {'T','y','p','e',0};
242 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
243 static const WCHAR szError
[] = {
244 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
245 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
246 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
247 static const WCHAR szDependencies
[] = {
248 'D','e','p','e','n','d','e','n','c','i','e','s',0};
249 static const WCHAR szDependOnService
[] = {
250 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
251 static const WCHAR szObjectName
[] = {
252 'O','b','j','e','c','t','N','a','m','e',0};
253 static const WCHAR szTag
[] = {
263 static inline void service_set_value( struct reg_value
*val
,
264 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
272 static inline void service_set_dword( struct reg_value
*val
,
273 LPCWSTR name
, const DWORD
*data
)
275 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
278 static inline void service_set_string( struct reg_value
*val
,
279 LPCWSTR name
, LPCWSTR string
)
281 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
282 service_set_value( val
, REG_SZ
, name
, string
, len
);
285 static inline void service_set_multi_string( struct reg_value
*val
,
286 LPCWSTR name
, LPCWSTR string
)
290 /* determine the length of a double null terminated multi string */
292 len
+= (lstrlenW( &string
[ len
] )+1);
293 } while ( string
[ len
++ ] );
295 len
*= sizeof (WCHAR
);
296 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
299 static inline LONG
service_write_values( HKEY hKey
,
300 const struct reg_value
*val
, int n
)
302 LONG r
= ERROR_SUCCESS
;
307 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
308 (const BYTE
*)val
[i
].data
, val
[i
].size
);
309 if( r
!= ERROR_SUCCESS
)
315 /******************************************************************************
316 * Service IPC functions
318 static LPWSTR
service_get_pipe_name(LPCWSTR service
)
320 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
321 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
325 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
326 name
= HeapAlloc(GetProcessHeap(), 0, len
);
327 strcpyW(name
, prefix
);
328 strcatW(name
, service
);
332 static HANDLE
service_open_pipe(LPCWSTR service
)
334 LPWSTR szPipe
= service_get_pipe_name( service
);
335 HANDLE handle
= INVALID_HANDLE_VALUE
;
338 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
339 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
340 if (handle
!= INVALID_HANDLE_VALUE
)
342 if (GetLastError() != ERROR_PIPE_BUSY
)
344 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
345 HeapFree(GetProcessHeap(), 0, szPipe
);
350 /******************************************************************************
351 * service_get_event_handle
353 static HANDLE
service_get_event_handle(LPCWSTR service
)
355 static const WCHAR prefix
[] = {
356 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
361 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
362 name
= HeapAlloc(GetProcessHeap(), 0, len
);
363 strcpyW(name
, prefix
);
364 strcatW(name
, service
);
365 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
366 HeapFree(GetProcessHeap(), 0, name
);
370 /******************************************************************************
373 * Call into the main service routine provided by StartServiceCtrlDispatcher.
375 static DWORD WINAPI
service_thread(LPVOID arg
)
377 service_data
*info
= arg
;
378 LPWSTR str
= info
->args
;
379 DWORD argc
= 0, len
= 0;
385 len
+= strlenW(&str
[len
]) + 1;
392 info
->proc
.w(0, NULL
);
394 info
->proc
.a(0, NULL
);
402 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
403 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
407 info
->proc
.w(argc
, argv
);
408 HeapFree(GetProcessHeap(), 0, argv
);
412 LPSTR strA
, *argv
, p
;
415 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
416 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
417 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
419 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
420 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
424 info
->proc
.a(argc
, argv
);
425 HeapFree(GetProcessHeap(), 0, argv
);
426 HeapFree(GetProcessHeap(), 0, strA
);
431 /******************************************************************************
432 * service_handle_start
434 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
436 DWORD read
= 0, result
= 0;
440 TRACE("%p %p %d\n", pipe
, service
, count
);
442 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
443 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
444 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
446 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
447 r
, count
, read
, debugstr_wn(args
, count
));
453 WARN("service is not stopped\n");
454 result
= ERROR_SERVICE_ALREADY_RUNNING
;
458 HeapFree(GetProcessHeap(), 0, service
->args
);
459 service
->args
= args
;
461 service
->thread
= CreateThread( NULL
, 0, service_thread
,
465 HeapFree(GetProcessHeap(), 0, args
);
466 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
471 /******************************************************************************
472 * service_send_start_message
474 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
476 DWORD i
, len
, count
, result
;
477 service_start_info
*ssi
;
481 TRACE("%p %p %d\n", pipe
, argv
, argc
);
483 /* calculate how much space do we need to send the startup info */
485 for (i
=0; i
<argc
; i
++)
486 len
+= strlenW(argv
[i
])+1;
488 ssi
= HeapAlloc(GetProcessHeap(),0,sizeof *ssi
+ (len
-1)*sizeof(WCHAR
));
489 ssi
->cmd
= WINESERV_STARTINFO
;
492 /* copy service args into a single buffer*/
494 for (i
=0; i
<argc
; i
++)
501 r
= WriteFile(pipe
, ssi
, sizeof *ssi
+ len
*sizeof(WCHAR
), &count
, NULL
);
504 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
507 SetLastError(result
);
512 HeapFree(GetProcessHeap(),0,ssi
);
517 /******************************************************************************
518 * service_handle_get_status
520 static BOOL
service_handle_get_status(HANDLE pipe
, const service_data
*service
)
524 return WriteFile(pipe
, &service
->status
,
525 sizeof service
->status
, &count
, NULL
);
528 /******************************************************************************
531 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS_PROCESS status
)
533 DWORD cmd
[2], count
= 0;
536 cmd
[0] = WINESERV_GETSTATUS
;
538 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
539 if (!r
|| count
!= sizeof cmd
)
541 ERR("service protocol error - failed to write pipe!\n");
544 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
545 if (!r
|| count
!= sizeof *status
)
546 ERR("service protocol error - failed to read pipe "
547 "r = %d count = %d!\n", r
, count
);
551 /******************************************************************************
552 * service_send_control
554 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
556 DWORD cmd
[2], count
= 0;
559 cmd
[0] = WINESERV_SENDCONTROL
;
561 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
562 if (!r
|| count
!= sizeof cmd
)
564 ERR("service protocol error - failed to write pipe!\n");
567 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
568 if (!r
|| count
!= sizeof *result
)
569 ERR("service protocol error - failed to read pipe "
570 "r = %d count = %d!\n", r
, count
);
574 /******************************************************************************
575 * service_accepts_control
577 static BOOL
service_accepts_control(const service_data
*service
, DWORD dwControl
)
579 DWORD a
= service
->status
.dwControlsAccepted
;
583 case SERVICE_CONTROL_INTERROGATE
:
585 case SERVICE_CONTROL_STOP
:
586 if (a
&SERVICE_ACCEPT_STOP
)
589 case SERVICE_CONTROL_SHUTDOWN
:
590 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
593 case SERVICE_CONTROL_PAUSE
:
594 case SERVICE_CONTROL_CONTINUE
:
595 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
598 case SERVICE_CONTROL_PARAMCHANGE
:
599 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
602 case SERVICE_CONTROL_NETBINDADD
:
603 case SERVICE_CONTROL_NETBINDREMOVE
:
604 case SERVICE_CONTROL_NETBINDENABLE
:
605 case SERVICE_CONTROL_NETBINDDISABLE
:
606 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
609 if (!service
->extended
)
613 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
614 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
617 case SERVICE_CONTROL_POWEREVENT
:
618 if (a
&SERVICE_ACCEPT_POWEREVENT
)
621 case SERVICE_CONTROL_SESSIONCHANGE
:
622 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
629 /******************************************************************************
630 * service_handle_control
632 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
635 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
637 TRACE("received control %d\n", dwControl
);
639 if (service_accepts_control(service
, dwControl
))
641 if (service
->extended
&& service
->handler
.handler_ex
)
643 service
->handler
.handler_ex(dwControl
, 0, NULL
, service
->context
);
646 else if (service
->handler
.handler
)
648 service
->handler
.handler(dwControl
);
652 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
655 /******************************************************************************
656 * service_reap_thread
658 static DWORD
service_reap_thread(service_data
*service
)
662 if (!service
->thread
)
664 GetExitCodeThread(service
->thread
, &exitcode
);
665 if (exitcode
!=STILL_ACTIVE
)
667 CloseHandle(service
->thread
);
673 /******************************************************************************
674 * service_control_dispatcher
676 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
678 service_data
*service
= arg
;
682 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
684 /* create a pipe to talk to the rest of the world with */
685 name
= service_get_pipe_name(service
->name
);
686 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
687 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
688 HeapFree(GetProcessHeap(), 0, name
);
690 /* let the process who started us know we've tried to create a pipe */
691 event
= service_get_event_handle(service
->name
);
695 if (pipe
==INVALID_HANDLE_VALUE
)
697 ERR("failed to create pipe for %s, error = %d\n",
698 debugstr_w(service
->name
), GetLastError());
702 /* dispatcher loop */
706 DWORD count
, req
[2] = {0,0};
708 r
= ConnectNamedPipe(pipe
, NULL
);
709 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
711 ERR("pipe connect failed\n");
715 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
716 if (!r
|| count
!=sizeof req
)
718 ERR("pipe read failed\n");
722 service_reap_thread(service
);
724 /* handle the request */
727 case WINESERV_STARTINFO
:
728 service_handle_start(pipe
, service
, req
[1]);
730 case WINESERV_GETSTATUS
:
731 service_handle_get_status(pipe
, service
);
733 case WINESERV_SENDCONTROL
:
734 service_handle_control(pipe
, service
, req
[1]);
737 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
740 FlushFileBuffers(pipe
);
741 DisconnectNamedPipe(pipe
);
748 /******************************************************************************
749 * service_run_threads
751 static BOOL
service_run_threads(void)
753 service_data
*service
;
757 EnterCriticalSection( &service_cs
);
759 count
= list_count( &service_list
);
761 TRACE("Starting %d pipe listener threads. Services running as process %d\n", count
, GetCurrentProcessId());
763 handles
= HeapAlloc(GetProcessHeap(), 0, sizeof(HANDLE
) * (count
+ 1));
765 handles
[n
++] = __wine_make_process_system();
767 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
769 service
->status
.dwProcessId
= GetCurrentProcessId();
770 handles
[n
++] = CreateThread( NULL
, 0, service_control_dispatcher
,
773 assert(n
== count
+ 1);
775 LeaveCriticalSection( &service_cs
);
777 /* wait for all the threads to pack up and exit */
780 DWORD ret
= WaitForMultipleObjects( min(n
,MAXIMUM_WAIT_OBJECTS
), handles
, FALSE
, INFINITE
);
781 if (!ret
) /* system process event */
783 TRACE( "last user process exited, shutting down\n" );
784 /* FIXME: we should maybe send a shutdown control to running services */
787 if (ret
< MAXIMUM_WAIT_OBJECTS
)
789 CloseHandle( handles
[ret
] );
790 memmove( &handles
[ret
], &handles
[ret
+1], (n
- ret
- 1) * sizeof(HANDLE
) );
796 while (n
) CloseHandle( handles
[--n
] );
797 HeapFree(GetProcessHeap(), 0, handles
);
802 /******************************************************************************
803 * StartServiceCtrlDispatcherA [ADVAPI32.@]
805 * See StartServiceCtrlDispatcherW.
807 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
813 TRACE("%p\n", servent
);
815 EnterCriticalSection( &service_cs
);
816 while (servent
->lpServiceName
)
818 LPSTR name
= servent
->lpServiceName
;
820 len
= MultiByteToWideChar(CP_ACP
, 0, name
, -1, NULL
, 0);
821 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
822 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
823 MultiByteToWideChar(CP_ACP
, 0, name
, -1, info
->name
, len
);
824 info
->proc
.a
= servent
->lpServiceProc
;
825 info
->unicode
= FALSE
;
826 list_add_head( &service_list
, &info
->entry
);
829 LeaveCriticalSection( &service_cs
);
831 service_run_threads();
836 /******************************************************************************
837 * StartServiceCtrlDispatcherW [ADVAPI32.@]
839 * Connects a process containing one or more services to the service control
843 * servent [I] A list of the service names and service procedures
849 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
855 TRACE("%p\n", servent
);
857 EnterCriticalSection( &service_cs
);
858 while (servent
->lpServiceName
)
860 LPWSTR name
= servent
->lpServiceName
;
863 sz
= len
*sizeof(WCHAR
) + sizeof *info
;
864 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
865 strcpyW(info
->name
, name
);
866 info
->proc
.w
= servent
->lpServiceProc
;
867 info
->unicode
= TRUE
;
868 list_add_head( &service_list
, &info
->entry
);
871 LeaveCriticalSection( &service_cs
);
873 service_run_threads();
878 /******************************************************************************
879 * LockServiceDatabase [ADVAPI32.@]
881 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
885 TRACE("%p\n",hSCManager
);
887 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
888 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
892 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
895 TRACE("returning %p\n", ret
);
900 /******************************************************************************
901 * UnlockServiceDatabase [ADVAPI32.@]
903 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
905 TRACE("%p\n",ScLock
);
907 return CloseHandle( ScLock
);
910 /******************************************************************************
911 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
913 SERVICE_STATUS_HANDLE WINAPI
914 RegisterServiceCtrlHandlerA( LPCSTR lpServiceName
, LPHANDLER_FUNCTION lpfHandler
)
916 LPWSTR lpServiceNameW
;
917 SERVICE_STATUS_HANDLE ret
;
919 lpServiceNameW
= SERV_dup(lpServiceName
);
920 ret
= RegisterServiceCtrlHandlerW( lpServiceNameW
, lpfHandler
);
921 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
925 /******************************************************************************
926 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
932 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR lpServiceName
,
933 LPHANDLER_FUNCTION lpfHandler
)
935 service_data
*service
;
936 SERVICE_STATUS_HANDLE handle
= 0;
938 EnterCriticalSection( &service_cs
);
939 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
941 if(!strcmpW(lpServiceName
, service
->name
))
943 service
->handler
.handler
= lpfHandler
;
944 handle
= (SERVICE_STATUS_HANDLE
)service
;
948 LeaveCriticalSection( &service_cs
);
952 /******************************************************************************
953 * SetServiceStatus [ADVAPI32.@]
960 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
962 service_data
*service
;
965 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
966 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
967 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
968 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
969 lpStatus
->dwWaitHint
);
971 EnterCriticalSection( &service_cs
);
972 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
974 if(service
== (service_data
*)hService
)
976 memcpy( &service
->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
977 TRACE("Set service status to %d\n",service
->status
.dwCurrentState
);
982 LeaveCriticalSection( &service_cs
);
988 /******************************************************************************
989 * OpenSCManagerA [ADVAPI32.@]
991 * Establish a connection to the service control manager and open its database.
994 * lpMachineName [I] Pointer to machine name string
995 * lpDatabaseName [I] Pointer to database name string
996 * dwDesiredAccess [I] Type of access
999 * Success: A Handle to the service control manager database
1002 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
1003 DWORD dwDesiredAccess
)
1005 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
1008 lpMachineNameW
= SERV_dup(lpMachineName
);
1009 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
1010 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
1011 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW
);
1012 HeapFree(GetProcessHeap(), 0, lpMachineNameW
);
1016 /******************************************************************************
1017 * OpenSCManagerW [ADVAPI32.@]
1019 * See OpenSCManagerA.
1021 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
1022 DWORD dwDesiredAccess
)
1024 struct sc_manager
*manager
;
1027 DWORD new_mask
= dwDesiredAccess
;
1029 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
1030 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
1032 if( lpDatabaseName
&& lpDatabaseName
[0] )
1034 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
1036 /* noop, all right */
1038 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
1040 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
1045 SetLastError( ERROR_INVALID_NAME
);
1050 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
1051 sc_handle_destroy_manager
);
1055 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
1056 if (r
!=ERROR_SUCCESS
)
1059 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
1060 RegCloseKey( hReg
);
1061 if (r
!=ERROR_SUCCESS
)
1064 RtlMapGenericMask(&new_mask
, &scm_generic
);
1065 manager
->dwAccess
= new_mask
;
1066 TRACE("returning %p (access : 0x%08x)\n", manager
, manager
->dwAccess
);
1068 return (SC_HANDLE
) &manager
->hdr
;
1071 sc_handle_free( &manager
->hdr
);
1076 /******************************************************************************
1077 * ControlService [ADVAPI32.@]
1079 * Send a control code to a service.
1082 * hService [I] Handle of the service control manager database
1083 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1084 * lpServiceStatus [O] Destination for the status of the service, if available
1091 * Unlike M$' implementation, control requests are not serialized and may be
1092 * processed asynchronously.
1094 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1095 LPSERVICE_STATUS lpServiceStatus
)
1097 struct sc_service
*hsvc
;
1101 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1103 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1106 SetLastError( ERROR_INVALID_HANDLE
);
1110 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1113 ERR("failed to query service status\n");
1114 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1118 switch (lpServiceStatus
->dwCurrentState
)
1120 case SERVICE_STOPPED
:
1121 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1123 case SERVICE_START_PENDING
:
1124 if (dwControl
==SERVICE_CONTROL_STOP
)
1127 case SERVICE_STOP_PENDING
:
1128 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1132 handle
= service_open_pipe(hsvc
->name
);
1133 if (handle
!=INVALID_HANDLE_VALUE
)
1135 DWORD result
= ERROR_SUCCESS
;
1136 ret
= service_send_control(handle
, dwControl
, &result
);
1137 CloseHandle(handle
);
1138 if (result
!=ERROR_SUCCESS
)
1140 SetLastError(result
);
1148 /******************************************************************************
1149 * CloseServiceHandle [ADVAPI32.@]
1151 * Close a handle to a service or the service control manager database.
1154 * hSCObject [I] Handle to service or service control manager database
1161 CloseServiceHandle( SC_HANDLE hSCObject
)
1163 TRACE("%p\n", hSCObject
);
1165 sc_handle_free( (struct sc_handle
*) hSCObject
);
1171 /******************************************************************************
1172 * OpenServiceA [ADVAPI32.@]
1174 * Open a handle to a service.
1177 * hSCManager [I] Handle of the service control manager database
1178 * lpServiceName [I] Name of the service to open
1179 * dwDesiredAccess [I] Access required to the service
1182 * Success: Handle to the service
1185 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1186 DWORD dwDesiredAccess
)
1188 LPWSTR lpServiceNameW
;
1191 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1193 lpServiceNameW
= SERV_dup(lpServiceName
);
1194 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1195 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1200 /******************************************************************************
1201 * OpenServiceW [ADVAPI32.@]
1205 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1206 DWORD dwDesiredAccess
)
1208 struct sc_manager
*hscm
;
1209 struct sc_service
*hsvc
;
1213 DWORD new_mask
= dwDesiredAccess
;
1215 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1217 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1220 SetLastError( ERROR_INVALID_HANDLE
);
1226 SetLastError(ERROR_INVALID_ADDRESS
);
1230 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1231 if (r
!=ERROR_SUCCESS
)
1233 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1237 len
= strlenW(lpServiceName
)+1;
1238 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1239 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1240 sc_handle_destroy_service
);
1246 strcpyW( hsvc
->name
, lpServiceName
);
1249 RtlMapGenericMask(&new_mask
, &svc_generic
);
1250 hsvc
->dwAccess
= new_mask
;
1252 /* add reference to SCM handle */
1253 hscm
->hdr
.ref_count
++;
1256 TRACE("returning %p\n",hsvc
);
1258 return (SC_HANDLE
) &hsvc
->hdr
;
1261 /******************************************************************************
1262 * CreateServiceW [ADVAPI32.@]
1265 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1266 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1267 DWORD dwServiceType
, DWORD dwStartType
,
1268 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1269 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1270 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1271 LPCWSTR lpPassword
)
1273 struct sc_manager
*hscm
;
1274 struct sc_service
*hsvc
= NULL
;
1278 struct reg_value val
[10];
1280 DWORD new_mask
= dwDesiredAccess
;
1282 WCHAR buffer
[MAX_PATH
];
1283 BOOL displayname_exists
= FALSE
;
1285 TRACE("%p %s %s\n", hSCManager
,
1286 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1288 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1291 SetLastError( ERROR_INVALID_HANDLE
);
1295 if (!lpServiceName
|| !lpBinaryPathName
)
1297 SetLastError(ERROR_INVALID_ADDRESS
);
1301 if (!(hscm
->dwAccess
& SC_MANAGER_CREATE_SERVICE
))
1303 SetLastError(ERROR_ACCESS_DENIED
);
1307 if (!lpServiceName
[0])
1309 SetLastError(ERROR_INVALID_NAME
);
1313 if (!lpBinaryPathName
[0])
1315 SetLastError(ERROR_INVALID_PARAMETER
);
1319 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1320 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1321 * runs under the LocalSystem account)
1323 switch (dwServiceType
)
1325 case SERVICE_KERNEL_DRIVER
:
1326 case SERVICE_FILE_SYSTEM_DRIVER
:
1327 case SERVICE_WIN32_OWN_PROCESS
:
1328 case SERVICE_WIN32_SHARE_PROCESS
:
1331 case SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
1332 case SERVICE_WIN32_SHARE_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
1333 /* FIXME : Do we need a more thorough check? */
1334 if (lpServiceStartName
)
1336 SetLastError(ERROR_INVALID_PARAMETER
);
1341 SetLastError(ERROR_INVALID_PARAMETER
);
1345 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1346 if (dwStartType
> SERVICE_DISABLED
)
1348 SetLastError(ERROR_INVALID_PARAMETER
);
1352 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1353 if (((dwStartType
== SERVICE_BOOT_START
) || (dwStartType
== SERVICE_SYSTEM_START
)) &&
1354 ((dwServiceType
& SERVICE_WIN32_OWN_PROCESS
) || (dwServiceType
& SERVICE_WIN32_SHARE_PROCESS
)))
1356 SetLastError(ERROR_INVALID_PARAMETER
);
1360 /* Loop through the registry to check if the service already exists and to
1361 * check if we can use the given displayname.
1362 * FIXME: Should we use EnumServicesStatusEx?
1364 len
= sizeof(buffer
);
1365 while (RegEnumKeyExW(hscm
->hkey
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1369 /* The service already exists, so bail out */
1370 if(!lstrcmpiW(lpServiceName
, buffer
))
1372 SetLastError(ERROR_SERVICE_EXISTS
);
1376 /* The given displayname matches the found servicename. We don't bail out
1377 * as servicename is checked before a duplicate displayname
1379 if(!lstrcmpiW(lpDisplayName
, buffer
))
1380 displayname_exists
= TRUE
;
1382 if (RegOpenKeyExW(hscm
->hkey
, buffer
, 0, KEY_READ
, &service_key
) == ERROR_SUCCESS
)
1384 WCHAR name
[MAX_PATH
];
1385 DWORD size
= sizeof(name
);
1387 if (RegQueryValueExW(service_key
, szDisplayName
, NULL
, NULL
, (LPBYTE
)name
, &size
) == ERROR_SUCCESS
)
1389 /* The given displayname matches the found displayname */
1390 if (!lstrcmpiW(lpDisplayName
, name
))
1391 displayname_exists
= TRUE
;
1393 RegCloseKey(service_key
);
1396 len
= sizeof(buffer
);
1399 if (lpDisplayName
&& displayname_exists
)
1401 SetLastError(ERROR_DUPLICATE_SERVICE_NAME
);
1405 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1406 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1407 if (r
!=ERROR_SUCCESS
)
1409 /* FIXME: Should we set an error? */
1414 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1416 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1417 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1418 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1420 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1422 if( lpLoadOrderGroup
)
1423 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1425 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1426 * There is no such key as what szDependencies refers to */
1427 if( lpDependencies
)
1428 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1431 FIXME("Don't know how to add a Password for a service.\n");
1433 if( lpServiceStartName
)
1434 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
1436 r
= service_write_values( hKey
, val
, n
);
1437 if( r
!= ERROR_SUCCESS
)
1440 len
= strlenW(lpServiceName
)+1;
1441 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1442 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1445 lstrcpyW( hsvc
->name
, lpServiceName
);
1448 RtlMapGenericMask(&new_mask
, &svc_generic
);
1449 hsvc
->dwAccess
= new_mask
;
1452 hscm
->hdr
.ref_count
++;
1454 return (SC_HANDLE
) &hsvc
->hdr
;
1457 RegCloseKey( hKey
);
1462 /******************************************************************************
1463 * CreateServiceA [ADVAPI32.@]
1466 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1467 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1468 DWORD dwServiceType
, DWORD dwStartType
,
1469 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1470 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1471 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1474 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1475 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1478 TRACE("%p %s %s\n", hSCManager
,
1479 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1481 lpServiceNameW
= SERV_dup( lpServiceName
);
1482 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1483 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1484 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1485 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1486 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1487 lpPasswordW
= SERV_dup( lpPassword
);
1489 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1490 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1491 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1492 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1494 HeapFree( GetProcessHeap(), 0, lpServiceNameW
);
1495 HeapFree( GetProcessHeap(), 0, lpDisplayNameW
);
1496 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW
);
1497 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW
);
1498 HeapFree( GetProcessHeap(), 0, lpDependenciesW
);
1499 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW
);
1500 HeapFree( GetProcessHeap(), 0, lpPasswordW
);
1506 /******************************************************************************
1507 * DeleteService [ADVAPI32.@]
1509 * Delete a service from the service control manager database.
1512 * hService [I] Handle of the service to delete
1518 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1520 struct sc_service
*hsvc
;
1522 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1525 SetLastError( ERROR_INVALID_HANDLE
);
1529 if (!(hsvc
->dwAccess
& DELETE
))
1531 SetLastError(ERROR_ACCESS_DENIED
);
1535 /* Close the key to the service */
1536 RegCloseKey(hsvc
->hkey
);
1538 /* Delete the service under the Service Control Manager key */
1539 RegDeleteTreeW(hsvc
->scm
->hkey
, hsvc
->name
);
1547 /******************************************************************************
1548 * StartServiceA [ADVAPI32.@]
1553 * hService [I] Handle of service
1554 * dwNumServiceArgs [I] Number of arguments
1555 * lpServiceArgVectors [I] Address of array of argument strings
1558 * - NT implements this function using an obscure RPC call.
1559 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1560 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1561 * - This will only work for shared address space. How should the service
1562 * args be transferred when address spaces are separated?
1563 * - Can only start one service at a time.
1564 * - Has no concept of privilege.
1570 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1571 LPCSTR
*lpServiceArgVectors
)
1573 LPWSTR
*lpwstr
=NULL
;
1577 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1579 if (dwNumServiceArgs
)
1580 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1581 dwNumServiceArgs
*sizeof(LPWSTR
) );
1583 for(i
=0; i
<dwNumServiceArgs
; i
++)
1584 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1586 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1588 if (dwNumServiceArgs
)
1590 for(i
=0; i
<dwNumServiceArgs
; i
++)
1591 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
1592 HeapFree(GetProcessHeap(), 0, lpwstr
);
1598 /******************************************************************************
1599 * service_start_process [INTERNAL]
1601 static DWORD
service_start_process(struct sc_service
*hsvc
, LPDWORD ppid
)
1603 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1604 PROCESS_INFORMATION pi
;
1606 LPWSTR path
= NULL
, str
;
1607 DWORD type
, size
, ret
, svc_type
;
1611 size
= sizeof(svc_type
);
1612 if (RegQueryValueExW(hsvc
->hkey
, szType
, NULL
, &type
, (LPBYTE
)&svc_type
, &size
) || type
!= REG_DWORD
)
1615 if (svc_type
== SERVICE_KERNEL_DRIVER
)
1617 static const WCHAR winedeviceW
[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1618 DWORD len
= GetSystemDirectoryW( NULL
, 0 ) + sizeof(winedeviceW
)/sizeof(WCHAR
) + strlenW(hsvc
->name
);
1620 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1621 GetSystemDirectoryW( path
, len
);
1622 lstrcatW( path
, winedeviceW
);
1623 lstrcatW( path
, hsvc
->name
);
1627 /* read the executable path from the registry */
1629 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1630 if (ret
!=ERROR_SUCCESS
)
1632 str
= HeapAlloc(GetProcessHeap(),0,size
);
1633 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1634 if (ret
==ERROR_SUCCESS
)
1636 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1637 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1638 ExpandEnvironmentStringsW(str
,path
,size
);
1640 HeapFree(GetProcessHeap(),0,str
);
1645 /* wait for the process to start and set an event or terminate */
1646 handles
[0] = service_get_event_handle( hsvc
->name
);
1647 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1648 si
.cb
= sizeof(STARTUPINFOW
);
1649 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1652 if (ppid
) *ppid
= pi
.dwProcessId
;
1654 handles
[1] = pi
.hProcess
;
1655 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1656 if(ret
!= WAIT_OBJECT_0
)
1658 SetLastError(ERROR_IO_PENDING
);
1662 CloseHandle( pi
.hThread
);
1663 CloseHandle( pi
.hProcess
);
1665 CloseHandle( handles
[0] );
1666 HeapFree(GetProcessHeap(),0,path
);
1670 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1673 SERVICE_STATUS status
;
1676 TRACE("%p\n", hService
);
1678 for (i
=0; i
<30; i
++)
1680 status
.dwCurrentState
= 0;
1681 r
= QueryServiceStatus(hService
, &status
);
1684 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1686 TRACE("Service started successfully\n");
1695 /******************************************************************************
1696 * StartServiceW [ADVAPI32.@]
1698 * See StartServiceA.
1700 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1701 LPCWSTR
*lpServiceArgVectors
)
1703 struct sc_service
*hsvc
;
1706 HANDLE handle
= INVALID_HANDLE_VALUE
;
1708 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1710 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1713 SetLastError(ERROR_INVALID_HANDLE
);
1717 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1721 handle
= service_open_pipe(hsvc
->name
);
1722 if (handle
==INVALID_HANDLE_VALUE
)
1724 /* start the service process */
1725 if (service_start_process(hsvc
, NULL
))
1726 handle
= service_open_pipe(hsvc
->name
);
1729 if (handle
!= INVALID_HANDLE_VALUE
)
1731 r
= service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1732 CloseHandle(handle
);
1735 UnlockServiceDatabase( hLock
);
1737 TRACE("returning %d\n", r
);
1740 service_wait_for_startup(hService
);
1745 /******************************************************************************
1746 * QueryServiceStatus [ADVAPI32.@]
1749 * hService [I] Handle to service to get information about
1750 * lpservicestatus [O] buffer to receive the status information for the service
1753 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1754 LPSERVICE_STATUS lpservicestatus
)
1756 SERVICE_STATUS_PROCESS SvcStatusData
;
1759 TRACE("%p %p\n", hService
, lpservicestatus
);
1761 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1762 sizeof(SERVICE_STATUS_PROCESS
), NULL
);
1763 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1768 /******************************************************************************
1769 * QueryServiceStatusEx [ADVAPI32.@]
1771 * Get information about a service.
1774 * hService [I] Handle to service to get information about
1775 * InfoLevel [I] Level of information to get
1776 * lpBuffer [O] Destination for requested information
1777 * cbBufSize [I] Size of lpBuffer in bytes
1778 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1784 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1785 LPBYTE lpBuffer
, DWORD cbBufSize
,
1786 LPDWORD pcbBytesNeeded
)
1788 struct sc_service
*hsvc
;
1789 DWORD size
, type
, val
;
1792 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
1794 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1796 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1798 SetLastError( ERROR_INVALID_LEVEL
);
1802 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
1803 if (pSvcStatusData
== NULL
)
1805 SetLastError( ERROR_INVALID_PARAMETER
);
1809 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1811 if( pcbBytesNeeded
!= NULL
)
1812 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1814 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1818 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1821 SetLastError( ERROR_INVALID_HANDLE
);
1825 pipe
= service_open_pipe(hsvc
->name
);
1826 if (pipe
!= INVALID_HANDLE_VALUE
)
1828 r
= service_get_status(pipe
, pSvcStatusData
);
1834 TRACE("Failed to read service status\n");
1836 /* read the service type from the registry */
1838 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1839 if (r
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
1842 pSvcStatusData
->dwServiceType
= val
;
1843 pSvcStatusData
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1844 pSvcStatusData
->dwControlsAccepted
= 0;
1845 pSvcStatusData
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1846 pSvcStatusData
->dwServiceSpecificExitCode
= 0;
1847 pSvcStatusData
->dwCheckPoint
= 0;
1848 pSvcStatusData
->dwWaitHint
= 0;
1853 /******************************************************************************
1854 * QueryServiceConfigA [ADVAPI32.@]
1856 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1857 DWORD size
, LPDWORD needed
)
1862 QUERY_SERVICE_CONFIGW
*configW
;
1864 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1866 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1868 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1871 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1872 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1873 if (!ret
) goto done
;
1875 config
->dwServiceType
= configW
->dwServiceType
;
1876 config
->dwStartType
= configW
->dwStartType
;
1877 config
->dwErrorControl
= configW
->dwErrorControl
;
1878 config
->lpBinaryPathName
= NULL
;
1879 config
->lpLoadOrderGroup
= NULL
;
1880 config
->dwTagId
= configW
->dwTagId
;
1881 config
->lpDependencies
= NULL
;
1882 config
->lpServiceStartName
= NULL
;
1883 config
->lpDisplayName
= NULL
;
1885 p
= (LPSTR
)(config
+ 1);
1886 n
= size
- sizeof(*config
);
1889 #define MAP_STR(str) \
1893 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1894 if (!sz) goto done; \
1901 MAP_STR( lpBinaryPathName
);
1902 MAP_STR( lpLoadOrderGroup
);
1903 MAP_STR( lpDependencies
);
1904 MAP_STR( lpServiceStartName
);
1905 MAP_STR( lpDisplayName
);
1908 *needed
= p
- (LPSTR
)config
;
1912 HeapFree( GetProcessHeap(), 0, buffer
);
1916 /******************************************************************************
1917 * QueryServiceConfigW [ADVAPI32.@]
1920 QueryServiceConfigW( SC_HANDLE hService
,
1921 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1922 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1924 WCHAR str_buffer
[ MAX_PATH
];
1926 DWORD type
, val
, sz
, total
, n
;
1929 struct sc_service
*hsvc
;
1931 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1932 cbBufSize
, pcbBytesNeeded
);
1934 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1937 SetLastError( ERROR_INVALID_HANDLE
);
1942 /* TODO: Check which members are mandatory and what the registry types
1943 * should be. This should of course also be tested when a service is
1947 /* calculate the size required first */
1948 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1950 sz
= sizeof(str_buffer
);
1951 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1952 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1954 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1955 if( 0 == sz
) return FALSE
;
1957 total
+= sizeof(WCHAR
) * sz
;
1961 /* FIXME: set last error */
1966 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1967 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1970 total
+= sizeof(WCHAR
);
1973 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1974 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1977 total
+= sizeof(WCHAR
);
1980 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, NULL
, &sz
);
1981 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1984 total
+= sizeof(WCHAR
);
1987 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1988 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1991 total
+= sizeof(WCHAR
);
1993 *pcbBytesNeeded
= total
;
1995 /* if there's not enough memory, return an error */
1996 if( total
> cbBufSize
)
1998 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
2002 ZeroMemory( lpServiceConfig
, total
);
2005 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
2006 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2007 lpServiceConfig
->dwServiceType
= val
;
2010 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
2011 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2012 lpServiceConfig
->dwStartType
= val
;
2015 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
2016 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2017 lpServiceConfig
->dwErrorControl
= val
;
2020 r
= RegQueryValueExW( hKey
, szTag
, 0, &type
, (LPBYTE
)&val
, &sz
);
2021 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
2022 lpServiceConfig
->dwTagId
= val
;
2024 /* now do the strings */
2025 p
= (LPBYTE
) &lpServiceConfig
[1];
2026 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
2028 sz
= sizeof(str_buffer
);
2029 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
2030 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
2032 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
2033 sz
*= sizeof(WCHAR
);
2034 if( 0 == sz
|| sz
> n
) return FALSE
;
2036 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
2042 /* FIXME: set last error */
2047 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
2048 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
2049 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2062 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
2063 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
2064 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2077 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, p
, &sz
);
2078 lpServiceConfig
->lpServiceStartName
= (LPWSTR
) p
;
2079 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2092 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, p
, &sz
);
2093 lpServiceConfig
->lpDisplayName
= (LPWSTR
) p
;
2094 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2107 ERR("Buffer overflow!\n");
2109 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
2110 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
2111 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
2112 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
2113 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
2118 /******************************************************************************
2119 * EnumServicesStatusA [ADVAPI32.@]
2122 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2123 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
2124 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2125 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2127 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2128 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2129 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2130 SetLastError (ERROR_ACCESS_DENIED
);
2134 /******************************************************************************
2135 * EnumServicesStatusW [ADVAPI32.@]
2138 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2139 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
2140 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2141 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2143 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2144 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2145 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2146 SetLastError (ERROR_ACCESS_DENIED
);
2150 /******************************************************************************
2151 * EnumServicesStatusExA [ADVAPI32.@]
2154 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2155 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2156 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
2158 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2159 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2160 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
2161 SetLastError (ERROR_ACCESS_DENIED
);
2165 /******************************************************************************
2166 * EnumServicesStatusExW [ADVAPI32.@]
2169 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2170 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2171 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
2173 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2174 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2175 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
2176 SetLastError (ERROR_ACCESS_DENIED
);
2180 /******************************************************************************
2181 * GetServiceKeyNameA [ADVAPI32.@]
2183 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2184 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2186 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2190 /******************************************************************************
2191 * GetServiceKeyNameW [ADVAPI32.@]
2193 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2194 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2196 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2200 /******************************************************************************
2201 * QueryServiceLockStatusA [ADVAPI32.@]
2203 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2204 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2205 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2207 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2212 /******************************************************************************
2213 * QueryServiceLockStatusW [ADVAPI32.@]
2215 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2216 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2217 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2219 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2224 /******************************************************************************
2225 * GetServiceDisplayNameA [ADVAPI32.@]
2227 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2228 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2230 LPWSTR lpServiceNameW
, lpDisplayNameW
= NULL
;
2231 DWORD size
, sizeW
, GLE
;
2234 TRACE("%p %s %p %p\n", hSCManager
,
2235 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2237 lpServiceNameW
= SERV_dup(lpServiceName
);
2238 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
2240 size
= sizeW
= *lpcchBuffer
;
2241 ret
= GetServiceDisplayNameW(hSCManager
, lpServiceNameW
,
2242 lpDisplayName
? lpDisplayNameW
: NULL
,
2244 /* Last error will be set by GetServiceDisplayNameW and must be preserved */
2245 GLE
= GetLastError();
2247 if (!lpDisplayName
&& *lpcchBuffer
&& !ret
&& (GLE
== ERROR_INSUFFICIENT_BUFFER
))
2249 /* Request for buffersize.
2251 * Only set the size for ERROR_INSUFFICIENT_BUFFER
2255 else if (lpDisplayName
&& *lpcchBuffer
&& !ret
)
2257 /* Request for displayname.
2259 * size only has to be set if this fails
2264 WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
2265 *lpcchBuffer
, NULL
, NULL
);
2267 *lpcchBuffer
= size
;
2269 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
2270 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
2276 /******************************************************************************
2277 * GetServiceDisplayNameW [ADVAPI32.@]
2279 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2280 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2282 struct sc_manager
*hscm
;
2286 TRACE("%p %s %p %p\n", hSCManager
,
2287 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2289 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2292 SetLastError(ERROR_INVALID_HANDLE
);
2298 SetLastError(ERROR_INVALID_ADDRESS
);
2302 size
= *lpcchBuffer
* sizeof(WCHAR
);
2303 ret
= RegGetValueW(hscm
->hkey
, lpServiceName
, szDisplayName
, RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2304 if (!ret
&& !lpDisplayName
&& size
)
2305 ret
= ERROR_MORE_DATA
;
2309 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2311 if (ret
== ERROR_MORE_DATA
)
2313 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2314 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2316 else if (ret
== ERROR_FILE_NOT_FOUND
)
2320 if (!RegOpenKeyW(hscm
->hkey
, lpServiceName
, &hkey
))
2322 INT len
= lstrlenW(lpServiceName
);
2325 if ((*lpcchBuffer
<= len
) || (!lpDisplayName
&& *lpcchBuffer
))
2326 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2327 else if (lpDisplayName
&& *lpcchBuffer
)
2329 /* No displayname, but the service exists and the buffer
2330 * is big enough. We should return the servicename.
2332 lstrcpyW(lpDisplayName
, lpServiceName
);
2341 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2348 /* Always return the correct needed size on success */
2349 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2354 /******************************************************************************
2355 * ChangeServiceConfigW [ADVAPI32.@]
2357 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2358 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2359 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2360 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2362 struct reg_value val
[10];
2363 struct sc_service
*hsvc
;
2364 DWORD r
= ERROR_SUCCESS
;
2368 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2369 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2370 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2371 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2372 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2374 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2377 SetLastError( ERROR_INVALID_HANDLE
);
2382 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2383 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2385 if( dwStartType
!= SERVICE_NO_CHANGE
)
2386 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2388 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2389 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2391 if( lpBinaryPathName
)
2392 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2394 if( lpLoadOrderGroup
)
2395 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2397 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2398 * There is no such key as what szDependencies refers to */
2399 if( lpDependencies
)
2400 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2403 FIXME("ignoring password\n");
2405 if( lpServiceStartName
)
2406 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
2408 r
= service_write_values( hsvc
->hkey
, val
, n
);
2410 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2413 /******************************************************************************
2414 * ChangeServiceConfigA [ADVAPI32.@]
2416 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2417 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2418 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2419 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2421 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2422 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2425 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2426 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2427 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2428 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2429 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2431 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2432 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2433 wDependencies
= SERV_dupmulti( lpDependencies
);
2434 wServiceStartName
= SERV_dup( lpServiceStartName
);
2435 wPassword
= SERV_dup( lpPassword
);
2436 wDisplayName
= SERV_dup( lpDisplayName
);
2438 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2439 dwStartType
, dwErrorControl
, wBinaryPathName
,
2440 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2441 wServiceStartName
, wPassword
, wDisplayName
);
2443 HeapFree( GetProcessHeap(), 0, wBinaryPathName
);
2444 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup
);
2445 HeapFree( GetProcessHeap(), 0, wDependencies
);
2446 HeapFree( GetProcessHeap(), 0, wServiceStartName
);
2447 HeapFree( GetProcessHeap(), 0, wPassword
);
2448 HeapFree( GetProcessHeap(), 0, wDisplayName
);
2453 /******************************************************************************
2454 * ChangeServiceConfig2A [ADVAPI32.@]
2456 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2461 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2463 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2465 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2466 SERVICE_DESCRIPTIONW sdw
;
2468 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2470 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2472 HeapFree( GetProcessHeap(), 0, sdw
.lpDescription
);
2474 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2476 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2477 SERVICE_FAILURE_ACTIONSW faw
;
2479 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2480 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2481 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2482 faw
.cActions
= fa
->cActions
;
2483 faw
.lpsaActions
= fa
->lpsaActions
;
2485 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2487 HeapFree( GetProcessHeap(), 0, faw
.lpRebootMsg
);
2488 HeapFree( GetProcessHeap(), 0, faw
.lpCommand
);
2491 SetLastError( ERROR_INVALID_PARAMETER
);
2496 /******************************************************************************
2497 * ChangeServiceConfig2W [ADVAPI32.@]
2499 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2503 struct sc_service
*hsvc
;
2505 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2508 SetLastError( ERROR_INVALID_HANDLE
);
2513 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2515 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2516 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2517 if (sd
->lpDescription
)
2519 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2520 if (sd
->lpDescription
[0] == 0)
2521 RegDeleteValueW(hKey
,szDescription
);
2523 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2524 (LPVOID
)sd
->lpDescription
,
2525 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2529 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2533 /******************************************************************************
2534 * QueryServiceObjectSecurity [ADVAPI32.@]
2536 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2537 SECURITY_INFORMATION dwSecurityInformation
,
2538 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2539 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2543 FIXME("%p %d %p %u %p\n", hService
, dwSecurityInformation
,
2544 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2546 InitializeSecurityDescriptor(lpSecurityDescriptor
, SECURITY_DESCRIPTOR_REVISION
);
2548 pACL
= HeapAlloc( GetProcessHeap(), 0, sizeof(ACL
) );
2549 InitializeAcl(pACL
, sizeof(ACL
), ACL_REVISION
);
2550 SetSecurityDescriptorDacl(lpSecurityDescriptor
, TRUE
, pACL
, TRUE
);
2554 /******************************************************************************
2555 * SetServiceObjectSecurity [ADVAPI32.@]
2557 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2558 SECURITY_INFORMATION dwSecurityInformation
,
2559 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2561 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2565 /******************************************************************************
2566 * SetServiceBits [ADVAPI32.@]
2568 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2569 DWORD dwServiceBits
,
2571 BOOL bUpdateImmediately
)
2573 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2574 bSetBitsOn
, bUpdateImmediately
);
2578 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR lpServiceName
,
2579 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2581 FIXME("%s %p %p\n", debugstr_a(lpServiceName
), lpHandlerProc
, lpContext
);
2585 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2586 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2588 service_data
*service
;
2589 SERVICE_STATUS_HANDLE handle
= 0;
2591 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2593 EnterCriticalSection( &service_cs
);
2594 LIST_FOR_EACH_ENTRY( service
, &service_list
, service_data
, entry
)
2596 if(!strcmpW(lpServiceName
, service
->name
))
2598 service
->handler
.handler_ex
= lpHandlerProc
;
2599 service
->context
= lpContext
;
2600 service
->extended
= TRUE
;
2601 handle
= (SERVICE_STATUS_HANDLE
)service
;
2605 LeaveCriticalSection( &service_cs
);