From e0cf2dd8b50721cc4261c3c15764044cfb11ca9e Mon Sep 17 00:00:00 2001 From: amrbashir Date: Fri, 9 May 2025 19:23:46 +0300 Subject: [PATCH 1/4] feat: check if webview runtime is accessible when creating a webview --- .changes/webview-runtime-check.md | 7 + crates/tauri-runtime-wry/Cargo.toml | 1 + crates/tauri-runtime-wry/src/dialog/mod.rs | 12 ++ .../tauri-runtime-wry/src/dialog/windows.rs | 123 ++++++++++++++++++ crates/tauri-runtime-wry/src/lib.rs | 18 +++ crates/tauri-runtime/src/lib.rs | 2 + crates/tauri/Cargo.toml | 1 + 7 files changed, 164 insertions(+) create mode 100644 .changes/webview-runtime-check.md create mode 100644 crates/tauri-runtime-wry/src/dialog/mod.rs create mode 100644 crates/tauri-runtime-wry/src/dialog/windows.rs diff --git a/.changes/webview-runtime-check.md b/.changes/webview-runtime-check.md new file mode 100644 index 000000000000..823d50f1bd70 --- /dev/null +++ b/.changes/webview-runtime-check.md @@ -0,0 +1,7 @@ +--- +"tauri": "patch:enhance" +"tauri-runtime-wry": "patch:enhance" +--- + +Check if the webview runtime is accessible when creating a webview, returning an error if it doesn't. + diff --git a/crates/tauri-runtime-wry/Cargo.toml b/crates/tauri-runtime-wry/Cargo.toml index 687c3d531b06..6678ec81427b 100644 --- a/crates/tauri-runtime-wry/Cargo.toml +++ b/crates/tauri-runtime-wry/Cargo.toml @@ -76,3 +76,4 @@ objc-exception = [] tracing = ["dep:tracing", "wry/tracing"] macos-proxy = ["wry/mac-proxy"] unstable = [] +common-controls-v6 = [] diff --git a/crates/tauri-runtime-wry/src/dialog/mod.rs b/crates/tauri-runtime-wry/src/dialog/mod.rs new file mode 100644 index 000000000000..f23d5b0e9a85 --- /dev/null +++ b/crates/tauri-runtime-wry/src/dialog/mod.rs @@ -0,0 +1,12 @@ +#[cfg(windows)] +mod windows; + +pub fn error>(err: S) { + #[cfg(windows)] + windows::error(err); + + #[cfg(not(windows))] + { + unimplemented!("Error dialog is not implemented for this platform"); + } +} diff --git a/crates/tauri-runtime-wry/src/dialog/windows.rs b/crates/tauri-runtime-wry/src/dialog/windows.rs new file mode 100644 index 000000000000..698091721a89 --- /dev/null +++ b/crates/tauri-runtime-wry/src/dialog/windows.rs @@ -0,0 +1,123 @@ +use windows::core::{w, HSTRING, PCWSTR}; + +enum Level { + Error, + #[allow(unused)] + Warning, + #[allow(unused)] + Info, +} + +pub fn error>(err: S) { + dialog_inner(err, Level::Error); +} + +fn dialog_inner>(err: S, level: Level) { + let err = err.as_ref(); + + let title = match level { + Level::Warning => w!("Warning"), + Level::Error => w!("Error"), + Level::Info => w!("Info"), + }; + + #[cfg(not(feature = "common-controls-v6"))] + { + use windows::Win32::UI::WindowsAndMessaging::*; + + let err = remove_hyperlink(err); + let err = HSTRING::from(err); + let err = PCWSTR(err.as_ptr()); + + unsafe { + MessageBoxW( + None, + err, + title, + match level { + Level::Warning => MB_ICONWARNING, + Level::Error => MB_ICONERROR, + Level::Info => MB_ICONINFORMATION, + }, + ) + }; + } + + #[cfg(feature = "common-controls-v6")] + { + use windows::core::HRESULT; + use windows::Win32::Foundation::*; + use windows::Win32::UI::Controls::*; + use windows::Win32::UI::Shell::*; + use windows::Win32::UI::WindowsAndMessaging::*; + + extern "system" fn task_dialog_callback( + _hwnd: HWND, + msg: TASKDIALOG_NOTIFICATIONS, + _wparam: WPARAM, + lparam: LPARAM, + _data: isize, + ) -> HRESULT { + if msg == TDN_HYPERLINK_CLICKED { + let link = PCWSTR(lparam.0 as _); + let _ = unsafe { ShellExecuteW(None, None, link, None, None, SW_SHOWNORMAL) }; + } + + S_OK + } + + let err = HSTRING::from(err); + let err = PCWSTR(err.as_ptr()); + + let task_dialog_config = TASKDIALOGCONFIG { + cbSize: std::mem::size_of::() as u32, + dwFlags: TDF_ALLOW_DIALOG_CANCELLATION | TDF_ENABLE_HYPERLINKS, + pszWindowTitle: title, + pszContent: err, + Anonymous1: TASKDIALOGCONFIG_0 { + pszMainIcon: match level { + Level::Warning => TD_WARNING_ICON, + Level::Error => TD_ERROR_ICON, + Level::Info => TD_INFORMATION_ICON, + }, + }, + dwCommonButtons: TDCBF_OK_BUTTON, + pfCallback: Some(task_dialog_callback), + ..Default::default() + }; + + let _ = unsafe { TaskDialogIndirect(&task_dialog_config, None, None, None) }; + } +} + +#[cfg(not(feature = "common-controls-v6"))] +fn remove_hyperlink(str: &str) -> String { + let mut result = String::new(); + let mut in_hyperlink = false; + + for c in str.chars() { + if c == '<' { + in_hyperlink = true; + } else if c == '>' { + in_hyperlink = false; + } else if !in_hyperlink { + result.push(c); + } + } + + result +} + +#[cfg(test)] +#[cfg(not(feature = "common-controls-v6"))] +mod tests { + use super::*; + + #[test] + fn test_remove_hyperlink() { + let input = "This is a test string."; + let expected = "This is a test string."; + let result = remove_hyperlink(input); + assert_eq!(result, expected); + } +} diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index ac5544a0690a..35cb0eea3635 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -130,6 +130,8 @@ use std::{ pub type WebviewId = u32; type IpcHandler = dyn Fn(Request) + 'static; +#[cfg(not(debug_assertions))] +mod dialog; mod monitor; #[cfg(any( windows, @@ -248,6 +250,7 @@ pub struct Context { next_webview_id: Arc, next_window_event_id: Arc, next_webview_event_id: Arc, + webview_runtime_installed: bool, } impl Context { @@ -2712,6 +2715,7 @@ impl Wry { next_webview_id: Default::default(), next_window_event_id: Default::default(), next_webview_event_id: Default::default(), + webview_runtime_installed: wry::webview_version().is_ok(), }; Ok(Self { @@ -4421,6 +4425,20 @@ fn create_webview( pending: PendingWebview>, #[allow(unused_variables)] focused_webview: Arc>>, ) -> Result { + if !context.webview_runtime_installed { + #[cfg(all(not(debug_assertions), windows))] + dialog::error( + r#"Could not find the WebView2 Runtime. + +Make sure it is installed or download it from https://developer.microsoft.com/en-us/microsoft-edge/webview2 + +You may have it installed on another user account, but it is not available for this one. +"#, + ); + + return Err(Error::WebviewRuntimeNotInstalled); + } + #[allow(unused_mut)] let PendingWebview { webview_attributes, diff --git a/crates/tauri-runtime/src/lib.rs b/crates/tauri-runtime/src/lib.rs index 201ec65b077d..546512261570 100644 --- a/crates/tauri-runtime/src/lib.rs +++ b/crates/tauri-runtime/src/lib.rs @@ -169,6 +169,8 @@ pub enum Error { #[cfg(any(target_os = "macos", target_os = "ios"))] #[error("failed to remove data store")] FailedToRemoveDataStore, + #[error("Could not find the webview runtime, make sure it is installed")] + WebviewRuntimeNotInstalled, } /// Result type. diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml index 6fb06201dfbd..cc72f79a311b 100644 --- a/crates/tauri/Cargo.toml +++ b/crates/tauri/Cargo.toml @@ -185,6 +185,7 @@ unstable = ["tauri-runtime-wry?/unstable"] common-controls-v6 = [ "tray-icon?/common-controls-v6", "muda/common-controls-v6", + "tauri-runtime-wry?/common-controls-v6", ] tray-icon = ["dep:tray-icon"] tracing = ["dep:tracing", "tauri-macros/tracing", "tauri-runtime-wry?/tracing"] From af9bc3b18821731abac3499c8b472852d1f0f66d Mon Sep 17 00:00:00 2001 From: amrbashir Date: Fri, 9 May 2025 19:24:42 +0300 Subject: [PATCH 2/4] license headers --- crates/tauri-runtime-wry/src/dialog/mod.rs | 4 ++++ crates/tauri-runtime-wry/src/dialog/windows.rs | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/crates/tauri-runtime-wry/src/dialog/mod.rs b/crates/tauri-runtime-wry/src/dialog/mod.rs index f23d5b0e9a85..156d6a6d2a4c 100644 --- a/crates/tauri-runtime-wry/src/dialog/mod.rs +++ b/crates/tauri-runtime-wry/src/dialog/mod.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + #[cfg(windows)] mod windows; diff --git a/crates/tauri-runtime-wry/src/dialog/windows.rs b/crates/tauri-runtime-wry/src/dialog/windows.rs index 698091721a89..710a256c1e84 100644 --- a/crates/tauri-runtime-wry/src/dialog/windows.rs +++ b/crates/tauri-runtime-wry/src/dialog/windows.rs @@ -1,3 +1,7 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + use windows::core::{w, HSTRING, PCWSTR}; enum Level { From fd1dcb2dab755c0abbcb9df6a1d31bcf432913aa Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Sat, 10 May 2025 05:05:19 +0300 Subject: [PATCH 3/4] Update crates/tauri-runtime-wry/src/dialog/windows.rs Co-authored-by: Tony <68118705+Legend-Master@users.noreply.github.com> --- crates/tauri-runtime-wry/src/dialog/windows.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/crates/tauri-runtime-wry/src/dialog/windows.rs b/crates/tauri-runtime-wry/src/dialog/windows.rs index 710a256c1e84..5ca5da8c487e 100644 --- a/crates/tauri-runtime-wry/src/dialog/windows.rs +++ b/crates/tauri-runtime-wry/src/dialog/windows.rs @@ -13,12 +13,10 @@ enum Level { } pub fn error>(err: S) { - dialog_inner(err, Level::Error); + dialog_inner(err.as_ref(), Level::Error); } -fn dialog_inner>(err: S, level: Level) { - let err = err.as_ref(); - +fn dialog_inner(err: &str, level: Level) { let title = match level { Level::Warning => w!("Warning"), Level::Error => w!("Error"), From 99bb35ad805fd2c5b8f286ccb2710bb36bbd7957 Mon Sep 17 00:00:00 2001 From: Amr Bashir Date: Sat, 10 May 2025 05:06:15 +0300 Subject: [PATCH 4/4] Update crates/tauri-runtime-wry/src/dialog/windows.rs Co-authored-by: Tony <68118705+Legend-Master@users.noreply.github.com> --- crates/tauri-runtime-wry/src/dialog/windows.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/tauri-runtime-wry/src/dialog/windows.rs b/crates/tauri-runtime-wry/src/dialog/windows.rs index 5ca5da8c487e..137371ef9641 100644 --- a/crates/tauri-runtime-wry/src/dialog/windows.rs +++ b/crates/tauri-runtime-wry/src/dialog/windows.rs @@ -29,7 +29,6 @@ fn dialog_inner(err: &str, level: Level) { let err = remove_hyperlink(err); let err = HSTRING::from(err); - let err = PCWSTR(err.as_ptr()); unsafe { MessageBoxW(