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

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

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

8
задан Mike_G 7 April 2010 в 15:53
поделиться

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);
6
ответ дан 5 December 2019 в 05:55
поделиться

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

2
ответ дан 5 December 2019 в 05:55
поделиться

Вы можете воспользоваться функцией SetDllDirectory API, она изменяет путь поиска для неуправляемых сборок. Храните 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);
14
ответ дан 5 December 2019 в 05:55
поделиться

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

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

3
ответ дан 5 December 2019 в 05:55
поделиться

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

3
ответ дан 5 December 2019 в 05:55
поделиться