Почему WebViewControlProcess.CreateWebViewControlAsync () никогда не завершается? - PullRequest
0 голосов
/ 01 февраля 2019

Я пытаюсь написать некоторый код Rust, который использует Windows.Web.UI.Interop.WebViewControl (который представляет собой внешнюю оболочку универсальной платформы Windows, специально разработанную так, чтобы приложения Win32 могли использовать EdgeHTML), и все это компилируется, но не работает должным образом во время выполнения.

Соответствующий код сводится к этому, используя ящики 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 работает, а *Функция 1010 *, похоже, заботится о значении, которое она получила как host_window_handle (передать 0 или единицу от фактического значения HWND, и она жалуется).Тем не менее, IAsyncOperation остается определенно на AsyncStatus.Started (0), и поэтому вызов blocking_get() зависает на неопределенное время.

Полная, работоспособная демонстрация проблемы (с немного большим количеством инструментария) .

У меня такое ощущение, что WebViewControlProcess виноват: его ProcessId застрял в 0, и он, похоже, не породил какой-либо подпроцесс.Событие ProcessExited не , кажется, запускается (1026 *) (я прикрепил что-то к нему сразу после создания экземпляра, есть ли возможность его запустить до этого?).Вызов Terminate() завершается неудачно, как и следовало ожидать в такой ситуации, E_FAIL.

Я пропустил какую-то инициализацию для использования Windows.Web.UI.Interop?Или есть какая-то другая причина, почему она не работает?

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Оказалось, что проблема связана с потоками: ящик winit делал цикл обработки событий в другом потоке, и я этого не осознавал;Я ошибочно предположил, что winit - это безобидная абстракция, а это оказалось не совсем .

Я обнаружил это, когда попытался свернуть и портировать известный функционирующий пример C ++, на этот разделать все вызовы Win32 API вручную, а не с помощью winit, чтобы перевод был правильным.Я заставил его работать и обнаружил следующее:

IAsyncOperation выполняется в цикле событий, глубоко внутри вызова DispatchMessageW. Это , когда вызывается обработчик Completion.Таким образом, для завершения операции вы должны запустить цикл обработки событий в том же потоке.(Цикл событий в другом потоке ничего не делает.) В противном случае он остается в состоянии Started.

К счастью, winit уже перемещается в новый цикл событий, который работает в том жепоток , с реализацией Windows, приземлившейся несколько дней назад;когда я перенес свой код, чтобы использовать ветку eventloop-2.0 из winit и использовать обработчик Completed вместо blocking_get(), все это начало работать.

Я уточню о blocking_get() ящика winrtвызов, который обычно является очевидным решением при создании прототипа: вы не можете использовать его в этом случае, потому что он вызывает взаимоблокировку, так как он блокирует до завершения IAsyncOperation, но IAsyncOperation не завершится, пока вы не обработаете сообщения в событиицикл (DispatchMessageW), который никогда не произойдет, потому что вы блокируете поток.

0 голосов
/ 04 февраля 2019

Попробуйте инициализировать WebViewProcessControl с помощью winrt::init_apartment(); И, возможно, потребуется однопоточная квартира (в соответствии с этим ответом ).

Больше внимания на Microsoft EdgeРуководство разработчика :

Наконец, опытные пользователи могут заметить появление приложения для просмотра веб-приложений для настольных компьютеров (ранее называлось Win32WebViewHost), внутреннего системного приложения, представляющего Win32 WebView, в следующих местах:

● В Центре действий Windows 10.Источник этих уведомлений следует понимать как WebView, размещенный в приложении Win32.

● В пользовательском интерфейсе настроек доступа к устройству (Настройки-> Конфиденциальность-> Камера / Расположение / Микрофон).Отключение любого из этих параметров запрещает доступ ко всем WebView, размещенным в приложениях Win32.

...