简体   繁体   English

如何在 C++ COM STA 中的 WebView2 接口上等待对 ExecuteScript 的调用完成

[英]How to wait for completion of a call to ExecuteScript on a WebView2 interface in a C++ COM STA

I have an COM STA, that hosts an ICoreWebView2.我有一个 COM STA,它承载一个 ICoreWebView2。

I try to get the complete HTML block and I found a documentation to achieve this with a script.我尝试获取完整的 HTML 块,并找到了一个文档来使用脚本实现这一点。 Here my code:这是我的代码:

    hr = m_spWebView->ExecuteScript(L"document.body.outerHTML",
        Callback<ICoreWebView2ExecuteScriptCompletedHandler>(
            [&val](HRESULT hr, LPCWSTR result) -> HRESULT 
            {
                if (SUCCEEDED(hr))
                    val = result;
                return S_OK;
            }
        ).Get()
    );

This code works, but it is executed asynchronous.此代码有效,但它是异步执行的。 So it takes some time to get the result.所以需要一些时间才能得到结果。 In fact I can see that the result arrives when the message pump is executed the next time (as I expect for an STA).事实上,我可以看到结果在下次执行消息泵时到达(正如我对 STA 的期望)。

In C# I would use an await to wait for the completion.在 C# 中,我会使用 await 来等待完成。 But using C++ there is nothing like this.但是使用 C++ 就没有这样的事情了。 Using an event wouldn't work, because I have an STA I would block the thread and the answer will never arrive.使用事件是行不通的,因为我有一个 STA,我会阻塞线程并且答案永远不会到达。

Is there any way to call a function that waits for the completion in C++?有没有办法在 C++ 中调用等待完成的函数? Or another help would be to use ExecuteScript synchron.或者另一个帮助是使用ExecuteScript同步。

You have to implement an IDispatch interface (COM stuf), and add it with:你必须实现一个 IDispatch 接口(COM stuf),并添加它:

m_spWebView->AddHostObjectToScript(L"host", &disp);

Then you let JavaScript call it when the documment is loaded.然后在加载文档时让 JavaScript 调用它。

struct CDispatch : IDispatch
{
...
} cdisp;

You will get the HTML as a parameter in a Invoke call.您将获得 HTML 作为 Invoke 调用中的参数。 Don't need to worry about the other methods, just confirm for IID_IDispatch in QueryInterface and watch for the Invoke.其他方法不用管,只需要在QueryInterface中确认IID_IDispatch并注意Invoke。

 window.chrome.webview.hostObjects.host(document.body.outerHTML);

I tried here and managed to do what you are willing to do.我在这里尝试并设法做你愿意做的事情。

If you have an STA then rather than explicitly waiting for completion, you can start your message loop or return back and allow your message loop to continue processing messages.如果您有一个 STA,那么您可以启动您的消息循环或返回并允许您的消息循环继续处理消息,而不是显式等待完成。

If you need to block execution and process messages without returning back to your message loop, you can try using CoWaitForMultipleHandles with COWAIT_DISPATCH_WINDOW_MESSAGES to ensure you process window messages which is necessary for WebView2 callbacks to execute.如果您需要在不返回消息循环的情况下阻止执行和处理消息,您可以尝试使用CoWaitForMultipleHandlesCOWAIT_DISPATCH_WINDOW_MESSAGES来确保您处理 WebView2 回调执行所必需的窗口消息。 However, this can open up your app to reentrancy or other synchronization issues and depending on how the rest of your app deals with this, could be a problem.但是,这可能会使您的应用程序面临重入或其他同步问题,并且取决于您的应用程序的其余部分如何处理此问题,这可能是一个问题。

Generally the better solution is to return back to your message loop.通常更好的解决方案是返回到您的消息循环。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM