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.
This commit is contained in:
Your Name
2026-02-07 10:51:49 +02:00
parent e9021e51e5
commit 4f4599c4c9
2 changed files with 24 additions and 45 deletions

View File

@@ -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<u16> {
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() {