Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changes/webview-runtime-check.md
Original file line number Diff line number Diff line change
@@ -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.

1 change: 1 addition & 0 deletions crates/tauri-runtime-wry/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -76,3 +76,4 @@ objc-exception = []
tracing = ["dep:tracing", "wry/tracing"]
macos-proxy = ["wry/mac-proxy"]
unstable = []
common-controls-v6 = []
16 changes: 16 additions & 0 deletions crates/tauri-runtime-wry/src/dialog/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT

#[cfg(windows)]
mod windows;

pub fn error<S: AsRef<str>>(err: S) {
#[cfg(windows)]
windows::error(err);

#[cfg(not(windows))]
{
unimplemented!("Error dialog is not implemented for this platform");
}
}
124 changes: 124 additions & 0 deletions crates/tauri-runtime-wry/src/dialog/windows.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// 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 {
Error,
#[allow(unused)]
Warning,
#[allow(unused)]
Info,
}

pub fn error<S: AsRef<str>>(err: S) {
dialog_inner(err.as_ref(), Level::Error);
}

fn dialog_inner(err: &str, level: Level) {
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);

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());
Comment thread
Legend-Master marked this conversation as resolved.

let task_dialog_config = TASKDIALOGCONFIG {
cbSize: std::mem::size_of::<TASKDIALOGCONFIG>() 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 <A href=\"some link\">test</A> string.";
let expected = "This is a test string.";
let result = remove_hyperlink(input);
assert_eq!(result, expected);
}
}
18 changes: 18 additions & 0 deletions crates/tauri-runtime-wry/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ use std::{
pub type WebviewId = u32;
type IpcHandler = dyn Fn(Request<String>) + 'static;

#[cfg(not(debug_assertions))]
mod dialog;
mod monitor;
#[cfg(any(
windows,
Expand Down Expand Up @@ -248,6 +250,7 @@ pub struct Context<T: UserEvent> {
next_webview_id: Arc<AtomicU32>,
next_window_event_id: Arc<AtomicU32>,
next_webview_event_id: Arc<AtomicU32>,
webview_runtime_installed: bool,
}

impl<T: UserEvent> Context<T> {
Expand Down Expand Up @@ -2712,6 +2715,7 @@ impl<T: UserEvent> Wry<T> {
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 {
Expand Down Expand Up @@ -4421,6 +4425,20 @@ fn create_webview<T: UserEvent>(
pending: PendingWebview<T, Wry<T>>,
#[allow(unused_variables)] focused_webview: Arc<Mutex<Option<String>>>,
) -> Result<WebviewWrapper> {
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 <A href="https://developer.microsoft.com/en-us/microsoft-edge/webview2">https://developer.microsoft.com/en-us/microsoft-edge/webview2</A>

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,
Expand Down
2 changes: 2 additions & 0 deletions crates/tauri-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions crates/tauri/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"]
Expand Down