Можно ли вызвать 64-битные собственные файлы C ++ DLL из приложения .NET, скомпилированного для «Любого процессора», работающего как 64-битный код? - PullRequest
3 голосов
/ 23 ноября 2010

Я пишу программу на .NET 3.5, которая в некоторых местах должна выходить и выполнять код из аппаратных API. Это все хорошо и работает в 32-битной Windows 7, Windows XP и т. Д. Проблема связана с 64-битной Windows 7.

Я компилирую в «Любой процессор», и он работает в 64-битной версии в Windows 7 64-битной. Таким образом, для взаимодействия с этим единым оборудованием мне пришлось написать свою собственную DLL-оболочку на неуправляемом C ++.

Итак, после того, как у меня все это заработало в 32 битах, я переключил переключатели, чтобы перейти на 64 бит, и в этом заключается проблема. Проблема, с которой я столкнулся, в значительной степени является ТОЧНОЙ противоположностью вопроса переполнения стека «Была предпринята попытка загрузить программу с неверным форматом», даже если платформы одинаковы . В этом вопросе он пытается заставить свой код работать в 32-битном режиме (принудительно) в Windows 7.

Хорошо, теперь я не хочу этого делать, поскольку существует IS 64-битный API для этого аппаратного обеспечения. Итак, я скомпилировал мой код в 64-битной среде, а затем, после многих проб и ошибок, получил правильное LINK в 64-битной версии, и у меня есть PURE 64-битная C ++ DLL и Depends.exe подтверждает это. Теперь Depends.exe также отображает файл DLL поставщика как чистый 64-битный. Это хорошо, потому что в первый раз код не работал, я начал исследование с производителем, и они немного обновили свой код с моей помощью, или я должен сказать, с моими ПРОБЛЕМАМИ ...:)

Итак, короткая история, я разбил это на настолько простую установку, насколько смог. Мой DLL-файл, HW API.dll (который также является родным C ++) и приложение .NET для их вызова с использованием того же синтаксиса P / Invoke и вызовов в качестве 64-битной версии. ..

Мои звонки, просто для справки, выглядят так:

[DllImport("xBiometrics.dll", ExactSpelling=true, SetLastError=true)]
[return: MarshalAs(UnmanagedType.I4)]
public static extern Int32 bioScanOpenDevice();

Теперь, когда я пытаюсь вызвать этот код из .NET, я получаю ошибку исключения:

"System.BadImageFormatException: 
An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)"

Это заставляет меня поверить, что НЕКОТОРЫЕ, что-то 32-битное вмешивается ... Как я мог это сказать? Я имею в виду, да, я уже заглянул в обозреватель ресурсов и убедился, что файлы DLL загружаются из правильного места, и опять же, они скомпилированы в 64-разрядной версии, а приложение .NET работает в 64-разрядной версии. , хотя он скомпилирован для «Любой процессор». Я все это проверил ...

Я что-то совершенно тупой? Я пропустил абзац, где говорится, что P / Invoke не работает на 64-разрядных или что-то? И если я это сделал, то почему он выбрасывает плохой формат изображения исключение?

Возможно ли то, что я делаю, или нет? Может ли 64-битное приложение .NET загружать и вызывать 64-битный собственный DLL-файл? И может ли этот файл DLL динамически связываться с другим собственным 64-разрядным файлом DLL? Будет ли иметь значение, если я использую управляемый 64-битный файл DLL в качестве файла DLL клина? Я использую только DLL-файл клина из-за некоторых вызовов в DLL-файле производителя оборудования. Они передают пустые указатели в буферы, и тому подобное, и это должно быть слишком сложно сделать в C # (необходимо проверить «Разрешить небезопасный код» и т. Д.) Итак, моя идея клина сработала намного лучше ... Я делаю все тяжелая работа в C ++ и передача более структурированных данных в код C #.

Ответы [ 5 ]

4 голосов
/ 23 ноября 2010

Я точно знаю, что могу вызывать 64-битную собственную DLL из программы на C #, которая была скомпилирована с «Любым ЦП» и работает в 64-битной среде выполнения.

Я бы предложилдля отладки выполните следующее:

1) В вашей программе на C # проверьте значение IntPtr.Size при запуске программы.Если это не == 8, значит, вы не используете 64-битную версию.

2) Установите полный путь к 64-битной DLL в вашем DllImport.То есть:

[DllImport(@"c:\fullpath\xBiometrics.dll", ExactSpelling=true, SetLastError=true)]

Если это работает (что, я подозреваю, так и будет), то проблема в том, что где-то в пути поиска DLL есть 32-битная копия DLL.Это сбило меня с толку не раз.

3 голосов
/ 23 ноября 2010

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

Тогда COM-маршалинг будет обрабатывать любые 32-64-битные проблемы интерфейса.

Хотя медленнее.

3 голосов
/ 23 ноября 2010

Наиболее вероятным источником ошибки является то, что вы объявили какой-то параметр неправильно - например, Int32, когда вы действительно хотели IntPtr.

Также возможно, что вам не удалось скомпилировать 64-битную версию.Например, я точно знаю, что VS укусил меня в задницу, прежде чем менять некоторые не связанные с битами настройки проекта при изменении размера адреса.Я хотел бы пройтись по всем настройкам вашего неуправляемого проекта и убедиться, что они все идентичны для 32-битной и 64-битной систем.

Наконец, попробуйте загрузить неуправляемую DLL из неуправляемого приложения.Вы хотите знать, находится ли ошибка на управляемой стороне или в неуправляемом коде.

0 голосов
/ 23 ноября 2010

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

0 голосов
/ 23 ноября 2010

Ранее я сталкивался с подобной проблемой и решил ее, убедившись, что мой код работает с указателями, определенными как long - проверьте, что они все 64-битные.

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