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"
39 WINE_DEFAULT_DEBUG_CHANNEL(service
);
41 static const WCHAR szLocalSystem
[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
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
75 LPHANDLER_FUNCTION_EX handler
;
77 SERVICE_STATUS_PROCESS status
;
81 LPSERVICE_MAIN_FUNCTIONA a
;
82 LPSERVICE_MAIN_FUNCTIONW w
;
88 static CRITICAL_SECTION service_cs
;
89 static CRITICAL_SECTION_DEBUG service_cs_debug
=
92 { &service_cs_debug
.ProcessLocksList
,
93 &service_cs_debug
.ProcessLocksList
},
94 0, 0, { (DWORD_PTR
)(__FILE__
": service_cs") }
96 static CRITICAL_SECTION service_cs
= { &service_cs_debug
, -1, 0, 0, 0, 0 };
98 static service_data
**services
;
99 static unsigned int nb_services
;
100 static HANDLE service_event
;
102 extern HANDLE
__wine_make_process_system(void);
104 /******************************************************************************
108 #define MAX_SERVICE_NAME 256
110 typedef enum { SC_HTYPE_MANAGER
, SC_HTYPE_SERVICE
} SC_HANDLE_TYPE
;
113 typedef VOID (*sc_handle_destructor
)(struct sc_handle
*);
117 SC_HANDLE_TYPE htype
;
119 sc_handle_destructor destroy
;
122 struct sc_manager
/* service control manager handle */
124 struct sc_handle hdr
;
125 HKEY hkey
; /* handle to services database in the registry */
129 struct sc_service
/* service handle */
131 struct sc_handle hdr
;
132 HKEY hkey
; /* handle to service entry in the registry (under hkey) */
134 struct sc_manager
*scm
; /* pointer to SCM handle */
138 static void *sc_handle_alloc(SC_HANDLE_TYPE htype
, DWORD size
,
139 sc_handle_destructor destroy
)
141 struct sc_handle
*hdr
;
143 hdr
= HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY
, size
);
148 hdr
->destroy
= destroy
;
150 TRACE("sc_handle type=%d -> %p\n", htype
, hdr
);
154 static void *sc_handle_get_handle_data(SC_HANDLE handle
, DWORD htype
)
156 struct sc_handle
*hdr
= (struct sc_handle
*) handle
;
160 if (hdr
->htype
!= htype
)
165 static void sc_handle_free(struct sc_handle
* hdr
)
169 if (--hdr
->ref_count
)
172 HeapFree(GetProcessHeap(), 0, hdr
);
175 static void sc_handle_destroy_manager(struct sc_handle
*handle
)
177 struct sc_manager
*mgr
= (struct sc_manager
*) handle
;
179 TRACE("destroying SC Manager %p\n", mgr
);
181 RegCloseKey(mgr
->hkey
);
184 static void sc_handle_destroy_service(struct sc_handle
*handle
)
186 struct sc_service
*svc
= (struct sc_service
*) handle
;
188 TRACE("destroying service %p\n", svc
);
190 RegCloseKey(svc
->hkey
);
192 sc_handle_free(&svc
->scm
->hdr
);
196 /******************************************************************************
197 * String management functions (same behaviour as strdup)
198 * NOTE: the caller of those functions is responsible for calling HeapFree
199 * in order to release the memory allocated by those functions.
201 static inline LPWSTR
SERV_dup( LPCSTR str
)
208 len
= MultiByteToWideChar( CP_ACP
, 0, str
, -1, NULL
, 0 );
209 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
210 MultiByteToWideChar( CP_ACP
, 0, str
, -1, wstr
, len
);
214 static inline LPWSTR
SERV_dupmulti(LPCSTR str
)
222 len
+= MultiByteToWideChar( CP_ACP
, 0, &str
[n
], -1, NULL
, 0 );
223 n
+= (strlen( &str
[n
] ) + 1);
228 wstr
= HeapAlloc( GetProcessHeap(), 0, len
*sizeof (WCHAR
) );
229 MultiByteToWideChar( CP_ACP
, 0, str
, n
, wstr
, len
);
233 /******************************************************************************
234 * registry access functions and data
236 static const WCHAR szDisplayName
[] = {
237 'D','i','s','p','l','a','y','N','a','m','e', 0 };
238 static const WCHAR szType
[] = {'T','y','p','e',0};
239 static const WCHAR szStart
[] = {'S','t','a','r','t',0};
240 static const WCHAR szError
[] = {
241 'E','r','r','o','r','C','o','n','t','r','o','l', 0};
242 static const WCHAR szImagePath
[] = {'I','m','a','g','e','P','a','t','h',0};
243 static const WCHAR szGroup
[] = {'G','r','o','u','p',0};
244 static const WCHAR szDependencies
[] = {
245 'D','e','p','e','n','d','e','n','c','i','e','s',0};
246 static const WCHAR szDependOnService
[] = {
247 'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
248 static const WCHAR szObjectName
[] = {
249 'O','b','j','e','c','t','N','a','m','e',0};
250 static const WCHAR szTag
[] = {
260 static inline void service_set_value( struct reg_value
*val
,
261 DWORD type
, LPCWSTR name
, LPCVOID data
, DWORD size
)
269 static inline void service_set_dword( struct reg_value
*val
,
270 LPCWSTR name
, const DWORD
*data
)
272 service_set_value( val
, REG_DWORD
, name
, data
, sizeof (DWORD
));
275 static inline void service_set_string( struct reg_value
*val
,
276 LPCWSTR name
, LPCWSTR string
)
278 DWORD len
= (lstrlenW(string
)+1) * sizeof (WCHAR
);
279 service_set_value( val
, REG_SZ
, name
, string
, len
);
282 static inline void service_set_multi_string( struct reg_value
*val
,
283 LPCWSTR name
, LPCWSTR string
)
287 /* determine the length of a double null terminated multi string */
289 len
+= (lstrlenW( &string
[ len
] )+1);
290 } while ( string
[ len
++ ] );
292 len
*= sizeof (WCHAR
);
293 service_set_value( val
, REG_MULTI_SZ
, name
, string
, len
);
296 static inline LONG
service_write_values( HKEY hKey
,
297 const struct reg_value
*val
, int n
)
299 LONG r
= ERROR_SUCCESS
;
304 r
= RegSetValueExW(hKey
, val
[i
].name
, 0, val
[i
].type
,
305 (const BYTE
*)val
[i
].data
, val
[i
].size
);
306 if( r
!= ERROR_SUCCESS
)
312 /******************************************************************************
313 * Service IPC functions
315 static LPWSTR
service_get_pipe_name(LPCWSTR service
)
317 static const WCHAR prefix
[] = { '\\','\\','.','\\','p','i','p','e','\\',
318 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
322 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
323 name
= HeapAlloc(GetProcessHeap(), 0, len
);
324 strcpyW(name
, prefix
);
325 strcatW(name
, service
);
329 static HANDLE
service_open_pipe(LPCWSTR service
)
331 LPWSTR szPipe
= service_get_pipe_name( service
);
332 HANDLE handle
= INVALID_HANDLE_VALUE
;
335 handle
= CreateFileW(szPipe
, GENERIC_READ
|GENERIC_WRITE
,
336 0, NULL
, OPEN_ALWAYS
, 0, NULL
);
337 if (handle
!= INVALID_HANDLE_VALUE
)
339 if (GetLastError() != ERROR_PIPE_BUSY
)
341 } while (WaitNamedPipeW(szPipe
, NMPWAIT_WAIT_FOREVER
));
342 HeapFree(GetProcessHeap(), 0, szPipe
);
347 /******************************************************************************
348 * service_get_event_handle
350 static HANDLE
service_get_event_handle(LPCWSTR service
)
352 static const WCHAR prefix
[] = {
353 '_','_','w','i','n','e','s','e','r','v','i','c','e','_',0};
358 len
= sizeof prefix
+ strlenW(service
)*sizeof(WCHAR
);
359 name
= HeapAlloc(GetProcessHeap(), 0, len
);
360 strcpyW(name
, prefix
);
361 strcatW(name
, service
);
362 handle
= CreateEventW(NULL
, TRUE
, FALSE
, name
);
363 HeapFree(GetProcessHeap(), 0, name
);
367 /******************************************************************************
370 * Call into the main service routine provided by StartServiceCtrlDispatcher.
372 static DWORD WINAPI
service_thread(LPVOID arg
)
374 service_data
*info
= arg
;
375 LPWSTR str
= info
->args
;
376 DWORD argc
= 0, len
= 0;
382 len
+= strlenW(&str
[len
]) + 1;
389 info
->proc
.w(0, NULL
);
391 info
->proc
.a(0, NULL
);
399 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPWSTR
));
400 for (argc
=0, p
=str
; *p
; p
+= strlenW(p
) + 1)
404 info
->proc
.w(argc
, argv
);
405 HeapFree(GetProcessHeap(), 0, argv
);
409 LPSTR strA
, *argv
, p
;
412 lenA
= WideCharToMultiByte(CP_ACP
,0, str
, len
, NULL
, 0, NULL
, NULL
);
413 strA
= HeapAlloc(GetProcessHeap(), 0, lenA
);
414 WideCharToMultiByte(CP_ACP
,0, str
, len
, strA
, lenA
, NULL
, NULL
);
416 argv
= HeapAlloc(GetProcessHeap(), 0, (argc
+1)*sizeof(LPSTR
));
417 for (argc
=0, p
=strA
; *p
; p
+= strlen(p
) + 1)
421 info
->proc
.a(argc
, argv
);
422 HeapFree(GetProcessHeap(), 0, argv
);
423 HeapFree(GetProcessHeap(), 0, strA
);
428 /******************************************************************************
429 * service_handle_start
431 static BOOL
service_handle_start(HANDLE pipe
, service_data
*service
, DWORD count
)
433 DWORD read
= 0, result
= 0;
437 TRACE("%p %p %d\n", pipe
, service
, count
);
439 args
= HeapAlloc(GetProcessHeap(), 0, count
*sizeof(WCHAR
));
440 r
= ReadFile(pipe
, args
, count
*sizeof(WCHAR
), &read
, NULL
);
441 if (!r
|| count
!=read
/sizeof(WCHAR
) || args
[count
-1])
443 ERR("pipe read failed r = %d count = %d read = %d args[n-1]=%s\n",
444 r
, count
, read
, debugstr_wn(args
, count
));
450 WARN("service is not stopped\n");
451 result
= ERROR_SERVICE_ALREADY_RUNNING
;
455 HeapFree(GetProcessHeap(), 0, service
->args
);
456 service
->args
= args
;
458 service
->status
.dwCurrentState
= SERVICE_START_PENDING
;
459 service
->thread
= CreateThread( NULL
, 0, service_thread
,
461 SetEvent( service_event
); /* notify the main loop */
464 HeapFree(GetProcessHeap(), 0, args
);
465 WriteFile( pipe
, &result
, sizeof result
, &read
, NULL
);
470 /******************************************************************************
471 * service_send_start_message
473 static BOOL
service_send_start_message(HANDLE pipe
, LPCWSTR
*argv
, DWORD argc
)
475 DWORD i
, len
, count
, result
;
476 service_start_info
*ssi
;
480 TRACE("%p %p %d\n", pipe
, argv
, argc
);
482 /* calculate how much space do we need to send the startup info */
484 for (i
=0; i
<argc
; i
++)
485 len
+= strlenW(argv
[i
])+1;
487 ssi
= HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info
, str
[len
]));
488 ssi
->cmd
= WINESERV_STARTINFO
;
491 /* copy service args into a single buffer*/
493 for (i
=0; i
<argc
; i
++)
500 r
= WriteFile(pipe
, ssi
, FIELD_OFFSET(service_start_info
, str
[len
]), &count
, NULL
);
503 r
= ReadFile(pipe
, &result
, sizeof result
, &count
, NULL
);
506 SetLastError(result
);
511 HeapFree(GetProcessHeap(),0,ssi
);
516 /******************************************************************************
517 * service_handle_get_status
519 static BOOL
service_handle_get_status(HANDLE pipe
, const service_data
*service
)
523 return WriteFile(pipe
, &service
->status
,
524 sizeof service
->status
, &count
, NULL
);
527 /******************************************************************************
530 static BOOL
service_get_status(HANDLE pipe
, LPSERVICE_STATUS_PROCESS status
)
532 DWORD cmd
[2], count
= 0;
535 cmd
[0] = WINESERV_GETSTATUS
;
537 r
= WriteFile( pipe
, cmd
, sizeof cmd
, &count
, NULL
);
538 if (!r
|| count
!= sizeof cmd
)
540 ERR("service protocol error - failed to write pipe!\n");
543 r
= ReadFile( pipe
, status
, sizeof *status
, &count
, NULL
);
544 if (!r
|| count
!= sizeof *status
)
545 ERR("service protocol error - failed to read pipe "
546 "r = %d count = %d!\n", r
, count
);
550 /******************************************************************************
551 * service_send_control
553 static BOOL
service_send_control(HANDLE pipe
, DWORD dwControl
, DWORD
*result
)
555 DWORD cmd
[2], count
= 0;
558 cmd
[0] = WINESERV_SENDCONTROL
;
560 r
= WriteFile(pipe
, cmd
, sizeof cmd
, &count
, NULL
);
561 if (!r
|| count
!= sizeof cmd
)
563 ERR("service protocol error - failed to write pipe!\n");
566 r
= ReadFile(pipe
, result
, sizeof *result
, &count
, NULL
);
567 if (!r
|| count
!= sizeof *result
)
568 ERR("service protocol error - failed to read pipe "
569 "r = %d count = %d!\n", r
, count
);
573 /******************************************************************************
574 * service_accepts_control
576 static BOOL
service_accepts_control(const service_data
*service
, DWORD dwControl
)
578 DWORD a
= service
->status
.dwControlsAccepted
;
582 case SERVICE_CONTROL_INTERROGATE
:
584 case SERVICE_CONTROL_STOP
:
585 if (a
&SERVICE_ACCEPT_STOP
)
588 case SERVICE_CONTROL_SHUTDOWN
:
589 if (a
&SERVICE_ACCEPT_SHUTDOWN
)
592 case SERVICE_CONTROL_PAUSE
:
593 case SERVICE_CONTROL_CONTINUE
:
594 if (a
&SERVICE_ACCEPT_PAUSE_CONTINUE
)
597 case SERVICE_CONTROL_PARAMCHANGE
:
598 if (a
&SERVICE_ACCEPT_PARAMCHANGE
)
601 case SERVICE_CONTROL_NETBINDADD
:
602 case SERVICE_CONTROL_NETBINDREMOVE
:
603 case SERVICE_CONTROL_NETBINDENABLE
:
604 case SERVICE_CONTROL_NETBINDDISABLE
:
605 if (a
&SERVICE_ACCEPT_NETBINDCHANGE
)
607 case SERVICE_CONTROL_HARDWAREPROFILECHANGE
:
608 if (a
&SERVICE_ACCEPT_HARDWAREPROFILECHANGE
)
611 case SERVICE_CONTROL_POWEREVENT
:
612 if (a
&SERVICE_ACCEPT_POWEREVENT
)
615 case SERVICE_CONTROL_SESSIONCHANGE
:
616 if (a
&SERVICE_ACCEPT_SESSIONCHANGE
)
623 /******************************************************************************
624 * service_handle_control
626 static BOOL
service_handle_control(HANDLE pipe
, service_data
*service
,
629 DWORD count
, ret
= ERROR_INVALID_SERVICE_CONTROL
;
631 TRACE("received control %d\n", dwControl
);
633 if (service_accepts_control(service
, dwControl
))
635 if (service
->handler
)
636 ret
= service
->handler(dwControl
, 0, NULL
, service
->context
);
638 return WriteFile(pipe
, &ret
, sizeof ret
, &count
, NULL
);
641 /******************************************************************************
642 * service_control_dispatcher
644 static DWORD WINAPI
service_control_dispatcher(LPVOID arg
)
646 service_data
*service
= arg
;
650 TRACE("%p %s\n", service
, debugstr_w(service
->name
));
652 /* create a pipe to talk to the rest of the world with */
653 name
= service_get_pipe_name(service
->name
);
654 pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
,
655 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
657 if (pipe
==INVALID_HANDLE_VALUE
)
658 ERR("failed to create pipe for %s, error = %d\n",
659 debugstr_w(service
->name
), GetLastError());
661 HeapFree(GetProcessHeap(), 0, name
);
663 /* let the process who started us know we've tried to create a pipe */
664 event
= service_get_event_handle(service
->name
);
668 if (pipe
==INVALID_HANDLE_VALUE
) return 0;
670 /* dispatcher loop */
674 DWORD count
, req
[2] = {0,0};
676 r
= ConnectNamedPipe(pipe
, NULL
);
677 if (!r
&& GetLastError() != ERROR_PIPE_CONNECTED
)
679 ERR("pipe connect failed\n");
683 r
= ReadFile( pipe
, &req
, sizeof req
, &count
, NULL
);
684 if (!r
|| count
!=sizeof req
)
686 ERR("pipe read failed\n");
690 /* handle the request */
693 case WINESERV_STARTINFO
:
694 service_handle_start(pipe
, service
, req
[1]);
696 case WINESERV_GETSTATUS
:
697 service_handle_get_status(pipe
, service
);
699 case WINESERV_SENDCONTROL
:
700 service_handle_control(pipe
, service
, req
[1]);
703 ERR("received invalid command %d length %d\n", req
[0], req
[1]);
706 FlushFileBuffers(pipe
);
707 DisconnectNamedPipe(pipe
);
714 /******************************************************************************
715 * service_run_threads
717 static BOOL
service_run_threads(void)
720 HANDLE wait_handles
[MAXIMUM_WAIT_OBJECTS
];
721 UINT wait_services
[MAXIMUM_WAIT_OBJECTS
];
723 service_event
= CreateEventW( NULL
, FALSE
, FALSE
, NULL
);
725 wait_handles
[0] = __wine_make_process_system();
726 wait_handles
[1] = service_event
;
728 TRACE("Starting %d pipe listener threads. Services running as process %d\n",
729 nb_services
, GetCurrentProcessId());
731 EnterCriticalSection( &service_cs
);
732 for (i
= 0; i
< nb_services
; i
++)
734 services
[i
]->status
.dwProcessId
= GetCurrentProcessId();
735 CloseHandle( CreateThread( NULL
, 0, service_control_dispatcher
, services
[i
], 0, NULL
));
737 LeaveCriticalSection( &service_cs
);
739 /* wait for all the threads to pack up and exit */
742 EnterCriticalSection( &service_cs
);
743 for (i
= 0, n
= 2; i
< nb_services
&& n
< MAXIMUM_WAIT_OBJECTS
; i
++)
745 if (!services
[i
]->thread
) continue;
746 wait_services
[n
] = i
;
747 wait_handles
[n
++] = services
[i
]->thread
;
749 LeaveCriticalSection( &service_cs
);
751 ret
= WaitForMultipleObjects( n
, wait_handles
, FALSE
, INFINITE
);
752 if (!ret
) /* system process event */
754 TRACE( "last user process exited, shutting down\n" );
755 /* FIXME: we should maybe send a shutdown control to running services */
760 continue; /* rebuild the list */
764 services
[wait_services
[ret
]]->thread
= 0;
765 CloseHandle( wait_handles
[ret
] );
766 if (n
== 3) return TRUE
; /* it was the last running thread */
772 /******************************************************************************
773 * StartServiceCtrlDispatcherA [ADVAPI32.@]
775 * See StartServiceCtrlDispatcherW.
777 BOOL WINAPI
StartServiceCtrlDispatcherA( const SERVICE_TABLE_ENTRYA
*servent
)
783 TRACE("%p\n", servent
);
787 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
790 while (servent
[nb_services
].lpServiceName
) nb_services
++;
791 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
793 for (i
= 0; i
< nb_services
; i
++)
795 DWORD len
= MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, NULL
, 0);
796 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
797 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
798 MultiByteToWideChar(CP_ACP
, 0, servent
[i
].lpServiceName
, -1, info
->name
, len
);
799 info
->proc
.a
= servent
[i
].lpServiceProc
;
800 info
->unicode
= FALSE
;
804 service_run_threads();
809 /******************************************************************************
810 * StartServiceCtrlDispatcherW [ADVAPI32.@]
812 * Connects a process containing one or more services to the service control
816 * servent [I] A list of the service names and service procedures
822 BOOL WINAPI
StartServiceCtrlDispatcherW( const SERVICE_TABLE_ENTRYW
*servent
)
828 TRACE("%p\n", servent
);
832 SetLastError( ERROR_SERVICE_ALREADY_RUNNING
);
835 while (servent
[nb_services
].lpServiceName
) nb_services
++;
836 services
= HeapAlloc( GetProcessHeap(), 0, nb_services
* sizeof(*services
) );
838 for (i
= 0; i
< nb_services
; i
++)
840 DWORD len
= strlenW(servent
[i
].lpServiceName
) + 1;
841 DWORD sz
= FIELD_OFFSET( service_data
, name
[len
] );
842 info
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sz
);
843 strcpyW(info
->name
, servent
[i
].lpServiceName
);
844 info
->proc
.w
= servent
[i
].lpServiceProc
;
845 info
->unicode
= TRUE
;
849 service_run_threads();
854 /******************************************************************************
855 * LockServiceDatabase [ADVAPI32.@]
857 SC_LOCK WINAPI
LockServiceDatabase (SC_HANDLE hSCManager
)
861 TRACE("%p\n",hSCManager
);
863 ret
= CreateSemaphoreW( NULL
, 1, 1, szSCMLock
);
864 if( ret
&& GetLastError() == ERROR_ALREADY_EXISTS
)
868 SetLastError( ERROR_SERVICE_DATABASE_LOCKED
);
871 TRACE("returning %p\n", ret
);
876 /******************************************************************************
877 * UnlockServiceDatabase [ADVAPI32.@]
879 BOOL WINAPI
UnlockServiceDatabase (SC_LOCK ScLock
)
881 TRACE("%p\n",ScLock
);
883 return CloseHandle( ScLock
);
886 /******************************************************************************
887 * SetServiceStatus [ADVAPI32.@]
894 SetServiceStatus( SERVICE_STATUS_HANDLE hService
, LPSERVICE_STATUS lpStatus
)
896 ULONG_PTR index
= HandleToULong(hService
) - 1;
899 TRACE("%p %x %x %x %x %x %x %x\n", hService
,
900 lpStatus
->dwServiceType
, lpStatus
->dwCurrentState
,
901 lpStatus
->dwControlsAccepted
, lpStatus
->dwWin32ExitCode
,
902 lpStatus
->dwServiceSpecificExitCode
, lpStatus
->dwCheckPoint
,
903 lpStatus
->dwWaitHint
);
905 EnterCriticalSection( &service_cs
);
906 if (index
< nb_services
)
908 memcpy( &services
[index
]->status
, lpStatus
, sizeof(SERVICE_STATUS
) );
909 TRACE("Set service status to %d\n",services
[index
]->status
.dwCurrentState
);
912 LeaveCriticalSection( &service_cs
);
918 /******************************************************************************
919 * OpenSCManagerA [ADVAPI32.@]
921 * Establish a connection to the service control manager and open its database.
924 * lpMachineName [I] Pointer to machine name string
925 * lpDatabaseName [I] Pointer to database name string
926 * dwDesiredAccess [I] Type of access
929 * Success: A Handle to the service control manager database
932 SC_HANDLE WINAPI
OpenSCManagerA( LPCSTR lpMachineName
, LPCSTR lpDatabaseName
,
933 DWORD dwDesiredAccess
)
935 LPWSTR lpMachineNameW
, lpDatabaseNameW
;
938 lpMachineNameW
= SERV_dup(lpMachineName
);
939 lpDatabaseNameW
= SERV_dup(lpDatabaseName
);
940 ret
= OpenSCManagerW(lpMachineNameW
, lpDatabaseNameW
, dwDesiredAccess
);
941 HeapFree(GetProcessHeap(), 0, lpDatabaseNameW
);
942 HeapFree(GetProcessHeap(), 0, lpMachineNameW
);
946 /******************************************************************************
947 * OpenSCManagerW [ADVAPI32.@]
949 * See OpenSCManagerA.
951 SC_HANDLE WINAPI
OpenSCManagerW( LPCWSTR lpMachineName
, LPCWSTR lpDatabaseName
,
952 DWORD dwDesiredAccess
)
954 struct sc_manager
*manager
;
957 DWORD new_mask
= dwDesiredAccess
;
959 TRACE("(%s,%s,0x%08x)\n", debugstr_w(lpMachineName
),
960 debugstr_w(lpDatabaseName
), dwDesiredAccess
);
962 if( lpDatabaseName
&& lpDatabaseName
[0] )
964 if( strcmpiW( lpDatabaseName
, SERVICES_ACTIVE_DATABASEW
) == 0 )
966 /* noop, all right */
968 else if( strcmpiW( lpDatabaseName
, SERVICES_FAILED_DATABASEW
) == 0 )
970 SetLastError( ERROR_DATABASE_DOES_NOT_EXIST
);
975 SetLastError( ERROR_INVALID_NAME
);
980 manager
= sc_handle_alloc( SC_HTYPE_MANAGER
, sizeof (struct sc_manager
),
981 sc_handle_destroy_manager
);
985 r
= RegConnectRegistryW(lpMachineName
,HKEY_LOCAL_MACHINE
,&hReg
);
986 if (r
!=ERROR_SUCCESS
)
989 r
= RegCreateKeyW(hReg
, szServiceManagerKey
, &manager
->hkey
);
991 if (r
!=ERROR_SUCCESS
)
994 RtlMapGenericMask(&new_mask
, &scm_generic
);
995 manager
->dwAccess
= new_mask
;
996 TRACE("returning %p (access : 0x%08x)\n", manager
, manager
->dwAccess
);
998 return (SC_HANDLE
) &manager
->hdr
;
1001 sc_handle_free( &manager
->hdr
);
1006 /******************************************************************************
1007 * ControlService [ADVAPI32.@]
1009 * Send a control code to a service.
1012 * hService [I] Handle of the service control manager database
1013 * dwControl [I] Control code to send (SERVICE_CONTROL_* flags from "winsvc.h")
1014 * lpServiceStatus [O] Destination for the status of the service, if available
1021 * Unlike M$' implementation, control requests are not serialized and may be
1022 * processed asynchronously.
1024 BOOL WINAPI
ControlService( SC_HANDLE hService
, DWORD dwControl
,
1025 LPSERVICE_STATUS lpServiceStatus
)
1027 struct sc_service
*hsvc
;
1031 TRACE("%p %d %p\n", hService
, dwControl
, lpServiceStatus
);
1033 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1036 SetLastError( ERROR_INVALID_HANDLE
);
1040 if (lpServiceStatus
)
1042 ret
= QueryServiceStatus(hService
, lpServiceStatus
);
1045 ERR("failed to query service status\n");
1046 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1050 switch (lpServiceStatus
->dwCurrentState
)
1052 case SERVICE_STOPPED
:
1053 SetLastError(ERROR_SERVICE_NOT_ACTIVE
);
1055 case SERVICE_START_PENDING
:
1056 if (dwControl
==SERVICE_CONTROL_STOP
)
1059 case SERVICE_STOP_PENDING
:
1060 SetLastError(ERROR_SERVICE_CANNOT_ACCEPT_CTRL
);
1065 handle
= service_open_pipe(hsvc
->name
);
1066 if (handle
!=INVALID_HANDLE_VALUE
)
1068 DWORD result
= ERROR_SUCCESS
;
1069 ret
= service_send_control(handle
, dwControl
, &result
);
1070 CloseHandle(handle
);
1071 if (result
!=ERROR_SUCCESS
)
1073 SetLastError(result
);
1081 /******************************************************************************
1082 * CloseServiceHandle [ADVAPI32.@]
1084 * Close a handle to a service or the service control manager database.
1087 * hSCObject [I] Handle to service or service control manager database
1094 CloseServiceHandle( SC_HANDLE hSCObject
)
1096 TRACE("%p\n", hSCObject
);
1098 sc_handle_free( (struct sc_handle
*) hSCObject
);
1104 /******************************************************************************
1105 * OpenServiceA [ADVAPI32.@]
1107 * Open a handle to a service.
1110 * hSCManager [I] Handle of the service control manager database
1111 * lpServiceName [I] Name of the service to open
1112 * dwDesiredAccess [I] Access required to the service
1115 * Success: Handle to the service
1118 SC_HANDLE WINAPI
OpenServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1119 DWORD dwDesiredAccess
)
1121 LPWSTR lpServiceNameW
;
1124 TRACE("%p %s %d\n", hSCManager
, debugstr_a(lpServiceName
), dwDesiredAccess
);
1126 lpServiceNameW
= SERV_dup(lpServiceName
);
1127 ret
= OpenServiceW( hSCManager
, lpServiceNameW
, dwDesiredAccess
);
1128 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
1133 /******************************************************************************
1134 * OpenServiceW [ADVAPI32.@]
1138 SC_HANDLE WINAPI
OpenServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1139 DWORD dwDesiredAccess
)
1141 struct sc_manager
*hscm
;
1142 struct sc_service
*hsvc
;
1146 DWORD new_mask
= dwDesiredAccess
;
1148 TRACE("%p %s %d\n", hSCManager
, debugstr_w(lpServiceName
), dwDesiredAccess
);
1150 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1153 SetLastError( ERROR_INVALID_HANDLE
);
1159 SetLastError(ERROR_INVALID_ADDRESS
);
1163 r
= RegOpenKeyExW( hscm
->hkey
, lpServiceName
, 0, KEY_ALL_ACCESS
, &hKey
);
1164 if (r
!=ERROR_SUCCESS
)
1166 SetLastError( ERROR_SERVICE_DOES_NOT_EXIST
);
1170 len
= strlenW(lpServiceName
)+1;
1171 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
,
1172 sizeof (struct sc_service
) + len
*sizeof(WCHAR
),
1173 sc_handle_destroy_service
);
1179 strcpyW( hsvc
->name
, lpServiceName
);
1182 RtlMapGenericMask(&new_mask
, &svc_generic
);
1183 hsvc
->dwAccess
= new_mask
;
1185 /* add reference to SCM handle */
1186 hscm
->hdr
.ref_count
++;
1189 TRACE("returning %p\n",hsvc
);
1191 return (SC_HANDLE
) &hsvc
->hdr
;
1194 /******************************************************************************
1195 * CreateServiceW [ADVAPI32.@]
1198 CreateServiceW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
1199 LPCWSTR lpDisplayName
, DWORD dwDesiredAccess
,
1200 DWORD dwServiceType
, DWORD dwStartType
,
1201 DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
1202 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1203 LPCWSTR lpDependencies
, LPCWSTR lpServiceStartName
,
1204 LPCWSTR lpPassword
)
1206 struct sc_manager
*hscm
;
1207 struct sc_service
*hsvc
= NULL
;
1211 struct reg_value val
[10];
1213 DWORD new_mask
= dwDesiredAccess
;
1215 WCHAR buffer
[MAX_PATH
];
1216 BOOL displayname_exists
= FALSE
;
1218 TRACE("%p %s %s\n", hSCManager
,
1219 debugstr_w(lpServiceName
), debugstr_w(lpDisplayName
));
1221 hscm
= sc_handle_get_handle_data( hSCManager
, SC_HTYPE_MANAGER
);
1224 SetLastError( ERROR_INVALID_HANDLE
);
1228 if (!lpServiceName
|| !lpBinaryPathName
)
1230 SetLastError(ERROR_INVALID_ADDRESS
);
1234 if (!(hscm
->dwAccess
& SC_MANAGER_CREATE_SERVICE
))
1236 SetLastError(ERROR_ACCESS_DENIED
);
1240 if (!lpServiceName
[0])
1242 SetLastError(ERROR_INVALID_NAME
);
1246 if (!lpBinaryPathName
[0])
1248 SetLastError(ERROR_INVALID_PARAMETER
);
1252 /* ServiceType can only be one value (except for SERVICE_INTERACTIVE_PROCESS which can be used
1253 * together with SERVICE_WIN32_OWN_PROCESS or SERVICE_WIN32_SHARE_PROCESS when the service
1254 * runs under the LocalSystem account)
1256 switch (dwServiceType
)
1258 case SERVICE_KERNEL_DRIVER
:
1259 case SERVICE_FILE_SYSTEM_DRIVER
:
1260 case SERVICE_WIN32_OWN_PROCESS
:
1261 case SERVICE_WIN32_SHARE_PROCESS
:
1264 case SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
1265 case SERVICE_WIN32_SHARE_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
1266 /* FIXME : Do we need a more thorough check? */
1267 if (lpServiceStartName
)
1269 SetLastError(ERROR_INVALID_PARAMETER
);
1274 SetLastError(ERROR_INVALID_PARAMETER
);
1278 if (!lpServiceStartName
&& (dwServiceType
& SERVICE_WIN32
))
1279 lpServiceStartName
= szLocalSystem
;
1281 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
1282 if (dwStartType
> SERVICE_DISABLED
)
1284 SetLastError(ERROR_INVALID_PARAMETER
);
1288 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START or only allowed for driver services */
1289 if (((dwStartType
== SERVICE_BOOT_START
) || (dwStartType
== SERVICE_SYSTEM_START
)) &&
1290 ((dwServiceType
& SERVICE_WIN32_OWN_PROCESS
) || (dwServiceType
& SERVICE_WIN32_SHARE_PROCESS
)))
1292 SetLastError(ERROR_INVALID_PARAMETER
);
1296 /* Loop through the registry to check if the service already exists and to
1297 * check if we can use the given displayname.
1298 * FIXME: Should we use EnumServicesStatusEx?
1300 len
= sizeof(buffer
);
1301 while (RegEnumKeyExW(hscm
->hkey
, index
, buffer
, &len
, NULL
, NULL
, NULL
, NULL
) == ERROR_SUCCESS
)
1305 /* Open service first before deciding whether it already exists or not
1306 * It could be that it's not a valid service, but only the registry key itself exists
1308 if (RegOpenKeyExW(hscm
->hkey
, buffer
, 0, KEY_READ
, &service_key
) == ERROR_SUCCESS
)
1310 WCHAR name
[MAX_PATH
];
1311 DWORD size
= sizeof(name
);
1313 if (RegQueryValueExW(service_key
, szDisplayName
, NULL
, NULL
, (LPBYTE
)name
, &size
) == ERROR_SUCCESS
)
1315 if (lpDisplayName
&& (!lstrcmpiW(lpDisplayName
, name
)
1316 || !lstrcmpiW(lpDisplayName
, buffer
)))
1317 displayname_exists
= TRUE
;
1319 if (!lstrcmpiW(lpServiceName
, buffer
))
1321 RegCloseKey(service_key
);
1322 SetLastError(ERROR_SERVICE_EXISTS
);
1326 RegCloseKey(service_key
);
1329 len
= sizeof(buffer
);
1332 if (displayname_exists
)
1334 SetLastError(ERROR_DUPLICATE_SERVICE_NAME
);
1338 r
= RegCreateKeyExW(hscm
->hkey
, lpServiceName
, 0, NULL
,
1339 REG_OPTION_NON_VOLATILE
, KEY_ALL_ACCESS
, NULL
, &hKey
, &dp
);
1340 if (r
!=ERROR_SUCCESS
)
1342 /* FIXME: Should we set an error? */
1347 service_set_string( &val
[n
++], szDisplayName
, lpDisplayName
);
1349 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
1350 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
1351 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
1353 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
1355 if( lpLoadOrderGroup
)
1356 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
1358 /* FIXME: lpDependencies is used to create both DependOnService and DependOnGroup
1359 * There is no such key as what szDependencies refers to */
1360 if( lpDependencies
)
1361 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
1364 FIXME("Don't know how to add a Password for a service.\n");
1366 if( lpServiceStartName
)
1367 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
1369 r
= service_write_values( hKey
, val
, n
);
1370 if( r
!= ERROR_SUCCESS
)
1373 len
= strlenW(lpServiceName
)+1;
1374 len
= sizeof (struct sc_service
) + len
*sizeof(WCHAR
);
1375 hsvc
= sc_handle_alloc( SC_HTYPE_SERVICE
, len
, sc_handle_destroy_service
);
1378 lstrcpyW( hsvc
->name
, lpServiceName
);
1381 RtlMapGenericMask(&new_mask
, &svc_generic
);
1382 hsvc
->dwAccess
= new_mask
;
1385 hscm
->hdr
.ref_count
++;
1387 return (SC_HANDLE
) &hsvc
->hdr
;
1390 RegCloseKey( hKey
);
1395 /******************************************************************************
1396 * CreateServiceA [ADVAPI32.@]
1399 CreateServiceA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
1400 LPCSTR lpDisplayName
, DWORD dwDesiredAccess
,
1401 DWORD dwServiceType
, DWORD dwStartType
,
1402 DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
1403 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
,
1404 LPCSTR lpDependencies
, LPCSTR lpServiceStartName
,
1407 LPWSTR lpServiceNameW
, lpDisplayNameW
, lpBinaryPathNameW
,
1408 lpLoadOrderGroupW
, lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
;
1411 TRACE("%p %s %s\n", hSCManager
,
1412 debugstr_a(lpServiceName
), debugstr_a(lpDisplayName
));
1414 lpServiceNameW
= SERV_dup( lpServiceName
);
1415 lpDisplayNameW
= SERV_dup( lpDisplayName
);
1416 lpBinaryPathNameW
= SERV_dup( lpBinaryPathName
);
1417 lpLoadOrderGroupW
= SERV_dup( lpLoadOrderGroup
);
1418 lpDependenciesW
= SERV_dupmulti( lpDependencies
);
1419 lpServiceStartNameW
= SERV_dup( lpServiceStartName
);
1420 lpPasswordW
= SERV_dup( lpPassword
);
1422 r
= CreateServiceW( hSCManager
, lpServiceNameW
, lpDisplayNameW
,
1423 dwDesiredAccess
, dwServiceType
, dwStartType
, dwErrorControl
,
1424 lpBinaryPathNameW
, lpLoadOrderGroupW
, lpdwTagId
,
1425 lpDependenciesW
, lpServiceStartNameW
, lpPasswordW
);
1427 HeapFree( GetProcessHeap(), 0, lpServiceNameW
);
1428 HeapFree( GetProcessHeap(), 0, lpDisplayNameW
);
1429 HeapFree( GetProcessHeap(), 0, lpBinaryPathNameW
);
1430 HeapFree( GetProcessHeap(), 0, lpLoadOrderGroupW
);
1431 HeapFree( GetProcessHeap(), 0, lpDependenciesW
);
1432 HeapFree( GetProcessHeap(), 0, lpServiceStartNameW
);
1433 HeapFree( GetProcessHeap(), 0, lpPasswordW
);
1439 /******************************************************************************
1440 * DeleteService [ADVAPI32.@]
1442 * Delete a service from the service control manager database.
1445 * hService [I] Handle of the service to delete
1451 BOOL WINAPI
DeleteService( SC_HANDLE hService
)
1453 struct sc_service
*hsvc
;
1455 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1458 SetLastError( ERROR_INVALID_HANDLE
);
1462 if (!(hsvc
->dwAccess
& DELETE
))
1464 SetLastError(ERROR_ACCESS_DENIED
);
1468 /* Close the key to the service */
1469 RegCloseKey(hsvc
->hkey
);
1471 /* Delete the service under the Service Control Manager key */
1472 RegDeleteTreeW(hsvc
->scm
->hkey
, hsvc
->name
);
1480 /******************************************************************************
1481 * StartServiceA [ADVAPI32.@]
1486 * hService [I] Handle of service
1487 * dwNumServiceArgs [I] Number of arguments
1488 * lpServiceArgVectors [I] Address of array of argument strings
1491 * - NT implements this function using an obscure RPC call.
1492 * - You might need to do a "setenv SystemRoot \\WINNT" in your .cshrc
1493 * to get things like "%SystemRoot%\\System32\\service.exe" to load.
1494 * - This will only work for shared address space. How should the service
1495 * args be transferred when address spaces are separated?
1496 * - Can only start one service at a time.
1497 * - Has no concept of privilege.
1503 BOOL WINAPI
StartServiceA( SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1504 LPCSTR
*lpServiceArgVectors
)
1506 LPWSTR
*lpwstr
=NULL
;
1510 TRACE("(%p,%d,%p)\n",hService
,dwNumServiceArgs
,lpServiceArgVectors
);
1512 if (dwNumServiceArgs
)
1513 lpwstr
= HeapAlloc( GetProcessHeap(), 0,
1514 dwNumServiceArgs
*sizeof(LPWSTR
) );
1516 for(i
=0; i
<dwNumServiceArgs
; i
++)
1517 lpwstr
[i
]=SERV_dup(lpServiceArgVectors
[i
]);
1519 r
= StartServiceW(hService
, dwNumServiceArgs
, (LPCWSTR
*)lpwstr
);
1521 if (dwNumServiceArgs
)
1523 for(i
=0; i
<dwNumServiceArgs
; i
++)
1524 HeapFree(GetProcessHeap(), 0, lpwstr
[i
]);
1525 HeapFree(GetProcessHeap(), 0, lpwstr
);
1531 /******************************************************************************
1532 * service_start_process [INTERNAL]
1534 static DWORD
service_start_process(struct sc_service
*hsvc
, LPDWORD ppid
)
1536 static const WCHAR _ImagePathW
[] = {'I','m','a','g','e','P','a','t','h',0};
1537 PROCESS_INFORMATION pi
;
1539 LPWSTR path
= NULL
, str
;
1540 DWORD type
, size
, ret
, svc_type
;
1544 size
= sizeof(svc_type
);
1545 if (RegQueryValueExW(hsvc
->hkey
, szType
, NULL
, &type
, (LPBYTE
)&svc_type
, &size
) || type
!= REG_DWORD
)
1548 if (svc_type
== SERVICE_KERNEL_DRIVER
)
1550 static const WCHAR winedeviceW
[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ',0};
1551 DWORD len
= GetSystemDirectoryW( NULL
, 0 ) + sizeof(winedeviceW
)/sizeof(WCHAR
) + strlenW(hsvc
->name
);
1553 if (!(path
= HeapAlloc( GetProcessHeap(), 0, len
* sizeof(WCHAR
) ))) return FALSE
;
1554 GetSystemDirectoryW( path
, len
);
1555 lstrcatW( path
, winedeviceW
);
1556 lstrcatW( path
, hsvc
->name
);
1560 /* read the executable path from the registry */
1562 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, NULL
, &size
);
1563 if (ret
!=ERROR_SUCCESS
)
1565 str
= HeapAlloc(GetProcessHeap(),0,size
);
1566 ret
= RegQueryValueExW(hsvc
->hkey
, _ImagePathW
, NULL
, &type
, (LPBYTE
)str
, &size
);
1567 if (ret
==ERROR_SUCCESS
)
1569 size
= ExpandEnvironmentStringsW(str
,NULL
,0);
1570 path
= HeapAlloc(GetProcessHeap(),0,size
*sizeof(WCHAR
));
1571 ExpandEnvironmentStringsW(str
,path
,size
);
1573 HeapFree(GetProcessHeap(),0,str
);
1578 /* wait for the process to start and set an event or terminate */
1579 handles
[0] = service_get_event_handle( hsvc
->name
);
1580 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1581 si
.cb
= sizeof(STARTUPINFOW
);
1582 if (!(svc_type
& SERVICE_INTERACTIVE_PROCESS
))
1584 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};
1585 si
.lpDesktop
= desktopW
;
1588 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, 0, NULL
, NULL
, &si
, &pi
);
1591 if (ppid
) *ppid
= pi
.dwProcessId
;
1593 handles
[1] = pi
.hProcess
;
1594 ret
= WaitForMultipleObjectsEx(2, handles
, FALSE
, 30000, FALSE
);
1595 if(ret
!= WAIT_OBJECT_0
)
1597 SetLastError(ERROR_IO_PENDING
);
1601 CloseHandle( pi
.hThread
);
1602 CloseHandle( pi
.hProcess
);
1604 CloseHandle( handles
[0] );
1605 HeapFree(GetProcessHeap(),0,path
);
1609 static BOOL
service_wait_for_startup(SC_HANDLE hService
)
1612 SERVICE_STATUS status
;
1615 TRACE("%p\n", hService
);
1617 for (i
=0; i
<20; i
++)
1619 status
.dwCurrentState
= 0;
1620 r
= QueryServiceStatus(hService
, &status
);
1623 if (status
.dwCurrentState
== SERVICE_RUNNING
)
1625 TRACE("Service started successfully\n");
1629 if (status
.dwCurrentState
!= SERVICE_START_PENDING
) break;
1635 /******************************************************************************
1636 * StartServiceW [ADVAPI32.@]
1638 * See StartServiceA.
1640 BOOL WINAPI
StartServiceW(SC_HANDLE hService
, DWORD dwNumServiceArgs
,
1641 LPCWSTR
*lpServiceArgVectors
)
1643 struct sc_service
*hsvc
;
1646 HANDLE handle
= INVALID_HANDLE_VALUE
;
1648 TRACE("%p %d %p\n", hService
, dwNumServiceArgs
, lpServiceArgVectors
);
1650 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1653 SetLastError(ERROR_INVALID_HANDLE
);
1657 hLock
= LockServiceDatabase((SC_HANDLE
)hsvc
->scm
);
1661 handle
= service_open_pipe(hsvc
->name
);
1662 if (handle
==INVALID_HANDLE_VALUE
)
1664 /* start the service process */
1665 if (service_start_process(hsvc
, NULL
))
1666 handle
= service_open_pipe(hsvc
->name
);
1669 if (handle
!= INVALID_HANDLE_VALUE
)
1671 r
= service_send_start_message(handle
, lpServiceArgVectors
, dwNumServiceArgs
);
1672 CloseHandle(handle
);
1675 UnlockServiceDatabase( hLock
);
1677 TRACE("returning %d\n", r
);
1680 service_wait_for_startup(hService
);
1685 /******************************************************************************
1686 * QueryServiceStatus [ADVAPI32.@]
1689 * hService [I] Handle to service to get information about
1690 * lpservicestatus [O] buffer to receive the status information for the service
1693 BOOL WINAPI
QueryServiceStatus(SC_HANDLE hService
,
1694 LPSERVICE_STATUS lpservicestatus
)
1696 SERVICE_STATUS_PROCESS SvcStatusData
;
1699 TRACE("%p %p\n", hService
, lpservicestatus
);
1701 ret
= QueryServiceStatusEx(hService
, SC_STATUS_PROCESS_INFO
, (LPBYTE
)&SvcStatusData
,
1702 sizeof(SERVICE_STATUS_PROCESS
), NULL
);
1703 if (ret
) memcpy(lpservicestatus
, &SvcStatusData
, sizeof(SERVICE_STATUS
)) ;
1708 /******************************************************************************
1709 * QueryServiceStatusEx [ADVAPI32.@]
1711 * Get information about a service.
1714 * hService [I] Handle to service to get information about
1715 * InfoLevel [I] Level of information to get
1716 * lpBuffer [O] Destination for requested information
1717 * cbBufSize [I] Size of lpBuffer in bytes
1718 * pcbBytesNeeded [O] Destination for number of bytes needed, if cbBufSize is too small
1724 BOOL WINAPI
QueryServiceStatusEx(SC_HANDLE hService
, SC_STATUS_TYPE InfoLevel
,
1725 LPBYTE lpBuffer
, DWORD cbBufSize
,
1726 LPDWORD pcbBytesNeeded
)
1728 struct sc_service
*hsvc
;
1729 DWORD size
, type
, val
;
1732 LPSERVICE_STATUS_PROCESS pSvcStatusData
;
1734 TRACE("%p %d %p %d %p\n", hService
, InfoLevel
, lpBuffer
, cbBufSize
, pcbBytesNeeded
);
1736 if (InfoLevel
!= SC_STATUS_PROCESS_INFO
)
1738 SetLastError( ERROR_INVALID_LEVEL
);
1742 pSvcStatusData
= (LPSERVICE_STATUS_PROCESS
) lpBuffer
;
1743 if (pSvcStatusData
== NULL
)
1745 SetLastError( ERROR_INVALID_PARAMETER
);
1749 if (cbBufSize
< sizeof(SERVICE_STATUS_PROCESS
))
1751 if( pcbBytesNeeded
!= NULL
)
1752 *pcbBytesNeeded
= sizeof(SERVICE_STATUS_PROCESS
);
1754 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1758 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1761 SetLastError( ERROR_INVALID_HANDLE
);
1765 pipe
= service_open_pipe(hsvc
->name
);
1766 if (pipe
!= INVALID_HANDLE_VALUE
)
1768 r
= service_get_status(pipe
, pSvcStatusData
);
1774 TRACE("Failed to read service status\n");
1776 /* read the service type from the registry */
1778 r
= RegQueryValueExA(hsvc
->hkey
, "Type", NULL
, &type
, (LPBYTE
)&val
, &size
);
1779 if (r
!= ERROR_SUCCESS
|| type
!= REG_DWORD
)
1782 pSvcStatusData
->dwServiceType
= val
;
1783 pSvcStatusData
->dwCurrentState
= SERVICE_STOPPED
; /* stopped */
1784 pSvcStatusData
->dwControlsAccepted
= 0;
1785 pSvcStatusData
->dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
1786 pSvcStatusData
->dwServiceSpecificExitCode
= 0;
1787 pSvcStatusData
->dwCheckPoint
= 0;
1788 pSvcStatusData
->dwWaitHint
= 0;
1793 /******************************************************************************
1794 * QueryServiceConfigA [ADVAPI32.@]
1796 BOOL WINAPI
QueryServiceConfigA( SC_HANDLE hService
, LPQUERY_SERVICE_CONFIGA config
,
1797 DWORD size
, LPDWORD needed
)
1802 QUERY_SERVICE_CONFIGW
*configW
;
1804 TRACE("%p %p %d %p\n", hService
, config
, size
, needed
);
1806 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, 2 * size
)))
1808 SetLastError( ERROR_NOT_ENOUGH_MEMORY
);
1811 configW
= (QUERY_SERVICE_CONFIGW
*)buffer
;
1812 ret
= QueryServiceConfigW( hService
, configW
, 2 * size
, needed
);
1813 if (!ret
) goto done
;
1815 config
->dwServiceType
= configW
->dwServiceType
;
1816 config
->dwStartType
= configW
->dwStartType
;
1817 config
->dwErrorControl
= configW
->dwErrorControl
;
1818 config
->lpBinaryPathName
= NULL
;
1819 config
->lpLoadOrderGroup
= NULL
;
1820 config
->dwTagId
= configW
->dwTagId
;
1821 config
->lpDependencies
= NULL
;
1822 config
->lpServiceStartName
= NULL
;
1823 config
->lpDisplayName
= NULL
;
1825 p
= (LPSTR
)(config
+ 1);
1826 n
= size
- sizeof(*config
);
1829 #define MAP_STR(str) \
1833 DWORD sz = WideCharToMultiByte( CP_ACP, 0, configW->str, -1, p, n, NULL, NULL ); \
1834 if (!sz) goto done; \
1841 MAP_STR( lpBinaryPathName
);
1842 MAP_STR( lpLoadOrderGroup
);
1843 MAP_STR( lpDependencies
);
1844 MAP_STR( lpServiceStartName
);
1845 MAP_STR( lpDisplayName
);
1848 *needed
= p
- (LPSTR
)config
;
1852 HeapFree( GetProcessHeap(), 0, buffer
);
1856 /******************************************************************************
1857 * QueryServiceConfigW [ADVAPI32.@]
1860 QueryServiceConfigW( SC_HANDLE hService
,
1861 LPQUERY_SERVICE_CONFIGW lpServiceConfig
,
1862 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
1864 WCHAR str_buffer
[ MAX_PATH
];
1866 DWORD type
, val
, sz
, total
, n
;
1869 struct sc_service
*hsvc
;
1871 TRACE("%p %p %d %p\n", hService
, lpServiceConfig
,
1872 cbBufSize
, pcbBytesNeeded
);
1874 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
1877 SetLastError( ERROR_INVALID_HANDLE
);
1882 /* TODO: Check which members are mandatory and what the registry types
1883 * should be. This should of course also be tested when a service is
1887 /* calculate the size required first */
1888 total
= sizeof (QUERY_SERVICE_CONFIGW
);
1890 sz
= sizeof(str_buffer
);
1891 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1892 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1894 sz
= ExpandEnvironmentStringsW(str_buffer
,NULL
,0);
1895 if( 0 == sz
) return FALSE
;
1897 total
+= sizeof(WCHAR
) * sz
;
1901 /* FIXME: set last error */
1906 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, NULL
, &sz
);
1907 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1910 total
+= sizeof(WCHAR
);
1913 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, NULL
, &sz
);
1914 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_MULTI_SZ
) )
1917 total
+= sizeof(WCHAR
);
1920 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, NULL
, &sz
);
1921 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1924 total
+= sizeof(WCHAR
);
1927 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, NULL
, &sz
);
1928 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
1931 total
+= sizeof(WCHAR
);
1933 *pcbBytesNeeded
= total
;
1935 /* if there's not enough memory, return an error */
1936 if( total
> cbBufSize
)
1938 SetLastError( ERROR_INSUFFICIENT_BUFFER
);
1942 ZeroMemory( lpServiceConfig
, total
);
1945 r
= RegQueryValueExW( hKey
, szType
, 0, &type
, (LPBYTE
)&val
, &sz
);
1946 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1947 lpServiceConfig
->dwServiceType
= val
;
1950 r
= RegQueryValueExW( hKey
, szStart
, 0, &type
, (LPBYTE
)&val
, &sz
);
1951 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1952 lpServiceConfig
->dwStartType
= val
;
1955 r
= RegQueryValueExW( hKey
, szError
, 0, &type
, (LPBYTE
)&val
, &sz
);
1956 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1957 lpServiceConfig
->dwErrorControl
= val
;
1960 r
= RegQueryValueExW( hKey
, szTag
, 0, &type
, (LPBYTE
)&val
, &sz
);
1961 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_DWORD
) )
1962 lpServiceConfig
->dwTagId
= val
;
1964 /* now do the strings */
1965 p
= (LPBYTE
) &lpServiceConfig
[1];
1966 n
= total
- sizeof (QUERY_SERVICE_CONFIGW
);
1968 sz
= sizeof(str_buffer
);
1969 r
= RegQueryValueExW( hKey
, szImagePath
, 0, &type
, (LPBYTE
) str_buffer
, &sz
);
1970 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
|| type
== REG_EXPAND_SZ
) )
1972 sz
= ExpandEnvironmentStringsW(str_buffer
, (LPWSTR
) p
, n
);
1973 sz
*= sizeof(WCHAR
);
1974 if( 0 == sz
|| sz
> n
) return FALSE
;
1976 lpServiceConfig
->lpBinaryPathName
= (LPWSTR
) p
;
1982 /* FIXME: set last error */
1987 r
= RegQueryValueExW( hKey
, szGroup
, 0, &type
, p
, &sz
);
1988 lpServiceConfig
->lpLoadOrderGroup
= (LPWSTR
) p
;
1989 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2002 r
= RegQueryValueExW( hKey
, szDependencies
, 0, &type
, p
, &sz
);
2003 lpServiceConfig
->lpDependencies
= (LPWSTR
) p
;
2004 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2017 r
= RegQueryValueExW( hKey
, szObjectName
, 0, &type
, p
, &sz
);
2018 lpServiceConfig
->lpServiceStartName
= (LPWSTR
) p
;
2019 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2032 r
= RegQueryValueExW( hKey
, szDisplayName
, 0, &type
, p
, &sz
);
2033 lpServiceConfig
->lpDisplayName
= (LPWSTR
) p
;
2034 if( ( r
== ERROR_SUCCESS
) && ( type
== REG_SZ
) )
2046 TRACE("Image path = %s\n", debugstr_w(lpServiceConfig
->lpBinaryPathName
) );
2047 TRACE("Group = %s\n", debugstr_w(lpServiceConfig
->lpLoadOrderGroup
) );
2048 TRACE("Dependencies = %s\n", debugstr_w(lpServiceConfig
->lpDependencies
) );
2049 TRACE("Service account name = %s\n", debugstr_w(lpServiceConfig
->lpServiceStartName
) );
2050 TRACE("Display name = %s\n", debugstr_w(lpServiceConfig
->lpDisplayName
) );
2055 /******************************************************************************
2056 * EnumServicesStatusA [ADVAPI32.@]
2059 EnumServicesStatusA( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2060 DWORD dwServiceState
, LPENUM_SERVICE_STATUSA lpServices
,
2061 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2062 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2064 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2065 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2066 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2067 SetLastError (ERROR_ACCESS_DENIED
);
2071 /******************************************************************************
2072 * EnumServicesStatusW [ADVAPI32.@]
2075 EnumServicesStatusW( SC_HANDLE hSCManager
, DWORD dwServiceType
,
2076 DWORD dwServiceState
, LPENUM_SERVICE_STATUSW lpServices
,
2077 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2078 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
)
2080 FIXME("%p type=%x state=%x %p %x %p %p %p\n", hSCManager
,
2081 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2082 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
);
2083 SetLastError (ERROR_ACCESS_DENIED
);
2087 /******************************************************************************
2088 * EnumServicesStatusExA [ADVAPI32.@]
2091 EnumServicesStatusExA(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2092 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2093 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCSTR pszGroupName
)
2095 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2096 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2097 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_a(pszGroupName
));
2098 *lpServicesReturned
= 0;
2099 SetLastError (ERROR_ACCESS_DENIED
);
2103 /******************************************************************************
2104 * EnumServicesStatusExW [ADVAPI32.@]
2107 EnumServicesStatusExW(SC_HANDLE hSCManager
, SC_ENUM_TYPE InfoLevel
, DWORD dwServiceType
,
2108 DWORD dwServiceState
, LPBYTE lpServices
, DWORD cbBufSize
, LPDWORD pcbBytesNeeded
,
2109 LPDWORD lpServicesReturned
, LPDWORD lpResumeHandle
, LPCWSTR pszGroupName
)
2111 FIXME("%p level=%d type=%x state=%x %p %x %p %p %p %s\n", hSCManager
, InfoLevel
,
2112 dwServiceType
, dwServiceState
, lpServices
, cbBufSize
,
2113 pcbBytesNeeded
, lpServicesReturned
, lpResumeHandle
, debugstr_w(pszGroupName
));
2114 SetLastError (ERROR_ACCESS_DENIED
);
2118 /******************************************************************************
2119 * GetServiceKeyNameA [ADVAPI32.@]
2121 BOOL WINAPI
GetServiceKeyNameA( SC_HANDLE hSCManager
, LPCSTR lpDisplayName
,
2122 LPSTR lpServiceName
, LPDWORD lpcchBuffer
)
2124 FIXME("%p %s %p %p\n", hSCManager
, debugstr_a(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2128 /******************************************************************************
2129 * GetServiceKeyNameW [ADVAPI32.@]
2131 BOOL WINAPI
GetServiceKeyNameW( SC_HANDLE hSCManager
, LPCWSTR lpDisplayName
,
2132 LPWSTR lpServiceName
, LPDWORD lpcchBuffer
)
2134 FIXME("%p %s %p %p\n", hSCManager
, debugstr_w(lpDisplayName
), lpServiceName
, lpcchBuffer
);
2138 /******************************************************************************
2139 * QueryServiceLockStatusA [ADVAPI32.@]
2141 BOOL WINAPI
QueryServiceLockStatusA( SC_HANDLE hSCManager
,
2142 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus
,
2143 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2145 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2150 /******************************************************************************
2151 * QueryServiceLockStatusW [ADVAPI32.@]
2153 BOOL WINAPI
QueryServiceLockStatusW( SC_HANDLE hSCManager
,
2154 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus
,
2155 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2157 FIXME("%p %p %08x %p\n", hSCManager
, lpLockStatus
, cbBufSize
, pcbBytesNeeded
);
2162 /******************************************************************************
2163 * GetServiceDisplayNameA [ADVAPI32.@]
2165 BOOL WINAPI
GetServiceDisplayNameA( SC_HANDLE hSCManager
, LPCSTR lpServiceName
,
2166 LPSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2168 LPWSTR lpServiceNameW
, lpDisplayNameW
;
2172 TRACE("%p %s %p %p\n", hSCManager
,
2173 debugstr_a(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2175 lpServiceNameW
= SERV_dup(lpServiceName
);
2177 lpDisplayNameW
= HeapAlloc(GetProcessHeap(), 0, *lpcchBuffer
* sizeof(WCHAR
));
2179 lpDisplayNameW
= NULL
;
2181 sizeW
= *lpcchBuffer
;
2182 if (!GetServiceDisplayNameW(hSCManager
, lpServiceNameW
, lpDisplayNameW
, &sizeW
))
2184 *lpcchBuffer
= sizeW
*2; /* we can only provide an upper estimation of string length */
2188 if (!WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, (sizeW
+ 1), lpDisplayName
,
2189 *lpcchBuffer
, NULL
, NULL
))
2191 *lpcchBuffer
= WideCharToMultiByte(CP_ACP
, 0, lpDisplayNameW
, -1, NULL
, 0, NULL
, NULL
);
2195 /* probably due to a bug GetServiceDisplayNameA doesn't modify lpcchBuffer on success.
2196 * (but if the function succeeded it means that is a good upper estimation of the size) */
2200 HeapFree(GetProcessHeap(), 0, lpDisplayNameW
);
2201 HeapFree(GetProcessHeap(), 0, lpServiceNameW
);
2205 /******************************************************************************
2206 * GetServiceDisplayNameW [ADVAPI32.@]
2208 BOOL WINAPI
GetServiceDisplayNameW( SC_HANDLE hSCManager
, LPCWSTR lpServiceName
,
2209 LPWSTR lpDisplayName
, LPDWORD lpcchBuffer
)
2211 struct sc_manager
*hscm
;
2215 TRACE("%p %s %p %p\n", hSCManager
,
2216 debugstr_w(lpServiceName
), lpDisplayName
, lpcchBuffer
);
2218 hscm
= sc_handle_get_handle_data(hSCManager
, SC_HTYPE_MANAGER
);
2221 SetLastError(ERROR_INVALID_HANDLE
);
2227 SetLastError(ERROR_INVALID_ADDRESS
);
2231 size
= *lpcchBuffer
* sizeof(WCHAR
);
2232 ret
= RegGetValueW(hscm
->hkey
, lpServiceName
, szDisplayName
, RRF_RT_REG_SZ
, &type
, lpDisplayName
, &size
);
2233 if (!ret
&& !lpDisplayName
&& size
)
2234 ret
= ERROR_MORE_DATA
;
2238 if (lpDisplayName
&& *lpcchBuffer
) *lpDisplayName
= 0;
2240 if (ret
== ERROR_MORE_DATA
)
2242 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2243 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2245 else if (ret
== ERROR_FILE_NOT_FOUND
)
2249 if (!RegOpenKeyW(hscm
->hkey
, lpServiceName
, &hkey
))
2251 UINT len
= lstrlenW(lpServiceName
);
2254 if ((*lpcchBuffer
<= len
) || (!lpDisplayName
&& *lpcchBuffer
))
2255 SetLastError(ERROR_INSUFFICIENT_BUFFER
);
2256 else if (lpDisplayName
&& *lpcchBuffer
)
2258 /* No displayname, but the service exists and the buffer
2259 * is big enough. We should return the servicename.
2261 lstrcpyW(lpDisplayName
, lpServiceName
);
2270 SetLastError(ERROR_SERVICE_DOES_NOT_EXIST
);
2277 /* Always return the correct needed size on success */
2278 *lpcchBuffer
= (size
/ sizeof(WCHAR
)) - 1;
2283 /******************************************************************************
2284 * ChangeServiceConfigW [ADVAPI32.@]
2286 BOOL WINAPI
ChangeServiceConfigW( SC_HANDLE hService
, DWORD dwServiceType
,
2287 DWORD dwStartType
, DWORD dwErrorControl
, LPCWSTR lpBinaryPathName
,
2288 LPCWSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCWSTR lpDependencies
,
2289 LPCWSTR lpServiceStartName
, LPCWSTR lpPassword
, LPCWSTR lpDisplayName
)
2291 struct reg_value val
[10];
2292 struct sc_service
*hsvc
;
2293 DWORD r
= ERROR_SUCCESS
;
2297 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2298 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2299 debugstr_w(lpBinaryPathName
), debugstr_w(lpLoadOrderGroup
),
2300 lpdwTagId
, lpDependencies
, debugstr_w(lpServiceStartName
),
2301 debugstr_w(lpPassword
), debugstr_w(lpDisplayName
) );
2303 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2306 SetLastError( ERROR_INVALID_HANDLE
);
2311 if( dwServiceType
!= SERVICE_NO_CHANGE
)
2312 service_set_dword( &val
[n
++], szType
, &dwServiceType
);
2314 if( dwStartType
!= SERVICE_NO_CHANGE
)
2315 service_set_dword( &val
[n
++], szStart
, &dwStartType
);
2317 if( dwErrorControl
!= SERVICE_NO_CHANGE
)
2318 service_set_dword( &val
[n
++], szError
, &dwErrorControl
);
2320 if( lpBinaryPathName
)
2321 service_set_string( &val
[n
++], szImagePath
, lpBinaryPathName
);
2323 if( lpLoadOrderGroup
)
2324 service_set_string( &val
[n
++], szGroup
, lpLoadOrderGroup
);
2326 /* FIXME: lpDependencies is used to create/change both DependOnService and DependOnGroup
2327 * There is no such key as what szDependencies refers to */
2328 if( lpDependencies
)
2329 service_set_multi_string( &val
[n
++], szDependencies
, lpDependencies
);
2332 FIXME("ignoring password\n");
2334 if( lpServiceStartName
)
2335 service_set_string( &val
[n
++], szObjectName
, lpServiceStartName
);
2337 r
= service_write_values( hsvc
->hkey
, val
, n
);
2339 return (r
== ERROR_SUCCESS
) ? TRUE
: FALSE
;
2342 /******************************************************************************
2343 * ChangeServiceConfigA [ADVAPI32.@]
2345 BOOL WINAPI
ChangeServiceConfigA( SC_HANDLE hService
, DWORD dwServiceType
,
2346 DWORD dwStartType
, DWORD dwErrorControl
, LPCSTR lpBinaryPathName
,
2347 LPCSTR lpLoadOrderGroup
, LPDWORD lpdwTagId
, LPCSTR lpDependencies
,
2348 LPCSTR lpServiceStartName
, LPCSTR lpPassword
, LPCSTR lpDisplayName
)
2350 LPWSTR wBinaryPathName
, wLoadOrderGroup
, wDependencies
;
2351 LPWSTR wServiceStartName
, wPassword
, wDisplayName
;
2354 TRACE("%p %d %d %d %s %s %p %p %s %s %s\n",
2355 hService
, dwServiceType
, dwStartType
, dwErrorControl
,
2356 debugstr_a(lpBinaryPathName
), debugstr_a(lpLoadOrderGroup
),
2357 lpdwTagId
, lpDependencies
, debugstr_a(lpServiceStartName
),
2358 debugstr_a(lpPassword
), debugstr_a(lpDisplayName
) );
2360 wBinaryPathName
= SERV_dup( lpBinaryPathName
);
2361 wLoadOrderGroup
= SERV_dup( lpLoadOrderGroup
);
2362 wDependencies
= SERV_dupmulti( lpDependencies
);
2363 wServiceStartName
= SERV_dup( lpServiceStartName
);
2364 wPassword
= SERV_dup( lpPassword
);
2365 wDisplayName
= SERV_dup( lpDisplayName
);
2367 r
= ChangeServiceConfigW( hService
, dwServiceType
,
2368 dwStartType
, dwErrorControl
, wBinaryPathName
,
2369 wLoadOrderGroup
, lpdwTagId
, wDependencies
,
2370 wServiceStartName
, wPassword
, wDisplayName
);
2372 HeapFree( GetProcessHeap(), 0, wBinaryPathName
);
2373 HeapFree( GetProcessHeap(), 0, wLoadOrderGroup
);
2374 HeapFree( GetProcessHeap(), 0, wDependencies
);
2375 HeapFree( GetProcessHeap(), 0, wServiceStartName
);
2376 HeapFree( GetProcessHeap(), 0, wPassword
);
2377 HeapFree( GetProcessHeap(), 0, wDisplayName
);
2382 /******************************************************************************
2383 * ChangeServiceConfig2A [ADVAPI32.@]
2385 BOOL WINAPI
ChangeServiceConfig2A( SC_HANDLE hService
, DWORD dwInfoLevel
,
2390 TRACE("%p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2392 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2394 LPSERVICE_DESCRIPTIONA sd
= (LPSERVICE_DESCRIPTIONA
) lpInfo
;
2395 SERVICE_DESCRIPTIONW sdw
;
2397 sdw
.lpDescription
= SERV_dup( sd
->lpDescription
);
2399 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &sdw
);
2401 HeapFree( GetProcessHeap(), 0, sdw
.lpDescription
);
2403 else if (dwInfoLevel
== SERVICE_CONFIG_FAILURE_ACTIONS
)
2405 LPSERVICE_FAILURE_ACTIONSA fa
= (LPSERVICE_FAILURE_ACTIONSA
) lpInfo
;
2406 SERVICE_FAILURE_ACTIONSW faw
;
2408 faw
.dwResetPeriod
= fa
->dwResetPeriod
;
2409 faw
.lpRebootMsg
= SERV_dup( fa
->lpRebootMsg
);
2410 faw
.lpCommand
= SERV_dup( fa
->lpCommand
);
2411 faw
.cActions
= fa
->cActions
;
2412 faw
.lpsaActions
= fa
->lpsaActions
;
2414 r
= ChangeServiceConfig2W( hService
, dwInfoLevel
, &faw
);
2416 HeapFree( GetProcessHeap(), 0, faw
.lpRebootMsg
);
2417 HeapFree( GetProcessHeap(), 0, faw
.lpCommand
);
2420 SetLastError( ERROR_INVALID_PARAMETER
);
2425 /******************************************************************************
2426 * ChangeServiceConfig2W [ADVAPI32.@]
2428 BOOL WINAPI
ChangeServiceConfig2W( SC_HANDLE hService
, DWORD dwInfoLevel
,
2432 struct sc_service
*hsvc
;
2434 hsvc
= sc_handle_get_handle_data(hService
, SC_HTYPE_SERVICE
);
2437 SetLastError( ERROR_INVALID_HANDLE
);
2442 if (dwInfoLevel
== SERVICE_CONFIG_DESCRIPTION
)
2444 static const WCHAR szDescription
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
2445 LPSERVICE_DESCRIPTIONW sd
= (LPSERVICE_DESCRIPTIONW
)lpInfo
;
2446 if (sd
->lpDescription
)
2448 TRACE("Setting Description to %s\n",debugstr_w(sd
->lpDescription
));
2449 if (sd
->lpDescription
[0] == 0)
2450 RegDeleteValueW(hKey
,szDescription
);
2452 RegSetValueExW(hKey
, szDescription
, 0, REG_SZ
,
2453 (LPVOID
)sd
->lpDescription
,
2454 sizeof(WCHAR
)*(strlenW(sd
->lpDescription
)+1));
2458 FIXME("STUB: %p %d %p\n",hService
, dwInfoLevel
, lpInfo
);
2462 /******************************************************************************
2463 * QueryServiceObjectSecurity [ADVAPI32.@]
2465 BOOL WINAPI
QueryServiceObjectSecurity(SC_HANDLE hService
,
2466 SECURITY_INFORMATION dwSecurityInformation
,
2467 PSECURITY_DESCRIPTOR lpSecurityDescriptor
,
2468 DWORD cbBufSize
, LPDWORD pcbBytesNeeded
)
2470 SECURITY_DESCRIPTOR descriptor
;
2475 FIXME("%p %d %p %u %p - semi-stub\n", hService
, dwSecurityInformation
,
2476 lpSecurityDescriptor
, cbBufSize
, pcbBytesNeeded
);
2478 if (dwSecurityInformation
!= DACL_SECURITY_INFORMATION
)
2479 FIXME("information %d not supported\n", dwSecurityInformation
);
2481 InitializeSecurityDescriptor(&descriptor
, SECURITY_DESCRIPTOR_REVISION
);
2483 InitializeAcl(&acl
, sizeof(ACL
), ACL_REVISION
);
2484 SetSecurityDescriptorDacl(&descriptor
, TRUE
, &acl
, TRUE
);
2487 succ
= MakeSelfRelativeSD(&descriptor
, lpSecurityDescriptor
, &size
);
2488 *pcbBytesNeeded
= size
;
2492 /******************************************************************************
2493 * SetServiceObjectSecurity [ADVAPI32.@]
2495 BOOL WINAPI
SetServiceObjectSecurity(SC_HANDLE hService
,
2496 SECURITY_INFORMATION dwSecurityInformation
,
2497 PSECURITY_DESCRIPTOR lpSecurityDescriptor
)
2499 FIXME("%p %d %p\n", hService
, dwSecurityInformation
, lpSecurityDescriptor
);
2503 /******************************************************************************
2504 * SetServiceBits [ADVAPI32.@]
2506 BOOL WINAPI
SetServiceBits( SERVICE_STATUS_HANDLE hServiceStatus
,
2507 DWORD dwServiceBits
,
2509 BOOL bUpdateImmediately
)
2511 FIXME("%p %08x %x %x\n", hServiceStatus
, dwServiceBits
,
2512 bSetBitsOn
, bUpdateImmediately
);
2516 /* thunk for calling the RegisterServiceCtrlHandler handler function */
2517 static DWORD WINAPI
ctrl_handler_thunk( DWORD control
, DWORD type
, void *data
, void *context
)
2519 LPHANDLER_FUNCTION func
= context
;
2522 return ERROR_SUCCESS
;
2525 /******************************************************************************
2526 * RegisterServiceCtrlHandlerA [ADVAPI32.@]
2528 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerA( LPCSTR name
, LPHANDLER_FUNCTION handler
)
2530 return RegisterServiceCtrlHandlerExA( name
, ctrl_handler_thunk
, handler
);
2533 /******************************************************************************
2534 * RegisterServiceCtrlHandlerW [ADVAPI32.@]
2536 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerW( LPCWSTR name
, LPHANDLER_FUNCTION handler
)
2538 return RegisterServiceCtrlHandlerExW( name
, ctrl_handler_thunk
, handler
);
2541 /******************************************************************************
2542 * RegisterServiceCtrlHandlerExA [ADVAPI32.@]
2544 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExA( LPCSTR name
, LPHANDLER_FUNCTION_EX handler
, LPVOID context
)
2547 SERVICE_STATUS_HANDLE ret
;
2549 nameW
= SERV_dup(name
);
2550 ret
= RegisterServiceCtrlHandlerExW( nameW
, handler
, context
);
2551 HeapFree( GetProcessHeap(), 0, nameW
);
2555 /******************************************************************************
2556 * RegisterServiceCtrlHandlerExW [ADVAPI32.@]
2558 SERVICE_STATUS_HANDLE WINAPI
RegisterServiceCtrlHandlerExW( LPCWSTR lpServiceName
,
2559 LPHANDLER_FUNCTION_EX lpHandlerProc
, LPVOID lpContext
)
2561 SERVICE_STATUS_HANDLE handle
= 0;
2564 TRACE("%s %p %p\n", debugstr_w(lpServiceName
), lpHandlerProc
, lpContext
);
2566 EnterCriticalSection( &service_cs
);
2567 for (i
= 0; i
< nb_services
; i
++)
2569 if(!strcmpW(lpServiceName
, services
[i
]->name
))
2571 services
[i
]->handler
= lpHandlerProc
;
2572 services
[i
]->context
= lpContext
;
2573 handle
= ULongToHandle( i
+ 1 );
2577 LeaveCriticalSection( &service_cs
);
2582 /******************************************************************************
2583 * EnumDependentServicesA [ADVAPI32.@]
2585 BOOL WINAPI
EnumDependentServicesA( SC_HANDLE hService
, DWORD dwServiceState
,
2586 LPENUM_SERVICE_STATUSA lpServices
, DWORD cbBufSize
,
2587 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2589 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2590 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2592 *lpServicesReturned
= 0;
2596 /******************************************************************************
2597 * EnumDependentServicesW [ADVAPI32.@]
2599 BOOL WINAPI
EnumDependentServicesW( SC_HANDLE hService
, DWORD dwServiceState
,
2600 LPENUM_SERVICE_STATUSW lpServices
, DWORD cbBufSize
,
2601 LPDWORD pcbBytesNeeded
, LPDWORD lpServicesReturned
)
2603 FIXME("%p 0x%08x %p 0x%08x %p %p - stub\n", hService
, dwServiceState
,
2604 lpServices
, cbBufSize
, pcbBytesNeeded
, lpServicesReturned
);
2606 *lpServicesReturned
= 0;