2 * Services - controls services keeps track of their state
4 * Copyright 2007 Google (Mikolaj Zalewski)
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #define WIN32_LEAN_AND_MEAN
33 #include "wine/debug.h"
34 #include "wine/heap.h"
39 #define MAX_SERVICE_NAME 260
41 WINE_DEFAULT_DEBUG_CHANNEL(service
);
43 struct scmdatabase
*active_database
;
45 DWORD service_pipe_timeout
= 10000;
46 DWORD service_kill_timeout
= 60000;
47 static DWORD default_preshutdown_timeout
= 180000;
48 static DWORD autostart_delay
= 120000;
49 static void *environment
= NULL
;
50 static HKEY service_current_key
= NULL
;
52 static const BOOL is_win64
= (sizeof(void *) > sizeof(int));
54 static const WCHAR SZ_LOCAL_SYSTEM
[] = {'L','o','c','a','l','S','y','s','t','e','m',0};
56 /* Registry constants */
57 static const WCHAR SZ_SERVICES_KEY
[] = { 'S','y','s','t','e','m','\\',
58 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
59 'S','e','r','v','i','c','e','s',0 };
61 /* Service key values names */
62 static const WCHAR SZ_DISPLAY_NAME
[] = {'D','i','s','p','l','a','y','N','a','m','e',0 };
63 static const WCHAR SZ_TYPE
[] = {'T','y','p','e',0 };
64 static const WCHAR SZ_START
[] = {'S','t','a','r','t',0 };
65 static const WCHAR SZ_ERROR
[] = {'E','r','r','o','r','C','o','n','t','r','o','l',0 };
66 static const WCHAR SZ_IMAGE_PATH
[] = {'I','m','a','g','e','P','a','t','h',0};
67 static const WCHAR SZ_GROUP
[] = {'G','r','o','u','p',0};
68 static const WCHAR SZ_DEPEND_ON_SERVICE
[] = {'D','e','p','e','n','d','O','n','S','e','r','v','i','c','e',0};
69 static const WCHAR SZ_DEPEND_ON_GROUP
[] = {'D','e','p','e','n','d','O','n','G','r','o','u','p',0};
70 static const WCHAR SZ_OBJECT_NAME
[] = {'O','b','j','e','c','t','N','a','m','e',0};
71 static const WCHAR SZ_TAG
[] = {'T','a','g',0};
72 static const WCHAR SZ_DESCRIPTION
[] = {'D','e','s','c','r','i','p','t','i','o','n',0};
73 static const WCHAR SZ_PRESHUTDOWN
[] = {'P','r','e','s','h','u','t','d','o','w','n','T','i','m','e','o','u','t',0};
74 static const WCHAR SZ_WOW64
[] = {'W','O','W','6','4',0};
75 static const WCHAR SZ_DELAYED_AUTOSTART
[] = {'D','e','l','a','y','e','d','A','u','t','o','S','t','a','r','t',0};
77 static DWORD
process_create(const WCHAR
*name
, struct process_entry
**entry
)
81 *entry
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**entry
));
83 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
84 (*entry
)->ref_count
= 1;
85 (*entry
)->control_mutex
= CreateMutexW(NULL
, TRUE
, NULL
);
86 if (!(*entry
)->control_mutex
)
88 (*entry
)->overlapped_event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
89 if (!(*entry
)->overlapped_event
)
91 (*entry
)->control_pipe
= CreateNamedPipeW(name
, PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
92 PIPE_TYPE_BYTE
|PIPE_WAIT
, 1, 256, 256, 10000, NULL
);
93 if ((*entry
)->control_pipe
== INVALID_HANDLE_VALUE
)
95 /* all other fields are zero */
100 if ((*entry
)->control_mutex
)
101 CloseHandle((*entry
)->control_mutex
);
102 if ((*entry
)->overlapped_event
)
103 CloseHandle((*entry
)->overlapped_event
);
104 HeapFree(GetProcessHeap(), 0, *entry
);
108 static void free_process_entry(struct process_entry
*entry
)
110 CloseHandle(entry
->process
);
111 CloseHandle(entry
->control_mutex
);
112 CloseHandle(entry
->control_pipe
);
113 CloseHandle(entry
->overlapped_event
);
114 HeapFree(GetProcessHeap(), 0, entry
);
117 DWORD
service_create(LPCWSTR name
, struct service_entry
**entry
)
119 *entry
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(**entry
));
121 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
122 (*entry
)->name
= strdupW(name
);
123 list_init(&(*entry
)->handles
);
126 HeapFree(GetProcessHeap(), 0, *entry
);
127 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
129 (*entry
)->status_changed_event
= CreateEventW(NULL
, TRUE
, FALSE
, NULL
);
130 if (!(*entry
)->status_changed_event
)
132 HeapFree(GetProcessHeap(), 0, (*entry
)->name
);
133 HeapFree(GetProcessHeap(), 0, *entry
);
134 return GetLastError();
136 (*entry
)->ref_count
= 1;
137 (*entry
)->status
.dwCurrentState
= SERVICE_STOPPED
;
138 (*entry
)->status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
139 (*entry
)->preshutdown_timeout
= default_preshutdown_timeout
;
140 /* all other fields are zero */
141 return ERROR_SUCCESS
;
144 void free_service_entry(struct service_entry
*entry
)
146 assert(list_empty(&entry
->handles
));
147 CloseHandle(entry
->status_changed_event
);
148 HeapFree(GetProcessHeap(), 0, entry
->name
);
149 HeapFree(GetProcessHeap(), 0, entry
->config
.lpBinaryPathName
);
150 HeapFree(GetProcessHeap(), 0, entry
->config
.lpDependencies
);
151 HeapFree(GetProcessHeap(), 0, entry
->config
.lpLoadOrderGroup
);
152 HeapFree(GetProcessHeap(), 0, entry
->config
.lpServiceStartName
);
153 HeapFree(GetProcessHeap(), 0, entry
->config
.lpDisplayName
);
154 HeapFree(GetProcessHeap(), 0, entry
->description
);
155 HeapFree(GetProcessHeap(), 0, entry
->dependOnServices
);
156 HeapFree(GetProcessHeap(), 0, entry
->dependOnGroups
);
157 if (entry
->process
) release_process(entry
->process
);
158 HeapFree(GetProcessHeap(), 0, entry
);
161 static DWORD
load_service_config(HKEY hKey
, struct service_entry
*entry
)
163 DWORD err
, value
= 0;
166 if ((err
= load_reg_string(hKey
, SZ_IMAGE_PATH
, TRUE
, &entry
->config
.lpBinaryPathName
)) != 0)
168 if ((err
= load_reg_string(hKey
, SZ_GROUP
, 0, &entry
->config
.lpLoadOrderGroup
)) != 0)
170 if ((err
= load_reg_string(hKey
, SZ_OBJECT_NAME
, TRUE
, &entry
->config
.lpServiceStartName
)) != 0)
172 if ((err
= load_reg_string(hKey
, SZ_DISPLAY_NAME
, 0, &entry
->config
.lpDisplayName
)) != 0)
174 if ((err
= load_reg_string(hKey
, SZ_DESCRIPTION
, 0, &entry
->description
)) != 0)
176 if ((err
= load_reg_multisz(hKey
, SZ_DEPEND_ON_SERVICE
, TRUE
, &entry
->dependOnServices
)) != 0)
178 if ((err
= load_reg_multisz(hKey
, SZ_DEPEND_ON_GROUP
, FALSE
, &entry
->dependOnGroups
)) != 0)
181 if ((err
= load_reg_dword(hKey
, SZ_TYPE
, &entry
->config
.dwServiceType
)) != 0)
183 if ((err
= load_reg_dword(hKey
, SZ_START
, &entry
->config
.dwStartType
)) != 0)
185 if ((err
= load_reg_dword(hKey
, SZ_ERROR
, &entry
->config
.dwErrorControl
)) != 0)
187 if ((err
= load_reg_dword(hKey
, SZ_TAG
, &entry
->config
.dwTagId
)) != 0)
189 if ((err
= load_reg_dword(hKey
, SZ_PRESHUTDOWN
, &entry
->preshutdown_timeout
)) != 0)
192 if (load_reg_dword(hKey
, SZ_WOW64
, &value
) == 0 && value
== 1)
193 entry
->is_wow64
= TRUE
;
194 if (load_reg_dword(hKey
, SZ_DELAYED_AUTOSTART
, &value
) == 0 && value
== 1)
195 entry
->delayed_autostart
= TRUE
;
197 WINE_TRACE("Image path = %s\n", wine_dbgstr_w(entry
->config
.lpBinaryPathName
) );
198 WINE_TRACE("Group = %s\n", wine_dbgstr_w(entry
->config
.lpLoadOrderGroup
) );
199 WINE_TRACE("Service account name = %s\n", wine_dbgstr_w(entry
->config
.lpServiceStartName
) );
200 WINE_TRACE("Display name = %s\n", wine_dbgstr_w(entry
->config
.lpDisplayName
) );
201 WINE_TRACE("Service dependencies : %s\n", entry
->dependOnServices
[0] ? "" : "(none)");
202 for (wptr
= entry
->dependOnServices
; *wptr
; wptr
+= lstrlenW(wptr
) + 1)
203 WINE_TRACE(" * %s\n", wine_dbgstr_w(wptr
));
204 WINE_TRACE("Group dependencies : %s\n", entry
->dependOnGroups
[0] ? "" : "(none)");
205 for (wptr
= entry
->dependOnGroups
; *wptr
; wptr
+= lstrlenW(wptr
) + 1)
206 WINE_TRACE(" * %s\n", wine_dbgstr_w(wptr
));
208 return ERROR_SUCCESS
;
211 static DWORD
reg_set_string_value(HKEY hKey
, LPCWSTR value_name
, LPCWSTR string
)
216 err
= RegDeleteValueW(hKey
, value_name
);
217 if (err
!= ERROR_FILE_NOT_FOUND
)
220 return ERROR_SUCCESS
;
223 return RegSetValueExW(hKey
, value_name
, 0, REG_SZ
, (const BYTE
*)string
, sizeof(WCHAR
)*(lstrlenW(string
) + 1));
226 static DWORD
reg_set_multisz_value(HKEY hKey
, LPCWSTR value_name
, LPCWSTR string
)
233 err
= RegDeleteValueW(hKey
, value_name
);
234 if (err
!= ERROR_FILE_NOT_FOUND
)
237 return ERROR_SUCCESS
;
241 while (*ptr
) ptr
+= lstrlenW(ptr
) + 1;
242 return RegSetValueExW(hKey
, value_name
, 0, REG_MULTI_SZ
, (const BYTE
*)string
, sizeof(WCHAR
)*(ptr
- string
+ 1));
245 DWORD
save_service_config(struct service_entry
*entry
)
250 err
= RegCreateKeyW(entry
->db
->root_key
, entry
->name
, &hKey
);
251 if (err
!= ERROR_SUCCESS
)
254 if ((err
= reg_set_string_value(hKey
, SZ_DISPLAY_NAME
, entry
->config
.lpDisplayName
)) != 0)
256 if ((err
= reg_set_string_value(hKey
, SZ_IMAGE_PATH
, entry
->config
.lpBinaryPathName
)) != 0)
258 if ((err
= reg_set_string_value(hKey
, SZ_GROUP
, entry
->config
.lpLoadOrderGroup
)) != 0)
260 if ((err
= reg_set_string_value(hKey
, SZ_OBJECT_NAME
, entry
->config
.lpServiceStartName
)) != 0)
262 if ((err
= reg_set_string_value(hKey
, SZ_DESCRIPTION
, entry
->description
)) != 0)
264 if ((err
= reg_set_multisz_value(hKey
, SZ_DEPEND_ON_SERVICE
, entry
->dependOnServices
)) != 0)
266 if ((err
= reg_set_multisz_value(hKey
, SZ_DEPEND_ON_GROUP
, entry
->dependOnGroups
)) != 0)
268 if ((err
= RegSetValueExW(hKey
, SZ_START
, 0, REG_DWORD
, (LPBYTE
)&entry
->config
.dwStartType
, sizeof(DWORD
))) != 0)
270 if ((err
= RegSetValueExW(hKey
, SZ_ERROR
, 0, REG_DWORD
, (LPBYTE
)&entry
->config
.dwErrorControl
, sizeof(DWORD
))) != 0)
272 if ((err
= RegSetValueExW(hKey
, SZ_TYPE
, 0, REG_DWORD
, (LPBYTE
)&entry
->config
.dwServiceType
, sizeof(DWORD
))) != 0)
274 if ((err
= RegSetValueExW(hKey
, SZ_PRESHUTDOWN
, 0, REG_DWORD
, (LPBYTE
)&entry
->preshutdown_timeout
, sizeof(DWORD
))) != 0)
276 if ((err
= RegSetValueExW(hKey
, SZ_PRESHUTDOWN
, 0, REG_DWORD
, (LPBYTE
)&entry
->preshutdown_timeout
, sizeof(DWORD
))) != 0)
280 const DWORD is_wow64
= 1;
281 if ((err
= RegSetValueExW(hKey
, SZ_WOW64
, 0, REG_DWORD
, (LPBYTE
)&is_wow64
, sizeof(DWORD
))) != 0)
285 if (entry
->config
.dwTagId
)
286 err
= RegSetValueExW(hKey
, SZ_TAG
, 0, REG_DWORD
, (LPBYTE
)&entry
->config
.dwTagId
, sizeof(DWORD
));
288 err
= RegDeleteValueW(hKey
, SZ_TAG
);
290 if (err
!= 0 && err
!= ERROR_FILE_NOT_FOUND
)
299 static void scmdatabase_add_process(struct scmdatabase
*db
, struct process_entry
*process
)
302 list_add_tail(&db
->processes
, &process
->entry
);
305 static void scmdatabase_remove_process(struct scmdatabase
*db
, struct process_entry
*process
)
307 list_remove(&process
->entry
);
308 process
->entry
.next
= process
->entry
.prev
= NULL
;
311 DWORD
scmdatabase_add_service(struct scmdatabase
*db
, struct service_entry
*service
)
315 if ((err
= save_service_config(service
)) != ERROR_SUCCESS
)
317 WINE_ERR("Couldn't store service configuration: error %u\n", err
);
318 return ERROR_GEN_FAILURE
;
321 list_add_tail(&db
->services
, &service
->entry
);
322 return ERROR_SUCCESS
;
325 static void scmdatabase_remove_service(struct scmdatabase
*db
, struct service_entry
*service
)
327 RegDeleteTreeW(db
->root_key
, service
->name
);
328 list_remove(&service
->entry
);
329 service
->entry
.next
= service
->entry
.prev
= NULL
;
332 static int __cdecl
compare_tags(const void *a
, const void *b
)
334 struct service_entry
*service_a
= *(struct service_entry
**)a
;
335 struct service_entry
*service_b
= *(struct service_entry
**)b
;
336 return service_a
->config
.dwTagId
- service_b
->config
.dwTagId
;
339 static PTP_CLEANUP_GROUP delayed_autostart_cleanup
;
341 struct delayed_autostart_params
344 struct service_entry
**services
;
347 static void CALLBACK
delayed_autostart_cancel_callback(void *object
, void *userdata
)
349 struct delayed_autostart_params
*params
= object
;
350 while(params
->count
--)
351 release_service(params
->services
[params
->count
]);
352 heap_free(params
->services
);
356 static void CALLBACK
delayed_autostart_callback(TP_CALLBACK_INSTANCE
*instance
, void *context
,
359 struct delayed_autostart_params
*params
= context
;
360 struct service_entry
*service
;
364 scmdatabase_lock_startup(active_database
, INFINITE
);
366 for (i
= 0; i
< params
->count
; i
++)
368 service
= params
->services
[i
];
369 if (service
->status
.dwCurrentState
== SERVICE_STOPPED
)
371 TRACE("Starting delayed auto-start service %s\n", debugstr_w(service
->name
));
372 err
= service_start(service
, 0, NULL
);
373 if (err
!= ERROR_SUCCESS
)
374 FIXME("Delayed auto-start service %s failed to start: %d\n",
375 wine_dbgstr_w(service
->name
), err
);
377 release_service(service
);
380 scmdatabase_unlock_startup(active_database
);
382 heap_free(params
->services
);
384 CloseThreadpoolTimer(timer
);
387 static BOOL
schedule_delayed_autostart(struct service_entry
**services
, unsigned int count
)
389 struct delayed_autostart_params
*params
;
390 TP_CALLBACK_ENVIRON environment
;
391 LARGE_INTEGER timestamp
;
395 if (!(delayed_autostart_cleanup
= CreateThreadpoolCleanupGroup()))
397 ERR("CreateThreadpoolCleanupGroup failed with error %u\n", GetLastError());
401 if (!(params
= heap_alloc(sizeof(*params
)))) return FALSE
;
402 params
->count
= count
;
403 params
->services
= services
;
405 memset(&environment
, 0, sizeof(environment
));
406 environment
.Version
= 1;
407 environment
.CleanupGroup
= delayed_autostart_cleanup
;
408 environment
.CleanupGroupCancelCallback
= delayed_autostart_cancel_callback
;
410 timestamp
.QuadPart
= (ULONGLONG
)autostart_delay
* -10000;
411 ft
.dwLowDateTime
= timestamp
.u
.LowPart
;
412 ft
.dwHighDateTime
= timestamp
.u
.HighPart
;
414 if (!(timer
= CreateThreadpoolTimer(delayed_autostart_callback
, params
, &environment
)))
416 ERR("CreateThreadpoolWait failed: %u\n", GetLastError());
421 SetThreadpoolTimer(timer
, &ft
, 0, 0);
425 static BOOL
is_root_pnp_service(HDEVINFO set
, const struct service_entry
*service
)
427 SP_DEVINFO_DATA device
= {sizeof(device
)};
428 WCHAR name
[MAX_SERVICE_NAME
];
431 for (i
= 0; SetupDiEnumDeviceInfo(set
, i
, &device
); ++i
)
433 if (SetupDiGetDeviceRegistryPropertyW(set
, &device
, SPDRP_SERVICE
, NULL
,
434 (BYTE
*)name
, sizeof(name
), NULL
)
435 && !wcsicmp(name
, service
->name
))
444 static void scmdatabase_autostart_services(struct scmdatabase
*db
)
446 static const WCHAR rootW
[] = {'R','O','O','T',0};
447 struct service_entry
**services_list
;
449 unsigned int size
= 32;
450 unsigned int delayed_cnt
= 0;
451 struct service_entry
*service
;
454 services_list
= HeapAlloc(GetProcessHeap(), 0, size
* sizeof(services_list
[0]));
458 if ((set
= SetupDiGetClassDevsW( NULL
, rootW
, NULL
, DIGCF_ALLCLASSES
)) == INVALID_HANDLE_VALUE
)
459 WINE_ERR("Failed to enumerate devices, error %#x.\n", GetLastError());
461 scmdatabase_lock(db
);
463 LIST_FOR_EACH_ENTRY(service
, &db
->services
, struct service_entry
, entry
)
465 if (service
->config
.dwStartType
== SERVICE_BOOT_START
||
466 service
->config
.dwStartType
== SERVICE_SYSTEM_START
||
467 service
->config
.dwStartType
== SERVICE_AUTO_START
||
468 (set
!= INVALID_HANDLE_VALUE
&& is_root_pnp_service(set
, service
)))
472 struct service_entry
**slist_new
;
474 slist_new
= HeapReAlloc(GetProcessHeap(), 0, services_list
, size
* sizeof(services_list
[0]));
477 services_list
= slist_new
;
479 services_list
[i
++] = grab_service(service
);
484 scmdatabase_unlock(db
);
485 qsort(services_list
, size
, sizeof(services_list
[0]), compare_tags
);
486 scmdatabase_lock_startup(db
, INFINITE
);
488 for (i
= 0; i
< size
; i
++)
491 service
= services_list
[i
];
492 if (service
->delayed_autostart
)
494 TRACE("delayed starting %s\n", wine_dbgstr_w(service
->name
));
495 services_list
[delayed_cnt
++] = service
;
498 err
= service_start(service
, 0, NULL
);
499 if (err
!= ERROR_SUCCESS
)
500 WINE_FIXME("Auto-start service %s failed to start: %d\n",
501 wine_dbgstr_w(service
->name
), err
);
502 release_service(service
);
505 scmdatabase_unlock_startup(db
);
507 if (!delayed_cnt
|| !schedule_delayed_autostart(services_list
, delayed_cnt
))
508 heap_free(services_list
);
509 SetupDiDestroyDeviceInfoList(set
);
512 static void scmdatabase_wait_terminate(struct scmdatabase
*db
)
514 struct list pending
= LIST_INIT(pending
);
517 scmdatabase_lock(db
);
518 list_move_tail(&pending
, &db
->processes
);
519 while ((ptr
= list_head(&pending
)))
521 struct process_entry
*process
= grab_process(LIST_ENTRY(ptr
, struct process_entry
, entry
));
523 scmdatabase_unlock(db
);
524 WaitForSingleObject(process
->process
, INFINITE
);
525 scmdatabase_lock(db
);
527 list_remove(&process
->entry
);
528 list_add_tail(&db
->processes
, &process
->entry
);
529 release_process(process
);
531 scmdatabase_unlock(db
);
534 BOOL
validate_service_name(LPCWSTR name
)
536 return (name
&& name
[0] && !wcschr(name
, '/') && !wcschr(name
, '\\'));
539 BOOL
validate_service_config(struct service_entry
*entry
)
541 if (entry
->config
.dwServiceType
& SERVICE_WIN32
&& (entry
->config
.lpBinaryPathName
== NULL
|| !entry
->config
.lpBinaryPathName
[0]))
543 WINE_ERR("Service %s is Win32 but has no image path set\n", wine_dbgstr_w(entry
->name
));
547 switch (entry
->config
.dwServiceType
)
549 case SERVICE_KERNEL_DRIVER
:
550 case SERVICE_FILE_SYSTEM_DRIVER
:
551 case SERVICE_WIN32_OWN_PROCESS
:
552 case SERVICE_WIN32_SHARE_PROCESS
:
555 case SERVICE_WIN32_OWN_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
556 case SERVICE_WIN32_SHARE_PROCESS
| SERVICE_INTERACTIVE_PROCESS
:
557 /* These can be only run as LocalSystem */
558 if (entry
->config
.lpServiceStartName
&& wcsicmp(entry
->config
.lpServiceStartName
, SZ_LOCAL_SYSTEM
) != 0)
560 WINE_ERR("Service %s is interactive but has a start name\n", wine_dbgstr_w(entry
->name
));
565 WINE_ERR("Service %s has an unknown service type (0x%x)\n", wine_dbgstr_w(entry
->name
), entry
->config
.dwServiceType
);
569 /* StartType can only be a single value (if several values are mixed the result is probably not what was intended) */
570 if (entry
->config
.dwStartType
> SERVICE_DISABLED
)
572 WINE_ERR("Service %s has an unknown start type\n", wine_dbgstr_w(entry
->name
));
576 /* SERVICE_BOOT_START and SERVICE_SYSTEM_START are only allowed for driver services */
577 if (((entry
->config
.dwStartType
== SERVICE_BOOT_START
) || (entry
->config
.dwStartType
== SERVICE_SYSTEM_START
)) &&
578 ((entry
->config
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
) || (entry
->config
.dwServiceType
& SERVICE_WIN32_SHARE_PROCESS
)))
580 WINE_ERR("Service %s - SERVICE_BOOT_START and SERVICE_SYSTEM_START are only allowed for driver services\n", wine_dbgstr_w(entry
->name
));
584 if (entry
->config
.lpServiceStartName
== NULL
)
585 entry
->config
.lpServiceStartName
= strdupW(SZ_LOCAL_SYSTEM
);
591 struct service_entry
*scmdatabase_find_service(struct scmdatabase
*db
, LPCWSTR name
)
593 struct service_entry
*service
;
595 LIST_FOR_EACH_ENTRY(service
, &db
->services
, struct service_entry
, entry
)
597 if (wcsicmp(name
, service
->name
) == 0)
604 struct service_entry
*scmdatabase_find_service_by_displayname(struct scmdatabase
*db
, LPCWSTR name
)
606 struct service_entry
*service
;
608 LIST_FOR_EACH_ENTRY(service
, &db
->services
, struct service_entry
, entry
)
610 if (service
->config
.lpDisplayName
&& wcsicmp(name
, service
->config
.lpDisplayName
) == 0)
617 struct process_entry
*grab_process(struct process_entry
*process
)
620 InterlockedIncrement(&process
->ref_count
);
624 void release_process(struct process_entry
*process
)
626 struct scmdatabase
*db
= process
->db
;
628 scmdatabase_lock(db
);
629 if (InterlockedDecrement(&process
->ref_count
) == 0)
631 scmdatabase_remove_process(db
, process
);
632 free_process_entry(process
);
634 scmdatabase_unlock(db
);
637 struct service_entry
*grab_service(struct service_entry
*service
)
640 InterlockedIncrement(&service
->ref_count
);
644 void release_service(struct service_entry
*service
)
646 struct scmdatabase
*db
= service
->db
;
648 scmdatabase_lock(db
);
649 if (InterlockedDecrement(&service
->ref_count
) == 0 && is_marked_for_delete(service
))
651 scmdatabase_remove_service(db
, service
);
652 free_service_entry(service
);
654 scmdatabase_unlock(db
);
657 static DWORD
scmdatabase_create(struct scmdatabase
**db
)
661 *db
= HeapAlloc(GetProcessHeap(), 0, sizeof(**db
));
663 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
665 (*db
)->service_start_lock
= FALSE
;
666 list_init(&(*db
)->processes
);
667 list_init(&(*db
)->services
);
669 InitializeCriticalSection(&(*db
)->cs
);
670 (*db
)->cs
.DebugInfo
->Spare
[0] = (DWORD_PTR
)(__FILE__
": scmdatabase");
672 err
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, SZ_SERVICES_KEY
, 0, NULL
,
673 REG_OPTION_NON_VOLATILE
, MAXIMUM_ALLOWED
, NULL
,
674 &(*db
)->root_key
, NULL
);
675 if (err
!= ERROR_SUCCESS
)
676 HeapFree(GetProcessHeap(), 0, *db
);
681 static void scmdatabase_destroy(struct scmdatabase
*db
)
683 RegCloseKey(db
->root_key
);
684 db
->cs
.DebugInfo
->Spare
[0] = 0;
685 DeleteCriticalSection(&db
->cs
);
686 HeapFree(GetProcessHeap(), 0, db
);
689 static DWORD
scmdatabase_load_services(struct scmdatabase
*db
)
694 for (i
= 0; TRUE
; i
++)
696 WCHAR szName
[MAX_SERVICE_NAME
];
697 struct service_entry
*entry
;
700 err
= RegEnumKeyW(db
->root_key
, i
, szName
, MAX_SERVICE_NAME
);
701 if (err
== ERROR_NO_MORE_ITEMS
)
706 WINE_ERR("Error %d reading key %d name - skipping\n", err
, i
);
710 err
= service_create(szName
, &entry
);
711 if (err
!= ERROR_SUCCESS
)
714 WINE_TRACE("Loading service %s\n", wine_dbgstr_w(szName
));
715 err
= RegOpenKeyExW(db
->root_key
, szName
, 0, KEY_READ
, &hServiceKey
);
716 if (err
== ERROR_SUCCESS
)
718 err
= load_service_config(hServiceKey
, entry
);
719 RegCloseKey(hServiceKey
);
722 if (err
!= ERROR_SUCCESS
)
724 WINE_ERR("Error %d reading registry key for service %s - skipping\n", err
, wine_dbgstr_w(szName
));
725 free_service_entry(entry
);
729 if (entry
->config
.dwServiceType
== 0)
731 /* Maybe an application only wrote some configuration in the service key. Continue silently */
732 WINE_TRACE("Even the service type not set for service %s - skipping\n", wine_dbgstr_w(szName
));
733 free_service_entry(entry
);
737 if (!validate_service_config(entry
))
739 WINE_ERR("Invalid configuration of service %s - skipping\n", wine_dbgstr_w(szName
));
740 free_service_entry(entry
);
744 entry
->status
.dwServiceType
= entry
->config
.dwServiceType
;
747 list_add_tail(&db
->services
, &entry
->entry
);
748 release_service(entry
);
750 return ERROR_SUCCESS
;
753 BOOL
scmdatabase_lock_startup(struct scmdatabase
*db
, int timeout
)
755 while (InterlockedCompareExchange(&db
->service_start_lock
, TRUE
, FALSE
))
757 if (timeout
!= INFINITE
)
760 if (timeout
<= 0) return FALSE
;
767 void scmdatabase_unlock_startup(struct scmdatabase
*db
)
769 InterlockedCompareExchange(&db
->service_start_lock
, FALSE
, TRUE
);
772 void scmdatabase_lock(struct scmdatabase
*db
)
774 EnterCriticalSection(&db
->cs
);
777 void scmdatabase_unlock(struct scmdatabase
*db
)
779 LeaveCriticalSection(&db
->cs
);
782 void service_lock(struct service_entry
*service
)
784 EnterCriticalSection(&service
->db
->cs
);
787 void service_unlock(struct service_entry
*service
)
789 LeaveCriticalSection(&service
->db
->cs
);
792 /* only one service started at a time, so there is no race on the registry
794 static LPWSTR
service_get_pipe_name(void)
796 static const WCHAR format
[] = { '\\','\\','.','\\','p','i','p','e','\\',
797 'n','e','t','\\','N','t','C','o','n','t','r','o','l','P','i','p','e','%','u',0};
798 static WCHAR name
[ARRAY_SIZE(format
) + 10]; /* lstrlenW("4294967295") */
799 static DWORD service_current
= 0;
800 DWORD len
, value
= -1;
805 ret
= RegQueryValueExW(service_current_key
, NULL
, NULL
, &type
,
806 (BYTE
*)&value
, &len
);
807 if (ret
== ERROR_SUCCESS
&& type
== REG_DWORD
)
808 service_current
= max(service_current
, value
+ 1);
809 RegSetValueExW(service_current_key
, NULL
, 0, REG_DWORD
,
810 (BYTE
*)&service_current
, sizeof(service_current
));
811 swprintf(name
, ARRAY_SIZE(name
), format
, service_current
);
816 static DWORD
get_service_binary_path(const struct service_entry
*service_entry
, WCHAR
**path
)
818 DWORD size
= ExpandEnvironmentStringsW(service_entry
->config
.lpBinaryPathName
, NULL
, 0);
820 *path
= HeapAlloc(GetProcessHeap(), 0, size
*sizeof(WCHAR
));
822 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
824 ExpandEnvironmentStringsW(service_entry
->config
.lpBinaryPathName
, *path
, size
);
826 /* if service image is configured to systemdir, redirect it to wow64 systemdir */
827 if (service_entry
->is_wow64
&& !(service_entry
->config
.dwServiceType
& (SERVICE_FILE_SYSTEM_DRIVER
| SERVICE_KERNEL_DRIVER
)))
829 WCHAR system_dir
[MAX_PATH
], *redirected
;
832 GetSystemDirectoryW( system_dir
, MAX_PATH
);
833 len
= lstrlenW( system_dir
);
835 if (wcsnicmp( system_dir
, *path
, len
))
836 return ERROR_SUCCESS
;
838 GetSystemWow64DirectoryW( system_dir
, MAX_PATH
);
840 redirected
= HeapAlloc( GetProcessHeap(), 0, (lstrlenW( *path
) + lstrlenW( system_dir
))*sizeof(WCHAR
));
843 HeapFree( GetProcessHeap(), 0, *path
);
844 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
847 lstrcpyW( redirected
, system_dir
);
848 lstrcatW( redirected
, &(*path
)[len
] );
849 HeapFree( GetProcessHeap(), 0, *path
);
851 TRACE("redirected to %s\n", debugstr_w(redirected
));
854 return ERROR_SUCCESS
;
857 static DWORD
get_winedevice_binary_path(struct service_entry
*service_entry
, WCHAR
**path
, BOOL
*is_wow64
)
859 static const WCHAR winedeviceW
[] = {'\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',0};
860 WCHAR system_dir
[MAX_PATH
];
865 else if (GetBinaryTypeW(*path
, &type
))
866 *is_wow64
= (type
== SCS_32BIT_BINARY
);
868 *is_wow64
= service_entry
->is_wow64
;
870 GetSystemDirectoryW(system_dir
, MAX_PATH
);
871 HeapFree(GetProcessHeap(), 0, *path
);
872 if (!(*path
= HeapAlloc(GetProcessHeap(), 0, lstrlenW(system_dir
) * sizeof(WCHAR
) + sizeof(winedeviceW
))))
873 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
875 lstrcpyW(*path
, system_dir
);
876 lstrcatW(*path
, winedeviceW
);
877 return ERROR_SUCCESS
;
880 static struct process_entry
*get_winedevice_process(struct service_entry
*service_entry
, WCHAR
*path
, BOOL is_wow64
)
882 struct service_entry
*winedevice_entry
;
884 if (!service_entry
->config
.lpLoadOrderGroup
)
887 LIST_FOR_EACH_ENTRY(winedevice_entry
, &service_entry
->db
->services
, struct service_entry
, entry
)
889 if (winedevice_entry
->status
.dwCurrentState
!= SERVICE_START_PENDING
&&
890 winedevice_entry
->status
.dwCurrentState
!= SERVICE_RUNNING
) continue;
891 if (!winedevice_entry
->process
) continue;
893 if (winedevice_entry
->is_wow64
!= is_wow64
) continue;
894 if (!winedevice_entry
->config
.lpBinaryPathName
) continue;
895 if (lstrcmpW(winedevice_entry
->config
.lpBinaryPathName
, path
)) continue;
897 if (!winedevice_entry
->config
.lpLoadOrderGroup
) continue;
898 if (lstrcmpW(winedevice_entry
->config
.lpLoadOrderGroup
, service_entry
->config
.lpLoadOrderGroup
)) continue;
900 return grab_process(winedevice_entry
->process
);
906 static DWORD
add_winedevice_service(const struct service_entry
*service
, WCHAR
*path
, BOOL is_wow64
,
907 struct service_entry
**entry
)
909 static const WCHAR format
[] = {'W','i','n','e','d','e','v','i','c','e','%','u',0};
910 static WCHAR name
[ARRAY_SIZE(format
) + 10]; /* lstrlenW("4294967295") */
911 static DWORD current
= 0;
912 struct scmdatabase
*db
= service
->db
;
917 swprintf(name
, ARRAY_SIZE(name
), format
, ++current
);
918 if (!scmdatabase_find_service(db
, name
)) break;
921 err
= service_create(name
, entry
);
922 if (err
!= ERROR_SUCCESS
)
925 (*entry
)->is_wow64
= is_wow64
;
926 (*entry
)->config
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
927 (*entry
)->config
.dwStartType
= SERVICE_DEMAND_START
;
928 (*entry
)->status
.dwServiceType
= (*entry
)->config
.dwServiceType
;
930 if (!((*entry
)->config
.lpBinaryPathName
= strdupW(path
)))
932 if (!((*entry
)->config
.lpServiceStartName
= strdupW(SZ_LOCAL_SYSTEM
)))
934 if (!((*entry
)->config
.lpDisplayName
= strdupW(name
)))
936 if (service
->config
.lpLoadOrderGroup
&&
937 !((*entry
)->config
.lpLoadOrderGroup
= strdupW(service
->config
.lpLoadOrderGroup
)))
942 list_add_tail(&db
->services
, &(*entry
)->entry
);
943 mark_for_delete(*entry
);
944 return ERROR_SUCCESS
;
947 free_service_entry(*entry
);
948 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
951 static DWORD
service_start_process(struct service_entry
*service_entry
, struct process_entry
**new_process
,
952 BOOL
*shared_process
)
954 struct process_entry
*process
;
955 PROCESS_INFORMATION pi
;
957 BOOL is_wow64
= FALSE
;
963 service_lock(service_entry
);
965 if ((process
= service_entry
->process
))
967 if (WaitForSingleObject(process
->process
, 0) == WAIT_TIMEOUT
)
969 service_unlock(service_entry
);
970 return ERROR_SERVICE_ALREADY_RUNNING
;
972 service_entry
->process
= NULL
;
973 process
->use_count
--;
974 release_process(process
);
977 service_entry
->force_shutdown
= FALSE
;
979 if ((err
= get_service_binary_path(service_entry
, &path
)))
981 service_unlock(service_entry
);
985 if (service_entry
->config
.dwServiceType
== SERVICE_KERNEL_DRIVER
||
986 service_entry
->config
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
)
988 struct service_entry
*winedevice_entry
;
991 if ((err
= get_winedevice_binary_path(service_entry
, &path
, &is_wow64
)))
993 service_unlock(service_entry
);
994 HeapFree(GetProcessHeap(), 0, path
);
998 if ((process
= get_winedevice_process(service_entry
, path
, is_wow64
)))
1000 HeapFree(GetProcessHeap(), 0, path
);
1004 err
= add_winedevice_service(service_entry
, path
, is_wow64
, &winedevice_entry
);
1005 HeapFree(GetProcessHeap(), 0, path
);
1006 if (err
!= ERROR_SUCCESS
)
1008 service_unlock(service_entry
);
1012 group
= strdupW(winedevice_entry
->config
.lpLoadOrderGroup
);
1013 service_unlock(service_entry
);
1015 err
= service_start(winedevice_entry
, group
!= NULL
, (const WCHAR
**)&group
);
1016 HeapFree(GetProcessHeap(), 0, group
);
1017 if (err
!= ERROR_SUCCESS
)
1019 release_service(winedevice_entry
);
1023 service_lock(service_entry
);
1024 process
= grab_process(winedevice_entry
->process
);
1025 release_service(winedevice_entry
);
1029 service_unlock(service_entry
);
1030 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1034 service_entry
->status
.dwCurrentState
= SERVICE_START_PENDING
;
1035 service_entry
->status
.dwControlsAccepted
= 0;
1036 ResetEvent(service_entry
->status_changed_event
);
1038 service_entry
->process
= grab_process(process
);
1039 service_entry
->shared_process
= *shared_process
= TRUE
;
1040 process
->use_count
++;
1041 service_unlock(service_entry
);
1043 err
= WaitForSingleObject(process
->control_mutex
, 30000);
1044 if (err
!= WAIT_OBJECT_0
)
1046 release_process(process
);
1047 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1050 *new_process
= process
;
1051 return ERROR_SUCCESS
;
1054 if ((err
= process_create(service_get_pipe_name(), &process
)))
1056 WINE_ERR("failed to create process object for %s, error = %u\n",
1057 wine_dbgstr_w(service_entry
->name
), err
);
1058 service_unlock(service_entry
);
1059 HeapFree(GetProcessHeap(), 0, path
);
1063 ZeroMemory(&si
, sizeof(STARTUPINFOW
));
1064 si
.cb
= sizeof(STARTUPINFOW
);
1065 if (!(service_entry
->config
.dwServiceType
& SERVICE_INTERACTIVE_PROCESS
))
1067 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};
1068 si
.lpDesktop
= desktopW
;
1071 if (!environment
&& OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
| TOKEN_DUPLICATE
, &token
))
1074 CreateEnvironmentBlock(&environment
, token
, FALSE
);
1075 if (GetEnvironmentVariableW( L
"WINEBOOTSTRAPMODE", val
, ARRAY_SIZE(val
) ))
1077 UNICODE_STRING name
, value
;
1079 RtlInitUnicodeString( &name
, L
"WINEBOOTSTRAPMODE" );
1080 RtlInitUnicodeString( &value
, val
);
1081 RtlSetEnvironmentVariable( (WCHAR
**)&environment
, &name
, &value
);
1086 service_entry
->status
.dwCurrentState
= SERVICE_START_PENDING
;
1087 service_entry
->status
.dwControlsAccepted
= 0;
1088 ResetEvent(service_entry
->status_changed_event
);
1090 scmdatabase_add_process(service_entry
->db
, process
);
1091 service_entry
->process
= grab_process(process
);
1092 service_entry
->shared_process
= *shared_process
= FALSE
;
1093 process
->use_count
++;
1094 service_unlock(service_entry
);
1096 r
= CreateProcessW(NULL
, path
, NULL
, NULL
, FALSE
, CREATE_UNICODE_ENVIRONMENT
, environment
, NULL
, &si
, &pi
);
1097 HeapFree(GetProcessHeap(), 0, path
);
1100 err
= GetLastError();
1101 process_terminate(process
);
1102 release_process(process
);
1106 process
->process_id
= pi
.dwProcessId
;
1107 process
->process
= pi
.hProcess
;
1108 CloseHandle( pi
.hThread
);
1110 *new_process
= process
;
1111 return ERROR_SUCCESS
;
1114 static DWORD
service_wait_for_startup(struct service_entry
*service
, struct process_entry
*process
)
1116 HANDLE handles
[2] = { service
->status_changed_event
, process
->process
};
1119 result
= WaitForMultipleObjects( 2, handles
, FALSE
, service_pipe_timeout
);
1120 if (result
!= WAIT_OBJECT_0
)
1121 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1123 service_lock(service
);
1124 result
= service
->status
.dwCurrentState
;
1125 service_unlock(service
);
1127 return (result
== SERVICE_START_PENDING
|| result
== SERVICE_RUNNING
) ?
1128 ERROR_SUCCESS
: ERROR_SERVICE_REQUEST_TIMEOUT
;
1131 /******************************************************************************
1132 * process_send_start_message
1134 static DWORD
process_send_start_message(struct process_entry
*process
, BOOL shared_process
,
1135 const WCHAR
*name
, const WCHAR
**argv
, DWORD argc
)
1137 OVERLAPPED overlapped
;
1138 DWORD i
, len
, result
;
1141 WINE_TRACE("%p %s %p %d\n", process
, wine_dbgstr_w(name
), argv
, argc
);
1143 overlapped
.hEvent
= process
->overlapped_event
;
1144 if (!ConnectNamedPipe(process
->control_pipe
, &overlapped
))
1146 if (GetLastError() == ERROR_IO_PENDING
)
1149 handles
[0] = process
->overlapped_event
;
1150 handles
[1] = process
->process
;
1151 if (WaitForMultipleObjects( 2, handles
, FALSE
, service_pipe_timeout
) != WAIT_OBJECT_0
)
1152 CancelIo(process
->control_pipe
);
1153 if (!HasOverlappedIoCompleted( &overlapped
))
1155 WINE_ERR("service %s failed to start\n", wine_dbgstr_w(name
));
1156 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1159 else if (GetLastError() != ERROR_PIPE_CONNECTED
)
1161 WINE_ERR("pipe connect failed\n");
1162 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1166 len
= lstrlenW(name
) + 1;
1167 for (i
= 0; i
< argc
; i
++)
1168 len
+= lstrlenW(argv
[i
])+1;
1169 len
= (len
+ 1) * sizeof(WCHAR
);
1171 if (!(str
= HeapAlloc(GetProcessHeap(), 0, len
)))
1172 return ERROR_NOT_ENOUGH_SERVER_MEMORY
;
1176 p
+= lstrlenW(name
) + 1;
1177 for (i
= 0; i
< argc
; i
++)
1179 lstrcpyW(p
, argv
[i
]);
1180 p
+= lstrlenW(p
) + 1;
1184 if (!process_send_control(process
, shared_process
, name
,
1185 SERVICE_CONTROL_START
, (const BYTE
*)str
, len
, &result
))
1186 result
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1188 HeapFree(GetProcessHeap(), 0, str
);
1192 DWORD
service_start(struct service_entry
*service
, DWORD service_argc
, LPCWSTR
*service_argv
)
1194 struct process_entry
*process
= NULL
;
1195 BOOL shared_process
;
1198 err
= service_start_process(service
, &process
, &shared_process
);
1199 if (err
== ERROR_SUCCESS
)
1201 err
= process_send_start_message(process
, shared_process
, service
->name
, service_argv
, service_argc
);
1203 if (err
== ERROR_SUCCESS
)
1204 err
= service_wait_for_startup(service
, process
);
1206 if (err
!= ERROR_SUCCESS
)
1208 service_lock(service
);
1209 if (service
->process
)
1211 service
->status
.dwCurrentState
= SERVICE_STOPPED
;
1212 service
->process
= NULL
;
1213 if (!--process
->use_count
) process_terminate(process
);
1214 release_process(process
);
1216 service_unlock(service
);
1219 ReleaseMutex(process
->control_mutex
);
1220 release_process(process
);
1223 WINE_TRACE("returning %d\n", err
);
1227 void process_terminate(struct process_entry
*process
)
1229 struct scmdatabase
*db
= process
->db
;
1230 struct service_entry
*service
;
1232 scmdatabase_lock(db
);
1233 TerminateProcess(process
->process
, 0);
1234 LIST_FOR_EACH_ENTRY(service
, &db
->services
, struct service_entry
, entry
)
1236 if (service
->process
!= process
) continue;
1237 service
->status
.dwCurrentState
= SERVICE_STOPPED
;
1238 service
->process
= NULL
;
1239 process
->use_count
--;
1240 release_process(process
);
1242 scmdatabase_unlock(db
);
1245 static void load_registry_parameters(void)
1247 static const WCHAR controlW
[] =
1248 { 'S','y','s','t','e','m','\\',
1249 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1250 'C','o','n','t','r','o','l',0 };
1251 static const WCHAR pipetimeoutW
[] =
1252 {'S','e','r','v','i','c','e','s','P','i','p','e','T','i','m','e','o','u','t',0};
1253 static const WCHAR killtimeoutW
[] =
1254 {'W','a','i','t','T','o','K','i','l','l','S','e','r','v','i','c','e','T','i','m','e','o','u','t',0};
1255 static const WCHAR autostartdelayW
[] =
1256 {'A','u','t','o','S','t','a','r','t','D','e','l','a','y',0};
1259 DWORD type
, count
, val
;
1261 if (RegOpenKeyW( HKEY_LOCAL_MACHINE
, controlW
, &key
)) return;
1263 count
= sizeof(buffer
);
1264 if (!RegQueryValueExW( key
, pipetimeoutW
, NULL
, &type
, (BYTE
*)buffer
, &count
) &&
1265 type
== REG_SZ
&& (val
= wcstol( buffer
, NULL
, 10 )))
1266 service_pipe_timeout
= val
;
1268 count
= sizeof(buffer
);
1269 if (!RegQueryValueExW( key
, killtimeoutW
, NULL
, &type
, (BYTE
*)buffer
, &count
) &&
1270 type
== REG_SZ
&& (val
= wcstol( buffer
, NULL
, 10 )))
1271 service_kill_timeout
= val
;
1273 count
= sizeof(val
);
1274 if (!RegQueryValueExW( key
, autostartdelayW
, NULL
, &type
, (BYTE
*)&val
, &count
) && type
== REG_DWORD
)
1275 autostart_delay
= val
;
1280 int __cdecl
main(int argc
, char *argv
[])
1282 static const WCHAR service_current_key_str
[] = { 'S','Y','S','T','E','M','\\',
1283 'C','u','r','r','e','n','t','C','o','n','t','r','o','l','S','e','t','\\',
1284 'C','o','n','t','r','o','l','\\',
1285 'S','e','r','v','i','c','e','C','u','r','r','e','n','t',0};
1286 static const WCHAR svcctl_started_event
[] = SVCCTL_STARTED_EVENT
;
1287 HANDLE started_event
;
1290 started_event
= CreateEventW(NULL
, TRUE
, FALSE
, svcctl_started_event
);
1292 err
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
, service_current_key_str
, 0,
1293 NULL
, REG_OPTION_VOLATILE
, KEY_SET_VALUE
| KEY_QUERY_VALUE
, NULL
,
1294 &service_current_key
, NULL
);
1295 if (err
!= ERROR_SUCCESS
)
1298 load_registry_parameters();
1299 err
= scmdatabase_create(&active_database
);
1300 if (err
!= ERROR_SUCCESS
)
1302 if ((err
= scmdatabase_load_services(active_database
)) != ERROR_SUCCESS
)
1304 if ((err
= RPC_Init()) == ERROR_SUCCESS
)
1306 scmdatabase_autostart_services(active_database
);
1307 SetEvent(started_event
);
1308 WaitForSingleObject(exit_event
, INFINITE
);
1309 scmdatabase_wait_terminate(active_database
);
1310 if (delayed_autostart_cleanup
)
1312 CloseThreadpoolCleanupGroupMembers(delayed_autostart_cleanup
, TRUE
, NULL
);
1313 CloseThreadpoolCleanupGroup(delayed_autostart_cleanup
);
1317 scmdatabase_destroy(active_database
);
1319 DestroyEnvironmentBlock(environment
);
1321 WINE_TRACE("services.exe exited with code %d\n", err
);