webview2_com/
lib.rs

1extern crate webview2_com_sys;
2pub use webview2_com_sys::Microsoft;
3
4#[macro_use]
5extern crate webview2_com_macros;
6
7mod callback;
8mod options;
9mod pwstr;
10
11use std::{fmt, sync::mpsc};
12
13use windows::{
14    core::HRESULT,
15    Win32::UI::WindowsAndMessaging::{self, MSG},
16};
17
18pub use callback::*;
19pub use options::*;
20pub use pwstr::*;
21
22#[derive(Debug)]
23pub enum Error {
24    WindowsError(windows::core::Error),
25    CallbackError(String),
26    TaskCanceled,
27    SendError,
28}
29
30impl fmt::Display for Error {
31    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32        write!(f, "{self:?}")
33    }
34}
35
36impl From<windows::core::Error> for Error {
37    fn from(err: windows::core::Error) -> Self {
38        Self::WindowsError(err)
39    }
40}
41
42impl From<HRESULT> for Error {
43    fn from(err: HRESULT) -> Self {
44        Self::WindowsError(windows::core::Error::from(err))
45    }
46}
47
48pub type Result<T> = std::result::Result<T, Error>;
49
50/// The WebView2 threading model runs everything on the UI thread, including callbacks which it triggers
51/// with `PostMessage`, and we're using this here because it's waiting for some async operations in WebView2
52/// to finish before starting the main message loop. As long as there are no pending results in `rx`, it
53/// will pump Window messages and check for a result after each message is dispatched.
54///
55/// `GetMessage` is a blocking call, so if we want to send results from another thread, senders from other
56/// threads should "kick" the message loop after sending the result by calling `PostThreadMessage` with an
57/// ignorable/unhandled message such as `WM_APP`.
58pub fn wait_with_pump<T>(rx: mpsc::Receiver<T>) -> Result<T> {
59    let mut msg = MSG::default();
60
61    loop {
62        if let Ok(result) = rx.try_recv() {
63            return Ok(result);
64        }
65
66        unsafe {
67            match WindowsAndMessaging::GetMessageA(&mut msg, None, 0, 0).0 {
68                -1 => {
69                    return Err(windows::core::Error::from_win32().into());
70                }
71                0 => return Err(Error::TaskCanceled),
72                _ => {
73                    let _ = WindowsAndMessaging::TranslateMessage(&msg);
74                    WindowsAndMessaging::DispatchMessageA(&msg);
75                }
76            }
77        }
78    }
79}