Целевая 32-разрядная или 64-разрядная нативная DLL-память в зависимости от среды
У меня есть родная DLL, которая поставляется как в 32-битной, так и в 64-разрядной версиях (x86). Я хочу создать оболочку, которая работает на обеих архитектурах (любой процессор) и загружает правильную версию DLL в зависимости от текущей среды (32 бит или 64 бит во время выполнения!). Этот процесс должен происходить автоматически, так что пользователям моей DLL не нужно настраивать определенную архитектуру.
Есть ли какие-либо рекомендации по тому, как это сделать? Любые примеры, которые могли бы мне помочь?
Я нашел одно возможное решение, которое использует управляемые прокси для каждой архитектуры, а затем использует событие Assembly.Resolve
для загрузки правильной версии. Однако для этого требуется, чтобы у меня было 3 управляемых сборки в дополнение к двум неуправляемым библиотекам, которые, похоже, немного переборщились.
- Почему вызовы Cdecl часто несовместимы в «стандартной» конвенции P / Invoke?
- Использование библиотеки C из кода C #
- Вызов функции PInvoke '' не сбалансировал стек
- Лучший способ доступа к COM-объектам из C #
- Не удалось загрузить DLL (модуль не найден HRESULT: 0x8007007E)
Есть ли другое решение?
- Как обрабатывать нулевые или необязательные параметры структуры dll в C #
- Как передать тип с нулевым значением в функцию P / invoked
- Являются ли атрибуты P / Invoke необязательными для массивов маршалинга?
- Рабочий пример CreateJobObject / SetInformationJobObject pinvoke в .net?
- Правильный способ (в .NET) переключить фокус на другое приложение
- Установить атрибут DllImport динамически
- Как вернуть текст из Native (C ++) кода
- Отсутствие вывода консоли при использовании AllocConsole и целевой архитектуры x86
Вот решение, которое я использовал для многих проектов:
- назовите 32-битную сборку «32-разрядным ориентированным именем». Например MyAssembly.Native.x86.dll
- назовите 64-битную сборку с «64-битным ориентированным именем». Например MyAssembly.Native.x64.dll
- скомпилируйте управляемую сборку как «Any Cpu»,
- отправляйте все по тому же пути
Вот как я объявляю методы P / Invoke:
[DllImport("MyAssembly.Native.x86.dll", EntryPoint = "MyTest")] private static extern void MyTest86(MyType myArg); [DllImport("MyAssembly.Native.x64.dll", EntryPoint = "MyTest")] private static extern void MyTest64(MyType myArg);
И вот соответствующая функция «MyTest», которую я всегда буду использовать (другие здесь только для правильной привязки биттирования). Он имеет ту же подпись, что и другие P / Invoke:
public static void MyTest(MyType myArg) { if (IntPtr.Size == 8) { MyTest64(myArg); return; } MyTest86(myArg); }
Преимущества:
- вы можете отправлять все двоичные файлы (DLL, EXE, …) по тому же пути
- вы поддерживаете 32-битные и 64-битные процессы и операционные системы с одинаковым расположением файлов
- вам не нужно прибегать к Win32 apis для изменения пути загрузки DLL
Неудобства:
- у вас будет 3 объявления метода для 1 ‘реального’ метода
- вы потеряете некоторые циклы процессора из-за теста на битту
- в зависимости от вашего контекста, иногда вы не можете изменять имена родных DLL, поэтому вы просто не можете этого сделать
То, как я это делаю, – это p / вызвать вызов LoadLibrary
перед вызовом любого из p / invokes в библиотеку.
- Используйте битту исполняющей сборки, чтобы определить, какую версию неуправляемой DLL загружать.
- Затем вызовите
LoadLibrary
чтобы загрузить его, передавая полный путь к DLL. - Затем, когда вы вызываете p / invokes, правильная DLL уже загружена в процесс, и p / invokes привязаны к ней.
Это зависит от неуправляемой DLL с одинаковым именем для 32 и 64 бит. Если это не так, тогда у вас проблемы. В этом случае вам может понадобиться явно связать DLL с помощью p / вызова GetProcAddress
. Это совсем не забавно. Или вы реализуете вид лесов, которые Саймон описывает в своем ответе.
Взгляните на class Microsoft.WinAny.Helper и It’a DynamicNativeLibrary, который поможет вам в том, что вам нужно.