Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: C++Builder объявление экспортируемых из .dll функций
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Nikolai Rihkov
Здравствуйте!
Работаю с Borland C++Builder 6 пробую подключить библиотеку .dll создал файлы .lib и .def как положено, но вот что то не получается с объявлением в моем Unit1.h экспортируемых из .dll функций, в основном я делаю так _declspec(dllexport) _stdcal void usb_init(void); сдесь все работает, но не могу понять что делать, как объявить в моем Unit1.h экспортируемую из .dll функцию usb_get_busses(void); как указатель на структуру struct usb_bus *usb_get_busses(void);?
Код

struct usb_bus
{
    struct usb_bus *next, *prev;

    char dirname[LIBUSB_PATH_MAX];

    struct usb_device *devices;
    unsigned long location;

    struct usb_device *root_dev;
};

XVR
Во первых - dllimport (а не dllexport)
Во вторых - не забудьте extern "C" {} вокруг импортируемых функций
Цитата
но не могу понять что делать, как объявить в моем Unit1.h экспортируемую из .dll функцию usb_get_busses(void); как указатель на структуру struct usb_bus *usb_get_busses(void);?

Так и объявлять -
Код
extern "C" {
__declspec(dllimport) __stdcall usb_bus *usb_get_busses(void);
}

PS. Если dll писалась не в Bulder, то скорее всего работать не будет, как функцию не объявляй sad.gif
Nikolai Rihkov
dll писалась не в Bulder, работать эта функция не хочет, может можно как то по другому ее объявить, другой подход к проблеме?
XVR
Цитата(Nikolai Rihkov @ Nov 25 2013, 19:42) *
dll писалась не в Bulder, работать эта функция не хочет, может можно как то по другому ее объявить, другой подход к проблеме?

Посмотрите под каким именем эта функция экспортируется из dll (через любой дампер, который умеет дамповать секцию экспорта). И еще посмотрите, что dll импортирует. Если там есть рантайм библиотеки VC, то скорее всего дело швах - они с BCB не совместимы
Xenia
Цитата(XVR @ Nov 25 2013, 21:52) *
Посмотрите под каким именем эта функция экспортируется из dll (через любой дампер, который умеет дамповать секцию экспорта). И еще посмотрите, что dll импортирует. Если там есть рантайм библиотеки VC, то скорее всего дело швах - они с BCB не совместимы

Странно. А я подцепляю к Builder 6.0 математическую библиотеку Intel MKL, писанную под VS2013, и всё нормально работает. Точно так же получилось пристыковать код dll-ки, написанный и скомпилированной на Фортране (как на Compaq Visual Fortran Professional v6.5, так и на Intel Fortran Composer XE 2013. В последнем случае пришлось повозиться, подбирая опции линкера).

Я, конечно, не уверена, что пристыковать можно любую библиотеку, но в большинстве случаев это получается.

Методика такая:
Первым делом снимаем с dll-файла дамп, напуская на него tdump.exe, входящий в состав Билдера. Лучше с выдачей в файл:
tdump xxx.dll > xxx.dmp
Потом вручную просматриваем файл xxx.dmp на предмет того, как в нем прописаны имена экспортируемых функций, обращая внимание на два обстоятельства: стоит ли спереди подчеркивание и есть ли в именах малые/строчные буквы.
Следом за этим генерим к этой dll-ке lib-файл. Если таковой уже прилагается, то выбрасываем его прочь, т.к. пристыковать его ни за что не получится - у VS слишком специфический формат объектных модулей и библиотек. Поэтому создаем свой lib-файл с помощью утилиты implib.exe (из того же Билдера). Делаем это так:
implib.exe -a -c xxx.lib xxx.dll > xxx.lst
xxx.lst - это просто листинг на предмет ошибок, его лучше сохранить, т.к. по экрану пробежит очень быстро.
xxx.dll - наша dll-ка.
xxx.lib - имя генерируемой либы (обычно с тем же именем, как у dll, только с другим расширением).
Но самое важное - это опции -a и -c
-a ставим только тогда, когда имена функций идут с передним подчеркиванием (для этого дамп делали!), иначе пропускаем.
-с ставим только тогда, когда имена функции содержат малые буквы (наряду с большими), иначе пропускаем.
Получаем в результате либу xxx.lib, которую добавляем в свой проект, а dll-ку xxx.dll кладем в тот же директорий рядышком (ее в проект добавлять не надо).
Вот и всё.

Но всё это только в отношении стыковки, тогда как при запуске проекта нужно быть готовыми к любой неожиданности.
Первая из них - если наша dll-ка при запуске позовет другую. Такое встречается почти всегда, поскольку dll-ки в момент запуска аллокируют память с помощью функций CALLOC/MALLOC, которых в себе не содержат. Если dll-ка старенькая, то, скорее всего, она найдет себе msvcr.dll среди компонентов Window. Но в моем случае пришлось добывать и подкладывать рядом msvcr100.dll из VS2013 Redistributable Pack или инсталлировать его.

Далее. Не плохо было бы встать отладчиком (поставить breakpoint) на CALL-вызове функции из данной dll-библиотеки, чтобы проверить, сохраняется ли указатель стека, до и после ее выполнения. Если же код сишный, то в норме програма должна восстановить указатель стека к прошлому значению на следуюших 1-2 шагах. Если этого не происходит, то ситуация становится серьезной и требует корректировки объявления функции в хидере. Но тут давать какие-то советы вперед бесполезно - надо разбираться с конкретным примером.
kolobok0
Цитата(Xenia @ Nov 26 2013, 02:00) *
...Не плохо было бы встать отладчиком...


всё верно описано.
можно добавить, что:
подчёркиваниями кодируют кто чистит стэк (вызывающий или вызываемый).
под отладчиком лучше не только (и не столько) проверить стэк, как пройтись по шагам на предмет чтения(ожидания) вызываемой функции
ваших переменных. Так например тот же фортран всегда оперирует указателями, в watcome чистка стэка идёт (как правило) внутри
вызываемой функции, кларион имеет свои заморочки по типам и способам передачи параметров, клипер например свои...и т.д. и т.п..

вязать можно практически всё, что вздумается. на передний план выходит обычно целесообразность всего этого огорода...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.