using System;
using System.Collections.Generic;
using System.Reflection;
using System.Runtime.InteropServices;
using NetVips.Interop;
namespace NetVips;
///
/// All code inside the method is ran as soon as the assembly is loaded.
///
public static class ModuleInitializer
{
///
/// Is vips initialized?
///
public static bool VipsInitialized;
///
/// Contains the exception when initialization of libvips fails.
///
public static Exception Exception;
///
/// Could contain the version number of libvips in an 3-bytes integer.
///
public static int? Version;
#if NET6_0_OR_GREATER
///
/// Windows specific: is GLib statically-linked in `libvips-42.dll`?
///
[System.Runtime.Versioning.SupportedOSPlatform("windows")]
private static bool _gLibStaticallyLinked = true;
///
/// A cache for .
///
internal static readonly Dictionary DllImportCache = new();
internal static string RemapLibraryName(string libraryName)
{
// For Windows, we try to locate the GLib symbols within
// `libvips-42.dll` first. If these symbols cannot be found there,
// we proceed to locate them within `libglib-2.0-0.dll` and
// `libgobject-2.0-0.dll`. Note that this is only possible when
// targeting .NET 6 or higher. As a result, we always ship at least
// 3 DLLs in a separate package for .NET Framework.
if (OperatingSystem.IsWindows())
{
return _gLibStaticallyLinked ? Libraries.Vips : libraryName;
}
// FIXME: Switch to `OperatingSystem.IsApplePlatform()` once public.
// See: https://github.com/dotnet/runtime/issues/113262
var isApplePlatform = OperatingSystem.IsMacOS() || OperatingSystem.IsIOS() ||
OperatingSystem.IsTvOS() || OperatingSystem.IsWatchOS();
// We can safely remap the library names to `libvips.so.42` on *nix
// and `libvips.42.dylib` on macOS since DLLImport uses dlsym() there.
// This function also searches for named symbols in the dependencies
// of the shared library. Therefore, we can provide libvips as a
// single shared library with all dependencies statically linked
// without breaking compatibility with the shared builds
// (i.e. what is usually installed via package managers).
return isApplePlatform ? "libvips.42.dylib" : "libvips.so.42";
}
internal static nint DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
libraryName = RemapLibraryName(libraryName);
if (DllImportCache.TryGetValue(libraryName, out var cachedHandle))
{
return cachedHandle;
}
var handle = NativeLibrary.Load(libraryName, assembly, searchPath);
DllImportCache[libraryName] = handle;
return handle;
}
#endif
///
/// Initializes the module.
///
#pragma warning disable CA2255
[System.Runtime.CompilerServices.ModuleInitializer]
#pragma warning restore CA2255
public static void Initialize()
{
#if NET6_0_OR_GREATER
try
{
NativeLibrary.SetDllImportResolver(typeof(ModuleInitializer).Assembly, DllImportResolver);
}
catch
{
// Ignored; allows this function to be called multiple times.
}
#endif
try
{
VipsInitialized = NetVips.Init();
if (VipsInitialized)
{
Version = NetVips.Version(0, false);
Version = (Version << 8) + NetVips.Version(1, false);
Version = (Version << 8) + NetVips.Version(2, false);
#if NET6_0_OR_GREATER
if (!OperatingSystem.IsWindows())
{
return;
}
try
{
_gLibStaticallyLinked = NetVips.TypeFromName("VipsImage") != IntPtr.Zero;
}
catch
{
_gLibStaticallyLinked = false;
}
#endif
}
else
{
Exception = new VipsException("unable to initialize libvips");
}
}
catch (Exception e)
{
VipsInitialized = false;
Exception = e;
}
}
}