-
Notifications
You must be signed in to change notification settings - Fork 64
Description
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);