Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,12 @@ wmi = "0.12.0"
winreg = "0.10.1"
windows = { version = "0.39.0", features = [
"Win32_Foundation",
"Win32_Graphics_Gdi",
"Win32_System_Power",
"Win32_System_SystemInformation",
"Win32_System_WindowsProgramming"
"Win32_System_WindowsProgramming",
"Win32_UI_HiDpi",
"Win32_UI_WindowsAndMessaging",
]}

[target.'cfg(not(target_os = "windows"))'.dependencies]
Expand Down
129 changes: 126 additions & 3 deletions src/windows/mod.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
use crate::traits::*;
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use std::path::PathBuf;
use winreg::enums::*;
use winreg::RegKey;
use wmi::WMIResult;
use wmi::{COMLibrary, Variant, WMIConnection};

use windows::{
core::PSTR, Win32::System::Power::GetSystemPowerStatus,
core::{PSTR, PCWSTR},
Win32::Graphics::Gdi::{
EnumDisplayDevicesW,
DISPLAY_DEVICEW,
},
Win32::System::Power::GetSystemPowerStatus,
Win32::System::Power::SYSTEM_POWER_STATUS,
Win32::System::SystemInformation::GetComputerNameExA,
Win32::System::SystemInformation::GetTickCount64,
Win32::System::SystemInformation::GlobalMemoryStatusEx,
Win32::System::SystemInformation::MEMORYSTATUSEX,
Win32::System::WindowsProgramming::GetUserNameA,
Win32::UI::WindowsAndMessaging::EDD_GET_DEVICE_INTERFACE_NAME,
};

impl From<wmi::WMIError> for ReadoutError {
Expand Down Expand Up @@ -343,7 +349,124 @@ impl GeneralReadout for WindowsGeneralReadout {
}

fn gpus(&self) -> Result<Vec<String>, ReadoutError> {
Err(ReadoutError::NotImplemented)
// Sources:
// https://github.com/Carterpersall/OxiFetch/blob/main/src/main.rs#L360
// https://github.com/lptstr/winfetch/pull/155

// Create the Vector to store each GPU's name.
let mut output: Vec<String> = Vec::new();

let hklm = RegKey::predef(HKEY_LOCAL_MACHINE);

// Open the location where some DirectX information is stored
if let Ok(dx_key) = hklm.open_subkey("SOFTWARE\\Microsoft\\DirectX\\") {
// Get the parent key's LastSeen value
if let Ok(lastseen) = dx_key.get_value::<u64, _>("LastSeen") {
// Iterate over the parent key's subkeys and find the ones with the same LastSeen value
for key in dx_key.enum_keys() {
if key.is_err() {
continue;
}
let key = key.unwrap();

let sublastseen = match dx_key
.open_subkey(&key)
.unwrap()
Comment thread
Carterpersall marked this conversation as resolved.
Outdated
.get_value::<u64, _>("LastSeen")
{
Ok(key) => key,
Err(_) => continue,
};

if sublastseen == lastseen {
// Get the GPU's name
let name = match dx_key
.open_subkey(&key)
.unwrap()
.get_value::<String, _>("Description")
{
Ok(key) => key,
Err(_) => continue,
};

// Exclude the Microsoft Basic Render Driver
if name == "Microsoft Basic Render Driver" {
continue;
}

// Add the GPU's name to the output vector
output.push(name);
}
}
};
};

// Some systems have a DirectX key that lacks the LastSeen value, so a backup method is needed.
if !output.is_empty() {
return Ok(output);
}

// Alternative Method 1: Get GPUs by getting every display device
let mut devices = Vec::new();
let mut index = 0;
let mut status = true;
// Iterate over EnumDisplayDevicesW until it returns false
while status {
devices.push(DISPLAY_DEVICEW::default());
devices[index].cb = std::mem::size_of::<DISPLAY_DEVICEW>() as u32;
unsafe {
status = EnumDisplayDevicesW(
PCWSTR::null(),
index as u32,
&mut devices[index],
EDD_GET_DEVICE_INTERFACE_NAME,
).as_bool();
};
index += 1;
}
// Remove the last element, which will be invalid
devices.pop();

// Create a hashset to store the GPU names, which will prevent duplicates
let mut gpus: HashSet<String> = HashSet::new();

// Iterate over each device
for device in devices {
// Convert [u16; 128] to a String and add to the HashSet
match String::from_utf16(&device.DeviceString) {
Ok(gpu) => {
gpus.insert(gpu.trim_matches(char::from(0)).to_string());
}
Err(_) => continue,
}
}

if !gpus.is_empty() {
// Convert the HashSet to a Vec and return it
return Ok(gpus.into_iter().collect());
}

// Alternative Method 2: Use WMI to query Win32_VideoController

// Create a WMI connection
let wmi_con = wmi_connection()?;

// Query the WMI connection
let results: Vec<HashMap<String, Variant>> =
wmi_con.raw_query("SELECT Name FROM Win32_VideoController")?;

// Get each GPU's name
for result in results {
if let Some(Variant::String(gpu)) = result.get("Name") {
output.push(gpu.to_string());
}
}

if !output.is_empty() {
return Ok(output);
}

Err(ReadoutError::Other("Failed to find any GPUs.".to_string()))
}
}

Expand Down