Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic libvips path ? #15

Closed
gjactat opened this issue Aug 31, 2018 · 3 comments
Closed

Dynamic libvips path ? #15

gjactat opened this issue Aug 31, 2018 · 3 comments
Labels
question Further information is requested

Comments

@gjactat
Copy link

gjactat commented Aug 31, 2018

Hello,
We have several types of C# processes that might use NetVips (and therefore, libvips). Some of them are 64bits and some of them are 32bits, some are web services, some are windows services.

To deal with that, I try to add the appropriate libvips path to the PATH environement variable at run time and at the process level (EnvironmentVariableTarget), depending of the current process architecure.

The problem is that ModuleInitializer's "Initialize" method is called way before any other code... So it's hard to patch the path variable without modifying NetVips code itself.

Do you a know a proper way to deal with this kind of dynamic libvips path ?

Thanks for your attention,
Guillaume

@gjactat gjactat changed the title Dynamic libvips path Dynamic libvips path ? Aug 31, 2018
@kleisauke
Copy link
Owner

kleisauke commented Aug 31, 2018

You could use an own module initializer in your program (to ensure that your own program is initialized first). For example, this program will P/Invoke SetDllDirectory with the location of libvips, depending on the architecture where the C# process is running on:

using System;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using NetVips;

namespace ConsoleApp
{
    /// <summary>
    /// All code inside the <see cref="Initialize"/> method is ran as soon as the assembly is loaded.
    /// </summary>
    internal class Program
    {
        /// <summary>
        /// Initializes the module.
        /// </summary>
        [ModuleInitializer]
        public static void Initialize()
        {
            Console.WriteLine("Loading libvips " + (Environment.Is64BitOperatingSystem ? "x64" : "x86") + "-binary.");
            SetDllDirectory(Path.GetFullPath(Environment.Is64BitOperatingSystem
                ? @"C:\vips-dev-8.12-w64\bin"
                : @"C:\vips-dev-8.12-w32\bin"));
        }

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetDllDirectory(string lpPathName);

        static void Main(string[] args)
        {
            using var image = Image.Text("Hello <i>World!</i>", dpi: 300);
            image.WriteToFile("hello-world.png");
        }
    }
}

(See here for more information about SetDllDirectory).

If you could not use an own module initializer in your program, then you'll need to build NetVips with the module initializer disabled and call NetVips.Base.VipsInit() by yourself. I do not intend to add a check for an environment variable to conditional disable the module initializer because for performance reasons and to not break someone's program.

@kleisauke kleisauke added the question Further information is requested label Aug 31, 2018
@gjactat
Copy link
Author

gjactat commented Aug 31, 2018

Thanks for your quick answer !
The change i've made to NetVips seems close to to your second solution.

@kleisauke
Copy link
Owner

This is much easier now with the ResolvingUnmanagedDll event.

using System.Runtime.InteropServices;
using System.Runtime.Loader;
using NetVips;

AssemblyLoadContext.Default.ResolvingUnmanagedDll += (_, libName) =>
    NativeLibrary.Load($"C:/vips-prefix/bin/{libName}");

// Try to init again in case the ModuleInitializer fails.
if (!ModuleInitializer.VipsInitialized)
{
    ModuleInitializer.Initialize();
}

using var image = Image.Text("Hello <i>World!</i>", dpi: 300);
image.WriteToFile("hello-world.png");

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants