Объедините 32- и 64-битные драйверы в одну программу - PullRequest
2 голосов
/ 12 марта 2019

Мне нужно загрузить различные драйверы оборудования, которые содержатся в файлах .dll. Проблема заключается в том, что драйверы для одного устройства приведены в 64-битной DLL, другое устройство (довольно старое), очевидно, полагается на драйверы, предоставленные в 32-битной DLL. Я хочу управлять ими через программу, написанную на C #, которая будет запускаться через оболочку Python.

Очевидно, что я не могу запустить оба устройства из одной программы напрямую, но мне нужен способ их адресации в зависимости друг от друга - например: устройство 1 ожидает, пока устройство 2 завершит какую-то работу. Есть ли способ обойти эту проблему, или мне нужно будет запустить их в двух отдельных программах и управлять действиями в зависимости друг от друга через оболочку Python?

Привет

Ответы [ 2 ]

4 голосов
/ 12 марта 2019

В 64-разрядных Windows 64-разрядные процессы не могут использовать 32-разрядные библиотеки DLL, а 32-разрядные процессы не могут использовать 64-разрядные библиотеки DLL. У Microsoft задокументировано это:

В 64-битной Windows 64-битный процесс не может загрузить 32-битную динамически подключаемую библиотеку (DLL). Кроме того, 32-разрядный процесс не может загрузить 64-разрядную DLL.

Вам потребуется 32-разрядный процесс, который взаимодействует с 32-разрядной библиотекой DLL, и 64-разрядный процесс для связи с 64-разрядной библиотекой DLL. Microsoft говорит это:

Однако 64-битная Windows поддерживает удаленные вызовы процедур (RPC) между 64-битными и 32-битными процессами (как на одном компьютере, так и на разных компьютерах).

Тогда проблема заключается в том, как заставить Python взаимодействовать с этими процессами. Необходима некоторая форма межпроцессного взаимодействия (IPC). Несколько десятилетий назад Microsoft создала технологию, которая может сделать именно это - интерфейсы COM с использованием COM-серверов вне процесса (вне процесса).

Общая идея такова:

  • Создает 64-битный сервер COM вне процесса, который оборачивает (и предоставляет) необходимые методы и данные 64-битной DLL.
  • Создайте 32-разрядный сервер COM вне процесса, который упаковывает (и предоставляет) необходимые методы и данные 32-разрядной библиотеки DLL.
  • Напишите 32-битный или 64-битный клиентский код, который создает экземпляры COM-объектов и вызывает их интерфейсы. Python может использоваться как COM-клиент через win32com

COM предоставляет механизм IPC, позволяющий 64-разрядному клиенту получить доступ к 64-разрядному COM-серверу вне процесса, а 64-разрядному клиенту получить доступ к 32-разрядному серверу вне процесса. , Вы даже можете иметь 32-битные клиенты, которые также могут обмениваться данными с 32-битными и 64-битными COM-серверами.

Я не выполнял низкоуровневую работу с Windows, используя более новые языки MS. Когда мне нужно было сделать то, что вам нужно в вашем вопросе, две основные технологии, которые облегчали написание COM-серверов и COM-интерфейсов:

У меня было предпочтение для ATL, так как он не требовал библиотеки MFC и имел меньше служебных данных.

2 голосов
/ 12 марта 2019

Да, вам понадобятся 2 отдельных процесса, запущенных из разных исполняемых файлов. Только 32-разрядные исполняемые файлы могут загружать 32-разрядные библиотеки DLL. (См. Ответ @ MichaelPetch для получения полезных советов о том, как заставить одного общаться с другим с помощью механизма удаленного вызова процедур, который может имитировать вызов 32-битных функций из 64-битного кода или наоборот.)

32-разрядная x86 и x86-64 - две отдельные архитектуры, которые, как оказалось, выполняются одним и тем же процессором в разных режимах. Их машинный код очень похож но не совместимы, и многое другое, в том числе формат объектного файла и детали ABI, такие как ширина указателя 8 против 4 байтов.


При наличии 64-битного процесса можно запустить поток , который выполняет jmp far для 32-битного сегмента кода, технически возможно (потому что GDT имеет 32- и 64-битные записи сегмента кода), но это безумие и очень плохо поддерживается всем, включая код динамической загрузки / разрешения символов DLL. ( Также включает ядро, так что это даже небезопасно: прерывание или системный вызов могут вернуться к 32-битному коду в 64-битном режиме, если вы попытаетесь это сделать, , потому что ядро ​​знает, что ваш поток / процесс запущен в 64-битном режиме.)

Вы не сможете убедить компилятор сгенерировать 32-битный код и связать его с 64-битным кодом, даже если вы использовали C в ОС, где это было «безопасно» для этого. Управляемый язык более высокого уровня делает его еще более непригодным для использования даже в том случае, если он «безопасен» при написании рукописного асма.

Я упоминаю об этом на всякий случай, если вам интересно, что технически потребуется для этого, , а не , потому что кто-то должен это делать.

Но если это было безопасно, теоретически вы могли бы написать (вручную в asm) функции-оболочки для каждой функции в 32-битной DLL, которая переходит в 32-битный режим перед вызовом функции.

Видимо, это было ранним 32-битным Windows; Вы можете вызывать 16-битные библиотеки DLL из 32-битного кода через оболочку «thunk», предоставляемую ОС. Но нет аналогичной поддержки 32-битных DLL из 64-битного кода или наоборот.

...