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 std::error::Error for Error {}
31
32impl fmt::Display for Error {
33    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
34        write!(f, "{self:?}")
35    }
36}
37
38impl From<windows::core::Error> for Error {
39    fn from(err: windows::core::Error) -> Self {
40        Self::WindowsError(err)
41    }
42}
43
44impl From<HRESULT> for Error {
45    fn from(err: HRESULT) -> Self {
46        Self::WindowsError(windows::core::Error::from(err))
47    }
48}
49
50pub type Result<T> = std::result::Result<T, Error>;
51
52/// The WebView2 threading model runs everything on the UI thread, including callbacks which it triggers
53/// with `PostMessage`, and we're using this here because it's waiting for some async operations in WebView2
54/// to finish before starting the main message loop. As long as there are no pending results in `rx`, it
55/// will pump Window messages and check for a result after each message is dispatched.
56///
57/// `GetMessage` is a blocking call, so if we want to send results from another thread, senders from other
58/// threads should "kick" the message loop after sending the result by calling `PostThreadMessage` with an
59/// ignorable/unhandled message such as `WM_APP`.
60pub fn wait_with_pump<T>(rx: mpsc::Receiver<T>) -> Result<T> {
61    let mut msg = MSG::default();
62
63    loop {
64        if let Ok(result) = rx.try_recv() {
65            return Ok(result);
66        }
67
68        unsafe {
69            match WindowsAndMessaging::GetMessageA(&mut msg, None, 0, 0).0 {
70                -1 => {
71                    return Err(windows::core::Error::from_win32().into());
72                }
73                0 => return Err(Error::TaskCanceled),
74                _ => {
75                    let _ = WindowsAndMessaging::TranslateMessage(&msg);
76                    WindowsAndMessaging::DispatchMessageA(&msg);
77                }
78            }
79        }
80    }
81}