Импорт внешних DLL на основе 64-битной или 32-битной ОС - PullRequest
8 голосов
/ 07 апреля 2010

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

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

Ответы [ 5 ]

14 голосов
/ 07 апреля 2010

Вы можете воспользоваться 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);
6 голосов
/ 07 апреля 2010

Можете ли вы импортировать их оба и принять решение о том, какой из них вместо этого вызывать через .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);
3 голосов
/ 07 апреля 2010

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

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

3 голосов
/ 07 апреля 2010

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

2 голосов
/ 07 апреля 2010

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...