From 4f4599c4c92b86fafb7a195d72dc2bc8063e1203 Mon Sep 17 00:00:00 2001 From: Your Name Date: Sat, 7 Feb 2026 10:51:49 +0200 Subject: [PATCH] Fix WebView2 detection - use loader API instead of registry Registry check gave false negatives on systems where WebView2 is installed through Edge rather than EdgeUpdate. Now calls GetAvailableCoreWebView2BrowserVersionString (statically linked) which detects all installation methods. --- src-tauri/Cargo.toml | 2 +- src-tauri/src/main.rs | 67 +++++++++++++++---------------------------- 2 files changed, 24 insertions(+), 45 deletions(-) diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index e7dc101..d670d8f 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -22,4 +22,4 @@ chrono = "0.4" anyhow = "1" [target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["winuser", "sysinfoapi", "windef", "winreg", "shellapi"] } +winapi = { version = "0.3", features = ["winuser", "sysinfoapi", "windef", "shellapi"] } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index e5a6614..2e14d9f 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -14,59 +14,38 @@ fn main() { #[cfg(windows)] mod webview2_check { use std::ptr; - use winapi::shared::minwindef::{HKEY, MAX_PATH}; - use winapi::um::winnt::{KEY_READ, REG_SZ}; - use winapi::um::winreg::{RegOpenKeyExW, RegQueryValueExW, RegCloseKey, HKEY_LOCAL_MACHINE, HKEY_CURRENT_USER}; use winapi::um::winuser::{MessageBoxW, MB_OK, MB_ICONWARNING}; use winapi::um::shellapi::ShellExecuteW; - const WEBVIEW2_GUID: &str = r"SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BEB-E15AB5810CD5}"; - const WEBVIEW2_GUID_USER: &str = r"Software\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BEB-E15AB5810CD5}"; + // Statically linked from WebView2LoaderStatic.lib via msvc_compat shims + extern "system" { + fn GetAvailableCoreWebView2BrowserVersionString( + browser_executable_folder: *const u16, + version_info: *mut *mut u16, + ) -> i32; + } + + extern "system" { + fn CoTaskMemFree(pv: *mut std::ffi::c_void); + } fn to_wide(s: &str) -> Vec { s.encode_utf16().chain(std::iter::once(0)).collect() } - fn check_registry_key(root: HKEY, subkey: &str) -> bool { - unsafe { - let subkey_w = to_wide(subkey); - let value_name = to_wide("pv"); - let mut hkey: HKEY = ptr::null_mut(); - - let status = RegOpenKeyExW(root, subkey_w.as_ptr(), 0, KEY_READ, &mut hkey); - if status != 0 { - return false; - } - - let mut data = [0u16; MAX_PATH]; - let mut data_size = (data.len() * 2) as u32; - let mut data_type = 0u32; - - let status = RegQueryValueExW( - hkey, - value_name.as_ptr(), - ptr::null_mut(), - &mut data_type, - data.as_mut_ptr() as *mut u8, - &mut data_size, - ); - - RegCloseKey(hkey); - - if status != 0 || data_type != REG_SZ { - return false; - } - - // Convert to string and check it's not empty or "0.0.0.0" - let len = (data_size as usize / 2).saturating_sub(1); // exclude null terminator - let version = String::from_utf16_lossy(&data[..len]); - !version.is_empty() && version != "0.0.0.0" - } - } - pub fn is_webview2_installed() -> bool { - check_registry_key(HKEY_LOCAL_MACHINE, WEBVIEW2_GUID) - || check_registry_key(HKEY_CURRENT_USER, WEBVIEW2_GUID_USER) + unsafe { + let mut version_info: *mut u16 = ptr::null_mut(); + let hr = GetAvailableCoreWebView2BrowserVersionString( + ptr::null(), + &mut version_info, + ); + let installed = hr == 0 && !version_info.is_null(); + if !version_info.is_null() { + CoTaskMemFree(version_info as *mut _); + } + installed + } } pub fn show_missing_dialog() {