Мне нужно динамически загрузить DLL в C ++.
Я следовал этому уроку http://msdn.microsoft.com/en-us/library/ms235636.aspx создать dll и все работало нормально.
Затем я последовал за этим http://msdn.microsoft.com/en-us/library/64tkc9y5.aspx и я адаптировал консольное приложение следующим образом:
typedef DOUBLE(CALLBACK* DllFunc)(DOUBLE, DOUBLE);
int _tmain(int argc, _TCHAR* argv[])
{
HINSTANCE hDLL; // Handle to DLL
DllFunc dllFunc1;
DOUBLE p1 = 1.0, p2 = 2.0, r;
hDLL = LoadLibrary(L"MathFuncsDLL");
if (hDLL != NULL)
{
cout << "DLL loaded: " << hDLL << endl;
dllFunc1 = (DllFunc)GetProcAddress(hDLL, "MyMathFuncs@MathFuncs@Multiply");
if (!dllFunc1)
{
// handle the error
FreeLibrary(hDLL);
cout << "Function not found!" << endl;
return -1;
}
else
{
// call the function
r = dllFunc1(p1, p2);
cout << "The result is: " << r << endl;
}
}
else {
cout << "Dll not found" << endl;
return -1;
}
cout << "Press any key to exit." << endl;
int i;
cin >> i;
return 0;
}
DLL загружена правильно и не является нулевой. Проблема в функции GetProcAddress (), которая всегда возвращает 0.
Я пробовал с каждой комбинацией пространства имен, имени класса, имени метода. Я попытался использовать оператор области (: 🙂 вместо @ в имени функции.
Я пытался определить все пространство имен как
extern «C», но ничего не меняется. Каждый раз, когда я запускаю или отлаживаю консольное приложение, оно не может найти функцию «Умножить».
Я думаю, что я что-то упустил …
Где я не прав?
РЕДАКТИРОВАТЬ
Зависимость Уокер выставил мне следующую таблицу экспорта:
Теперь мне интересно, что означает последняя часть имени функции …
Почему __declspec (dllexports) добавляет эти символы?
Используйте такой инструмент, как dumpbin или Dependency Viewer, чтобы проверить экспортированные имена функций. Это позволит вам определить, какой из возможных режимов отказа относится к вашему случаю:
Добро пожаловать в C ++. Все, что компилятор добавляет к именам ваших функций, это гарантирует, что каждая функция с уникальной подписью имеет уникальное имя. Microsoft называет искажение имен одним способом, а GCC / Clang — другим. Он не стандартизирован, но все компиляторы в конкретной ОС одинаково именуют друг друга, поэтому они могут уживаться друг с другом.
Единственный способ обеспечить предсказуемость вашего имени людьми — объявить экспортированную функцию DLL как extern "C"
, Тем не менее, это ограничивает вас для экспорта функций C.
В библиотеках, над которыми я работал, есть одна экспортированная функция C, которая инициализирует библиотеку и возвращает указатель на интерфейс. В этом случае «интерфейс» означает абстрактный виртуальный базовый класс без данных и только виртуальные функции.
Это правильный способ объявить интерфейсный класс:
struct my_interface
{
virtual int my_function1( int param1, int param2 ) = 0;
virtual int my_function2( const char *param ) = 0;
#if CHOOSE_DESTRUCTION_TYPE
protected:
// Protected non-virtual destructor prevents the use of delete on the interface pointer.
// Must be defined because it will be used as objects of derived types are destructed.
~my_interface() {};
#else
// Public virtual destructor allows the use of delete on the interface pointer.
virtual ~my_interface() = 0;
#endif
private:
// Private copy assignment prevents "*ptr1 = *ptr2".
// This odd syntax CAN be supported, but you probably shouldn't.
// Only needs to be declared because nobody can call it.
my_interface & operator=( const my_interface & );
// Ditto for move assignment.
my_interface & operator=( my_interface && );
};