// Copyright © 2020 The CefSharp Authors. All rights reserved. // // Use of this source code is governed by a BSD-style license that can be found in the LICENSE file. using System; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace CefSharp { /// /// CLR Module Initializer /// Used to load libcef.dll if required /// public static class Initializer { //TODO: Internal debugging only for now, needs improving if users are going to //get meaningful data from this. internal static IntPtr? LibCefHandle { get; private set; } internal static bool LibCefLoaded { get; private set; } internal static string LibCefPath { get; private set; } internal static string BrowserSubProcessPath { get; private set; } internal static string BrowserSubProcessCorePath { get; private set; } [ModuleInitializer] internal static void ModuleInitializer() { string currentFolder; var executingAssembly = Assembly.GetEntryAssembly(); //The GetEntryAssembly method can return null when a managed assembly has been loaded from an unmanaged application. //https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.getentryassembly?view=net-5.0 if (executingAssembly == null) { currentFolder = GetCefSharpCoreAssemblyLocation(); } else { currentFolder = Path.GetDirectoryName(executingAssembly.Location); } //In .NET 5.0 and later versions, for bundled assemblies, Assembly.Location is an empty string. //https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.location?view=net-5.0 //Which results in Path.GetDirectoryName returning null, in that case use use AppContext.BaseDirectory //otherwise Path.Combine will throw an exception. //In .NET 5.0 and later versions, for bundled assemblies, AppContext.BaseDirectory returns the containing directory of the host executable. //https://docs.microsoft.com/en-us/dotnet/api/system.appcontext.basedirectory?view=net-5.0 if(string.IsNullOrEmpty(currentFolder)) { currentFolder = AppContext.BaseDirectory; } var libCefPath = Path.Combine(currentFolder, "libcef.dll"); if (File.Exists(libCefPath)) { //We didn't load CEF, it was already next to our calling assembly, the //framework should load it correctly on it's own LibCefPath = libCefPath; LibCefLoaded = false; } else { var arch = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); var archFolder = $"runtimes\\win-{arch}\\native"; libCefPath = Path.Combine(currentFolder, archFolder, "libcef.dll"); if (!File.Exists(libCefPath)) { // For cases where the library is dynamically loaded and no RuntimeIdentifier // specified, attempt to locate libcef.dll next to CefSharp.Core.dll currentFolder = GetCefSharpCoreAssemblyLocation(); libCefPath = Path.Combine(currentFolder, archFolder, "libcef.dll"); } if (File.Exists(libCefPath)) { LibCefLoaded = NativeLibrary.TryLoad(libCefPath, out IntPtr handle); if (LibCefLoaded) { BrowserSubProcessPath = Path.Combine(currentFolder, archFolder, "CefSharp.BrowserSubprocess.exe"); BrowserSubProcessCorePath = Path.Combine(currentFolder, archFolder, "CefSharp.BrowserSubprocess.Core.dll"); LibCefPath = libCefPath; LibCefHandle = handle; } } else { LibCefPath = libCefPath; LibCefLoaded = false; } } } private static string GetCefSharpCoreAssemblyLocation() { return Path.GetDirectoryName(typeof(Initializer).Assembly.Location); } } }