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"
41 WINE_DEFAULT_DEBUG_CHANNEL(service
);
43 static const WCHAR szLocalSystem
[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
44 static const WCHAR szServiceManagerKey
[] = { 'S','y','s','t','e','m','\\',
45 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
46 'S','e','r','v','i','c','e','s',0 };
47 static const WCHAR szSCMLock
[] = {'A','D','V','A','P','I','_','S','C','M',
50 void __RPC_FAR
* __RPC_USER
MIDL_user_allocate(size_t len
)
52 return HeapAlloc(GetProcessHeap(), 0, len
);
55 void __RPC_USER
MIDL_user_free(void __RPC_FAR
* ptr
)
57 HeapFree(GetProcessHeap(), 0, ptr
);
60 static const GENERIC_MAPPING scm_generic
= {
61 (STANDARD_RIGHTS_READ
| SC_MANAGER_ENUMERATE_SERVICE
| SC_MANAGER_QUERY_LOCK_STATUS
),
62 (STANDARD_RIGHTS_WRITE
| SC_MANAGER_CREATE_SERVICE
| SC_MANAGER_MODIFY_BOOT_CONFIG
),
63 (STANDARD_RIGHTS_EXECUTE
| SC_MANAGER_CONNECT
| SC_MANAGER_LOCK
),
67 static const GENERIC_MAPPING svc_generic
= {
68 (STANDARD_RIGHTS_READ
| SERVICE_QUERY_CONFIG
| SERVICE_QUERY_STATUS
| SERVICE_INTERROGATE
| SERVICE_ENUMERATE_DEPENDENTS
),
69 (STANDARD_RIGHTS_WRITE
| SERVICE_CHANGE_CONFIG
),
70 (STANDARD_RIGHTS_EXECUTE
| SERVICE_START
| SERVICE_STOP
| SERVICE_PAUSE_CONTINUE
| SERVICE_USER_DEFINED_CONTROL
),
74 typedef struct service_start_info_t
81 #define WINESERV_STARTINFO 1
82 #define WINESERV_GETSTATUS 2
83 #define WINESERV_SENDCONTROL 3
85 typedef struct service_data_t
87 LPHANDLER_FUNCTION_EX handler
;
89 SERVICE_STATUS_PROCESS status
;
93 LPSERVICE_MAIN_FUNCTIONA a
;
94 LPSERVICE_MAIN_FUNCTIONW w
;
100 static CRITICAL_SECTION service_cs
;
101 static CRITICAL_SECTION_DEBUG service_cs_debug
=
104 { &service_cs_debug
.ProcessLocksList
,
105 &service_cs_debug
.ProcessLocksList
},
106 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
108 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
110 static service_data
**services
;
111 static unsigned int nb_services
;
112 static HANDLE service_event
;
114 extern HANDLE
__wine_make_process_system(void);
116 /******************************************************************************
120 #define MAX_SERVICE_NAME 256
122 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
125 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
129 SC_HANDLE_TYPE htype
;
131 sc_handle_destructor destroy
;
132 SC_RPC_HANDLE server_handle
; /* server-side handle */
135 struct sc_manager
/* service control manager handle */
137 struct sc_handle hdr
;
138 HKEY hkey
; /* handle to services database in the registry */
142 struct sc_service
/* service handle */
144 struct sc_handle hdr
;
145 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
147 struct sc_manager
*scm
; /* pointer to SCM handle */
151 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
152 sc_handle_destructor destroy
)
154 struct sc_handle
*hdr
;
156 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
161 hdr
->destroy
= destroy
;
163 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
167 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
169 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
173 if (hdr
->htype
!= htype
)
178 static void sc_handle_free(struct sc_handle
* hdr
)
182 if (--hdr
->ref_count
)
185 HeapFree(GetProcessHeap(), 0, hdr
);
188 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
190 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
192 TRACE("destroying SC Manager %p\n", mgr
);
194 RegCloseKey(mgr
->hkey
);
197 static void sc_handle_destroy_service(struct sc_handle
*handle
)
199 struct sc_service
*svc
= (struct sc_service
*) handle
;
201 TRACE("destroying service %p\n", svc
);
203 RegCloseKey(svc
->hkey
);
205 sc_handle_free(&svc
->scm
->hdr
);
209 /******************************************************************************
210 * String management functions (same behaviour as strdup)
211 * NOTE: the caller of those functions is responsible for calling HeapFree
212 * in order to release the memory allocated by those functions.
214 static inline LPWSTR
SERV_dup( LPCSTR str
)
221 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
222 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
223 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
227 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
235 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
236 n
+= (strlen( &str
[n
] ) + 1);
241 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
242 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
246 static inline DWORD
multisz_cb(LPCWSTR wmultisz
)
248 const WCHAR
*wptr
= wmultisz
;
250 if (wmultisz
== NULL
)
254 wptr
+= lstrlenW(wptr
)+1;
255 return (wptr
- wmultisz
+ 1)*sizeof(WCHAR
);
258 /******************************************************************************
259 * RPC connection with servies.exe
262 static BOOL
check_services_exe(void)
264 static const WCHAR svcctl_started_event
[] = SVCCTL_STARTED_EVENT
;
265 HANDLE hEvent
= OpenEventW(SYNCHRONIZE
, FALSE
, svcctl_started_event
);
266 if (hEvent
== NULL
) /* need to start services.exe */
268 static const WCHAR services
[] = {'\\','s','e','r','v','i','c','e','s','.','e','x','e',0};
269 PROCESS_INFORMATION out
;
271 HANDLE wait_handles
[2];
272 WCHAR path
[MAX_PATH
];
274 if (!GetSystemDirectoryW(path
, MAX_PATH
- strlenW(services
)))
276 strcatW(path
, services
);
277 ZeroMemory(&si
, sizeof(si
));
279 if (!CreateProcessW(path
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &out
))
281 ERR("Couldn't start services.exe: error %u\n", GetLastError());
284 CloseHandle(out
.hThread
);
286 hEvent
= CreateEventW(NULL
, TRUE
, FALSE
, svcctl_started_event
);
287 wait_handles
[0] = hEvent
;
288 wait_handles
[1] = out
.hProcess
;
290 /* wait for the event to become available or the process to exit */
291 if ((WaitForMultipleObjects(2, wait_handles
, FALSE
, INFINITE
)) == WAIT_OBJECT_0
+ 1)
294 GetExitCodeProcess(out
.hProcess
, &exit_code
);
295 ERR("Unexpected termination of services.exe - exit code %d\n", exit_code
);
296 CloseHandle(out
.hProcess
);
301 TRACE("services.exe started successfully\n");
302 CloseHandle(out
.hProcess
);
307 TRACE("Waiting for services.exe to be available\n");
308 WaitForSingleObject(hEvent
, INFINITE
);
309 TRACE("Services.exe are available\n");
315 handle_t __RPC_USER
MACHINE_HANDLEW_bind(MACHINE_HANDLEW MachineName
)
317 WCHAR transport
[] = SVCCTL_TRANSPORT
;
318 WCHAR endpoint
[] = SVCCTL_ENDPOINT
;
319 LPWSTR server_copy
= NULL
;
320 RPC_WSTR binding_str
;
324 /* unlike Windows we start services.exe on demand. We start it always as
325 * checking if this is our address can be tricky */
326 if (!check_services_exe())
329 status
= RpcStringBindingComposeW(NULL
, transport
, (RPC_WSTR
)MachineName
, endpoint
, NULL
, &binding_str
);
330 HeapFree(GetProcessHeap(), 0, server_copy
);
331 if (status
!= RPC_S_OK
)
333 ERR("RpcStringBindingComposeW failed (%d)\n", (DWORD
)status
);
337 status
= RpcBindingFromStringBindingW(binding_str
, &rpc_handle
);
338 RpcStringFreeW(&binding_str
);
340 if (status
!= RPC_S_OK
)
342 ERR("Couldn't connect to services.exe: error code %u\n", (DWORD
)status
);
349 void __RPC_USER
MACHINE_HANDLEW_unbind(MACHINE_HANDLEW MachineName
, handle_t h
)
354 /******************************************************************************
355 * registry access functions and data
357 static const WCHAR szDisplayName
[] = {
358 'D','i','s','p','l','a','y','N','a','m','e', 0 };
359 static const WCHAR szType
[] = {'T','y','p','e',0};
360 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
361 static const WCHAR szError
[] = {
362 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
363 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
364 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
365 static const WCHAR szDependencies
[] = {
366 'D','e','p','e','n','d','e','n','c','i','e','s',0};
367 static const WCHAR szDependOnService
[] = {
368 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
369 static const WCHAR szObjectName
[] = {
370 'O','b','j','e','c','t','N','a','m','e',0};
371 static const WCHAR szTag
[] = {
381 static inline void service_set_value( struct reg_value
*val
,
382 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
390 static inline void service_set_dword( struct reg_value
*val
,
391 LPCWSTR name
, const DWORD
*data
)
393 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
396 static inline void service_set_string( struct reg_value
*val
,
397 LPCWSTR name
, LPCWSTR string
)
399 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
400 service_set_value( val
, REG_SZ
, name
, string
, len
);
403 static inline void service_set_multi_string( struct reg_value
*val
,
404 LPCWSTR name
, LPCWSTR string
)
408 /* determine the length of a double null terminated multi string */
410 len
+= (lstrlenW( &string
[ len
] )+1);
411 } while ( string
[ len
++ ] );
413 len
*= sizeof (WCHAR
);
414 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
417 static inline LONG
service_write_values( HKEY hKey
,
418 const struct reg_value
*val
, int n
)
420 LONG r
= ERROR_SUCCESS
;
425 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
426 (const BYTE
*)val
[i
].data
, val
[i
].size
);
427 if( r
!= ERROR_SUCCESS
)
433 /******************************************************************************
434 * Service IPC functions
436 static LPWSTR
service_get_pipe_name(LPCWSTR service
)
438 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
439 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
443 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
444 name
= HeapAlloc(GetProcessHeap(), 0, len
);
445 strcpyW(name
, prefix
);
446 strcatW(name
, service
);
450 static HANDLE
service_open_pipe(LPCWSTR service
)
452 LPWSTR szPipe
= service_get_pipe_name( service
);
453 HANDLE handle
= INVALID_HANDLE_VALUE
;
456 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
457 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
458 if (handle
!= INVALID_HANDLE_VALUE
)
460 if (GetLastError() != ERROR_PIPE_BUSY
)
462 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
463 HeapFree(GetProcessHeap(), 0, szPipe
);
468 /******************************************************************************
469 * service_get_event_handle
471 static HANDLE
service_get_event_handle(LPCWSTR service
)
473 static const WCHAR prefix
[] = {
474 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
479 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
480 name
= HeapAlloc(GetProcessHeap(), 0, len
);
481 strcpyW(name
, prefix
);
482 strcatW(name
, service
);
483 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
484 HeapFree(GetProcessHeap(), 0, name
);
488 /******************************************************************************
491 * Call into the main service routine provided by StartServiceCtrlDispatcher.
493 static DWORD WINAPI
service_thread(LPVOID arg
)
495 service_data
*info
= arg
;
496 LPWSTR str
= info
->args
;
497 DWORD argc
= 0, len
= 0;
503 len
+= strlenW(&str
[len
]) + 1;
510 info
->proc
.w(0, NULL
);
512 info
->proc
.a(0, NULL
);
520 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
521 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
525 info
->proc
.w(argc
, argv
);
526 HeapFree(GetProcessHeap(), 0, argv
);
530 LPSTR strA
, *argv
, p
;
533 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
534 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
535 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
537 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
538 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
542 info
->proc
.a(argc
, argv
);
543 HeapFree(GetProcessHeap(), 0, argv
);
544 HeapFree(GetProcessHeap(), 0, strA
);
549 /******************************************************************************
550 * service_handle_start
552 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
554 DWORD read
= 0, result
= 0;
558 TRACE("%p %p %d\n", pipe
, service
, count
);
560 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
561 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
562 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
564 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
565 r
, count
, read
, debugstr_wn(args
, count
));
571 WARN("service is not stopped\n");
572 result
= ERROR_SERVICE_ALREADY_RUNNING
;
576 HeapFree(GetProcessHeap(), 0, service
->args
);
577 service
->args
= args
;
579 service
->status
.dwCurrentState
= SERVICE_START_PENDING
;
580 service
->thread
= CreateThread( NULL
, 0, service_thread
,
582 SetEvent( service_event
); /* notify the main loop */
585 HeapFree(GetProcessHeap(), 0, args
);
586 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
591 /******************************************************************************
592 * service_send_start_message
594 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
596 DWORD i
, len
, count
, result
;
597 service_start_info
*ssi
;
601 TRACE("%p %p %d\n", pipe
, argv
, argc
);
603 /* calculate how much space do we need to send the startup info */
605 for (i
=0; i
<argc
; i
++)
606 len
+= strlenW(argv
[i
])+1;
608 ssi
= HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info
, str
[len
]));
609 ssi
->cmd
= WINESERV_STARTINFO
;
612 /* copy service args into a single buffer*/
614 for (i
=0; i
<argc
; i
++)
621 r
= WriteFile(pipe
, ssi
, FIELD_OFFSET(service_start_info
, str
[len
]), &count
, NULL
);
624 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
627 SetLastError(result
);
632 HeapFree(GetProcessHeap(),0,ssi
);
637 /******************************************************************************
638 * service_handle_get_status
640 static BOOL
service_handle_get_status(HANDLE pipe
, const service_data
*service
)
644 return WriteFile(pipe
, &service
->status
,
645 sizeof service
->status
, &count
, NULL
);
648 /******************************************************************************
649 * service_send_control
651 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
653 DWORD cmd
[2], count
= 0;
656 cmd
[0] = WINESERV_SENDCONTROL
;
658 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
659 if (!r
|| count
!= sizeof cmd
)
661 ERR("service protocol error - failed to write pipe!\n");
664 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
665 if (!r
|| count
!= sizeof *result
)
666 ERR("service protocol error - failed to read pipe "
667 "r = %d count = %d!\n", r
, count
);
671 /******************************************************************************
672 * service_accepts_control
674 static BOOL
service_accepts_control(const service_data
*service
, DWORD dwControl
)
676 DWORD a
= service
->status
.dwControlsAccepted
;
680 case SERVICE_CONTROL_INTERROGATE
:
682 case SERVICE_CONTROL_STOP
:
683 if (a
&SERVICE_ACCEPT_STOP
)
686 case SERVICE_CONTROL_SHUTDOWN
:
687 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
690 case SERVICE_CONTROL_PAUSE
:
691 case SERVICE_CONTROL_CONTINUE
:
692 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
695 case SERVICE_CONTROL_PARAMCHANGE
:
696 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
699 case SERVICE_CONTROL_NETBINDADD
:
700 case SERVICE_CONTROL_NETBINDREMOVE
:
701 case SERVICE_CONTROL_NETBINDENABLE
:
702 case SERVICE_CONTROL_NETBINDDISABLE
:
703 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
705 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
706 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
709 case SERVICE_CONTROL_POWEREVENT
:
710 if (a
&SERVICE_ACCEPT_POWEREVENT
)
713 case SERVICE_CONTROL_SESSIONCHANGE
:
714 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
721 /******************************************************************************
722 * service_handle_control
724 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
727 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
729 TRACE("received control %d\n", dwControl
);
731 if (service_accepts_control(service
, dwControl
))
733 if (service
->handler
)
734 ret
= service
->handler(dwControl
, 0, NULL
, service
->context
);
736 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
739 /******************************************************************************
740 * service_control_dispatcher
742 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
744 service_data
*service
= arg
;
748 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
750 /* create a pipe to talk to the rest of the world with */
751 name
= service_get_pipe_name(service
->name
);
752 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
753 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
755 if (pipe
==INVALID_HANDLE_VALUE
)
756 ERR("failed to create pipe for %s, error = %d\n",
757 debugstr_w(service
->name
), GetLastError());
759 HeapFree(GetProcessHeap(), 0, name
);
761 /* let the process who started us know we've tried to create a pipe */
762 event
= service_get_event_handle(service
->name
);
766 if (pipe
==INVALID_HANDLE_VALUE
) return 0;
768 /* dispatcher loop */
772 DWORD count
, req
[2] = {0,0};
774 r
= ConnectNamedPipe(pipe
, NULL
);
775 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
777 ERR("pipe connect failed\n");
781 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
782 if (!r
|| count
!=sizeof req
)
784 ERR("pipe read failed\n");
788 /* handle the request */
791 case WINESERV_STARTINFO
:
792 service_handle_start(pipe
, service
, req
[1]);
794 case WINESERV_GETSTATUS
:
795 service_handle_get_status(pipe
, service
);
797 case WINESERV_SENDCONTROL
:
798 service_handle_control(pipe
, service
, req
[1]);
801 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
804 FlushFileBuffers(pipe
);
805 DisconnectNamedPipe(pipe
);
812 /******************************************************************************
813 * service_run_threads
815 static BOOL
service_run_threads(void)
818 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
819 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
821 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
823 wait_handles
[0] = __wine_make_process_system();
824 wait_handles
[1] = service_event
;
826 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
827 nb_services
, GetCurrentProcessId());
829 EnterCriticalSection( &service_cs
);
830 for (i
= 0; i
< nb_services
; i
++)
832 services
[i
]->status
.dwProcessId
= GetCurrentProcessId();
833 CloseHandle( CreateThread( NULL
, 0, service_control_dispatcher
, services
[i
], 0, NULL
));
835 LeaveCriticalSection( &service_cs
);
837 /* wait for all the threads to pack up and exit */
840 EnterCriticalSection( &service_cs
);
841 for (i
= 0, n
= 2; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
843 if (!services
[i
]->thread
) continue;
844 wait_services
[n
] = i
;
845 wait_handles
[n
++] = services
[i
]->thread
;
847 LeaveCriticalSection( &service_cs
);
849 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
850 if (!ret
) /* system process event */
852 TRACE( "last user process exited, shutting down\n" );
853 /* FIXME: we should maybe send a shutdown control to running services */
858 continue; /* rebuild the list */
862 services
[wait_services
[ret
]]->thread
= 0;
863 CloseHandle( wait_handles
[ret
] );
864 if (n
== 3) return TRUE
; /* it was the last running thread */
870 /******************************************************************************
871 * StartServiceCtrlDispatcherA [ADVAPI32.@]
873 * See StartServiceCtrlDispatcherW.
875 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
881 TRACE("%p\n", servent
);
885 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
888 while (servent
[nb_services
].lpServiceName
) nb_services
++;
889 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
891 for (i
= 0; i
< nb_services
; i
++)
893 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
894 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
895 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
896 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
897 info
->proc
.a
= servent
[i
].lpServiceProc
;
898 info
->unicode
= FALSE
;
902 service_run_threads();
907 /******************************************************************************
908 * StartServiceCtrlDispatcherW [ADVAPI32.@]
910 * Connects a process containing one or more services to the service control
914 * servent [I] A list of the service names and service procedures
920 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
926 TRACE("%p\n", servent
);
930 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
933 while (servent
[nb_services
].lpServiceName
) nb_services
++;
934 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
936 for (i
= 0; i
< nb_services
; i
++)
938 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
939 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
940 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
941 strcpyW(info
->name
, servent
[i
].lpServiceName
);
942 info
->proc
.w
= servent
[i
].lpServiceProc
;
943 info
->unicode
= TRUE
;
947 service_run_threads();
952 /******************************************************************************
953 * LockServiceDatabase [ADVAPI32.@]
955 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
959 TRACE("%p\n",hSCManager
);
961 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
962 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
966 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
969 TRACE("returning %p\n", ret
);
974 /******************************************************************************
975 * UnlockServiceDatabase [ADVAPI32.@]
977 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
979 TRACE("%p\n",ScLock
);
981 return CloseHandle( ScLock
);
984 /******************************************************************************
985 * SetServiceStatus [ADVAPI32.@]
992 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
994 struct sc_service
*hsvc
;
997 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
998 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
999 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
1000 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
1001 lpStatus
->dwWaitHint
);
1003 hsvc
= sc_handle_get_handle_data((SC_HANDLE
)hService
, SC_HTYPE_SERVICE
);
1006 SetLastError( ERROR_INVALID_HANDLE
);
1010 err
= svcctl_SetServiceStatus( hsvc
->hdr
.server_handle
, lpStatus
);
1011 if (err
!= ERROR_SUCCESS
)
1017 if (lpStatus
->dwCurrentState
== SERVICE_STOPPED
)
1018 CloseServiceHandle((SC_HANDLE
)hService
);
1024 /******************************************************************************
1025 * OpenSCManagerA [ADVAPI32.@]
1027 * Establish a connection to the service control manager and open its database.
1030 * lpMachineName [I] Pointer to machine name string
1031 * lpDatabaseName [I] Pointer to database name string
1032 * dwDesiredAccess [I] Type of access
1035 * Success: A Handle to the service control manager database
1038 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
1039 DWORD dwDesiredAccess
)
1041 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
1044 lpMachineNameW
= SERV_dup(lpMachineName
);
1045 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
1046 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
1047 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW
);
1048 HeapFree(GetProcessHeap(), 0, lpMachineNameW
);
1052 /******************************************************************************
1053 * OpenSCManagerW [ADVAPI32.@]
1055 * See OpenSCManagerA.
1057 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
1058 DWORD dwDesiredAccess
)
1060 struct sc_manager
*manager
;
1063 DWORD new_mask
= dwDesiredAccess
;
1065 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
1066 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
1068 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
1069 sc_handle_destroy_manager
);
1073 r
= svcctl_OpenSCManagerW(lpMachineName
, lpDatabaseName
, dwDesiredAccess
, &manager
->hdr
.server_handle
);
1074 if (r
!=ERROR_SUCCESS
)
1077 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
1078 if (r
!=ERROR_SUCCESS
)
1081 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
1082 RegCloseKey( hReg
);
1083 if (r
!=ERROR_SUCCESS
)
1086 RtlMapGenericMask(&new_mask
, &scm_generic
);
1087 manager
->dwAccess
= new_mask
;
1088 TRACE("returning %p (access : 0x%08x)\n", manager
, manager
->dwAccess
);
1090 return (SC_HANDLE
) &manager
->hdr
;
1093 sc_handle_free( &manager
->hdr
);
1098 /******************************************************************************
1099 * ControlService [ADVAPI32.@]
1101 * Send a control code to a service.
1104 * hService [I] Handle of the service control manager database
1105 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1106 * lpServiceStatus [O] Destination for the status of the service, if available
1113 * Unlike M$' implementation, control requests are not serialized and may be
1114 * processed asynchronously.
1116 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1117 LPSERVICE_STATUS lpServiceStatus
)
1119 struct sc_service
*hsvc
;
1123 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1125 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1128 SetLastError( ERROR_INVALID_HANDLE
);
1132 if (lpServiceStatus
)
1134 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1137 ERR("failed to query service status\n");
1138 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1142 switch (lpServiceStatus
->dwCurrentState
)
1144 case SERVICE_STOPPED
:
1145 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1147 case SERVICE_START_PENDING
:
1148 if (dwControl
==SERVICE_CONTROL_STOP
)
1151 case SERVICE_STOP_PENDING
:
1152 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1157 handle
= service_open_pipe(hsvc
->name
);
1158 if (handle
!=INVALID_HANDLE_VALUE
)
1160 DWORD result
= ERROR_SUCCESS
;
1161 ret
= service_send_control(handle
, dwControl
, &result
);
1162 CloseHandle(handle
);
1163 if (result
!=ERROR_SUCCESS
)
1165 SetLastError(result
);
1173 /******************************************************************************
1174 * CloseServiceHandle [ADVAPI32.@]
1176 * Close a handle to a service or the service control manager database.
1179 * hSCObject [I] Handle to service or service control manager database
1186 CloseServiceHandle( SC_HANDLE hSCObject
)
1188 struct sc_handle
*obj
;
1191 TRACE("%p\n", hSCObject
);
1192 if (hSCObject
== NULL
)
1194 SetLastError(ERROR_INVALID_HANDLE
);
1198 obj
= (struct sc_handle
*)hSCObject
;
1199 err
= svcctl_CloseServiceHandle(&obj
->server_handle
);
1200 sc_handle_free( obj
);
1202 if (err
!= ERROR_SUCCESS
)
1211 /******************************************************************************
1212 * OpenServiceA [ADVAPI32.@]
1214 * Open a handle to a service.
1217 * hSCManager [I] Handle of the service control manager database
1218 * lpServiceName [I] Name of the service to open
1219 * dwDesiredAccess [I] Access required to the service
1222 * Success: Handle to the service
1225 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1226 DWORD dwDesiredAccess
)
1228 LPWSTR lpServiceNameW
;
1231 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1233 lpServiceNameW
= SERV_dup(lpServiceName
);
1234 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1235 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1240 /******************************************************************************
1241 * OpenServiceW [ADVAPI32.@]
1245 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1246 DWORD dwDesiredAccess
)
1248 struct sc_manager
*hscm
;
1249 struct sc_service
*hsvc
;
1252 DWORD new_mask
= dwDesiredAccess
;
1254 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1256 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1259 SetLastError( ERROR_INVALID_HANDLE
);
1265 SetLastError(ERROR_INVALID_ADDRESS
);
1269 len
= strlenW(lpServiceName
)+1;
1270 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1271 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1272 sc_handle_destroy_service
);
1275 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1278 strcpyW( hsvc
->name
, lpServiceName
);
1280 /* add reference to SCM handle */
1281 hscm
->hdr
.ref_count
++;
1284 err
= svcctl_OpenServiceW(hscm
->hdr
.server_handle
, lpServiceName
, dwDesiredAccess
, &hsvc
->hdr
.server_handle
);
1286 if (err
!= ERROR_SUCCESS
)
1288 sc_handle_free(&hsvc
->hdr
);
1293 /* for parts of advapi32 not using services.exe yet */
1294 RtlMapGenericMask(&new_mask
, &svc_generic
);
1295 hsvc
->dwAccess
= new_mask
;
1297 err
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hsvc
->hkey
);
1298 if (err
!= ERROR_SUCCESS
)
1299 ERR("Shouldn't hapen - service key for service validated by services.exe doesn't exist\n");
1301 TRACE("returning %p\n",hsvc
);
1303 return (SC_HANDLE
) &hsvc
->hdr
;
1306 /******************************************************************************
1307 * CreateServiceW [ADVAPI32.@]
1310 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1311 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1312 DWORD dwServiceType
, DWORD dwStartType
,
1313 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1314 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1315 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1316 LPCWSTR lpPassword
)
1318 struct sc_manager
*hscm
;
1319 struct sc_service
*hsvc
= NULL
;
1320 DWORD new_mask
= dwDesiredAccess
;
1324 TRACE("%p %s %s\n", hSCManager
,
1325 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1327 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1330 SetLastError( ERROR_INVALID_HANDLE
);
1334 if (!lpServiceName
|| !lpBinaryPathName
)
1336 SetLastError(ERROR_INVALID_ADDRESS
);
1341 passwdlen
= (strlenW(lpPassword
) + 1) * sizeof(WCHAR
);
1345 len
= strlenW(lpServiceName
)+1;
1346 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1347 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1350 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
1353 lstrcpyW( hsvc
->name
, lpServiceName
);
1356 hscm
->hdr
.ref_count
++;
1358 err
= svcctl_CreateServiceW(hscm
->hdr
.server_handle
, lpServiceName
,
1359 lpDisplayName
, dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1360 lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
, (LPBYTE
)lpDependencies
,
1361 multisz_cb(lpDependencies
), lpServiceStartName
, (LPBYTE
)lpPassword
, passwdlen
,
1362 &hsvc
->hdr
.server_handle
);
1364 if (err
!= ERROR_SUCCESS
)
1367 sc_handle_free(&hsvc
->hdr
);
1371 /* for parts of advapi32 not using services.exe yet */
1372 err
= RegOpenKeyW(hscm
->hkey
, lpServiceName
, &hsvc
->hkey
);
1373 if (err
!= ERROR_SUCCESS
)
1374 WINE_ERR("Couldn't open key that should have been created by services.exe\n");
1376 RtlMapGenericMask(&new_mask
, &svc_generic
);
1377 hsvc
->dwAccess
= new_mask
;
1379 return (SC_HANDLE
) &hsvc
->hdr
;
1383 /******************************************************************************
1384 * CreateServiceA [ADVAPI32.@]
1387 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1388 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1389 DWORD dwServiceType
, DWORD dwStartType
,
1390 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1391 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1392 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1395 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1396 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1399 TRACE("%p %s %s\n", hSCManager
,
1400 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1402 lpServiceNameW
= SERV_dup( lpServiceName
);
1403 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1404 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1405 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1406 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1407 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1408 lpPasswordW
= SERV_dup( lpPassword
);
1410 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1411 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1412 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1413 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1415 HeapFree( GetProcessHeap(), 0, lpServiceNameW
);
1416 HeapFree( GetProcessHeap(), 0, lpDisplayNameW
);
1417 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW
);
1418 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW
);
1419 HeapFree( GetProcessHeap(), 0, lpDependenciesW
);
1420 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW
);
1421 HeapFree( GetProcessHeap(), 0, lpPasswordW
);
1427 /******************************************************************************
1428 * DeleteService [ADVAPI32.@]
1430 * Delete a service from the service control manager database.
1433 * hService [I] Handle of the service to delete
1439 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1441 struct sc_service
*hsvc
;
1444 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1447 SetLastError( ERROR_INVALID_HANDLE
);
1451 err
= svcctl_DeleteService(hsvc
->hdr
.server_handle
);
1458 /* Close the key to the service */
1459 RegCloseKey(hsvc
->hkey
);
1465 /******************************************************************************
1466 * StartServiceA [ADVAPI32.@]
1471 * hService [I] Handle of service
1472 * dwNumServiceArgs [I] Number of arguments
1473 * lpServiceArgVectors [I] Address of array of argument strings
1476 * - NT implements this function using an obscure RPC call.
1477 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1478 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1479 * - This will only work for shared address space. How should the service
1480 * args be transferred when address spaces are separated?
1481 * - Can only start one service at a time.
1482 * - Has no concept of privilege.
1488 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1489 LPCSTR
*lpServiceArgVectors
)
1491 LPWSTR
*lpwstr
=NULL
;
1495 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1497 if (dwNumServiceArgs
)
1498 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1499 dwNumServiceArgs
*sizeof(LPWSTR
) );
1501 for(i
=0; i
<dwNumServiceArgs
; i
++)
1502 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1504 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1506 if (dwNumServiceArgs
)
1508 for(i
=0; i
<dwNumServiceArgs
; i
++)
1509 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
1510 HeapFree(GetProcessHeap(), 0, lpwstr
);
1516 /******************************************************************************
1517 * service_start_process [INTERNAL]
1519 static DWORD
service_start_process(struct sc_service
*hsvc
, LPDWORD ppid
)
1521 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1522 PROCESS_INFORMATION pi
;
1524 LPWSTR path
= NULL
, str
;
1525 DWORD type
, size
, ret
, svc_type
;
1529 size
= sizeof(svc_type
);
1530 if (RegQueryValueExW(hsvc
->hkey
, szType
, NULL
, &type
, (LPBYTE
)&svc_type
, &size
) || type
!= REG_DWORD
)
1533 if (svc_type
== SERVICE_KERNEL_DRIVER
)
1535 static const WCHAR winedeviceW
[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1536 DWORD len
= GetSystemDirectoryW( NULL
, 0 ) + sizeof(winedeviceW
)/sizeof(WCHAR
) + strlenW(hsvc
->name
);
1538 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1539 GetSystemDirectoryW( path
, len
);
1540 lstrcatW( path
, winedeviceW
);
1541 lstrcatW( path
, hsvc
->name
);
1545 /* read the executable path from the registry */
1547 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1548 if (ret
!=ERROR_SUCCESS
)
1550 str
= HeapAlloc(GetProcessHeap(),0,size
);
1551 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1552 if (ret
==ERROR_SUCCESS
)
1554 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1555 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1556 ExpandEnvironmentStringsW(str
,path
,size
);
1558 HeapFree(GetProcessHeap(),0,str
);
1563 /* wait for the process to start and set an event or terminate */
1564 handles
[0] = service_get_event_handle( hsvc
->name
);
1565 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1566 si
.cb
= sizeof(STARTUPINFOW
);
1567 if (!(svc_type
& SERVICE_INTERACTIVE_PROCESS
))
1569 static WCHAR desktopW
[] = {'_','_','w','i','n','e','s','e','r','v','i','c','e','_','w','i','n','s','t','a','t','i','o','n','\\','D','e','f','a','u','l','t',0};
1570 si
.lpDesktop
= desktopW
;
1573 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1576 if (ppid
) *ppid
= pi
.dwProcessId
;
1578 handles
[1] = pi
.hProcess
;
1579 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1580 if(ret
!= WAIT_OBJECT_0
)
1582 SetLastError(ERROR_IO_PENDING
);
1586 CloseHandle( pi
.hThread
);
1587 CloseHandle( pi
.hProcess
);
1589 CloseHandle( handles
[0] );
1590 HeapFree(GetProcessHeap(),0,path
);
1594 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1597 SERVICE_STATUS status
;
1600 TRACE("%p\n", hService
);
1602 for (i
=0; i
<20; i
++)
1604 status
.dwCurrentState
= 0;
1605 r
= QueryServiceStatus(hService
, &status
);
1608 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1610 TRACE("Service started successfully\n");
1614 if (status
.dwCurrentState
!= SERVICE_START_PENDING
) break;
1620 /******************************************************************************
1621 * StartServiceW [ADVAPI32.@]
1623 * See StartServiceA.
1625 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1626 LPCWSTR
*lpServiceArgVectors
)
1628 struct sc_service
*hsvc
;
1631 HANDLE handle
= INVALID_HANDLE_VALUE
;
1633 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1635 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1638 SetLastError(ERROR_INVALID_HANDLE
);
1642 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1646 handle
= service_open_pipe(hsvc
->name
);
1647 if (handle
==INVALID_HANDLE_VALUE
)
1649 /* start the service process */
1650 if (service_start_process(hsvc
, NULL
))
1651 handle
= service_open_pipe(hsvc
->name
);
1654 if (handle
!= INVALID_HANDLE_VALUE
)
1656 r
= service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1657 CloseHandle(handle
);
1660 UnlockServiceDatabase( hLock
);
1662 TRACE("returning %d\n", r
);
1665 service_wait_for_startup(hService
);
1670 /******************************************************************************
1671 * QueryServiceStatus [ADVAPI32.@]
1674 * hService [I] Handle to service to get information about
1675 * lpservicestatus [O] buffer to receive the status information for the service
1678 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1679 LPSERVICE_STATUS lpservicestatus
)
1681 SERVICE_STATUS_PROCESS SvcStatusData
;
1685 TRACE("%p %p\n", hService
, lpservicestatus
);
1687 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1688 sizeof(SERVICE_STATUS_PROCESS
), &dummy
);
1689 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1694 /******************************************************************************
1695 * QueryServiceStatusEx [ADVAPI32.@]
1697 * Get information about a service.
1700 * hService [I] Handle to service to get information about
1701 * InfoLevel [I] Level of information to get
1702 * lpBuffer [O] Destination for requested information
1703 * cbBufSize [I] Size of lpBuffer in bytes
1704 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1710 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1711 LPBYTE lpBuffer
, DWORD cbBufSize
,
1712 LPDWORD pcbBytesNeeded
)
1714 struct sc_service
*hsvc
;
1717 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1719 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1722 SetLastError( ERROR_INVALID_HANDLE
);
1726 err
= svcctl_QueryServiceStatusEx(hsvc
->hdr
.server_handle
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1727 if (err
!= ERROR_SUCCESS
)
1736 /******************************************************************************
1737 * QueryServiceConfigA [ADVAPI32.@]
1739 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1740 DWORD size
, LPDWORD needed
)
1745 QUERY_SERVICE_CONFIGW
*configW
;
1747 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1749 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1751 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1754 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1755 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1756 if (!ret
) goto done
;
1758 config
->dwServiceType
= configW
->dwServiceType
;
1759 config
->dwStartType
= configW
->dwStartType
;
1760 config
->dwErrorControl
= configW
->dwErrorControl
;
1761 config
->lpBinaryPathName
= NULL
;
1762 config
->lpLoadOrderGroup
= NULL
;
1763 config
->dwTagId
= configW
->dwTagId
;
1764 config
->lpDependencies
= NULL
;
1765 config
->lpServiceStartName
= NULL
;
1766 config
->lpDisplayName
= NULL
;
1768 p
= (LPSTR
)(config
+ 1);
1769 n
= size
- sizeof(*config
);
1772 #define MAP_STR(str) \
1776 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1777 if (!sz) goto done; \
1784 MAP_STR( lpBinaryPathName
);
1785 MAP_STR( lpLoadOrderGroup
);
1786 MAP_STR( lpDependencies
);
1787 MAP_STR( lpServiceStartName
);
1788 MAP_STR( lpDisplayName
);
1791 *needed
= p
- (LPSTR
)config
;
1795 HeapFree( GetProcessHeap(), 0, buffer
);
1799 static DWORD
move_string_to_buffer(BYTE
**buf
, LPWSTR
*string_ptr
)
1802 WCHAR empty_str
[] = {0};
1805 *string_ptr
= empty_str
;
1807 cb
= (strlenW(*string_ptr
) + 1)*sizeof(WCHAR
);
1809 memcpy(*buf
, *string_ptr
, cb
);
1810 MIDL_user_free(*string_ptr
);
1811 *string_ptr
= (LPWSTR
)*buf
;
1817 static DWORD
size_string(LPWSTR string
)
1819 return (string
? (strlenW(string
) + 1)*sizeof(WCHAR
) : sizeof(WCHAR
));
1822 /******************************************************************************
1823 * QueryServiceConfigW [ADVAPI32.@]
1826 QueryServiceConfigW( SC_HANDLE hService
,
1827 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1828 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1830 QUERY_SERVICE_CONFIGW config
;
1831 struct sc_service
*hsvc
;
1836 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1837 cbBufSize
, pcbBytesNeeded
);
1839 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1842 SetLastError( ERROR_INVALID_HANDLE
);
1846 memset(&config
, 0, sizeof(config
));
1848 if ((err
= svcctl_QueryServiceConfigW(hsvc
->hdr
.server_handle
, &config
)) != 0)
1850 TRACE("services.exe: error %u\n", err
);
1855 /* calculate the size required first */
1856 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1857 total
+= size_string(config
.lpBinaryPathName
);
1858 total
+= size_string(config
.lpLoadOrderGroup
);
1859 total
+= size_string(config
.lpDependencies
);
1860 total
+= size_string(config
.lpServiceStartName
);
1861 total
+= size_string(config
.lpDisplayName
);
1863 *pcbBytesNeeded
= total
;
1865 /* if there's not enough memory, return an error */
1866 if( total
> cbBufSize
)
1868 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1869 MIDL_user_free(config
.lpBinaryPathName
);
1870 MIDL_user_free(config
.lpLoadOrderGroup
);
1871 MIDL_user_free(config
.lpDependencies
);
1872 MIDL_user_free(config
.lpServiceStartName
);
1873 MIDL_user_free(config
.lpDisplayName
);
1877 *lpServiceConfig
= config
;
1878 bufpos
= ((BYTE
*)lpServiceConfig
) + sizeof(QUERY_SERVICE_CONFIGW
);
1879 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpBinaryPathName
);
1880 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpLoadOrderGroup
);
1881 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDependencies
);
1882 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpServiceStartName
);
1883 move_string_to_buffer(&bufpos
, &lpServiceConfig
->lpDisplayName
);
1885 if (bufpos
- (LPBYTE
)lpServiceConfig
> cbBufSize
)
1886 ERR("Buffer overflow!\n");
1888 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
1889 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
1890 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
1891 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
1892 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
1897 /******************************************************************************
1898 * QueryServiceConfig2A [ADVAPI32.@]
1901 * observed under win2k:
1902 * The functions QueryServiceConfig2A and QueryServiceConfig2W return the same
1903 * required buffer size (in byte) at least for dwLevel SERVICE_CONFIG_DESCRIPTION
1905 BOOL WINAPI
QueryServiceConfig2A(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1906 DWORD size
, LPDWORD needed
)
1909 LPBYTE bufferW
= NULL
;
1912 bufferW
= HeapAlloc( GetProcessHeap(), 0, size
);
1914 ret
= QueryServiceConfig2W(hService
, dwLevel
, bufferW
, size
, needed
);
1915 if(!ret
) goto cleanup
;
1918 case SERVICE_CONFIG_DESCRIPTION
:
1919 { LPSERVICE_DESCRIPTIONA configA
= (LPSERVICE_DESCRIPTIONA
) buffer
;
1920 LPSERVICE_DESCRIPTIONW configW
= (LPSERVICE_DESCRIPTIONW
) bufferW
;
1921 if (configW
->lpDescription
) {
1923 configA
->lpDescription
= (LPSTR
)(configA
+ 1);
1924 sz
= WideCharToMultiByte( CP_ACP
, 0, configW
->lpDescription
, -1,
1925 configA
->lpDescription
, size
- sizeof(SERVICE_DESCRIPTIONA
), NULL
, NULL
);
1927 FIXME("WideCharToMultiByte failed for configW->lpDescription\n");
1929 configA
->lpDescription
= NULL
;
1932 else configA
->lpDescription
= NULL
;
1936 FIXME("conversation W->A not implemented for level %d\n", dwLevel
);
1941 HeapFree( GetProcessHeap(), 0, bufferW
);
1945 /******************************************************************************
1946 * QueryServiceConfig2W [ADVAPI32.@]
1948 BOOL WINAPI
QueryServiceConfig2W(SC_HANDLE hService
, DWORD dwLevel
, LPBYTE buffer
,
1949 DWORD size
, LPDWORD needed
)
1954 struct sc_service
*hsvc
;
1956 if(dwLevel
!= SERVICE_CONFIG_DESCRIPTION
) {
1957 if((dwLevel
== SERVICE_CONFIG_DELAYED_AUTO_START_INFO
) ||
1958 (dwLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
) ||
1959 (dwLevel
== SERVICE_CONFIG_FAILURE_ACTIONS_FLAG
) ||
1960 (dwLevel
== SERVICE_CONFIG_PRESHUTDOWN_INFO
) ||
1961 (dwLevel
== SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO
) ||
1962 (dwLevel
== SERVICE_CONFIG_SERVICE_SID_INFO
))
1963 FIXME("Level %d not implemented\n", dwLevel
);
1964 SetLastError(ERROR_INVALID_LEVEL
);
1967 if(!needed
|| (!buffer
&& size
)) {
1968 SetLastError(ERROR_INVALID_ADDRESS
);
1972 TRACE("%p 0x%d %p 0x%d %p\n", hService
, dwLevel
, buffer
, size
, needed
);
1974 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1977 SetLastError(ERROR_INVALID_HANDLE
);
1983 case SERVICE_CONFIG_DESCRIPTION
: {
1984 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
1985 LPSERVICE_DESCRIPTIONW config
= (LPSERVICE_DESCRIPTIONW
) buffer
;
1986 LPBYTE strbuf
= NULL
;
1987 *needed
= sizeof (SERVICE_DESCRIPTIONW
);
1988 sz
= size
- *needed
;
1989 if(config
&& (*needed
<= size
))
1990 strbuf
= (LPBYTE
) (config
+ 1);
1991 r
= RegQueryValueExW( hKey
, szDescription
, 0, &type
, strbuf
, &sz
);
1992 if((r
== ERROR_SUCCESS
) && ( type
!= REG_SZ
)) {
1993 FIXME("SERVICE_CONFIG_DESCRIPTION: don't know how to handle type %d\n", type
);
1998 if(r
== ERROR_SUCCESS
)
1999 config
->lpDescription
= (LPWSTR
) (config
+ 1);
2001 config
->lpDescription
= NULL
;
2007 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2009 return (*needed
<= size
);
2012 /******************************************************************************
2013 * EnumServicesStatusA [ADVAPI32.@]
2016 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2017 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
2018 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2019 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2021 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2022 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2023 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2024 SetLastError (ERROR_ACCESS_DENIED
);
2028 /******************************************************************************
2029 * EnumServicesStatusW [ADVAPI32.@]
2032 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2033 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
2034 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2035 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2037 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2038 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2039 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2040 SetLastError (ERROR_ACCESS_DENIED
);
2044 /******************************************************************************
2045 * EnumServicesStatusExA [ADVAPI32.@]
2048 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2049 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2050 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
2052 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2053 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2054 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
2055 *lpServicesReturned
= 0;
2056 SetLastError (ERROR_ACCESS_DENIED
);
2060 /******************************************************************************
2061 * EnumServicesStatusExW [ADVAPI32.@]
2064 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2065 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2066 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
2068 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2069 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2070 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
2071 SetLastError (ERROR_ACCESS_DENIED
);
2075 /******************************************************************************
2076 * GetServiceKeyNameA [ADVAPI32.@]
2078 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2079 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2081 LPWSTR lpDisplayNameW
, lpServiceNameW
;
2085 TRACE("%p %s %p %p\n", hSCManager
,
2086 debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2088 lpDisplayNameW
= SERV_dup(lpDisplayName
);
2090 lpServiceNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
2092 lpServiceNameW
= NULL
;
2094 sizeW
= *lpcchBuffer
;
2095 if (!GetServiceKeyNameW(hSCManager
, lpDisplayNameW
, lpServiceNameW
, &sizeW
))
2097 if (*lpcchBuffer
&& lpServiceName
)
2098 lpServiceName
[0] = 0;
2099 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
2103 if (!WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, (sizeW
+ 1), lpServiceName
,
2104 *lpcchBuffer
, NULL
, NULL
))
2106 if (*lpcchBuffer
&& lpServiceName
)
2107 lpServiceName
[0] = 0;
2108 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpServiceNameW
, -1, NULL
, 0, NULL
, NULL
);
2112 /* lpcchBuffer not updated - same as in GetServiceDisplayNameA */
2116 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
2117 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
2121 /******************************************************************************
2122 * GetServiceKeyNameW [ADVAPI32.@]
2124 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2125 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2127 struct sc_manager
*hscm
;
2130 TRACE("%p %s %p %p\n", hSCManager
,
2131 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2133 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2136 SetLastError(ERROR_INVALID_HANDLE
);
2142 SetLastError(ERROR_INVALID_ADDRESS
);
2146 err
= svcctl_GetServiceKeyNameW(hscm
->hdr
.server_handle
,
2147 lpDisplayName
, lpServiceName
, lpServiceName
? *lpcchBuffer
: 0, lpcchBuffer
);
2151 return err
== ERROR_SUCCESS
;
2154 /******************************************************************************
2155 * QueryServiceLockStatusA [ADVAPI32.@]
2157 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2158 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2159 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2161 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2166 /******************************************************************************
2167 * QueryServiceLockStatusW [ADVAPI32.@]
2169 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2170 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2171 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2173 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2178 /******************************************************************************
2179 * GetServiceDisplayNameA [ADVAPI32.@]
2181 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2182 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2184 LPWSTR lpServiceNameW
, lpDisplayNameW
;
2188 TRACE("%p %s %p %p\n", hSCManager
,
2189 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2191 lpServiceNameW
= SERV_dup(lpServiceName
);
2193 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
2195 lpDisplayNameW
= NULL
;
2197 sizeW
= *lpcchBuffer
;
2198 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
2200 if (*lpcchBuffer
&& lpDisplayName
)
2201 lpDisplayName
[0] = 0;
2202 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
2206 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
2207 *lpcchBuffer
, NULL
, NULL
))
2209 if (*lpcchBuffer
&& lpDisplayName
)
2210 lpDisplayName
[0] = 0;
2211 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
2215 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2216 * (but if the function succeeded it means that is a good upper estimation of the size) */
2220 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
2221 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
2225 /******************************************************************************
2226 * GetServiceDisplayNameW [ADVAPI32.@]
2228 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2229 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2231 struct sc_manager
*hscm
;
2234 TRACE("%p %s %p %p\n", hSCManager
,
2235 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2237 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2240 SetLastError(ERROR_INVALID_HANDLE
);
2246 SetLastError(ERROR_INVALID_ADDRESS
);
2250 err
= svcctl_GetServiceDisplayNameW(hscm
->hdr
.server_handle
,
2251 lpServiceName
, lpDisplayName
, lpDisplayName
? *lpcchBuffer
: 0, lpcchBuffer
);
2255 return err
== ERROR_SUCCESS
;
2258 /******************************************************************************
2259 * ChangeServiceConfigW [ADVAPI32.@]
2261 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2262 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2263 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2264 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2266 struct sc_service
*hsvc
;
2270 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2271 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2272 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2273 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2274 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2276 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2279 SetLastError( ERROR_INVALID_HANDLE
);
2283 cb_pwd
= lpPassword
? (strlenW(lpPassword
) + 1)*sizeof(WCHAR
) : 0;
2285 err
= svcctl_ChangeServiceConfigW(hsvc
->hdr
.server_handle
, dwServiceType
,
2286 dwStartType
, dwErrorControl
, lpBinaryPathName
, lpLoadOrderGroup
, lpdwTagId
,
2287 (const BYTE
*)lpDependencies
, multisz_cb(lpDependencies
), lpServiceStartName
,
2288 (const BYTE
*)lpPassword
, cb_pwd
, lpDisplayName
);
2290 if (err
!= ERROR_SUCCESS
)
2293 return err
== ERROR_SUCCESS
;
2296 /******************************************************************************
2297 * ChangeServiceConfigA [ADVAPI32.@]
2299 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2300 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2301 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2302 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2304 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2305 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2308 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2309 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2310 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2311 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2312 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2314 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2315 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2316 wDependencies
= SERV_dupmulti( lpDependencies
);
2317 wServiceStartName
= SERV_dup( lpServiceStartName
);
2318 wPassword
= SERV_dup( lpPassword
);
2319 wDisplayName
= SERV_dup( lpDisplayName
);
2321 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2322 dwStartType
, dwErrorControl
, wBinaryPathName
,
2323 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2324 wServiceStartName
, wPassword
, wDisplayName
);
2326 HeapFree( GetProcessHeap(), 0, wBinaryPathName
);
2327 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup
);
2328 HeapFree( GetProcessHeap(), 0, wDependencies
);
2329 HeapFree( GetProcessHeap(), 0, wServiceStartName
);
2330 HeapFree( GetProcessHeap(), 0, wPassword
);
2331 HeapFree( GetProcessHeap(), 0, wDisplayName
);
2336 /******************************************************************************
2337 * ChangeServiceConfig2A [ADVAPI32.@]
2339 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2344 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2346 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2348 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2349 SERVICE_DESCRIPTIONW sdw
;
2351 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2353 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2355 HeapFree( GetProcessHeap(), 0, sdw
.lpDescription
);
2357 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2359 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2360 SERVICE_FAILURE_ACTIONSW faw
;
2362 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2363 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2364 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2365 faw
.cActions
= fa
->cActions
;
2366 faw
.lpsaActions
= fa
->lpsaActions
;
2368 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2370 HeapFree( GetProcessHeap(), 0, faw
.lpRebootMsg
);
2371 HeapFree( GetProcessHeap(), 0, faw
.lpCommand
);
2374 SetLastError( ERROR_INVALID_PARAMETER
);
2379 /******************************************************************************
2380 * ChangeServiceConfig2W [ADVAPI32.@]
2382 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2386 struct sc_service
*hsvc
;
2388 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2391 SetLastError( ERROR_INVALID_HANDLE
);
2396 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2398 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2399 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2400 if (sd
->lpDescription
)
2402 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2403 if (sd
->lpDescription
[0] == 0)
2404 RegDeleteValueW(hKey
,szDescription
);
2406 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2407 (LPVOID
)sd
->lpDescription
,
2408 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2412 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2416 /******************************************************************************
2417 * QueryServiceObjectSecurity [ADVAPI32.@]
2419 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2420 SECURITY_INFORMATION dwSecurityInformation
,
2421 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2422 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2424 SECURITY_DESCRIPTOR descriptor
;
2429 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2430 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2432 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2433 FIXME("information %d not supported\n", dwSecurityInformation
);
2435 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2437 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2438 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2441 succ
= MakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2442 *pcbBytesNeeded
= size
;
2446 /******************************************************************************
2447 * SetServiceObjectSecurity [ADVAPI32.@]
2449 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2450 SECURITY_INFORMATION dwSecurityInformation
,
2451 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2453 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2457 /******************************************************************************
2458 * SetServiceBits [ADVAPI32.@]
2460 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2461 DWORD dwServiceBits
,
2463 BOOL bUpdateImmediately
)
2465 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2466 bSetBitsOn
, bUpdateImmediately
);
2470 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2471 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
2473 LPHANDLER_FUNCTION func
= context
;
2476 return ERROR_SUCCESS
;
2479 /******************************************************************************
2480 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2482 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
2484 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
2487 /******************************************************************************
2488 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2490 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
2492 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
2495 /******************************************************************************
2496 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2498 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
2501 SERVICE_STATUS_HANDLE ret
;
2503 nameW
= SERV_dup(name
);
2504 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
2505 HeapFree( GetProcessHeap(), 0, nameW
);
2509 /******************************************************************************
2510 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2512 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2513 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2520 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2522 hSCM
= OpenSCManagerW( NULL
, NULL
, SC_MANAGER_CONNECT
);
2525 hService
= OpenServiceW( hSCM
, lpServiceName
, SERVICE_SET_STATUS
);
2526 CloseServiceHandle(hSCM
);
2530 EnterCriticalSection( &service_cs
);
2531 for (i
= 0; i
< nb_services
; i
++)
2533 if(!strcmpW(lpServiceName
, services
[i
]->name
))
2535 services
[i
]->handler
= lpHandlerProc
;
2536 services
[i
]->context
= lpContext
;
2541 LeaveCriticalSection( &service_cs
);
2545 CloseServiceHandle(hService
);
2546 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2550 return (SERVICE_STATUS_HANDLE
)hService
;
2553 /******************************************************************************
2554 * EnumDependentServicesA [ADVAPI32.@]
2556 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2557 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2558 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2560 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2561 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2563 *lpServicesReturned
= 0;
2567 /******************************************************************************
2568 * EnumDependentServicesW [ADVAPI32.@]
2570 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2571 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2572 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2574 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2575 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2577 *lpServicesReturned
= 0;