1use crate::{HardwareQueryError, Result};
3use std::collections::HashMap;
4use wmi::{COMLibrary, Variant, WMIConnection};
5
6#[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 pub fn query() -> Result<Self> {
31 let com_lib = COMLibrary::new()?;
32 let wmi_con = WMIConnection::new(com_lib)?;
33
34 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, 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, temperature: None, })
65 }
66
67 pub fn get_temperature(&self) -> Result<Option<f32>> {
69 let com_lib = COMLibrary::new()?;
70 let wmi_con = WMIConnection::new(com_lib)?;
71
72 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 return Ok(Some((temp / 10.0) - 273.15));
81 }
82 }
83
84 Ok(None)
85 }
86
87 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 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 pub fn get_vulnerabilities(&self) -> Result<Vec<String>> {
108 let vulnerabilities = Vec::new();
109
110 Ok(vulnerabilities)
115 }
116
117 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 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 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#[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 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, };
190 gpu_info.push(info);
191 }
192
193 Ok(gpu_info)
194 }
195
196 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 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#[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 pub fn query() -> Result<Self> {
246 let com_lib = COMLibrary::new()?;
247 let wmi_con = WMIConnection::new(com_lib)?;
248
249 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 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 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}