hardware_query/platform/
windows.rs

1/// Enhanced platform-specific hardware detection for Windows
2use crate::{HardwareQueryError, Result};
3use std::collections::HashMap;
4use wmi::{COMLibrary, Variant, WMIConnection};
5
6/// Windows-specific CPU information
7#[derive(Debug, Clone)]
8pub struct WindowsCPUInfo {
9    pub name: String,
10    pub vendor: String,
11    pub description: String,
12    pub family: Option<u32>,
13    pub model: Option<u32>,
14    pub stepping: Option<u32>,
15    pub microcode: Option<String>,
16    pub cores: u32,
17    pub threads: u32,
18    pub base_frequency: u32,
19    pub max_frequency: u32,
20    pub l1_cache: u32,
21    pub l2_cache: u32,
22    pub l3_cache: u32,
23    pub voltage: Option<f32>,
24    pub power_consumption: Option<f32>,
25    pub temperature: Option<f32>,
26}
27
28impl WindowsCPUInfo {
29    /// Query detailed CPU information from Windows WMI
30    pub fn query() -> Result<Self> {
31        let com_lib = COMLibrary::new()?;
32        let wmi_con = WMIConnection::new(com_lib)?;
33
34        // Query processor information
35        let processor_query = "SELECT Name, Manufacturer, Description, Family, Model, Stepping, NumberOfCores, NumberOfLogicalProcessors, MaxClockSpeed, L1CacheSize, L2CacheSize, L3CacheSize, Voltage, CurrentVoltage FROM Win32_Processor";
36        let processors: Vec<HashMap<String, Variant>> = wmi_con.raw_query(processor_query)?;
37
38        if processors.is_empty() {
39            return Err(HardwareQueryError::system_info_unavailable(
40                "No processor information found",
41            ));
42        }
43
44        let processor = &processors[0];
45
46        Ok(Self {
47            name: Self::get_string_value(processor, "Name").unwrap_or_default(),
48            vendor: Self::get_string_value(processor, "Manufacturer").unwrap_or_default(),
49            description: Self::get_string_value(processor, "Description").unwrap_or_default(),
50            family: Self::get_u32_value(processor, "Family"),
51            model: Self::get_u32_value(processor, "Model"),
52            stepping: Self::get_u32_value(processor, "Stepping"),
53            microcode: None, // Not available through WMI
54            cores: Self::get_u32_value(processor, "NumberOfCores").unwrap_or(0),
55            threads: Self::get_u32_value(processor, "NumberOfLogicalProcessors").unwrap_or(0),
56            base_frequency: Self::get_u32_value(processor, "MaxClockSpeed").unwrap_or(0),
57            max_frequency: Self::get_u32_value(processor, "MaxClockSpeed").unwrap_or(0),
58            l1_cache: Self::get_u32_value(processor, "L1CacheSize").unwrap_or(0),
59            l2_cache: Self::get_u32_value(processor, "L2CacheSize").unwrap_or(0),
60            l3_cache: Self::get_u32_value(processor, "L3CacheSize").unwrap_or(0),
61            voltage: Self::get_f32_value(processor, "CurrentVoltage"),
62            power_consumption: None, // Requires additional queries
63            temperature: None,       // Requires additional queries
64        })
65    }
66
67    /// Get CPU temperature from thermal sensors
68    pub fn get_temperature(&self) -> Result<Option<f32>> {
69        let com_lib = COMLibrary::new()?;
70        let wmi_con = WMIConnection::new(com_lib)?;
71
72        // Try to get temperature from thermal zone
73        let thermal_query = "SELECT Temperature FROM Win32_TemperatureProbe";
74        let thermal_info: Vec<HashMap<String, Variant>> =
75            wmi_con.raw_query(thermal_query).unwrap_or_default();
76
77        for info in thermal_info {
78            if let Some(temp) = Self::get_f32_value(&info, "Temperature") {
79                // Convert from tenths of Kelvin to Celsius
80                return Ok(Some((temp / 10.0) - 273.15));
81            }
82        }
83
84        Ok(None)
85    }
86
87    /// Get CPU power consumption
88    pub fn get_power_consumption(&self) -> Result<Option<f32>> {
89        let com_lib = COMLibrary::new()?;
90        let wmi_con = WMIConnection::new(com_lib)?;
91
92        // Try to get power information from performance counters
93        let power_query = "SELECT PowerConsumption FROM Win32_Processor";
94        let power_info: Vec<HashMap<String, Variant>> =
95            wmi_con.raw_query(power_query).unwrap_or_default();
96
97        for info in power_info {
98            if let Some(power) = Self::get_f32_value(&info, "PowerConsumption") {
99                return Ok(Some(power));
100            }
101        }
102
103        Ok(None)
104    }
105
106    /// Get CPU vulnerabilities from registry or system info
107    pub fn get_vulnerabilities(&self) -> Result<Vec<String>> {
108        let vulnerabilities = Vec::new();
109
110        // Check for common CPU vulnerabilities
111        // This would require reading from registry or system files
112        // For now, return empty list
113
114        Ok(vulnerabilities)
115    }
116
117    /// Helper function to extract string values from WMI results
118    fn get_string_value(map: &HashMap<String, Variant>, key: &str) -> Option<String> {
119        match map.get(key) {
120            Some(Variant::String(s)) => Some(s.clone()),
121            Some(Variant::Null) => None,
122            _ => None,
123        }
124    }
125
126    /// Helper function to extract u32 values from WMI results
127    fn get_u32_value(map: &HashMap<String, Variant>, key: &str) -> Option<u32> {
128        match map.get(key) {
129            Some(Variant::UI4(val)) => Some(*val),
130            Some(Variant::UI2(val)) => Some(*val as u32),
131            Some(Variant::UI1(val)) => Some(*val as u32),
132            Some(Variant::I4(val)) => Some(*val as u32),
133            Some(Variant::I2(val)) => Some(*val as u32),
134            Some(Variant::I1(val)) => Some(*val as u32),
135            Some(Variant::Null) => None,
136            _ => None,
137        }
138    }
139
140    /// Helper function to extract f32 values from WMI results
141    fn get_f32_value(map: &HashMap<String, Variant>, key: &str) -> Option<f32> {
142        match map.get(key) {
143            Some(Variant::R4(val)) => Some(*val),
144            Some(Variant::R8(val)) => Some(*val as f32),
145            Some(Variant::UI4(val)) => Some(*val as f32),
146            Some(Variant::I4(val)) => Some(*val as f32),
147            Some(Variant::Null) => None,
148            _ => None,
149        }
150    }
151}
152
153/// Windows-specific GPU information
154#[derive(Debug, Clone)]
155pub struct WindowsGPUInfo {
156    pub name: String,
157    pub vendor: String,
158    pub memory_mb: u64,
159    pub driver_version: Option<String>,
160    pub device_id: Option<String>,
161    pub adapter_ram: Option<u64>,
162    pub dedicated_memory: Option<u64>,
163    pub shared_memory: Option<u64>,
164    pub current_usage: Option<f32>,
165}
166
167impl WindowsGPUInfo {
168    /// Query GPU information from Windows WMI
169    pub fn query_all() -> Result<Vec<Self>> {
170        let com_lib = COMLibrary::new()?;
171        let wmi_con = WMIConnection::new(com_lib)?;
172
173        let gpu_query = "SELECT Name, AdapterCompatibility, AdapterRAM, DriverVersion, DeviceID, DedicatedVideoMemory, SharedSystemMemory FROM Win32_VideoController";
174        let gpus: Vec<HashMap<String, Variant>> = wmi_con.raw_query(gpu_query)?;
175
176        let mut gpu_info = Vec::new();
177
178        for gpu in gpus {
179            let info = Self {
180                name: Self::get_string_value(&gpu, "Name").unwrap_or_default(),
181                vendor: Self::get_string_value(&gpu, "AdapterCompatibility").unwrap_or_default(),
182                memory_mb: Self::get_u64_value(&gpu, "AdapterRAM").unwrap_or(0) / (1024 * 1024),
183                driver_version: Self::get_string_value(&gpu, "DriverVersion"),
184                device_id: Self::get_string_value(&gpu, "DeviceID"),
185                adapter_ram: Self::get_u64_value(&gpu, "AdapterRAM"),
186                dedicated_memory: Self::get_u64_value(&gpu, "DedicatedVideoMemory"),
187                shared_memory: Self::get_u64_value(&gpu, "SharedSystemMemory"),
188                current_usage: None, // Would require performance counters
189            };
190            gpu_info.push(info);
191        }
192
193        Ok(gpu_info)
194    }
195
196    /// Helper function to extract string values from WMI results
197    fn get_string_value(map: &HashMap<String, Variant>, key: &str) -> Option<String> {
198        match map.get(key) {
199            Some(Variant::String(s)) => Some(s.clone()),
200            Some(Variant::Null) => None,
201            _ => None,
202        }
203    }
204
205    /// Helper function to extract u64 values from WMI results
206    fn get_u64_value(map: &HashMap<String, Variant>, key: &str) -> Option<u64> {
207        match map.get(key) {
208            Some(Variant::UI8(val)) => Some(*val),
209            Some(Variant::UI4(val)) => Some(*val as u64),
210            Some(Variant::UI2(val)) => Some(*val as u64),
211            Some(Variant::UI1(val)) => Some(*val as u64),
212            Some(Variant::I8(val)) => Some(*val as u64),
213            Some(Variant::I4(val)) => Some(*val as u64),
214            Some(Variant::I2(val)) => Some(*val as u64),
215            Some(Variant::I1(val)) => Some(*val as u64),
216            Some(Variant::Null) => None,
217            _ => None,
218        }
219    }
220}
221
222/// Windows-specific memory information
223#[derive(Debug, Clone)]
224pub struct WindowsMemoryInfo {
225    pub total_physical_mb: u64,
226    pub available_physical_mb: u64,
227    pub total_virtual_mb: u64,
228    pub available_virtual_mb: u64,
229    pub modules: Vec<WindowsMemoryModule>,
230}
231
232#[derive(Debug, Clone)]
233pub struct WindowsMemoryModule {
234    pub capacity_mb: u64,
235    pub speed_mhz: u32,
236    pub memory_type: String,
237    pub manufacturer: Option<String>,
238    pub part_number: Option<String>,
239    pub bank_label: Option<String>,
240    pub device_locator: Option<String>,
241}
242
243impl WindowsMemoryInfo {
244    /// Query memory information from Windows WMI
245    pub fn query() -> Result<Self> {
246        let com_lib = COMLibrary::new()?;
247        let wmi_con = WMIConnection::new(com_lib)?;
248
249        // Query physical memory
250        let memory_query = "SELECT TotalPhysicalMemory, AvailablePhysicalMemory, TotalVirtualMemorySize, AvailableVirtualMemory FROM Win32_OperatingSystem";
251        let memory_info: Vec<HashMap<String, Variant>> = wmi_con.raw_query(memory_query)?;
252
253        let mut total_physical_mb = 0;
254        let mut available_physical_mb = 0;
255        let mut total_virtual_mb = 0;
256        let mut available_virtual_mb = 0;
257
258        if let Some(info) = memory_info.first() {
259            total_physical_mb = WindowsGPUInfo::get_u64_value(info, "TotalPhysicalMemory")
260                .unwrap_or(0)
261                / (1024 * 1024);
262            available_physical_mb = WindowsGPUInfo::get_u64_value(info, "AvailablePhysicalMemory")
263                .unwrap_or(0)
264                / (1024 * 1024);
265            total_virtual_mb = WindowsGPUInfo::get_u64_value(info, "TotalVirtualMemorySize")
266                .unwrap_or(0)
267                / (1024 * 1024);
268            available_virtual_mb = WindowsGPUInfo::get_u64_value(info, "AvailableVirtualMemory")
269                .unwrap_or(0)
270                / (1024 * 1024);
271        }
272
273        // Query memory modules
274        let modules_query = "SELECT Capacity, Speed, MemoryType, Manufacturer, PartNumber, BankLabel, DeviceLocator FROM Win32_PhysicalMemory";
275        let modules: Vec<HashMap<String, Variant>> = wmi_con.raw_query(modules_query)?;
276
277        let mut memory_modules = Vec::new();
278        for module in modules {
279            let module_info = WindowsMemoryModule {
280                capacity_mb: WindowsGPUInfo::get_u64_value(&module, "Capacity").unwrap_or(0)
281                    / (1024 * 1024),
282                speed_mhz: WindowsGPUInfo::get_u64_value(&module, "Speed").unwrap_or(0) as u32,
283                memory_type: Self::parse_memory_type(
284                    WindowsGPUInfo::get_u64_value(&module, "MemoryType").unwrap_or(0),
285                ),
286                manufacturer: WindowsGPUInfo::get_string_value(&module, "Manufacturer"),
287                part_number: WindowsGPUInfo::get_string_value(&module, "PartNumber"),
288                bank_label: WindowsGPUInfo::get_string_value(&module, "BankLabel"),
289                device_locator: WindowsGPUInfo::get_string_value(&module, "DeviceLocator"),
290            };
291            memory_modules.push(module_info);
292        }
293
294        Ok(Self {
295            total_physical_mb,
296            available_physical_mb,
297            total_virtual_mb,
298            available_virtual_mb,
299            modules: memory_modules,
300        })
301    }
302
303    /// Parse memory type from WMI integer value
304    fn parse_memory_type(type_code: u64) -> String {
305        match type_code {
306            20 => "DDR".to_string(),
307            21 => "DDR2".to_string(),
308            22 => "DDR2 FB-DIMM".to_string(),
309            24 => "DDR3".to_string(),
310            26 => "DDR4".to_string(),
311            34 => "DDR5".to_string(),
312            _ => format!("Unknown ({type_code})"),
313        }
314    }
315}