getprocaddress не находит функцию

Функция GetProcAddress извлекает адрес экспортируемой функции или переменной из заданной динамически подключаемой библиотеки (DLL).

[in] Дескриптор модуля DLL, который содержит функцию или переменную. Функция LoadLibrary или GetModuleHandle возвращает этот дескриптор.

[in] Указатель на символьную строку с нулем в конце, которая определяет функцию или имя переменной, или порядковое значение функции. Если этот параметр — порядковое значение, оно должно находиться в младшем слове; старшее слово — должно быть нуль.

Если функция завершается успешно, возвращаемое значение — адрес экспортируемой функции или переменной.

Если функция завершается ошибкой, возвращаемое значение — ПУСТО (NULL). Чтобы получить дополнительную информацию об ошибке, вызовите GetLastError.

Проверка правописания и регистра имени функции, на которое указывает параметр lpProcName должны быть идентичны такому же в операторе EXPORTS определения модуля исходного (.def) файла DLL. Имена экспортируемых функций могут отличаться от имен, которые Вы используете при вызове этих функций в вашем коде. Это различие скрыто макроопределением, используемым в заголовочных файлах SDK. Дополнительную информацию, см. в статье Соглашения для прототипов функций .

Параметр lpProcName может идентифицировать функцию DLL, определяя порядковое значение, связанное с функцией в операторе EXPORTS . GetProcAddress проверяет, что указанный порядковый номер находится в диапазоне от 1 до самого высокого порядкового числа, экспортируемого в .def файле. Функция тогда использует порядковый номер как индекс, чтобы читать адрес функции из таблицы функций. Если .def файл не считает функции последовательно от 1 до N (где N — число экспортируемых функций), может произойти ошибка, где GetProcAddress возвращает недопустимый, не-NULL адрес, даже при том, что функции с указанным порядковым номером нет.

В случаях, когда функция не может существовать, она должна задаваться по имени, а не порядковым значением.

Размещение и совместимость GetProcAddress

Мне нужно динамически загрузить DLL в C ++.

Я следовал этому уроку http://msdn.microsoft.com/en-us/library/ms235636.aspx создать dll и все работало нормально.

Затем я последовал за этим http://msdn.microsoft.com/en-us/library/64tkc9y5.aspx и я адаптировал консольное приложение следующим образом:

DLL загружена правильно и не является нулевой. Проблема в функции GetProcAddress (), которая всегда возвращает 0.

Я пробовал с каждой комбинацией пространства имен, имени класса, имени метода. Я попытался использовать оператор области (: �� вместо @ в имени функции.

Я пытался определить все пространство имен как
extern «C», но ничего не меняется. Каждый раз, когда я запускаю или отлаживаю консольное приложение, оно не может найти функцию «Умножить».

Я думаю, что я что-то упустил …
Где я не прав?

РЕДАКТИРОВАТЬ

Зависимость Уокер выставил мне следующую таблицу экспорта:

Теперь мне интересно, что означает последняя часть имени функции …
Почему __declspec (dllexports) добавляет эти символы?

Решение

Используйте такой инструмент, как dumpbin или Dependency Viewer, чтобы проверить экспортированные имена функций. Это позволит вам определить, какой из возможных режимов отказа относится к вашему случаю:

  1. Функция не экспортируется, или
  2. Функция экспортируется, но имя оформлено, или
  3. Функция экспортируется с именем, которое вы ожидали, но вы просто ввели его неправильно.

Другие решения

Добро пожаловать в C ++. Все, что компилятор добавляет к именам ваших функций, это гарантирует, что каждая функция с уникальной подписью имеет уникальное имя. Microsoft называет искажение имен одним способом, а GCC / Clang — другим. Он не стандартизирован, но все компиляторы в конкретной ОС одинаково именуют друг друга, поэтому они могут уживаться друг с другом.

Единственный способ обеспечить предсказуемость вашего имени людьми — объявить экспортированную функцию DLL как extern «C» , Тем не менее, это ограничивает вас для экспорта функций C.

В библиотеках, над которыми я работал, есть одна экспортированная функция C, которая инициализирует библиотеку и возвращает указатель на интерфейс. В этом случае «интерфейс» означает абстрактный виртуальный базовый класс без данных и только виртуальные функции.

Это правильный способ объявить интерфейсный класс:

Пытаюсь динамически загрузить библиотеку FANN. Цель изначально состояла в том, чтобы подключить её к Qt, но официальный враппер, видимо, предназначен для подключения исключительно компилятором VS.

Написал свой простейший врапер, в котором содержится большинство функций, и их загрузку посредством GetProcAddress . Итого, из 83 функций он загружает только 2, а на остальных выдает ошибку, что данной функции нет в файле.

У всех проставлено __declspec(dllexport)

1 ответ 1

Не могу сказать, по какой причине Ваш собственный враппер работает некорректно, однако, как сама библиотека, так и её официальный C++-враппер вроде бы без проблем собираются компилятором MinGW 4.9.1 из состава Qt 5.4.1 (наверняка и с другими версиями MinGW будет собираться).

По ссылке пример сборки.

Обновление

Я собирал под win7 x86 (версии Qt и MinGW уже обозначены в ответе), поэтому, если Вы использовали мои файлы, то, возможно, имеется некая несовместимость с Вашей средой. Не могу предполагать, в чём конкретно эта несовместимость может заключаться, т.к. деталей Вы до сих пор не уточнили. А вообще я рекомендую тогда собрать flann самостоятельно и подключать именно свою сборку к проекту. Если же будут проблемы, то соответственно публиковать здесь вопросы с указанием конкретных ошибок, которые будут возникать. Гадание редко приводит к профиту.

Обновление 2

Ну как раз ошибки говорящие. Попробовал у себя собрать. Также ругнулось. Посмотрел заголовочный «fann_cpp.h». Проблема в том, что он не подключает «fann.h». Может разрабы это забыли сделать или ещё по какой причине, но факт. Я просто добавил подключение «fann.h» перед «fann_cpp.h» и ошибок не стало.

Вот так корректно можно подключить fann в Qt-проект:

$$PWD означает путь к папке с исходниками текущего проекта. Слэш — прямой, а не обратный, как это принято обычно в виндовс. Обе папки с fann должны лежать на одном уровне с папкой исходников проекта (ну либо нужно поправить путь на собственный).

Оцените статью