Использование unmanaged dll из C#

(на картинке, более новая версия устройства CAN-USB)
Имеется у меня старенький девайс, USB-CAN от Marathon. (у них уже две или три более новых версии появилось. А этот, чтоб под семеркой запустить, даже пришлось пошаманить с inf файлами драйверов.) Плюс его, по-отношению к другим устройствам подобного типа, в том что марафоновцы предоставляют API для написания своего софта. API заключено в DLL. Я использую старую версию библитотеки (новые уже не поддерживают мою версию прибора, а новый прибор покупать — смысла пока не вижу). Раньше, я писал к нему программы используя C++Builder 6. Но, среда сильно устаревшая, современные RAD Studio от Embarcadero и Codegear, меня как-то «не вставили». Короче решил прикрутить библиотеку к C#. О чем и хочу рассказать в порядке моих собственных действий, мыслей и ошибок.

Для начала решил прикрутить одну функцию. Без параметров, возвращающюю 16-ти битный int статуса:
__declspec( dllexport) _s16 CiInit(void);
создаю следующий файл chai.cs (для импорта функций и объявления структур):

И в основной файл проекта в Form_Load добавляю вызов этой функции:

Компилируем и запускаем — выдает исключение. Немного помучившись разбираюсь. Target у проекта AnyCPU меняю на x86 (dll-то старая, 32-х битная). Все выполняется нормально.
Идем дальше, добавим немного взаимодействия с библиотекой. Импортируем функцию получающую информацию об устройстве. Ну и объявляем структуру, совместимую с той, что требуется функции:

Ну с объявлением функции все почти понятно. Вместо указателя сообщаем, что в параметре будет ссылка на объект, физически оно одинаково обрабатывается через Invoke. Но как оказалось, нужно было еще добавить тип соглашения о вызове Cdecl. Иначе оно работало, Но ругалось на нарушение стека.

А вот со структурой, тут не все так явно. Во-первых мы не можем объявить Int16 chip[4] поле в структуре. Поэтому объявляем его как Int16[] chip; А в атрибуте указываем, что это неуправляемый массив из четырех элементов (библиотека же у нас не управляемая).
Далее с полями типа char[64]. Там все почти идентично, но т.к. мы используем эти поля не как массивы, а как строки, то и указываем их как строки в 64 символа. А так как char – однобайтный символ, то и сообщаем что у нас однобайтная кодировка в структуре используется (CharSet = CharSet.Ansi):

Итого имеем файл «импорта»:

И в главном файле, получаем информацию об адаптере и выводим ее в заголовок окна (формы):

app_1

Продолжение следует…

Leave a Reply

Ваш e-mail не будет опубликован. Обязательные поля помечены *