Signed-off-by: Zebediah Figura z.figura12@gmail.com --- Windows starts up all root PnP drivers on startup. Native root PnP drivers are generally marked as SERVICE_DEMAND_START, so they will not be started up otherwise.
If using setupapi from services.exe is unpalatable or architecturally wrong, I can send a patch to duplicate the logic, so that we check the registry directly. I would appreciate an explanation of why this is the case, however. If loading root PnP drivers on startup itself from services.exe is unpalatable or architecturally wrong, we will have to warn users that any root PnP drivers they install will have to have their startup type changed from SERVICE_DEMAND_START.
programs/services/Makefile.in | 2 +- programs/services/services.c | 29 ++++++++++++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-)
diff --git a/programs/services/Makefile.in b/programs/services/Makefile.in index e06514cbdd1..560e277a9bf 100644 --- a/programs/services/Makefile.in +++ b/programs/services/Makefile.in @@ -1,5 +1,5 @@ MODULE = services.exe -IMPORTS = rpcrt4 advapi32 userenv +IMPORTS = rpcrt4 advapi32 userenv setupapi
EXTRADLLFLAGS = -mconsole -mno-cygwin
diff --git a/programs/services/services.c b/programs/services/services.c index 2dff8115595..96a18bcd18e 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -27,6 +27,7 @@ #include <winsvc.h> #include <rpc.h> #include <userenv.h> +#include <setupapi.h>
#include "wine/debug.h" #include "wine/heap.h" @@ -423,25 +424,50 @@ static BOOL schedule_delayed_autostart(struct service_entry **services, unsigned return TRUE; }
+static BOOL is_root_pnp_service(const struct service_entry *service, HDEVINFO set) +{ + SP_DEVINFO_DATA device = {sizeof(device)}; + WCHAR name[MAX_SERVICE_NAME]; + unsigned int i; + + for (i = 0; SetupDiEnumDeviceInfo(set, i, &device); ++i) + { + if (SetupDiGetDeviceRegistryPropertyW(set, &device, SPDRP_SERVICE, NULL, + (BYTE *)name, sizeof(name), NULL) + && !wcsicmp(name, service->name)) + { + return TRUE; + } + } + + return FALSE; +} + static void scmdatabase_autostart_services(struct scmdatabase *db) { + static const WCHAR rootW[] = {'R','O','O','T',0}; struct service_entry **services_list; unsigned int i = 0; unsigned int size = 32; unsigned int delayed_cnt = 0; struct service_entry *service; + HDEVINFO set;
services_list = HeapAlloc(GetProcessHeap(), 0, size * sizeof(services_list[0])); if (!services_list) return;
+ if ((set = SetupDiGetClassDevsW( NULL, rootW, NULL, DIGCF_ALLCLASSES )) == INVALID_HANDLE_VALUE) + WINE_ERR("Failed to enumerate devices, error %#x.\n", GetLastError()); + scmdatabase_lock(db);
LIST_FOR_EACH_ENTRY(service, &db->services, struct service_entry, entry) { if (service->config.dwStartType == SERVICE_BOOT_START || service->config.dwStartType == SERVICE_SYSTEM_START || - service->config.dwStartType == SERVICE_AUTO_START) + service->config.dwStartType == SERVICE_AUTO_START || + (set != INVALID_HANDLE_VALUE && is_root_pnp_service(set, service))) { if (i+1 >= size) { @@ -482,6 +508,7 @@ static void scmdatabase_autostart_services(struct scmdatabase *db)
if (!delayed_cnt || !schedule_delayed_autostart(services_list, delayed_cnt)) heap_free(services_list); + SetupDiDestroyDeviceInfoList(set); }
static void scmdatabase_wait_terminate(struct scmdatabase *db)