DLL и VCL классы
Помогите плз, проблема такая:
создаю DLL а в ней опмсан класс в конструкторе которого создается объект класса TRichEdit.
И тестирующее приложение с формой на которой и должен рисоваться этот RichEdit.
Если в опциях проэктов не сняты галочки с Use dynamic RTL и Build with runtime packages то все ОК! Но как только я их снимаю то линкер выдает немыслимое количество ошибок Unresolved external...
Можно ли это как-то побороть?
Цитата:
Originally posted by Gerret
Доброго времени суток всем!
Помогите плз, проблема такая:
создаю DLL а в ней опмсан класс в конструкторе которого создается объект класса TRichEdit.
И тестирующее приложение с формой на которой и должен рисоваться этот RichEdit.
Если в опциях проэктов не сняты галочки с Use dynamic RTL и Build with runtime packages то все ОК! Но как только я их снимаю то линкер выдает немыслимое количество ошибок Unresolved external...
Можно ли это как-то побороть?
Доброго времени суток всем!
Помогите плз, проблема такая:
создаю DLL а в ней опмсан класс в конструкторе которого создается объект класса TRichEdit.
И тестирующее приложение с формой на которой и должен рисоваться этот RichEdit.
Если в опциях проэктов не сняты галочки с Use dynamic RTL и Build with runtime packages то все ОК! Но как только я их снимаю то линкер выдает немыслимое количество ошибок Unresolved external...
Можно ли это как-то побороть?
Так а с чем... э-э-э ЗА ЧТО боремся? За место? (ну то есть за размер исполняемого модуля?)
Если так, то можно конечно выкинуть Use dynamic RTL, то есть прога скомпилируется, только Runtime библиотеки придётся перетаскивать вместе с программой ручками, а EXE ПОЛУЧИТСЯ СУЧЕСТВЕННО МЕНЬШЕ...
А по поводу Build with тра-та-та ... если Вы знаете, КАКИЕ DLL используются классами вашего проекта, тогда можете повыкидывать ненужные из ProjectOptions -> Packages -> Runtime Packages ... хотя я бы-таки не стал... Отследить ВСЮ иерархию - ПОДВИГ не меньше :)
Хотя tdump показал что для работы моей DLL нужны только vcl60 и rtl60 (~1.5Мб), что меня вполне устраивает. Но всеже вопрос остается...
Можно ли сделать DLL с VCL классами полностью автономной?
Цитата:
Originally posted by Gerret
Боремся мы за автономность модуля...
Хотя tdump показал что для работы моей DLL нужны только vcl60 и rtl60 (~1.5Мб), что меня вполне устраивает. Но всеже вопрос остается...
Можно ли сделать DLL с VCL классами полностью автономной?
Боремся мы за автономность модуля...
Хотя tdump показал что для работы моей DLL нужны только vcl60 и rtl60 (~1.5Мб), что меня вполне устраивает. Но всеже вопрос остается...
Можно ли сделать DLL с VCL классами полностью автономной?
Можно, всё можно, вот побалуйтесь с этим:
Вот тебе для размышления:
Q: Я разделил свою программу на основной Exe и Dll. после этого все стало
глючить.
(Возможные симптомы: программа отображается на линейке 2 раза, появляются
загадочные сообщения типа "Cannot assign TFont to TFont", базы данных спрашивают
пароль 2 раза(один раз для dll и один раз для exe), происходят загадочные Access
Violation )
Вы неправильно скомпоновали вашу dll. Для того чтобы все заработало нужно
скомпилить и Exe и Dll c dynamic rtl и runtime packages. Проверьте так же что
все Packages перечислены в списке RP. Т.е. может быть такая ситуация,
что RP включены, но какой нибудь из них в списке пропущен и используется
статически.
Многим людям лень искать какие dll нужны поэтому они все линкуют
в свои exe и dll. Я категорически рекомендую не делать этого.
Уже если вы разделили прогу на exe dll то используйте все остальное
тоже в dll
Несколько причин последовать этому совету:
Причина 1.
Вы все наверняка работали с чужими dll. Хотя бы вызывая функции Windows.
Вы обратили внимание что все строки в них передаются с помощью char*.
Кроме того когда вы например вызываете функцию GetComputerName,
то она не просто возвращает строку, а заставляет вас передать указатель
на буфер и его длину. Это сделано для того чтобы не было таких вещей
чтобы память выделялась в одном модуле а стиралась в другом. Потому как
это некорректно.
В каждом модуле есть такая штука как memory manager которая
выделяет память, освобождает ее и ведет список свободных и занятых блоков.
Так вот когда у вас exe и dll скомпилены без dynamic rtl то получается что у вас
2 разных memory manager-а. Как вы думаете что будет если вы попросили у одного
из них память, а потом попросили другого его стереть?
Я думаю ничего хорошего не получится. Можно конечно дать совет не делать
так. Но учтите что при передаче AnsiString в качестве параметра память
выделяется в вызывающей функции, а уничтожается в вызваной.
Таким образом получается, что нельзя вызывать из dll функции с
параметром AnsiString.
Как это лечится.
1) Достаточно включить use dynamic rtl и у вас получится один менеджер
памяти в специальной dll borlndmm.dll
2) Можно не включать, а сделать как написано в большом комментарии в начале
новосозданной dll. Там рекомендуют включить в проект MEMMGR.LIB. Но в этом
случае все равно будет использоваться borlndmm.dll.
Легче сделать как сказано в пункте 1.
Причина 2.
Вы знаете о существовании глобальных переменных Application, Session и т.п?
А знаете где они объявлены? Соответственно в Forms и Dbtables. А догадываетесь
что будет если подключить эти unit-ы статистически к exe и dll? Правильно у вас
будет по 2 копии этих переменных, одна в одном модуле другая в другом.
Именно из-за этого появляются такие эффекты как двойное название приложения
в линейке задач (чего вы удивляетесь, у вас на самом деле 2 приложения) и
то что пароли к базе данных(имеется ввиду BDE)спрашиваются 2 раза
(у вас 2 сессии, один раз введите пароль для одной и один для другой.
Кстати соединений с БД у вас тоже будет 2).
Как это лечится.
Ну например в случае раздвоения на линейке задач можно передать в dll
Application->Handle из exe и присвоить его местному Application->Handle.
Для Session это наверное тоже как нибудь лечится. Но самый простой
путь это включить Runtime Packages. Тогда у вас будет только одна
копия переменных в отдельном Bpl
Причина 3.
Вы не задумывались как работают операции динамического определения типа.
dynamic_cast в C++ и is/as в Pascal? Они сравнивают указатель на виртуальную
таблицу. Что будет если один и тот же компонент есть в 2 модулях? Правильно,
у него будет 2 виртуальные таблицы. Что будут делать операторы определения
типа когда определяют тип компонента из другого модуля пытаясь сравнить его
vptr с vptr который должен быть в этом модуле? Правильно, они скажут что это
разные компоненты. Отсюда всякие извраты типа Cannot assign TFont to TFont.
Кроме того например Toolbar2000 будучи пристыкован статически не опознает
свои собственные Toolbar-ы из другого модуля и отказывается их пристыковывать.
Есть информация что IBX в таком состоянии просто глючит. Некоторые компоненты
все таки ведут себя вполне прилично, но вы готовы рисковать работоспособностью
программы чтобы выяснить что тот компонент который вы используете именно такой?
Как лечить. Те классы которые не наследуются от TObject определяется
правильно ( Magic! ). С наследниками TObject сделать ничего нельзя.
Единственный выход это включить Runtime Packages.
Причина 4.
При всем этом суммарный объем кода увеличивается т.к. один и тот же код
содержится и в dll и в exe.
Мораль.
Либо не используйте dll вообще либо делайте их с dynamic rtl и
runtime packages. Обычно эти опции отключают чтобы не искать какие
dll и bpl еще нужны. Но поверьте это ничто по сравнению с тем количеством
проблем которые вас ожидают если вы не воспользуетесь этим советом.