Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

773
Visualizações
Embedding WebView2 DLL into wpf portable executable

I am trying to embed WebView2 DLL in a C# project. I have added the 3 DLLs :

Microsoft.Web.WebView2.Wpf.dll
Microsoft.Web.WebView2.Core.dll
WebView2Loader.dll

as embedded resource to my project. Since it is a WPF project I have no need of Microsoft.Web.WebView2.Forms.dll.

I have already Newtonsoft.Json.dll correctly incorporated.

In debug mode, there is no problem because all DLL are copied to the output directory.

As I want that the executable to be portable, I want only a single file (I know that copying the DLL with the exe will work, but I need a single file). When I move the main executable only to another folder, the application crashes when I use the webview2 control (the control is not loaded at start).

I have tried to figure out if all the DLL were involved. Microsoft.Web.WebView2.Wpf.dll is correctly embedded and I have no need of it in the destination folder.

However, the last two ones are still required. I think this is probably because they are called by Microsoft.Web.WebView2.Wpf.dll and not by the main assemby.

How can I load the last two ones from the main assembly to have a single execution file ?

EDIT: All DLL are added to the project as embedded resource

EDIT2

Thanks to @mm8 to give me ideas to partialy (any suggestions for complete solution are welcomed) achieve this.

So, It is possible to embed the 3 WebView2 DLL into you project by adding them and setting them as embedded resource. Microsoft.Web.WebView2.Wpf.dll (or Microsoft.Web.WebView2.WinForms.dll, depending on your choice) can be loaded directly into memory. But the last two ones (Microsoft.Web.WebView2.Core.dll and WebView2Loader.dll) need to be saved as files :

public MainWindow()
{
   // For Newtonsoft.Json.dll, Microsoft.Web.WebView2.Wpf.dll, Microsoft.Web.WebView2.Core.dll and WebView2Loader.dll
   // Incorporation as embedded resource
   // To avoid having multiple files, only one executable
   AppDomain.CurrentDomain.AssemblyResolve += GetEmbeddedDll;
   ExtractWebDLLFromAssembly();

   InitializeComponent();
}

private byte[] GetAssemblyBytes(string assemblyResource)
{
    using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(assemblyResource))
    {
        return new BinaryReader(stream).ReadBytes((int)stream.Length);
    }
}

// For Newtonsoft.Json.dll and Microsoft.Web.WebView2.Wpf.dll
private Assembly GetEmbeddedDll(object sender, ResolveEventArgs args)
{
    string keyName = new AssemblyName(args.Name).Name;

    // If DLL is loaded then don't load it again just return
    if (_libs.ContainsKey(keyName))
    {
        return _libs[keyName];
    }

    Assembly assembly = Assembly.Load(GetAssemblyBytes(Assembly.GetExecutingAssembly().GetName().Name + "." + keyName + ".dll"));
    _libs[keyName] = assembly;
    return assembly;
}

// For Microsoft.Web.WebView2.Core.dll and WebView2Loader.dll
// Incorporation as embedded resource but need to be extracted
private void ExtractWebDLLFromAssembly()
{
    string[] dllNames = new string[] { "Microsoft.Web.WebView2.Core.dll", "WebView2Loader.dll" };
    string thisAssemblyName = Assembly.GetExecutingAssembly().GetName().Name;
    foreach (string dllName in dllNames)
    {
        string dllFullPath = Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, dllName);
        try
        {
            File.WriteAllBytes(dllFullPath, GetAssemblyBytes(thisAssemblyName + "." + dllName));
        }
        catch
        {
            // Depending on what you want to do, continue or exit
        }
    }
}

The ExtractWebDLLFromAssembly method is based from this post @nawfal's answer

As the ExtractWebDLLFromAssembly method is called only once, its code can also be directly integrated in MainWindow.

One thing is still missing :

I am facing issues when I try to delete these files in the MainWindow_OnClosing event saying that files are in use by another process (in fact, the main process), even if the control is not loaded or is disposed. I am using this code to be sure that CoreWebView2 was unloaded inside the control :

int maxTimeout = 2000;
uint wvProcessId = wv_ctrl.CoreWebView2.BrowserProcessId;
string userDataFolder = wv_ctrl.CoreWebView2.Environment.UserDataFolder;
int timeout = 10;
wv_ctrl.Dispose();
try
{
    while (System.Diagnostics.Process.GetProcessById(Convert.ToInt32(wvProcessId)) != null && timeout < maxTimeout)
    {
        System.Threading.Thread.Sleep(10);
        timeout += 10;
    }
}
catch { }

This code allows me to correctly delete the UserDataFolder, but the DLL are still in use.

After further inspection, I know that Microsoft.Web.WebView2.Core.dll is still loaded as an assembly in the CurrentAppDomain which is obviously a problem.
And WebView2Loader.dll is loaded as a module of the Process. If I try to force to unload it with

 [DllImport("kernel32.dll", SetLastError = true)]
 public static extern void FreeLibrary(IntPtr module)

this does not work. I think this is because Microsoft.Web.WebView2.Core.dll use it. And this should be the root problem left for me.

EDIT 3

I have tried to load the WebView control in an other thread. I don't need to retrieve values from the control. I only need to set the source on code behind. I have tried several things without any success, the source of the threaded control is not updated (the EnsureCoreWebView2Async method called after the control Loaded event stays awaited indefinitly). The main idea to achieve this is inspired from here

EDIT 4

Ok, I manage one file :). WebView2Loader.dll can be unloaded with FreeLibrary contrary that what I said in edit 2, I was trying to unload it after the Dispose() method, while you need to wait the dispose is completed. So you need to call it after the catch block

int maxTimeout = 2000;
uint wvProcessId = wv_ctrl.CoreWebView2.BrowserProcessId;
string userDataFolder = wv_ctrl.CoreWebView2.Environment.UserDataFolder;
int timeout = 10;
wv_ctrl.Dispose();
try
{
    while (System.Diagnostics.Process.GetProcessById(Convert.ToInt32(wvProcessId)) != null && timeout < maxTimeout)
    {
        System.Threading.Thread.Sleep(10);
        timeout += 10;
    }
}
catch { }
UnloadModule("WebView2Loader.dll");
if (Settings.Default.DeleteBrowserNavigationData)
{
    try
    {
        Directory.Delete(userDataFolder, true);
    }
    catch { }
}
// Delete WebView2 DLLs (2nd line throws an error)
try
{
    File.Delete(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "WebView2Loader.dll"));
    File.Delete(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Microsoft.Web.WebView2.Core.dll"));
 }
 catch { }

The UnloadModule method is taken from this, @SI4's answer

The last dll, Microsoft.Web.WebView2.Core.dll is opened within the CurrentAppDomain and cannot unloaded this way nor be deleted. I should probably load it within a new AppDomain so that I can unload it. However, I don't know how to achieve this with the ability to change the Source property of the control. May be the whole code should be loaded in a new AppDomain ?

EDIT 5

I have found a new option that could be the solution : WPF Add-In I have created the files from the example, the user control contains WebView2 instead of a button. However, for both AddInAdapter and HostAdapter, FrameworkElementAdapters is marked with an error "The name does not exist in the current context" ??? (References has been added to the project which is targetting .Net 4.6.2). Any clue ? But, it seems that application needs to have different folders. If this is the case, this is a wrong turn. I still need one executable and nothing more.

Thanks

over 4 years ago · Santiago Trujillo
1 Respostas
Responde à pergunta

0

If your application does not need to target a particular framework which does not yet integrate this functionality, you have the option of using the Single File Application available since .NET Core 3.0.

I have tried with a WPF Application using a WebView2, and with this method you can publish the application and the references in the same .exe file.

Since WebView2 works with native libraries, you just need to add the following line in your PropertyGroup of your .csproj file.:

<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda