diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 4194787..e7dc101 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"] } +winapi = { version = "0.3", features = ["winuser", "sysinfoapi", "windef", "winreg", "shellapi"] } diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 74841d0..e5a6614 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -2,5 +2,87 @@ #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")] fn main() { + #[cfg(windows)] + if !webview2_check::is_webview2_installed() { + webview2_check::show_missing_dialog(); + return; + } + core_cooldown_lib::run() } + +#[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}"; + + 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) + } + + pub fn show_missing_dialog() { + let title = to_wide("Core Cooldown - WebView2 Required"); + let message = to_wide( + "Microsoft WebView2 Runtime is required to run Core Cooldown, \ + but it was not found on this system.\n\n\ + Click OK to open the download page in your browser.\n\n\ + After installing WebView2, restart Core Cooldown." + ); + let url = to_wide("https://developer.microsoft.com/en-us/microsoft-edge/webview2/consumer"); + let open = to_wide("open"); + + unsafe { + MessageBoxW(ptr::null_mut(), message.as_ptr(), title.as_ptr(), MB_OK | MB_ICONWARNING); + ShellExecuteW(ptr::null_mut(), open.as_ptr(), url.as_ptr(), ptr::null(), ptr::null(), 1); + } + } +}