I have simple default Windows desktop form Form1
with one button btn_Go
as a test.
I want to run multiple parallel WebView2 instances and process html code from rendered page.
To run WebView2 in parallel I use SemaphoreSlim (set to parallel 2). Another SemaphoreSlim is used for wait until WebView2 render the document (with some time delay).
But my code falls on await webBrowser.EnsureCoreWebView2Async();
. Inner exception from debuger in WebView2
instance webBrowser
is:
{"Cannot change thread mode after it is set. (Exception from HRESULT: 0x80010106 (RPC_E_CHANGED_MODE))"} System.Exception {System.Runtime.InteropServices.COMException}
How can I call WebView2 multiple times in parallel and process all urls?
Full demo code:
using Microsoft.Web.WebView2.WinForms;
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WebView2Test
{
public partial class Form1 : Form
{
public Form1() { InitializeComponent(); }
private void btn_Go_Click(object sender, EventArgs e) { Start(); }
private async void Start()
{
var urls = new List<string>() { "https://www.google.com/search?q=test1", "https://www.google.com/search?q=test2", "https://www.google.com/search?q=test3" };
var tasks = new List<Task>();
var semaphoreSlim = new SemaphoreSlim(2);
foreach (var url in urls)
{
await semaphoreSlim.WaitAsync();
tasks.Add(
Task.Run(async () => {
try { await StartBrowser(url); }
finally { semaphoreSlim.Release(); }
}));
}
await Task.WhenAll(tasks);
}
public async Task<bool> StartBrowser(string url)
{
SemaphoreSlim semaphore = new System.Threading.SemaphoreSlim(0, 1);
System.Timers.Timer wait = new System.Timers.Timer();
wait.Interval = 500;
wait.Elapsed += (s, e) =>
{
semaphore.Release();
};
WebView2 webBrowser = new WebView2();
webBrowser.NavigationCompleted += (s, e) =>
{
if (wait.Enabled) { wait.Stop(); }
wait.Start();
};
await webBrowser.EnsureCoreWebView2Async();
webBrowser.CoreWebView2.Navigate(url);
await semaphore.WaitAsync();
if (wait.Enabled) { wait.Stop(); }
var html = await webBrowser.CoreWebView2.ExecuteScriptAsync("document.documentElement.outerHTML");
return html.Length > 10;
}
}
}
I have WebView2 runtime installed.
-- Tests
Prepare WebView2
in main thread and send it into child threads.
I have already tried to create list of WebView2
in Start
method from main Thread var bro = new List<WebView2>() { new WebView2(), new WebView2(), new WebView2() };
and send WebView2 instance into await StartBrowser(bro[index], url);
... but this ends with the same error.