ImageMagick: не удалось загрузить DLL 'Magick.Native-Q8-x86.dll' - PullRequest
0 голосов
/ 06 августа 2020

Происходит очень странная вещь. Я хочу использовать Image Magick в своем исходном коде вместо использования пакета командной строки, поэтому я пробую Image Magick. Net (https://recordnotfound.com/Magick-NET-dlemstra-154214), но ....

Давайте опишем вещи тем точнее.

  1. Я использую XP Pro SP3 32 бит версии 2002 Я вхожу в систему как администратор.

В моей системе

  • Microsoft Visual C ++ 2012 Redistribuable (x86) 11.0.610.30
  • Redistribuable Microsoft Visual C ++ 2017 (x86) 14.11.25325

Открываю VS 2008

Создаю новый проект типа Консольное приложение в C#. Я назвал его TestDLL.

В файле Program.cs в методе stati c void Main (string [] args) 'я создаю экземпляр объекта ImageMagick.

Я загружаю библиотеки DLL с сайта nuget https://www.nuget.org/profiles/dlemstra:

  • Magick.Native-Q8- x86.dll 13,7 МБ (14 450 896 байт) 7.0.10.25 Авторские права 2013-2020 Дирк Лемстра

  • Magick. NET .Core.dll 1,34 МБ (1407 696 байт) 4.1.0.0 Авторские права 2013-2020 Дирк Лемстра

  • Magick. NET -Q8-x86.dll 467 КБ (478 928 байт) 7.21.1.0 Авторские права 2013-2020 Дирк Лемстра

Я копирую эти библиотеки DLL в эти каталоги (при условии, что я собираю с профилем отладки)

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

Я сделал ссылку в консольном приложении на Magick. NET .Core.dll и Magick. NET -Q8-x86.dll

Я использовал ключевое слово в Program.cs для обнаружения объекта MagickImage.

Я создаю профиль отладки: все в порядке (сборка завершена)

Я запускаю.

Я получаю исключение: «Инициализатор типа для 'NativeMagickSettings' вызвал исключение.»

*

Это исключение содержит внутреннее исключение:

«Невозможно загрузить DLL 'Magick.Native-Q8-x86.dll': указанная процедура не может быть найдена. (Исключение из HRESULT: 0x8007007F)»

I Я не мог понять, почему он треснул sh ... Я сделал все, что ожидал, и это очень «минималистичный c» проект, просто чтобы протестировать ...

Чего я скучаю?

Спасибо за помощь :)

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();
        }
    }
}

Трассировка стека:

в ImageMagick.MagickSettings.NativeMagickSettings..ctor () в ImageMagick.MagickSettings..ct или () в ImageMagick.MagickImage..ctor () в TestDLL.Program.Main (String [] args) в D: \ CODE \ StandAlone \ TESTS \ TestDLL \ TestDLL \ Program.cs: строка 13 в System.AppDomain._nExecuteAssembly (сборка сборки, String [] args) в System.AppDomain.ExecuteAssembly (String AssemblyFile, Evidence assemblySecurity, String [] args) в Microsoft.VisualStudio.HostingProcess.HostPro c .RunUsersAssembly () в System.Threading.ThreadHelper.ThreadStart_Context (состояние объекта) в System.Threading.ExecutionContext.Run (ExecutionContext executionContext, обратного вызова ContextCallback, состояние объекта) в System.Threading.ThreadHelper.ThreadStart ()

Моя установка VS:

Microsoft Visual Studio 2008 версии 9.0.30729.1 SP Microsoft. NET Framework версии 3.5 SP1 Установленная версия: Professional Microsoft Visual C# 2008 91605-270-1746647-60768

1 Ответ

0 голосов
/ 07 августа 2020

Сначала я подозреваю, что имя файла DLL было каким-то образом искажено.

Я просматривал исходный код и обнаружил:

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();
} 

Имя DLL генерируется динамически перед вызовом Interop .. .

Процесс был здесь:

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
    }
}

Итак, я проверяю, что NativeLibrary.X86Name = "Magick.Native-Q8-x86.dll"

Итак, я получаю Мое подозрение, что вызов Interop или сама DLL каким-то образом плохи.

Я делаю тестовый код только для вызова начала и конца процесса DLL.

[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 1.66:

Magick.Native-Q8-x86.dll: 1186 экспортируемых функций

Имя функции: MagickSettings_Dispose Address : 0x10024e90 Относительный адрес: 0x00024e90 Порядковый номер: 548 (0x224) Имя файла: Magick.Native-Q8-x86.dll Тип : Экспортированная функция

Имя функции: MagickSettings_Create Address : 0x10024e10 Относительный адрес: 0x00024e10 Порядковый номер: 541 (0x21d) Имя файла: Magick.Native-Q8-x86.dll Тип : Экспортированная функция

С помощью этого простого кода:

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);
    }
}

Я получил: Невозможно загрузить DLL 'Magick.Native-Q8-x86.dll': указанная процедура не смогла быть найденным. (Исключение из HRESULT: 0x8007007F).

Итак, у DLL есть проблема.

После исследования я понял, что Magick.Native-Q8-x86.dll имеет огромные зависимости, которые делают cra sh код в зависимости от того, какая у вас ОС (win7,8,10), какая у вас архитектура (32/64) и работает ли вы как настольный компьютер или удаленный сервер.

Требуется время для запуска после всех библиотек DLL которые могут пропустить в конкретной конфигурации, и с каждой новой конфигурацией проблема возникает снова и по-разному.

Создание большой статической c DLL не решает проблему, потому что это определенно генерирует гигантский файл с данными в гигабайтах ...

Это не самый простой способ развертывания сценария.

Я предпочитаю переключиться на переносную версию приложения. Его просто скачать, просто установить (просто дважды щелкнуть), никакого кошмара зависимости. Он работает даже с XP.

Единственный недостаток в том, что он не так интегрирован в код, как могла бы быть Magick. Net.

Вот и все.

...