Skip to content

Commit

Permalink
Improve components retrieval on Windows
Browse files Browse the repository at this point in the history
  • Loading branch information
GuillaumeGomez committed Nov 25, 2024
1 parent 48d04ec commit becbc9a
Showing 1 changed file with 42 additions and 26 deletions.
68 changes: 42 additions & 26 deletions src/windows/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use windows::core::{w, VARIANT};
use windows::Win32::Foundation::{SysAllocString, SysFreeString};
use windows::Win32::Security::PSECURITY_DESCRIPTOR;
use windows::Win32::System::Com::{
CoCreateInstance, CoInitializeEx, CoInitializeSecurity, CoSetProxyBlanket, CoUninitialize,
CoCreateInstance, CoInitializeEx, CoInitializeSecurity, CoSetProxyBlanket,
CLSCTX_INPROC_SERVER, EOAC_NONE, RPC_C_AUTHN_LEVEL_CALL, RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
};
Expand All @@ -17,6 +17,9 @@ use windows::Win32::System::Wmi::{
WBEM_FLAG_NONSYSTEM_ONLY, WBEM_FLAG_RETURN_IMMEDIATELY, WBEM_INFINITE,
};

use std::cell::OnceCell;
use std::sync::OnceLock;

pub(crate) struct ComponentInner {
temperature: f32,
max: f32,
Expand All @@ -29,7 +32,6 @@ impl ComponentInner {
/// Creates a new `ComponentInner` with the given information.
fn new() -> Option<Self> {
let mut c = Connection::new()
.and_then(|x| x.initialize_security())
.and_then(|x| x.create_instance())
.and_then(|x| x.connect_server())
.and_then(|x| x.set_proxy_blanket())
Expand Down Expand Up @@ -64,7 +66,6 @@ impl ComponentInner {
pub(crate) fn refresh(&mut self) {
if self.connection.is_none() {
self.connection = Connection::new()
.and_then(|x| x.initialize_security())
.and_then(|x| x.create_instance())
.and_then(|x| x.connect_server())
.and_then(|x| x.set_proxy_blanket());
Expand Down Expand Up @@ -130,42 +131,60 @@ struct Connection {
instance: Option<IWbemLocator>,
server_connection: Option<IWbemServices>,
enumerator: Option<IEnumWbemClassObject>,
initialized: bool,
}

#[allow(clippy::non_send_fields_in_send_ty)]
unsafe impl Send for Connection {}
unsafe impl Sync for Connection {}

static SECURITY: OnceLock<Result<(), ()>> = OnceLock::new();
thread_local! {
pub static CONNECTION: OnceCell<Result<(), ()>> = OnceCell::new();
}

unsafe fn initialize_connection() -> Result<(), ()> {
if CoInitializeEx(None, Default::default()).is_err() {
sysinfo_debug!("Failed to initialize connection");
Err(())
} else {
Ok(())
}
}

unsafe fn initialize_security() -> Result<(), ()> {
if CoInitializeSecurity(
PSECURITY_DESCRIPTOR::default(),
-1,
None,
None,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
None,
EOAC_NONE,
None,
).is_err() {
sysinfo_debug!("Failed to initialize security");
Err(())
} else {
Ok(())
}
}

impl Connection {
#[allow(clippy::unnecessary_wraps)]
fn new() -> Option<Connection> {
let val = unsafe { CoInitializeEx(None, Default::default()) };
if CONNECTION.with(|x| *x.get_or_init(|| unsafe { initialize_connection() })).is_err()
|| SECURITY.get_or_init(|| unsafe { initialize_security() }).is_err()
{
return None;
}
Some(Connection {
instance: None,
server_connection: None,
enumerator: None,
initialized: val.is_ok(),
})
}

fn initialize_security(self) -> Option<Connection> {
unsafe {
CoInitializeSecurity(
PSECURITY_DESCRIPTOR::default(),
-1,
None,
None,
RPC_C_AUTHN_LEVEL_DEFAULT,
RPC_C_IMP_LEVEL_IMPERSONATE,
None,
EOAC_NONE,
None,
)
}
.map_or(None, |_| Some(self))
}

fn create_instance(mut self) -> Option<Connection> {
let instance =
unsafe { CoCreateInstance(&WbemLocator, None, CLSCTX_INPROC_SERVER) }.ok()?;
Expand Down Expand Up @@ -302,8 +321,5 @@ impl Drop for Connection {
self.enumerator.take();
self.server_connection.take();
self.instance.take();
if self.initialized {
unsafe { CoUninitialize() };
}
}
}

0 comments on commit becbc9a

Please sign in to comment.