Как зайти в Даркнет?!
25th January, 01:11
6
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
895
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
948
0
Очень долго работает Update запрос Oracle
27th January, 09:58
914
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
905
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
938
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1724
0
период по дням
25th October, 10:44
3955
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3720
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4613
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4381
0
Помогите пожалуйста решить задачи
24th November, 23:53
6086
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4351
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4396
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Экспорт класса C++ из класса DLL
Большая часть моей разработки C/C++ включает монолитные файлы модулей и абсолютно никаких классов, поэтому обычно, когда мне нужно сделать DLL с доступными функциями, я просто экспортирую их, используя стандартную директиву __declspec(dllexport) . Затем доступ к ним осуществляется либо динамически через LoadLibrary() , либо во время компиляции с помощью заголовка и lib-файла.
Как это сделать, если вы хотите экспортировать весь класс (и все его открытые методы и свойства)?
Можно ли динамически загрузить этот класс во время выполнения, и если да, то как?
Как бы вы сделали это с заголовком и lib для связывания времени компиляции?
Когда вы создаете DLL и модуль, который будет использовать DLL, есть какой-то #define, который можно использовать для различения одного и другого, тогда вы можете сделать что-то вроде этого в вашем заголовочном файле класса:
#if defined( BUILD_DLL )
#define IMPORT_EXPORT __declspec(dllexport)
#else
#define IMPORT_EXPORT __declspec(dllimport)
#endif
class IMPORT_EXPORT MyClass {
...
};
Edit: crashmstr опередил меня!
А как насчет позднего связывания? Как в загрузке
это с LoadLibrary() и
GetProcAddress() ? Я привык быть способным
чтобы загрузить библиотеку во время выполнения и она
было бы здорово, если бы вы могли это сделать
здесь.
А как насчет позднего связывания? Как в загрузке это с LoadLibrary() и GetProcAddress() ? Я привык быть способным чтобы загрузить библиотеку во время выполнения и она было бы здорово, если бы вы могли это сделать здесь.
Таким образом, есть два способа загрузить DLL. Первый - ссылаться на один или несколько символов из DLL (например, имя класса), предоставить соответствующий импорт .LIB и позволить компоновщику все выяснить.
Второй-явная загрузка DLL через LoadLibrary.
Любой из этих подходов прекрасно работает для экспорта функций уровня C. Вы можете либо позволить компоновщику обработать его, либо вызвать GetProcAddress, как вы уже отметили.
Но когда речь заходит об экспортируемых классах, обычно используется только первый подход, т. е. неявная ссылка на DLL. В этом случае DLL загружается во время запуска приложения, и приложение не загружается, если DLL не удается найти.
Если вы хотите связать с классом, определенным в DLL, и хотите, чтобы DLL загружался динамически, через некоторое время после запуска программы, у вас есть два варианта:
Создавайте объекты класса с помощью специальной фабричной функции, которая внутренне должна будет использовать (совсем немного) ассемблер для "hook up" вновь созданных объектов с соответствующими им смещениями. Это должно быть сделано во время выполнения AFTER DLL был загружен, очевидно. Хорошее объяснение этому подходу можно найти здесь .
Используйте задержку загрузки DLL .
Учитывая все обстоятельства... вероятно, лучше просто пойти с неявным связыванием, и в этом случае вы определенно хотите использовать технику препроцессора, показанную выше. Фактически, если вы создадите новый DLL в Visual Studio и выберете параметр "export symbols", эти macros будут созданы для вас.
Удачи...
Я использую некоторые macros, чтобы пометить код для импорта или экспорта
#ifdef ISDLL #define DLL __declspec(dllexport) #endif #ifdef USEDLL #define DLL __declspec(dllimport) #endif
Затем объявите класс в заголовочном файле:
class DLL MyClassToExport { ... }
Затем #define ISDLL в библиотеке и USEDLL перед включением файла заголовка в то место, где вы хотите использовать класс.
Я не знаю, нужно ли вам делать что-то другое для работы с LoadLibrary
Добавление простого рабочего примера для экспорта класса C++ из класса DLL :
Приведенный ниже пример дает вам только краткий обзор того, как dll и exe могут взаимодействовать друг с другом (самоочевидно), но ему нужно добавить больше вещей для изменения в производственный код.
Полный пример примера разделен на две части
A. создание библиотеки .dll (MyDLL.dll)
B. создание приложения, которое использует библиотеку .dll (приложение).
A. .dll файл проекта (MyDLL.dll):
1. dllHeader.h
#ifdef MYDLL_EXPORTS
#define DLLCALL __declspec(dllexport) /* Should be enabled before compiling
.dll project for creating .dll*/
#else
#define DLLCALL __declspec(dllimport) /* Should be enabled in Application side
for using already created .dll*/
#endif
// Interface Class
class ImyMath {
public:
virtual ~ImyMath() {;}
virtual int Add(int a, int b) = 0;
virtual int Subtract(int a, int b) = 0;
};
// Concrete Class
class MyMath: public ImyMath {
public:
MyMath() {}
int Add(int a, int b);
int Subtract(int a, int b);
int a,b;
};
// Factory function that will return the new object instance. (Only function
// should be declared with DLLCALL)
extern "C" /*Important for avoiding Name decoration*/
{
DLLCALL ImyMath* _cdecl CreateMathObject();
};
// Function Pointer Declaration of CreateMathObject() [Entry Point Function]
typedef ImyMath* (*CREATE_MATH) ();
2. dllSrc.cpp
#include "dllHeader.h"
// Create Object
DLLCALL ImyMath* _cdecl CreateMathObject() {
return new MyMath();
}
int MyMath::Add(int a, int b) {
return a+b;
}
int MyMath::Subtract(int a, int b) {
return a-b;
}
Б. Проект приложения, который загружает и связывает уже созданный файл .dll:
#include <iostream>
#include <windows.h>
#include "dllHeader.h"
int main()
{
HINSTANCE hDLL = LoadLibrary(L"MyDLL.dll"); // L".\Debug\MyDLL.dll"
if (hDLL == NULL) {
std::cout << "Failed to load library.\n";
}
else {
CREATE_MATH pEntryFunction = (CREATE_MATH)GetProcAddress(hDLL,"CreateMathObject");
ImyMath* pMath = pEntryFunction();
if (pMath) {
std::cout << "10+10=" << pMath->Add(10, 10) << std::endl;
std::cout << "50-10=" << pMath->Subtract(50, 10) << std::endl;
}
FreeLibrary(hDLL);
}
std::cin.get();
return 0;
}
Недавно я задал себе точно такой же вопрос и кратко изложил свои выводы в блоге . Вы можете найти это полезным.
Он охватывает экспорт классов C++ из A DLL, а также их динамическую загрузку с помощью LoadLibrary и обсуждает некоторые связанные с этим проблемы, такие как управление памятью, искажение имен и соглашения о вызовах.
Если вы хотите поместить vtable в экспортируемый класс, вы можете экспортировать функцию, которая возвращает интерфейс и реализует класс в .dll, а затем поместить его в файл .def. Возможно, вам придется проделать несколько трюков с декларацией, но это не должно быть слишком сложно.
Совсем как COM. :)