Skip to content

Commit bf1b5b5

Browse files
committed
fix(hardware): add PowerShell fallback for model name detection and filter placeholder values
detect_model_name had no PowerShell fallback — unlike all other detection functions, it returned None immediately if WMI failed via the ? operator. Restructured to try WMI first and fall back to PowerShell Get-CimInstance (querying cspVersion, cspName, csModel in priority order) so the model name is detected even on systems where WMI is unavailable. Added "system version", "none", "n/a", and "not applicable" to the normalize_model_name filter list, and introduced is_placeholder_model_name so that startup auto-fill also triggers when the saved model name is a known BIOS placeholder — not just when it is empty.
1 parent ade61ec commit bf1b5b5

3 files changed

Lines changed: 67 additions & 26 deletions

File tree

src-tauri/Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src-tauri/src/hardware.rs

Lines changed: 63 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -380,47 +380,87 @@ pub fn detect_system_brand() -> String {
380380

381381
// --- Model name detection --------------------------------------------------
382382

383+
#[cfg(windows)]
384+
#[derive(Deserialize, Debug, Default)]
385+
struct ModelNameInfo {
386+
#[serde(rename = "cspVersion")]
387+
csp_version: Option<String>,
388+
#[serde(rename = "cspName")]
389+
csp_name: Option<String>,
390+
#[serde(rename = "csModel")]
391+
cs_model: Option<String>,
392+
}
393+
383394
fn normalize_model_name(raw: &str) -> Option<String> {
384395
let trimmed = raw.trim();
385396
if trimmed.is_empty() {
386397
return None;
387398
}
388-
let invalid = ["to be filled by o.e.m.", "system product name", "default string", "unknown"];
399+
let invalid = ["to be filled by o.e.m.", "system product name", "system version", "default string", "unknown", "none", "n/a", "not applicable"];
389400
let lower = trimmed.to_ascii_lowercase();
390401
if invalid.iter().any(|x| lower == *x) {
391402
return None;
392403
}
393404
Some(trimmed.to_string())
394405
}
395406

407+
/// Returns true if the given model name is a known BIOS placeholder that
408+
/// should be replaced by auto-detection on the next startup.
409+
pub(crate) fn is_placeholder_model_name(name: &str) -> bool {
410+
normalize_model_name(name).is_none()
411+
}
412+
396413
/// Detects the system model name from WMI `Win32_ComputerSystemProduct`.
414+
/// Falls back to PowerShell `Get-CimInstance` if WMI is unavailable.
397415
pub fn detect_model_name() -> Option<String> {
398416
#[cfg(windows)]
399417
{
400-
let com = wmi::COMLibrary::new().ok()?;
401-
let conn = wmi::WMIConnection::new(com.into()).ok()?;
402-
403-
let products: Vec<ComputerSystemProduct> = conn.query().ok().unwrap_or_default();
404-
if let Some(v) = products
405-
.iter()
406-
.filter_map(|p| p.version.as_deref().and_then(normalize_model_name))
407-
.next()
408-
{
409-
return Some(v);
410-
}
411-
if let Some(v) = products
412-
.iter()
413-
.filter_map(|p| p.name.as_deref().and_then(normalize_model_name))
414-
.next()
415-
{
416-
return Some(v);
418+
if let Ok(com) = wmi::COMLibrary::new() {
419+
if let Ok(conn) = wmi::WMIConnection::new(com.into()) {
420+
let products: Vec<ComputerSystemProduct> = conn.query().ok().unwrap_or_default();
421+
if let Some(v) = products
422+
.iter()
423+
.filter_map(|p| p.version.as_deref().and_then(normalize_model_name))
424+
.next()
425+
{
426+
return Some(v);
427+
}
428+
if let Some(v) = products
429+
.iter()
430+
.filter_map(|p| p.name.as_deref().and_then(normalize_model_name))
431+
.next()
432+
{
433+
return Some(v);
434+
}
435+
let systems: Vec<ComputerSystem> = conn.query().ok().unwrap_or_default();
436+
if let Some(v) = systems
437+
.iter()
438+
.filter_map(|s| s.model.as_deref().and_then(normalize_model_name))
439+
.next()
440+
{
441+
return Some(v);
442+
}
443+
}
417444
}
418445

419-
let systems: Vec<ComputerSystem> = conn.query().ok().unwrap_or_default();
420-
systems
421-
.iter()
422-
.filter_map(|s| s.model.as_deref().and_then(normalize_model_name))
423-
.next()
446+
// Fallback: query via PowerShell CIM if WMI is unavailable.
447+
let output = run_hidden_command(
448+
"powershell",
449+
&[
450+
"-NoProfile",
451+
"-Command",
452+
"$csp=Get-CimInstance Win32_ComputerSystemProduct;$cs=Get-CimInstance Win32_ComputerSystem;[pscustomobject]@{cspVersion=$csp.Version;cspName=$csp.Name;csModel=$cs.Model}|ConvertTo-Json -Compress",
453+
],
454+
)
455+
.ok()?;
456+
if !output.status.success() {
457+
return None;
458+
}
459+
let raw = String::from_utf8_lossy(&output.stdout).trim().to_string();
460+
let info = serde_json::from_str::<ModelNameInfo>(&raw).ok()?;
461+
if let Some(v) = info.csp_version.as_deref().and_then(normalize_model_name) { return Some(v); }
462+
if let Some(v) = info.csp_name.as_deref().and_then(normalize_model_name) { return Some(v); }
463+
info.cs_model.as_deref().and_then(normalize_model_name)
424464
}
425465

426466
#[cfg(not(windows))]

src-tauri/src/main.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use debug::{append_debug_log, reset_debug_log};
2727
use diagnostics::collect_diagnostics;
2828
use hardware::{
2929
detect_gpu_vram_total_mb, detect_model_name, detect_ping_target, detect_ram_details,
30-
detect_ram_spec, detect_system_brand, probe_wmi_status,
30+
detect_ram_spec, detect_system_brand, is_placeholder_model_name, probe_wmi_status,
3131
};
3232
use lhm_process::ensure_lhm_running;
3333
use monitor::pick_target_monitor;
@@ -140,7 +140,8 @@ fn main() {
140140

141141
let mut settings = load_settings(&app_handle);
142142
let should_autofill_model = settings.model_name.trim().is_empty()
143-
|| settings.model_name.trim() == LEGACY_DEFAULT_MODEL_NAME;
143+
|| settings.model_name.trim() == LEGACY_DEFAULT_MODEL_NAME
144+
|| is_placeholder_model_name(settings.model_name.trim());
144145
if should_autofill_model {
145146
if let Some(model_name) = detect_model_name() {
146147
settings.model_name = model_name;

0 commit comments

Comments
 (0)