ImageMagick : Unable to load DLL 'Magick.Native-Q8-x86.dll'

0

A very strange thing happens. I want to use Image Magick in my source code instead of using a command line batch so I try Image Magick.Net (https://recordnotfound.com/Magick-NET-dlemstra-154214) but ....

Let's describing things the more precisely.

  1. I am on XP Pro SP3 32 bits version 2002 I log in as administrator.

My system has

  • Microsoft Visual C++ 2012 Redistribuable (x86) 11.0.610.30
  • Microsoft Visual C++ 2017 Redistribuable (x86) 14.11.25325
  1. I open VS 2008

  2. I create a new project of type Console Application in C#. I named it 'TestDLL'.

  3. In file Program.cs, in 'static void Main(string[] args)' method, I instantiate an ImageMagick object.

  4. I download DLLs from nuget site https://www.nuget.org/profiles/dlemstra :

  • Magick.Native-Q8-x86.dll 13,7 MB (14 450 896 bytes) 7.0.10.25 Copyright 2013-2020 Dirk Lemstra

  • Magick.NET.Core.dll 1,34 MB (1 407 696 bytes) 4.1.0.0 Copyright 2013-2020 Dirk Lemstra

  • Magick.NET-Q8-x86.dll 467 KB (478 928 bytes) 7.21.1.0 Copyright 2013-2020 Dirk Lemstra

  1. I copy those DLLs in those directories (assuming I build with debug profile)

'TestDLL' 'TestDLL\bin' 'TestDLL\bin\Debug'

  1. I made reference in console application to Magick.NET.Core.dll and Magick.NET-Q8-x86.dll

  2. I had a using keyword in Program.cs to detect MagickImage object.

  3. I build in debug profile : all ok (Build succeeded)

  4. I launch.

  5. I obtain an exception : "The type initializer for 'NativeMagickSettings' threw an exception."

These exception contains an inner exception :

"Unable to load DLL 'Magick.Native-Q8-x86.dll': The specified procedure could not be found. (Exception from HRESULT: 0x8007007F)"

I could not see why it crash ... I made all expected things and it is a very 'minimalistic' project just to test ...

What I miss ?

Thanks for all help :)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ImageMagick;

namespace TestDLL
{
    class Program
    {
        static void Main(string[] args)
        {
            MagickImage image = new MagickImage();
        }
    }
}

Stack trace :

at ImageMagick.MagickSettings.NativeMagickSettings..ctor() at ImageMagick.MagickSettings..ctor() at ImageMagick.MagickImage..ctor() at TestDLL.Program.Main(String[] args) in D:\CODE\StandAlone\TESTS\TestDLL\TestDLL\Program.cs:line 13
at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args) at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state) at System.Threading.ThreadHelper.ThreadStart()

My VS install :

Microsoft Visual Studio 2008 Version 9.0.30729.1 SP Microsoft .NET Framework Version 3.5 SP1 Installed Edition: Professional Microsoft Visual C# 2008 91605-270-1746647-60768

c#
dll
imagemagick
windows-xp
32-bit
asked on Stack Overflow Aug 5, 2020 by NobodyzPerfect • edited Aug 5, 2020 by NobodyzPerfect

1 Answer

0

First I suspect that file name of DLL was malformed somehow.

I browse the source code and found :

public partial class MagickSettings
{
            #if PLATFORM_x86 || PLATFORM_AnyCPU
            public static class X86
            {
                #if PLATFORM_AnyCPU
                static X86() { NativeLibraryLoader.Load(); }
                #endif
                [DllImport(NativeLibrary.X86Name, CallingConvention = CallingConvention.Cdecl)]
                public static extern IntPtr MagickSettings_Create();
} 

The name of DLL is generated dynamically before calling Interop ...

The process was here :

namespace ImageMagick
{
    internal static class NativeLibrary
    {
        public const string Name = "Magick.Native";

        public const string QuantumName = Quantum + OpenMP;

        public const string X86Name = Name + "-" + QuantumName + "-x86.dll";

        public const string X64Name = Name + "-" + QuantumName + "-x64.dll";

#if Q8
        private const string Quantum = "Q8";
#elif Q16
        private const string Quantum = "Q16";
#elif Q16HDRI
        private const string Quantum = "Q16-HDRI";
#else
#error Not implemented!
#endif

#if OPENMP
        private const string OpenMP = "-OpenMP";
#else
        private const string OpenMP = "";
#endif

#if PLATFORM_AnyCPU
        public static string PlatformName => Is64Bit ? "x64" : "x86";

        public static bool Is64Bit
        {
            get
            {
                return IntPtr.Size == 8;
            }
        }
#endif
    }
}

So I verify that NativeLibrary.X86Name = "Magick.Native-Q8-x86.dll"

So I turn out my suspicion to Interop call or the DLL itself to be bad somehow.

I make a test code only to call start and end of DLL process.

[DllImport(NativeLibrary.X86Name, CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr MagickSettings_Create();

[DllImport(NativeLibrary.X86Name, CallingConvention = CallingConvention.Cdecl)]
public static extern void MagickSettings_Dispose(IntPtr instance);

DLL export Viewer 1.66 :

Magick.Native-Q8-x86.dll : 1186 exported functions

Function name :MagickSettings_Dispose Address
:0x10024e90 Relative address :0x00024e90 Ordinal :548 (0x224) FileName :Magick.Native-Q8-x86.dll Type
:Exported Function

Function name :MagickSettings_Create Address
:0x10024e10 Relative address :0x00024e10 Ordinal :541 (0x21d) FileName :Magick.Native-Q8-x86.dll Type
:Exported Function

Whith this simple code :

using System;
using System.Runtime.InteropServices;

public sealed class InteropTest
{   
    [DllImport("Magick.Native-Q8-x86.dll", EntryPoint = "#541", CallingConvention = CallingConvention.Cdecl )]
    public static extern IntPtr MagickSettings_Create();

    [DllImport("Magick.Native-Q8-x86.dll", EntryPoint = "#548", CallingConvention = CallingConvention.Cdecl)]
    public static extern void MagickSettings_Dispose(IntPtr instance);
    
    public InteropTest()
    {
        IntPtr p = MagickSettings_Create();

        MagickSettings_Dispose(p);
    }
}

I obtained : Unable to load DLL 'Magick.Native-Q8-x86.dll': The specified procedure could not be found. (Exception from HRESULT: 0x8007007F).

So DLL has a problem.

After investigating, I realize that Magick.Native-Q8-x86.dll has a huge dependencies that make crash code depending on what OS (win7,8,10) you have, what arch (32/64) you have and if you work as desktop or remote server.

It takes times to run after all the DLLs that could miss in particular configuration and each new configuration the problem comes again and differently.

Making a big static DLL does not solve the problem because it would certainly generate a monster file of gigabytes data ...

That's not a good easy way to deploy scenario.

I prefer to switch to the portable app version. It is simple to download, simple to install (just double click), no dependency nightmare. It works even with XP.

The only drawback that it is not so integrated in code that Magick.Net could be.

That's all folks.

answered on Stack Overflow Aug 7, 2020 by NobodyzPerfect

User contributions licensed under CC BY-SA 3.0