Импорт внешних DLL на основе 64-битной или 32-битной ОС

У меня есть DLL, которая поставляется в 32-битной и 64-битной версии. Мой.NET WinForm настроен на "Любой ЦП", и мой начальник не разрешит нам проводить отдельные установки для разных версий ОС. Поэтому мне интересно: если я упакую обе библиотеки в процессе установки, то есть ли способ заставить WinForm определить, является ли он 64-битным /32-битным, и загрузить соответствующую DLL.

Я нашел эту статью для определения версии. Но я не уверен, как ввести правильный способ определения атрибута DLLImport в методах, которые я хочу использовать. Есть идеи?

5 ответов

Решение

Можете ли вы импортировать их оба и принять решение о том, какой из них вызывать через.NET?

Например:

[DllImport("32bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe32 (IntPtr hWnd, String text, String caption, uint type);

[DllImport("64bit.dll", CharSet = CharSet.Unicode, EntryPoint="CallMe")]
public static extern int CallMe64 (IntPtr hWnd, String text, String caption, uint type);

Вы можете воспользоваться API-функцией SetDllDirectory, которая изменяет путь поиска для неуправляемых сборок. Сохраните свои 32-разрядные библиотеки DLL в подкаталоге x86 каталога установки приложения, а 64-разрядные библиотеки DLL - в подкаталоге x64.

Запустите этот код при запуске приложения, прежде чем выполнять P/Invoke:

using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;
...

    public static void SetUnmanagedDllDirectory() {
        string path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
        path = Path.Combine(path, IntPtr.Size == 8 ? "x64 " : "x86");
        if (!SetDllDirectory(path)) throw new System.ComponentModel.Win32Exception();
    }

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern bool SetDllDirectory(string path);

Вы должны сделать два разных частных extern методы, и сделать внутренний метод, который проверяет IntPtr.Size и называет правильную версию.

Мое решение заключается в создании одного абстрактного класса с конкретной версией, которая загружает и упаковывает мою 32-битную DLL, и отдельной реализацией, которая загружает и упаковывает 64-битную DLL. Один метод фабрики в базовом классе может использоваться для создания экземпляра соответствующей реализации на основе IntPtr.Size,

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

... или вы можете использовать Marshal.GetDelegateForFunctionPointer() делать динамический P / Invoke.
...или позвоните по телефону LoadLibrary() с полным путем, прежде чем CLR попытается загрузить его для вас.

Другие вопросы по тегам