First off I would just like to mention that I am by no means a C# or a windows developer expert. The following code is kind of a mish-mash I've slap together from examples and tutorials I found on the internet.
The premise of the code is to create a webview2 component in a winform, where the winform is a DLL that gets loaded by a third-party application.
Now, the third-party application loads my DLL and calls this function:
Integrations::ShowForm("Form1");
My winform is a basic C# Windows Forms App using .Net Framework.
My Form1.cs looks as follows:
namespace GuiIntegrations
{
public partial class Form1 : Form
{
public Form1()
{
string webview2DllPath = @"C:\TestFolder\runtimes\win-x64\native";
CoreWebView2Environment.SetLoaderDllFolderPath(webview2DllPath);
Environment.SetEnvironmentVariable("WEBVIEW2_USER_DATA_FOLDER", @"C:\TestFolder\user-data");
InitializeComponent();
_ = InitializeAsync();
}
}
}
My Form1.Designer.cs file looks like:
namespace GuiIntegrations
{
public partial class Form1 : Form
{
private System.ComponentModel.IContainer components = null;
#region Windows Form Designer generated code
...
#endregion
private Microsoft.Web.WebView2.WinForms.WebView2 webView21;
async Task InitializeAsync()
{
try
{
string webview2FixedPath = @"C:\TestFolder\Microsoft.WebView2.FixedVersionRuntime.105.0.1343.33.x64";
var env = await CoreWebView2Environment.CreateAsync(browserExecutableFolder: webview2FixedPath , userDataFolder: @"C:\TestFolder\user-data");
await webView21.EnsureCoreWebView2Async(env);
webView21.Source = new Uri("https://www.google.com");
}
catch (Exception e)
{
// The exception goes into an event-list that can be processed outside the DLL
}
}
}
}
(The excluded #region is just your normal winform generated code). Also in the DLL is a class called Integrations.cs, that looks like this:
namespace GuiIntegrations
{
public static class Integrations
{
private static Form1 form;
private static Thread formThread;
[STAThread]
public static void ShowForm(string formName)
{
try
{
Assembly assembly = Assembly.GetExecutingAssembly();
Type[] types = assembly.GetTypes();
foreach (Type type in types)
{
if (type.BaseType == typeof(Form) && type.Name == formName)
{
object obj_form = type.Assembly.CreateInstance(type.FullName);
form = (Form1)obj_form;
formThread = new Thread(() => Application.Run(form));
formThread.SetApartmentState(ApartmentState.STA);
formThread.Start();
Thread.Sleep(200);
}
}
} catch (Exception e)
{
MessageBox.Show(e.Message);
}
}
}
}
Apologies that its not the most eloquent source, but I kind of did it on the fly.
FYI:
- C:\TestFolder\runtimes\win-x64\native is the location for the 'WebView2Loader.dll' DLL of the webview2 component.
- my winform DLL location also contains the 3 other webview2 DLLs Microsoft.Web.WebView2.Core.dll, Microsoft.Web.WebView2.WinForms.dll, Microsoft.Web.WebView2.Wpf.dll
- C:\TestFolder\Microsoft.WebView2.FixedVersionRuntime.105.0.1343.33.x64 is the extracted location of the fixed runtime for webview2.
The problem occurs when 'CoreWebView2Environment.CreateAsync' is called. As soon as its executed, it throws an exception 'Exception: CoInitialize has not been called. (Exception from HRESULT: 0x800401F0 (CO_E_NOTINITIALIZED)'.
As far as I could determine from the error, its not entering the single-apartment state, which is strange considering that I am setting the thread-state that starts the form as STA.
I've also checked that my component doesn't contain a 'Source' field: ComponentProperties
Any help would be greatly appreciate.
PS. When I compile the program as a Windows Application and run it, the component loads fine and shows the google page.