cefsharp / CefSharp

.NET (WPF and Windows Forms) bindings for the Chromium Embedded Framework

Home Page:http://cefsharp.github.io/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Feature Request - Add AnyCPU Support

amaitland opened this issue · comments

UPDATE: Starting with release v87.1.132 the Nuget packages have been restructured to greatly simplify using AnyCPU. Issue #3319 has some specific information.

Those upgrading from versions prior to v87.1.132 shouldn't need to make any code changes.

Option 1

When targeting AnyCPU when your project has Prefer 32bit set to true then the resulting exe will be 32bit, the Nuget package checks for this and copies only the x86 files. This is the default for a number of Visual Studio project templates. No further changes are required.

To manually set Prefer 32bit open your project properties and under the build tab check prefer 32bit.

visualstudioprefer32bit

Option 2

Add a dependency resolver, this is more complicated and needs to be hooked up before any calls to classes in the CefSharp.* namespaces. Here is one method of doing this. It's important that LoadApp is not in-lined, so the calls to CefSharp are delayed long enough to hookup the Assembly Resolver

  • Add <CefSharpAnyCpuSupport>true</CefSharpAnyCpuSupport> to the first <PropertyGroup> in your project (e.g. .csproj file).
  • Implement the code below (modifying any setting that you require).
[STAThread]
public static void Main()
{
    CefRuntime.SubscribeAnyCpuAssemblyResolver();

    LoadApp();
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static void LoadApp()
{
    var settings = new CefSettings();

    Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);

    var browser = new BrowserForm();
    Application.Run(browser);
}

The MinimalExample now has AnyCPU as a target to demo the CefSharpAnyCpuSupport option.

Example WPF solution.

You must add <CefSharpAnyCpuSupport>true</CefSharpAnyCpuSupport> to the first <PropertyGroup> in your project (e.g. .csproj file).

public partial class App : Application
{
    public App()
    {
        CefRuntime.SubscribeAnyCpuAssemblyResolver();

        //Any CefSharp references have to be in another method with NonInlining
        // attribute so the assembly rolver has time to do it's thing.
        InitializeCefSharp();
    }

    [MethodImpl(MethodImplOptions.NoInlining)]
    private static void InitializeCefSharp()
    {
        var settings = new CefSettings();

        Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);
    }
}

The MinimalExample now has AnyCPU as a target to demo the CefSharpAnyCpuSupport option.

I've updated the original issue at the top here to include details about adding a CefSharpAnyCpuSupport property to your project file. This is only required for AnyCPU support and will through an error as part of your build process until it's been added. The error directs people to this issue.

See https://github.com/cefsharp/CefSharp.MinimalExample/tree/demo/anycpu for the original demo project that I used for testing. I currently have no plans on maintaining this branch, it's purely provided as a working example. See the commit log to see exactly what changes were made to get things working.

There was a mismatch between the processor architecture of the project being built "MSIL" and the processor architecture of the reference "CefSharp.Core", "x86".

The above warning in your Error List is safe to ignore. If you wish to disable this warning see http://thebuildingcoder.typepad.com/blog/2013/06/processor-architecture-mismatch-warning.html

You must add <CefSharpAnyCpuSupport>true</CefSharpAnyCpuSupport> to the first <PropertyGroup> in your project (e.g. .csproj file).

Option 3

I've not tested this option in any great detail, so use at you own risk. It requires the user to have Write Permission to the applications executing folder. No special resolves or methods of loading the dlls is required. The relevant files are copied to the executing folder and unused resources deleted

  • Copies CefSharp resources from the x86 or x64 folder depending on application bitness
  • Removes x86 and x64 folders

NOTE

  • If you upgrade/downgrade you will need to manually remove the libs from the executing folder (A simple Git Cleanup would suffice)
  • This option would be best used when deploying using an installer.
//Example WinForms Code (WPF  would be very similar)
[STAThread]
public static void Main()
{
	var executingFolder = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;

	//If libcef.dll doesn't exist in our executing folder then we'll copy the files
	//For this method the user must have write permissions to the executing folder.
	if (!File.Exists(Path.Combine(executingFolder, "libcef.dll")))
	{
		var libPath = Path.Combine(executingFolder, Environment.Is64BitProcess ? "x64" : "x86");

		CopyFilesRecursively(new DirectoryInfo(libPath), new DirectoryInfo(executingFolder));

		Directory.Delete("x86", recursive: true);
		Directory.Delete("x64", recursive: true);
	}

	LoadApp();
}

//https://stackoverflow.com/a/58779/4583726
private static void CopyFilesRecursively(DirectoryInfo source, DirectoryInfo target)
{
	foreach (DirectoryInfo dir in source.GetDirectories())
	{
		CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
	}

	foreach (FileInfo file in source.GetFiles())
	{
		file.CopyTo(Path.Combine(target.FullName, file.Name));
	}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static void LoadApp()
{
	//Perform dependency check to make sure all relevant resources are in our output directory.
	var settings = new CefSettings();

	Cef.Initialize(settings, performDependencyCheck: false, browserProcessHandler: null);

	var browser = new BrowserForm();
	Application.Run(browser);
}

Starting with release v87.1.132 there is another option for AnyCPU support.

Option 4

  • Unlike the other options don't set CefSharpAnyCpuSupport in your project file.
  • Make sure your application has an app.config
  • Ensure your copy of Visual Studio has the Web Developer Tools installed OR
  • Install the MSBuild.Microsoft.VisualStudio.Web.targets Nuget package (whilst Microsoft is included in the package name, this package is released by a 3rd party).

The resulting app.config file (e.g. CefSharp.MinimalExample.OffScreen.exe.config) will look something like below.
The Microsoft.Web.Publishing.Tasks.dll contains a transform which modifies your app.config as part of the build process adding entries that resolve the CefSharp.Core.Runtime.dll at runtime. Note this doesn't modify your app.config in your project root, only the generated version in your bin folder.

THIS IS AN EXAMPLE OF THE GENERATED APP.CONFIG, NO CODE CHANGES ARE REQUIRED

<?xml version="1.0"?>
<configuration>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2"/></startup>
  <!--<runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <probing privatePath="MyCefSharpTargetDir"/>
    </assemblyBinding>
  </runtime>-->
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="CefSharp.Core.Runtime" processorArchitecture="x86" publicKeyToken="40c4b6fc221f4138" culture="neutral"/>
        <codeBase version="89.0.170.0" href="x86/CefSharp.Core.Runtime.dll"/>
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="CefSharp.Core.Runtime" processorArchitecture="amd64" publicKeyToken="40c4b6fc221f4138" culture="neutral"/>
        <codeBase version="89.0.170.0" href="x64/CefSharp.Core.Runtime.dll"/>
      </dependentAssembly>
    </assemblyBinding>
  </runtime>

</configuration>