为什么 WebViewControlProcess.CreateWebViewControlAsync() 永远不会完成?
Why is WebViewControlProcess.CreateWebViewControlAsync() never completing?
我正在尝试编写一些使用 Windows.Web.UI.Interop.WebViewControl
的 Rust 代码(这是一个通用的 Windows 平台进程外包装器,专门设计用于 Win32 应用程序可以使用 EdgeHTML),它是所有编译,但在运行时无法正常工作。
相关代码归结为这样,使用了 winit、winapi 和 winrt crates:
use winit::os::windows::WindowExt;
use winit::{EventsLoop, WindowBuilder};
use winapi::winrt::roapi::{RoInitialize, RO_INIT_SINGLETHREADED};
use winapi::shared::winerror::S_OK;
use winrt::{RtDefaultConstructible, RtAsyncOperation};
use winrt::windows::foundation::Rect;
use winrt::windows::web::ui::interop::WebViewControlProcess;
fn main() {
assert!(unsafe { RoInitialize(RO_INIT_SINGLETHREADED) } == S_OK);
let mut events_loop = EventsLoop::new();
let window = WindowBuilder::new()
.build(&events_loop)
.unwrap();
WebViewControlProcess::new()
.create_web_view_control_async(
window.get_hwnd() as usize as i64,
Rect {
X: 0.0,
Y: 0.0,
Width: 800.0,
Height: 600.0,
},
)
.expect("Creation call failed")
.blocking_get()
.expect("Creation async task failed")
.expect("Creation produced None");
}
WebViewControlProcess
实例化有效,CreateWebViewControlAsync
函数似乎确实关心它作为 host_window_handle
收到的值(传递 0,或从实际 HWND
值,它会抱怨)。然而 IAsyncOperation
坚定地停留在 AsyncStatus.Started
(0),因此 blocking_get()
调用无限期挂起。
A full, runnable demonstration of the issue (with a bit more instrumentation).
我感觉 WebViewControlProcess
出了问题:它的 ProcessId
停留在 0,而且看起来没有生成任何子进程。 ProcessExited
事件 似乎 没有被触发(我在实例化后立即附加了一些东西,它是否有机会在此之前被触发?)。在这种情况下,调用 Terminate()
可能会失败,E_FAIL
.
我是否错过了使用 Windows.Web.UI.Interop
的某种初始化?还是有其他原因导致它不起作用?
尝试用 winrt::init_apartment();
初始化 WebViewProcessControl
并且它可能需要一个单线程单元(根据这个 )。
更多关注Microsoft Edge Developer Guide:
Lastly, power users might notice the apppearance of the Desktop App
Web Viewer (previously named Win32WebViewHost), an internal system app
representing the Win32 WebView, in the following places:
● In the Windows 10 Action Center. The source of these notifications
should be understood as from a WebView hosted from a Win32 app.
● In the device access settings UI
(Settings->Privacy->Camera/Location/Microphone). Disabling any of
these settings denies access from all WebViews hosted in Win32 apps.
事实证明问题与线程有关:winit crate 在不同的线程中执行其事件循环,而我没有意识到这一点;我曾错误地认为 winit 是一种无害的抽象,结果证明 完全 不是。
我在尝试最小化和移植一个已知功能的 C++ 示例时发现了这一点,这次是手动执行所有 Win32 API 调用而不是使用 winit,因此转换是正确的。我让它开始工作,并发现了这一点:
IAsyncOperation
在事件循环中实现,在 DispatchMessageW
调用的深处。 That 是调用 Completion
处理程序的时间。因此,要完成操作,您必须 运行 同一线程上的事件循环。 (另一个线程上的事件循环不执行任何操作。)否则,它会保持 Started
状态。
幸运的是,winit is already moving to a new event loop which operates in the same thread,Windows 实施已在几天前落地;当我迁移我的代码以使用 winit 的 eventloop-2.0 分支,并使用 Completed
处理程序而不是 blocking_get()
时,一切都开始工作了。
我将澄清 winrt crate 的 blocking_get()
调用,这通常是原型设计时显而易见的解决方案:在这种情况下你不能使用它,因为它会导致死锁,因为它会阻塞直到 IAsyncOperation
完成,但 IAsyncOperation
将不会完成,直到您在事件循环 (DispatchMessageW
) 中处理消息,这永远不会发生,因为您阻塞了线程。
我正在尝试编写一些使用 Windows.Web.UI.Interop.WebViewControl
的 Rust 代码(这是一个通用的 Windows 平台进程外包装器,专门设计用于 Win32 应用程序可以使用 EdgeHTML),它是所有编译,但在运行时无法正常工作。
相关代码归结为这样,使用了 winit、winapi 和 winrt crates:
use winit::os::windows::WindowExt;
use winit::{EventsLoop, WindowBuilder};
use winapi::winrt::roapi::{RoInitialize, RO_INIT_SINGLETHREADED};
use winapi::shared::winerror::S_OK;
use winrt::{RtDefaultConstructible, RtAsyncOperation};
use winrt::windows::foundation::Rect;
use winrt::windows::web::ui::interop::WebViewControlProcess;
fn main() {
assert!(unsafe { RoInitialize(RO_INIT_SINGLETHREADED) } == S_OK);
let mut events_loop = EventsLoop::new();
let window = WindowBuilder::new()
.build(&events_loop)
.unwrap();
WebViewControlProcess::new()
.create_web_view_control_async(
window.get_hwnd() as usize as i64,
Rect {
X: 0.0,
Y: 0.0,
Width: 800.0,
Height: 600.0,
},
)
.expect("Creation call failed")
.blocking_get()
.expect("Creation async task failed")
.expect("Creation produced None");
}
WebViewControlProcess
实例化有效,CreateWebViewControlAsync
函数似乎确实关心它作为 host_window_handle
收到的值(传递 0,或从实际 HWND
值,它会抱怨)。然而 IAsyncOperation
坚定地停留在 AsyncStatus.Started
(0),因此 blocking_get()
调用无限期挂起。
A full, runnable demonstration of the issue (with a bit more instrumentation).
我感觉 WebViewControlProcess
出了问题:它的 ProcessId
停留在 0,而且看起来没有生成任何子进程。 ProcessExited
事件 似乎 没有被触发(我在实例化后立即附加了一些东西,它是否有机会在此之前被触发?)。在这种情况下,调用 Terminate()
可能会失败,E_FAIL
.
我是否错过了使用 Windows.Web.UI.Interop
的某种初始化?还是有其他原因导致它不起作用?
尝试用 winrt::init_apartment();
初始化 WebViewProcessControl
并且它可能需要一个单线程单元(根据这个
更多关注Microsoft Edge Developer Guide:
Lastly, power users might notice the apppearance of the Desktop App Web Viewer (previously named Win32WebViewHost), an internal system app representing the Win32 WebView, in the following places:
● In the Windows 10 Action Center. The source of these notifications should be understood as from a WebView hosted from a Win32 app.
● In the device access settings UI (Settings->Privacy->Camera/Location/Microphone). Disabling any of these settings denies access from all WebViews hosted in Win32 apps.
事实证明问题与线程有关:winit crate 在不同的线程中执行其事件循环,而我没有意识到这一点;我曾错误地认为 winit 是一种无害的抽象,结果证明 完全 不是。
我在尝试最小化和移植一个已知功能的 C++ 示例时发现了这一点,这次是手动执行所有 Win32 API 调用而不是使用 winit,因此转换是正确的。我让它开始工作,并发现了这一点:
IAsyncOperation
在事件循环中实现,在 DispatchMessageW
调用的深处。 That 是调用 Completion
处理程序的时间。因此,要完成操作,您必须 运行 同一线程上的事件循环。 (另一个线程上的事件循环不执行任何操作。)否则,它会保持 Started
状态。
幸运的是,winit is already moving to a new event loop which operates in the same thread,Windows 实施已在几天前落地;当我迁移我的代码以使用 winit 的 eventloop-2.0 分支,并使用 Completed
处理程序而不是 blocking_get()
时,一切都开始工作了。
我将澄清 winrt crate 的 blocking_get()
调用,这通常是原型设计时显而易见的解决方案:在这种情况下你不能使用它,因为它会导致死锁,因为它会阻塞直到 IAsyncOperation
完成,但 IAsyncOperation
将不会完成,直到您在事件循环 (DispatchMessageW
) 中处理消息,这永远不会发生,因为您阻塞了线程。