diff --git a/Cargo.lock b/Cargo.lock index 1897730d..c59bd113 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2447,7 +2447,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "virtual-display-driver" -version = "0.2.1" +version = "0.2.2" dependencies = [ "bytemuck", "driver-ipc", diff --git a/virtual-display-driver/Cargo.toml b/virtual-display-driver/Cargo.toml index 752fb66b..25ecdaca 100644 --- a/virtual-display-driver/Cargo.toml +++ b/virtual-display-driver/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "virtual-display-driver" -version = "0.2.1" +version = "0.2.2" edition = "2021" [lib] diff --git a/virtual-display-driver/src/entry.rs b/virtual-display-driver/src/entry.rs index 0e08453a..e01d30b1 100644 --- a/virtual-display-driver/src/entry.rs +++ b/virtual-display-driver/src/entry.rs @@ -1,12 +1,13 @@ use driver_ipc::Monitor; -use log::{error, LevelFilter}; +use log::{error, info, LevelFilter}; use wdf_umdf::{ IddCxDeviceInitConfig, IddCxDeviceInitialize, IntoHelper, WdfDeviceCreate, - WdfDeviceInitSetPnpPowerEventCallbacks, WdfDriverCreate, + WdfDeviceInitSetPnpPowerEventCallbacks, WdfDeviceSetFailed, WdfDriverCreate, }; use wdf_umdf_sys::{ - IDD_CX_CLIENT_CONFIG, NTSTATUS, WDFDEVICE_INIT, WDFDRIVER__, WDFOBJECT, WDF_DRIVER_CONFIG, - WDF_OBJECT_ATTRIBUTES, WDF_PNPPOWER_EVENT_CALLBACKS, _DRIVER_OBJECT, _UNICODE_STRING, + IDD_CX_CLIENT_CONFIG, NTSTATUS, WDFDEVICE_INIT, WDFDRIVER__, WDFOBJECT, + WDF_DEVICE_FAILED_ACTION, WDF_DRIVER_CONFIG, WDF_OBJECT_ATTRIBUTES, + WDF_PNPPOWER_EVENT_CALLBACKS, _DRIVER_OBJECT, _UNICODE_STRING, }; use winreg::{ enums::{HKEY_LOCAL_MACHINE, KEY_READ}, @@ -32,19 +33,68 @@ extern "C-unwind" fn DriverEntry( driver_object: *mut _DRIVER_OBJECT, registry_path: *mut _UNICODE_STRING, ) -> NTSTATUS { - let status = winlog::init( - "VirtualDisplayDriver", - if cfg!(debug_assertions) { - LevelFilter::Debug - } else { - LevelFilter::Info - }, - ) - .map(|_| NTSTATUS::STATUS_SUCCESS) - .unwrap_or(NTSTATUS::STATUS_UNSUCCESSFUL); + // During system bootup, `RegisterEventSourceW` fails and causes the driver to not bootup + // Pretty unfortunate, therefore, we will run this on a thread until it succeeds and let the rest of + // the driver start. I know this is suboptimal considering it's our main code to catch panics. + // + // It always starts immediately when the computer is already booted up. + // If you have a better solution, please by all means open an issue report + let init_log = || { + winlog::init( + "VirtualDisplayDriver", + if cfg!(debug_assertions) { + LevelFilter::Debug + } else { + LevelFilter::Info + }, + ) + .map(|_| NTSTATUS::STATUS_SUCCESS) + .unwrap_or(NTSTATUS::STATUS_UNSUCCESSFUL) + }; + + let status = init_log(); if !status.is_success() { - return status; + // Okay, let's try another method then + struct Sendable(T); + unsafe impl Send for Sendable {} + unsafe impl Sync for Sendable {} + + let device = Sendable(driver_object); + + std::thread::spawn(move || { + #[allow(clippy::redundant_locals)] + let device = device; + let mut time_waited = 0u64; + // in ms + let sleep_for = 500; + + loop { + let status = init_log(); + std::thread::sleep(std::time::Duration::from_millis(sleep_for)); + + time_waited += sleep_for; + + // if it succeeds, great. if it didn't conclude after + // 1 second in ms * 60 seconds * 5 minutes = 5 minutes + // Surely a users system is booted up before then? + let timeout = time_waited >= 1000 * 60 * 5; + if status.is_success() || timeout { + if timeout { + unsafe { + _ = WdfDeviceSetFailed( + device.0 as *mut _, + WDF_DEVICE_FAILED_ACTION::WdfDeviceFailedNoRestart, + ); + } + } else { + info!("Service took {} seconds to start", time_waited / 1000); + } + + break; + } + } + }); } // set the panic hook to capture and log panics diff --git a/wdf-umdf/src/wdf.rs b/wdf-umdf/src/wdf.rs index daafeef8..0a32db70 100644 --- a/wdf-umdf/src/wdf.rs +++ b/wdf-umdf/src/wdf.rs @@ -4,8 +4,9 @@ use std::ffi::c_void; use wdf_umdf_sys::{ NTSTATUS, PCUNICODE_STRING, PCWDF_OBJECT_CONTEXT_TYPE_INFO, PDRIVER_OBJECT, PWDFDEVICE_INIT, - PWDF_DRIVER_CONFIG, PWDF_OBJECT_ATTRIBUTES, WDFDEVICE, WDFDRIVER, WDFOBJECT, WDF_NO_HANDLE, - WDF_NO_OBJECT_ATTRIBUTES, WDF_OBJECT_ATTRIBUTES, _WDF_PNPPOWER_EVENT_CALLBACKS, + PWDF_DRIVER_CONFIG, PWDF_OBJECT_ATTRIBUTES, WDFDEVICE, WDFDRIVER, WDFOBJECT, + WDF_DEVICE_FAILED_ACTION, WDF_NO_HANDLE, WDF_NO_OBJECT_ATTRIBUTES, WDF_OBJECT_ATTRIBUTES, + _WDF_PNPPOWER_EVENT_CALLBACKS, }; use crate::IntoHelper; @@ -507,3 +508,20 @@ pub unsafe fn WdfObjectDelete( ) } } + +/// # Safety +/// +/// None. User is responsible for safety. +pub unsafe fn WdfDeviceSetFailed( + // in + Device: WDFDEVICE, + // in + FailedAction: WDF_DEVICE_FAILED_ACTION, +) -> Result<(), WdfError> { + WdfCall! { + WdfDeviceSetFailed( + Device, + FailedAction + ) + } +}