From: Aric Stewart Subject: [PATCH 4/4 v2] programs/services: Load device drivers of the same group into the same winedevice process Message-Id: <493a0068-9b7f-17cf-5fcb-21db94ec1fe9@codeweavers.com> Date: Wed, 10 Aug 2016 11:54:12 -0500 v2: Update to new RPC data format from Sebastian Lackner Signed-off-by: Aric Stewart --- programs/services/services.c | 111 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/programs/services/services.c b/programs/services/services.c index ebde6c7..72a669c 100644 --- a/programs/services/services.c +++ b/programs/services/services.c @@ -325,6 +325,49 @@ static void scmdatabase_remove_service(struct scmdatabase *db, struct service_en service->entry.next = service->entry.prev = NULL; } +static DWORD add_driver_group_service(struct scmdatabase *db, LPCWSTR lpLoadOrderGroup) +{ + static WCHAR szCommand[] = {'%','W','I','N','D','I','R','%','\\','s','y','s','t','e','m','3','2','\\','w','i','n','e','d','e','v','i','c','e','.','e','x','e',' ','/','g','r','o','u','p',' ',0}; + static WCHAR szGroupName[] = {'g','r','o','u','p','_',0}; + struct service_entry *driver_group_service = NULL; + WCHAR *name; + DWORD err; + + name = HeapAlloc(GetProcessHeap(), 0, sizeof(szGroupName) + lstrlenW(lpLoadOrderGroup) * sizeof(WCHAR)); + lstrcpyW(name, szGroupName); + lstrcatW(name, lpLoadOrderGroup); + + driver_group_service = scmdatabase_find_service(db, name); + if (driver_group_service) + { + HeapFree(GetProcessHeap(), 0, name); + return ERROR_SUCCESS; + } + + WINE_TRACE("Adding group driver service %s\n",debugstr_w(name)); + + err = service_create(name, &driver_group_service); + HeapFree(GetProcessHeap(), 0, name); + if (err != ERROR_SUCCESS) + return err; + + driver_group_service->config.dwServiceType = SERVICE_WIN32; + driver_group_service->config.dwStartType = SERVICE_BOOT_START; + driver_group_service->config.dwErrorControl = 1; + driver_group_service->config.dwTagId = 0; + driver_group_service->config.lpBinaryPathName = HeapAlloc(GetProcessHeap(), 0, sizeof(szCommand) + lstrlenW(lpLoadOrderGroup) * sizeof(WCHAR)); + lstrcpyW(driver_group_service->config.lpBinaryPathName, szCommand); + lstrcatW(driver_group_service->config.lpBinaryPathName, lpLoadOrderGroup); + driver_group_service->config.lpLoadOrderGroup = strdupW(lpLoadOrderGroup); + driver_group_service->config.lpServiceStartName = strdupW(SZ_LOCAL_SYSTEM); + driver_group_service->config.lpDisplayName = strdupW(lpLoadOrderGroup); + driver_group_service->status.dwServiceType = driver_group_service->config.dwServiceType; + driver_group_service->db = db; + list_add_tail(&db->services, &driver_group_service->entry); + + return err; +} + static int compare_tags(const void* a, const void *b) { struct service_entry *service_a = (struct service_entry*)a; @@ -647,6 +690,12 @@ static DWORD scmdatabase_load_services(struct scmdatabase *db) entry->db = db; list_add_tail(&db->services, &entry->entry); + + if (entry->config.lpLoadOrderGroup && + (entry->config.dwServiceType == SERVICE_KERNEL_DRIVER || + entry->config.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)) + add_driver_group_service(db, entry->config.lpLoadOrderGroup); + release_service(entry); } return ERROR_SUCCESS; @@ -940,11 +989,73 @@ static BOOL process_send_start_message(struct process_entry *process, const WCHA return r; } +static DWORD load_into_driver_group(struct service_entry *service) +{ + static WCHAR szGroupName[] = {'g','r','o','u','p','_',0}; + DWORD err; + WCHAR *name; + struct service_entry *driver_group_service = NULL; + + service_start_info *ssi; + DWORD len; + WCHAR *p; + DWORD result; + + name = HeapAlloc(GetProcessHeap(), 0, sizeof(szGroupName) + lstrlenW(service->config.lpLoadOrderGroup) * sizeof(WCHAR)); + lstrcpyW(name, szGroupName); + lstrcatW(name, service->config.lpLoadOrderGroup); + driver_group_service = scmdatabase_find_service(service->db, name); + HeapFree(GetProcessHeap(), 0, name); + + if (driver_group_service) + { + if (driver_group_service->status.dwCurrentState == SERVICE_STOPPED) + { + err = service_start(driver_group_service, 0, NULL); + if (err != ERROR_SUCCESS) + { + WINE_ERR("Failed to start driver group, drivers will be loaded independently\n"); + return err; + } + } + + len = strlenW(service->name) + 1; + len += strlenW(driver_group_service->name) + 1; + len = len * sizeof(WCHAR); + + ssi = HeapAlloc(GetProcessHeap(),0,FIELD_OFFSET(service_start_info, data[len])); + ssi->cmd = WINESERV_SENDCONTROL; + ssi->control = SERVICE_USER_DEFINED_CONTROL + 1; + ssi->total_size = FIELD_OFFSET(service_start_info, data[len]); + ssi->name_size = strlenW(driver_group_service->name) + 1; + + strcpyW( (WCHAR*)ssi->data, driver_group_service->name ); + p = (WCHAR *)&ssi->data[ssi->name_size * sizeof(WCHAR)]; + strcpyW(p, service->name); + + process_send_command( driver_group_service->process, ssi, ssi->total_size, &result ); + + HeapFree(GetProcessHeap(), 0, ssi); + return result; + } + + WINE_ERR("No driver group service found for this driver\n"); + return ERROR_FILE_NOT_FOUND; +} + DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *service_argv) { struct process_entry *process = NULL; DWORD err; + if (service->config.lpLoadOrderGroup && + (service->config.dwServiceType == SERVICE_KERNEL_DRIVER || + service->config.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)) + { + if (load_into_driver_group(service) == ERROR_SUCCESS) + return ERROR_SUCCESS; + } + err = scmdatabase_lock_startup(service->db); if (err != ERROR_SUCCESS) return err;