Skip to content

Get ICoreWebView2 reference in CDP callbacks and avoid callback hell #2571

@IMFJS

Description

@IMFJS

My goal is to modify an HTML element inside the web-content via CallDevToolsProtocolMethod when I receive a specific WebMessage.

This requires multiple steps/method calls and thus multiple nested calls of CallDevToolsProtocolMethod, which each depend on the previous call's return value: I first get the nodeId of the desired element via the CDP methods DOM.getDocument and DOM.querySelector and then manipulate that node via DOM.setFileInputFiles as shown below, with m_webView being of type wil::com_ptr<ICoreWebView2>. Although this works (so far), I am not entirely satisfied and confident with this solution.

One problem is that I need to have a reference to ICoreWebView2 inside the callbacks, which I curiously only get back as a parameter in the ICoreWebView2WebMessageReceivedEventHandler ("sender" parameter), but not in the ICoreWebView2CallDevToolsProtocolMethodCompletedHandler. Is there a reason for this? Should I not be allowed to access ICoreWebView2 inside the callbacks which do not provide a reference to it? If not, why and how should I go about multiple dependent CDP calls then? Because currently, to work around this, I am capturing the wil::com_ptr<ICoreWebView2> m_webView (by capturing this) in the lambdas like it is done in the official documentation. Is this even safe with the callbacks being asynchronous?

Another problem is that having all these nested asynchronous callbacks as lambdas leads to callback hell. Having what are effectively serialized remote procedure calls hurts the readability bad enough, so I would really like to avoid this additional lambda-nesting complexity. I know about the async/await pattern from JavaScript, which elegantly solves this or more specifically promise/future chaining (albeit it only being syntactic sugar) and I also know about co_routines in C++20, but I have no idea how those interact with Win32 callbacks and if they could help here. So what is the recommended way to go about this? Does anyone have experience with this?

m_webView->add_WebMessageReceived(Callback<ICoreWebView2WebMessageReceivedEventHandler>(
     [this](ICoreWebView2* sender, ICoreWebView2WebMessageReceivedEventArgs* args) -> HRESULT
     {
       // ...
       sender->CallDevToolsProtocolMethod(
         L"DOM.getDocument",
         L"{}",
         Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
           [this](HRESULT errorCode, LPCWSTR pszJsonResult) -> HRESULT {
             // Get nodeId from json result
             const nlohmann::json jsonResult = nlohmann::json::parse(std::wstring{ pszJsonResult });
             const uint32_t& nNodeId = jsonResult["root"]["nodeId"];

             // Prepare Chrome-DevTools-Protocol RPC
             const std::wstring strDevToolsMethodName = L"DOM.querySelector";
             const nlohmann::json jsonDevToolsMethodParams{
               { "nodeId", nNodeId },
               { "selector", "input[type='file'][accept='.zip']" }
             };
             const std::wstring strDevToolsMethodParams = UnicodeConversion::UTF8toUTF16(jsonDevToolsMethodParams.dump());

             // Execute Chrome-DevTools-Protocol RPC
             this->m_webView->CallDevToolsProtocolMethod(
               strDevToolsMethodName.c_str(),
               strDevToolsMethodParams.c_str(),
               Callback<ICoreWebView2CallDevToolsProtocolMethodCompletedHandler>(
                 [this](HRESULT, LPCWSTR pszJsonResult) -> HRESULT {
                   // Get nodeId from json result
                   std::wstring strJsonResult{ pszJsonResult };
                   const nlohmann::json jsonResult = nlohmann::json::parse(strJsonResult);
                   const uint32_t& nNodeId = jsonResult["nodeId"];

                   // Prepare Chrome-DevTools-Protocol RPC
                   const std::wstring strDevToolsMethodName = L"DOM.setFileInputFiles";
                   const nlohmann::json jsonDevToolsMethodParams{
                     { "files", { "Dummy.zip" } },
                     { "nodeId", nNodeId }
                   };
                   const std::wstring strDevToolsMethodParams = UnicodeConversion::UTF8toUTF16(jsonDevToolsMethodParams.dump());

                   // Execute Chrome-DevTools-Protocol RPC
                   this->m_webView->CallDevToolsProtocolMethod(
                     strDevToolsMethodName.c_str(),
                     strDevToolsMethodParams.c_str(),
                     nullptr); // In the future, there might even be one more callback here

                   return S_OK;
                 }).Get());
             return S_OK;
           }).Get());
       return S_OK;
     }
   ).Get(), nullptr);

AB#41557741

Metadata

Metadata

Labels

docdocumentation issuestrackedWe are tracking this work internally.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions