Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > dll-явное связывание + классы


Автор: Nastya 23.3.2005, 09:36
Если в dll-модуле у меня описан некий класс.
Как к нему добраться при явном свзывании (т.е. создать объект этого класса) и как для этого его в dll надо правльно объявлять.

Автор: bel_nikita 23.3.2005, 09:44
Через __declspec(dllexport) и __declspec(dllimport)
В dll экспорт, в программе импорт

*.Н
Код

class __declspec(dllimport) CMeasData
{
...
public:
...
};



Только __declspec(dllimport) заменить макросом, чтоб в ДЛЛ это был экспорт, а в программе импорт

Автор: Nastya 23.3.2005, 10:37
Спасибо, но тут еще тиакая проблема, если функцию я получаю через
GetProcAdress, как мне то же самое сделать для имени класса?
Как таким же образом создать объект?

Автор: Fire-Plug 23.3.2005, 11:03
Цитата
функцию я получаю через
GetProcAdress, как мне то же самое сделать для имени класса


Фигушки.
Я бы сделал экспортируемую ф-цию, возвращающую указатель на объект класса, к-рый создается к-либо кодом, реализованным в DLL. Объявил бы интерфейс класса (без реализации) в его заголовочном файле.
Т.е. что-то вроде:
Код

#include "myClass.h" // здесь только интерфейс класса, избегайте реализации

...
myClass * (__cdecl *Proc)(); // например такой указатель на ф-цию

HANDLE hDLL= LoadLibrary("SomeLib"); // грузим библиотеку

Proc myProc= (Proc)::GetProcAddress(hDLL, "SomeName");

myClass *myObj= myProc();

if(myObj)
   myObj->Foo(); // весь public интерфейс к вашим услугам
...


ЗЫ: Отсюда до идеи COM уже совсем недалеко...

Автор: Fire-Plug 23.3.2005, 11:14
Хотя, ваще-то попадалась мне какая-то статейка, где рассматривалось как можно с помощью GetProcAddress получить адрес конструктора класса... Вот не помню, где это я ее читал.
Но это выёживание. Будьте проще и к вам потянутся люди.

Автор: Nastya 23.3.2005, 16:23
Спасибо.
А если без подключения .h файла, то как я поняла, без com никуда?

Автор: Fire-Plug 24.3.2005, 04:29
Цитата
А если без подключения .h файла, то как я поняла, без com никуда

Без объявления типа переменной(объект - это тоже переменная, тип к-рой определен пользователем) вообще никуда! Переменную неопределенного типа ни создать нельзя, ни ссылку/указатель получить. Исключение - указатель на тип void *. Но указатель void * - это не то, что нам нужно.

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

Для COM-классов можно указать, чтобы компилер сгенерил заголовочный файл, содержащий объявление требуемого класса, используя его(класса) type library. Например, директива
Код

#import <msxml4.dll> raw_interfaces_only 

требует используя содержимое библиотеки msxml4.dll сгенерить заголовочный файл с объявлениями соотв. COM-классов.

Автор: np9mi7 10.4.2005, 10:41
Nastya, а почему именно явное связывание? Есть ведь такая вещь как отложенная загрузка (правда если на BCB то там какой фишки нет smile , придеться ручками писать, ну это тоже не проблема -> http://www.rsdn.ru/article/cpp/delayload.xml)...
Код

#include "myClass.h" // здесь только интерфейс класса, избегайте реализации
...
myClass * (__cdecl *Proc)(); // например такой указатель на ф-цию
HANDLE hDLL= LoadLibrary("SomeLib"); // грузим библиотеку
Proc myProc= (Proc)::GetProcAddress(hDLL, "SomeName");
myClass *myObj= myProc();
if(myObj)
   myObj->Foo(); // весь public интерфейс к вашим услугам
...

Кстати интересно, как при таком подходе деструктор объекта вызывается...???

Статья про которую говорил Fire-Plug находиться http://rsdn.ru/article/baseserv/dlluse.xml

Автор: Fire-Plug 12.4.2005, 08:00
Цитата(np9mi7 @ 10.4.2005, 10:41)
Кстати интересно, как при таком подходе деструктор объекта вызывается...???

Тут уместно применить принцип: "Я тебя породил, я тебя и убью". Т.е., если объект создается в коде DLL, то и уничтожаться он должен там же.
Вариантов реализации можно предложить несколько.
1) Динамический объект помещается, например, в авто-указатель, к-рый жив покуда DLL не выгружена.
2) Можно удалять объект по требованию. Тогда нужно будет добавить в DLL экспортируемую ф-цию для уничтожения объекта, передавая в кач-ве параметра его адрес. В DLL хранить объект в нек-ром контейнере, где он разыскивается с целю приведения приговора в исполнение.
3) Можно 2) реализовать путем заимствования идеи COM в плане подсчета ссылок. Тогда лучше возвращать указатель не на сам объект, а объект типа COM-указателя для целевого класса, для к-рого нужно будет добавить методы аналогичные AddREf() и Release(). А в DLL реализовать механизм для хранения и удаления объекта, если к-во его ссылок = 0.

Автор: np9mi7 12.4.2005, 08:05
Цитата
1) Динамический объект помещается, например, в авто-указатель, к-рый жив покуда DLL не выгружена.
, не катит, адреса деструктора у тебя нет;

Цитата
2) Можно удалять объект по требованию. Тогда нужно будет добавить в DLL экспортируемую ф-цию для уничтожения объекта, передавая в кач-ве параметра его адрес. В DLL хранить объект в нек-ром контейнере, где он разыскивается с целю приведения приговора в исполнение.
, пахнет чем то не хорошим, тебе так ни кажеться?

Цитата
3) Можно 2) реализовать путем заимствования идеи COM в плане подсчета ссылок. Тогда лучше возвращать указатель не на сам объект, а объект типа COM-указателя для целевого класса, для к-рого нужно будет добавить методы аналогичные AddREf() и Release(). А в DLL реализовать механизм для хранения и удаления объекта, если к-во его ссылок = 0.
, может сразу com объект и все?

Мне кажеться тут лучше всего отложенная загрузка.

Автор: Guest 12.4.2005, 23:11
Цитата(np9mi7 @ 12.4.2005, 08:05)
не катит, адреса деструктора у тебя нет;

Это-то в коде, где реализован конкретный класс, т.е. в коде DLL? Не смешите меня.
Цитата(np9mi7 @ 12.4.2005, 08:05)
Цитата
2) Можно удалять объект по требованию. Тогда нужно будет добавить в DLL экспортируемую ф-цию для уничтожения объекта, передавая в кач-ве параметра его адрес. В DLL хранить объект в нек-ром контейнере, где он разыскивается с целю приведения приговора в исполнение.

, пахнет чем то не хорошим, тебе так ни кажеться?

Ничем не хуже, чем delete myObj. "не хорошим" - явл. только ситуация, в к-рой следует соблюдать договоренности, а именно, удалять обьект с помощью спец. экспортируемой ф-ции. Но и указатель на обьект был получен также с помощью другой спец. ф-ции, а не через new

Цитата
, может сразу com объект и все?

Конечно можно, если охота для частной задачи писать реализацию обязательной части интерфейса и возиться с его регистрацией.

Автор: np9mi7 13.4.2005, 10:26
Цитата
1) Динамический объект помещается, например, в авто-указатель, к-рый жив покуда DLL не выгружена

Цитата
Это-то в коде, где реализован конкретный класс, т.е. в коде DLL? Не смешите меня.
, задам один вопрос: где smatr pointer?

Автор: Fire-Plug 13.4.2005, 16:43
Цитата(np9mi7 @ 13.4.2005, 10:26)
задам один вопрос: где smatr pointer?

В коде DLL, конечно.

Автор: np9mi7 13.4.2005, 22:58
ну, тогда твоему ptr нужен адрес деструктора объекта... Нет?

Автор: Fantasist 13.4.2005, 23:09
Вообще, экспортируемые классы суть набор экспортируемых ими методов куда входят и конструкторы и деструкторы. Кажется вполне возможным написать обертку, которая будет грузить библиотеку с помощью LoadLibrary и вызывать методы через GetProcAddress (включая конструкторы и деструкторы).


Автор: Fire-Plug 14.4.2005, 04:43
Цитата(Fantasist @ 13.4.2005, 23:09)
Кажется вполне возможным написать обертку, которая будет грузить библиотеку с помощью LoadLibrary и вызывать методы через GetProcAddress (включая конструкторы и деструкторы).

В статье по вышеуказ. ссылке http://rsdn.ru/article/baseserv/dlluse.xml как раз и рассматривается конкрентная техника как это сделать. Хотя надо сразу сказать, что это достаточно неудобно.
Потому и шла речь о том, чтобы в DLL реализовать класс(ы) и способ его создания (фабрику объектов или что угодно) и по запросу только получать указатель на объект нужного типа. В DLL также нужно реализовать мехнизм удаления объекта по запросу или просто при ее выгрузке.

Автор: chipset 15.4.2005, 22:20
Цитата(Fantasist @ 13.4.2005, 13:09)
Кажется вполне возможным написать обертку, которая будет грузить библиотеку с помощью LoadLibrary и вызывать методы через GetProcAddress (включая конструкторы и деструкторы).

А в чём преимущество такого подхода? Почему бы просто не получать указатель на фабрику классов?

Кстати, имхо, лучшим вариантом было бы:
Цитата(Fire @ 11.4.2005, 22:00)
3) Можно 2) реализовать путем заимствования идеи COM в плане подсчета ссылок. Тогда лучше возвращать указатель не на сам объект, а объект типа COM-указателя для целевого класса, для к-рого нужно будет добавить методы аналогичные AddREf() и Release(). А в DLL реализовать механизм для хранения и удаления объекта, если к-во его ссылок = 0.


Цитата(Guest @ 12.4.2005, 13:11)
Ничем не хуже, чем delete myObj.

А если обьектом пользуются сразу два процесса?
Добавлено @ 22:21
Цитата(Fire @ 13.4.2005, 18:43)
В DLL также нужно реализовать мехнизм удаления объекта по запросу

А если два процесса на один обьект?

Автор: Fantasist 15.4.2005, 22:26
Цитата(Guest @ 12.4.2005, 20:11)
Конечно можно, если охота для частной задачи писать реализацию обязательной части интерфейса и возиться с его регистрацией.


Из обязательной части там только IUnknown реализовать нужно, да и его реализацию можно сделать ATL'ем. Регестрировать тоже не обязательно, можно создавать объект напрямую вызывая DllGetClassObject.


Хотя я бы возвращал указатель на экземляр из dll. А в самом классе создал бы метод Destroy, который бы удалял сам себя, и перегрузил бы delete для него, чтобы он происходил через вызов Destroy(). В этом случае даже если delete будет вызван в основном модуле для указателя полученного из dll, объект удалится в dll.


Добавлено @ 22:29
Цитата(chipset @ 15.4.2005, 19:20)
А если обьектом пользуются сразу два процесса?
Добавлено @ 19:21
Цитата (Fire-Plug @ 13.4.2005, 18:43)
В DLL также нужно реализовать мехнизм удаления объекта по запросу

А если два процесса на один обьект?


Вопросы синхронизации к данной теме не относятся. К тому же, один объект не может быть использован в разных процессах ибо у них разное адресное пространство (ну, конечно, это возможно, но только после дополнительных телодвижений).
Добавлено @ 22:31
Цитата(chipset @ 15.4.2005, 19:20)
А в чём преимущество такого подхода? Почему бы просто не получать указатель на фабрику классов?


Преимущество в том, что не надо думать, как правильно создать и удалить объект.

Автор: chipset 15.4.2005, 22:32
Цитата(Fantasist @ 15.4.2005, 12:26)
Из обязательной части там только IUnknown реализовать нужно, да и его реализацию можно сделать ATL'ем.

Ещё ATL прикручивать... smile

Цитата(Fantasist @ 15.4.2005, 12:26)
Хотя я бы возвращал указатель на экземляр из dll.

Тогда это и есть мини-фабрика обьектов, как я её понимаю.. smile

Автор: Fire-Plug 18.4.2005, 07:57
Цитата(chipset @ 15.4.2005, 22:20)
А если обьектом пользуются сразу два процесса?

У каждого процесса - своя память, в т.ч. динамическая. Ф-цию DLL может вызывать фуева хуча процесссов.
Цитата(chipset @ 15.4.2005, 22:20)
А если два процесса на один обьект?

Сейчас поищу ссылку на статейку, к-рая рассказывает, как память DLL отображается на адресное пространство процесса. Все переменные, что экспортируются из/создаются кодом DLL - уникальны в адресном пространстве данного процесса и процесами не разделяются (not shared).
Иначе, спрашивается, нахрена нужна была бы куча механизмов IPC(Inter-Process Communication), ежели бы переменные из разных процессов так запросто можно было бы share-ть. А вот исполняемый код - разделяется всеми процессами, к-рые юзают данную DLL.
Ну, че искать статейку? Ваще ее в MSDN можно было года 3-4 назад легко найти. Только вот назывется больно обидно "DLL for beginners".

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)