Добрый день!
Есть очень простой вопрос (для Вас) и сложный для меня!
Приложение MDI и "Дети" находятся в DLL
Все работает, однако в созданных "Детях" на получается использовать
if x.Components[i] is TButton then // x - форма из DLL (Child естественно)
showmessage((x.Components[i] as TButton).Caption); (Шесто чудо)
Как возможно обойти данное ограничение?
Зарание спасибо!
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
30-01-2009 05:35
При правильной организации кода утечек не будет вообще.
Вообще, управлять компонентами в dll из ехе - не самая лучшая идея. Объясню почему. Заложившись на эту логику и отладив все dll вы можете забыть о проблеме. Потом вы перейдете на другую версию делфи и перекомпилируете только ехе - и тогда столкнетесь с большими проблемами, ибо смещения до методов в dll будут совсем другие и вы будете долго гадать откуда выползают AV на рабочем коде
Лучше всего будет управлять компонентами в самой dll, а ехе будет отправлять команды заданного вида, вызывая экспортируемые из dll функции. А еще лучше использовать интерфейсы и технологию COM вообще.
Sega-Zero Большое спасибо за совет, вполне приемлемое решение - загнать функцию в ДЛЛ однако не будет ли большой утечки памяти ? проект планируется около 100 доп модулей с большим кол-вом компонентов на форме
Если не хотите таскать за собой пакеты, то выводите всю логику работы с компонентами модулей в сами модули. Делайте экспортиуемую функцию, которая, скажем, будет принимать символическое имя класса компонента и ссылку на компонент и возвращать True если класс является оным.
А в dll эта функция будет создавать классовую ссылку с помощью FindClass и делать проверку на своей копии Classes
большое спасибо за предложенные варианты решенияе варианты решения, однако я использую D 2007 и при компиляции обоих пакетов alt+p,u рантаймы не работаю а если по отдельности то все ок, но как сделать так чтоб не тоскать за проэктом пакеты
ой... Не учел что это могут быть потомки кнопок, и проверка имени ничего не даст....
Где то был поиск класса по имени - в интересах сериализации, названия ф-ции и модуль - не помню, и InheritsFrom...
В любом случае - идея понятна. Кнопки надо искать там, где они ищуться, складывать в список объектов и скармливать ф-ции обработки из места, где они не ищуться ))) -
По моему - должно сработать. А?
Класс TButton В основной программе и класс TButton в каждой dll'ке - это каждый раз новый класс
- Не знал я этого раньше, спасибо, буду иметь в виду.
но... хоть классы и разные - имя то у них одно (ClassName)! = TButton - можно поменять
x.Components[i] is TButton
на
x.Components[i].ClassName()='TButton'
Класс TButton В основной программе и класс TButton в каждой dll'ке - это каждый раз новый класс, который друг другу не равен никогда. В каждую dll'ку прибавляется код, отвечающий за класс TButton (другие классы - тоже, но сейчас не об этом). В результате получается, что у вас просто плодятся классы. И естественно, что один другому не соответствует. Верней не равен в сравнениях по оператору is, хотя с точки зрения пользователя выглядит, как брат близнец. Но в том-то и дело, что брат, а не один и тот же класс...
Про run-time пакеты вам правильно сказали. Может только не очень подробно. Посмотрите, хоть по Королевству, хоть шире - какие проблемы возникают при использовании классов из dll'ек - описывалось не раз. И способы этого избежать или обойти тоже не раз обсуждались.
Если использовать run-time пакеты, то у вас всегда будет только ОДИН класс TButton на все формы в программе. Это первый вариант - "Избежать".
Если вам нужно всё же dll'к, то можно второй вариант - "Обойти". В этом случае всю работа с классами (формами) из dll'ек надо делать в самих dll'ках.
На мой взгляд проще всё же первый вариант. Особо если вспомнить, что пакеты - это те же dll'ки, и загружать их тоже можно, когда возникает в том необходимость...
TButton в dll и TButton в exe - разные классы с точки зрения компилятора. использование runtime пакетов позволяет разрешить эту проблему, потому что использоваться будет одна и та же классовая ссылка.
Раздельная компиляция - это и зло и благо. Попробуйте объявить еще один класс TButton в другом модуле, отличном от StdCtrls и присоедините в uses. и поэкспериментируйте;)
procedure TMainForm.StartClick(Sender: TObject);
var
DllHandle: THandle;
ProcAddr: FarProc;
ProvaChild: T_ProvaChild;
begin
DllHandle := LoadLibrary('ProjectDll');
ProcAddr := GetProcAddress(DllHandle, 'ProvaChild');
if ProcAddr <> nil then
begin
ProvaChild := ProcAddr;
ProvaChild(Application,Self,screen);
end;
end;
procedure TMainForm.werwerw1Click(Sender: TObject);
var
I: Integer;
begin
for I := 0 to application.MainForm.MDIChildren[0].ComponentCount - 1 do
if application.MainForm.MDIChildren[0].Components[i] is TButton then
showmessage((application.MainForm.MDIChildren[0].Components[i] as TButton).caption);
end;
end.
dll
library ProjectDll;
{ Important note about DLL memory management: ShareMem must be the
first unit in your library's USES clause AND your project's (select
Project-View Source) USES clause if your DLL exports any procedures or
functions that pass strings as parameters or function results. This
applies to all strings passed to and from your DLL--even those that
are nested in records and classes. ShareMem is the interface unit to
the BORLNDMM.DLL shared memory manager, which must be deployed along
with your DLL. To avoid using BORLNDMM.DLL, pass string information
using PChar or ShortString parameters. }
procedure ProvaChild(ParentApplication: TApplication; ParentForm: TForm; SCR :TScreen); export; stdcall;
var
Form1: TForm1;
DllProc: Pointer; { Called whenever DLL entry point is called }
procedure DLLUnloadProc(Reason: Integer); register;
begin
if Reason = DLL_PROCESS_DETACH then
begin
Application:=DllApplication;
screen := DLLSCreen;
end;
end;
exports
ProvaChild;
begin
DllApplication:=Application;
DLLscreen := SCreen;
DLLProc := @DLLUnloadProc;
end.
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.