我正在尝试编写一些使用 Windows.Web.UI.Interop.WebViewControl (这是一种通用Windows平台进程外包装,明确设计为Win32应用程序可以使用EdgeHTML)的Rust代码,并且都可以编译,但在运行时无法正常工作。

相关代码使用winit,winapi和winrt包装箱归结为以下内容:

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值中减去1,然后提示)。但是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进行的某种初始化?还是有其他原因导致它不起作用?

最佳答案

原来,问题是与线程有关的:winit crate 在另一个线程中进行事件循环,而我没有意识到这一点。我错误地认为winit是一种无害的抽象,事实证明事实并非如此。

当我尝试最小化和移植一个已知功能的C++示例时,我发现了这一点,这次是手动进行所有Win32 API调用,而不是使用winit,以便翻译正确。我得到它的工作,并发现了这一点:
IAsyncOperation在事件循环中实现,位于DispatchMessageW调用的深处。那是当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()调用的信息,该调用通常是原型(prototype)制作时的明显解决方案:在这种情况下,您将无法使用它,因为它会导致死锁,因为它会阻塞直到IAsyncOperation完成,但是IAsyncOperation直到您处理后才会完成事件循环中的消息(DispatchMessageW),因为您正在阻塞线程,所以永远不会发生。

关于winapi - 为什么WebViewControlProcess.CreateWebViewControlAsync()从未完成?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/54472925/

10-11 16:06