Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Прорисовка формы в DLL [D7, WinXP]


Страницы:   1 2

vers ©   (2005-07-29 14:27:00) 

DLL динамически подключается к приложению, в DLL переменной Application присваивается Application приложения, создаются 2 формы, в качестве ParentWindow форм указывается хэндл формы приложения. Проблема: не прорисовываются некоторые компоненты форм DLL, например, SpeedButton'ы, при проведении через них мышью. То есть кнопка становится выпуклой при наведении на нее мышью, а в обратное состояние не возвращается, при уходе мышью с нее. В случае со SpeedButton'ами проблему решил путем установки таймера c интервалом в 100 мс, в обработчике для всех кнопок вызываю UpdateTracking, но как быть с компонентами, у которых нет метода UpdateTracking? Вызов Update или посылка сообщения WM_PAINT не помогают.


vers   (2005-08-01 16:32:00) [1]

Я про то, что если использовать LoadPackage, то сообщения об ошибке при отсутствии необходимого пакета никак не избежать. Вместо этого я вызываю SafeLoadLibrary, а затем InitializePackage.
Список требуемых пакетов можно узнать до его загрузки. Для этого нужно загрузить его PE-заголовок и просмотреть таблицу импорта. Файлы с расширением *.bpl в нем - требуемые пакеты. Но для моего проекта это уже чересчур.


Юрий Зотов   (2005-08-01 04:02:00) [2]

> vers ©   (31.07.05 16:43) [34]

> А можно ли узнать, какие пакеты требуются для пакета, до его
> загрузки?

Можно. У разработчика пакета. Сам пакет об этом сообщить не сможет, раз он еще не загружен. А других вариантов, вроде как, и нет.

> ошибочное состояние сигнализируется handle=0, а не сообщением
> об ошибке.

А что же еще надо? Проверяйте хэндл, если надо - возбуждайте ошибку.


vers   (2005-07-31 18:13:00) [3]


> vers ©   (31.07.05 16:43) [34]
> может можно заменить вызов LoadPackage на LoadLibrary?

точнее на

SafeLoadLibrary('c:\package.bpl',SEM_NOOPENFILEERRORBOX+SEM_FAILCRITICALERRORS)


vers   (2005-07-31 16:43:00) [4]

А можно ли узнать, какие пакеты требуются для пакета, до его загрузки? И можно ли как-то перехватить вывод сообщения об ошибке "приложению не удалось запуститься, поскольку такой-то пакет не был найден", возникающее при загрузке пакета, когда один из требуемых им пакетов отсутствует? try .. except не помогает, видимо потому, что сообщение генерирует Windows. Порывшись в исходниках LoadPackage обнаружил, что она вызывает SafeLoadLibrary, которая в свою очередь вызывает LoadLibrary, может можно заменить вызов LoadPackage на LoadLibrary? При этом ошибочное состояние сигнализируется handle=0, а не сообщением об ошибке.


Юрий Зотов   (2005-07-31 14:57:00) [5]

> isasa ©   (31.07.05 12:21) [32]

> В DLL будут существовать Application и Screen, если
> uses ..., Forms,..

Сабж называется "Прорисовка формы в DLL". Чтобы получить форму в DLL, в ней придется написать uses ..., Forms,..

> но будут ли они инициализированы.

Будут.


isasa   (2005-07-31 12:21:00) [6]

>И все же использование интерфейсов представляется более предпочтительным.

Очень правильная мысль.

>Вообще-то, Application и Screen - это глобальные объекты модуля Forms

В DLL будут существовать Application и Screen, если
uses ..., Forms,..
но будут ли они инициализированы. Аналог theApp из Visual Studio, там это более прозрачно.


vers   (2005-07-31 09:41:00) [7]

Я так и делаю. Одно плохо: если на форму, которая в пакете, положить еще один компонент, класс формы поменяется, и придется перекомпилировать не только пакет, но и приложение, вследствие чего исключается возможность "горячей" замены плагинов. А остальные неизменные классы я уже описал в интерфейсных модулях.


Юрий Зотов   (2005-07-31 07:12:00) [8]

И все же использование интерфейсов представляется более предпочтительным.


vers   (2005-07-31 06:54:00) [9]

А пример я нашел здесь:
http://www.delphikingdom.com/mastering/plugins.htm


Юрий Зотов   (2005-07-31 04:58:00) [10]

> vers ©   (31.07.05 04:00) [27]

> Оччень заманчиво было бы использовать классы напрямую, чем
> писать для них функции-обертки.

Очень хороший вариант - использование интерфейсов. Пишете юнит (или несколько юнитов), где декларируете набор нужных интерфейсов. Эти юниты через uses используются как программой, так и пакетом. В пакете сидят классы, реализующие эти интерфейсы. Еще пакет экспортирует функции с заранее известными именами, а эти функции возвращают ссылки на интерфейсы. Программа вызывает такую функцию, получает от нее ссылку на интерфейс - а потом напрямую использует свойства и методы этого интерфейса. Очень просто и очень удобно получается.


vers   (2005-07-31 04:00:00) [11]


> Юрий Зотов ©   (31.07.05 03:20) [26]

> А если вредный пользователь сотрет DLL, то будет точно то
> же самое.


Не совсем. Если пользователь стирает DLL, основная программа запускается, видит, что файла DLL не хватает, и скачивает его снова. DLL тут не необходимая для запуска программы часть. Но это не принципально: сотрет пользователь пакет - сам дурак, пусть снова качает полный дистрибутив.


> при динамической используйте GetProcAddress


А классы из пакета при динамической загрузке можно достать? Оччень заманчиво было бы использовать классы напрямую, чем писать для них функции-обертки.


Юрий Зотов   (2005-07-31 03:20:00) [12]

> vers ©   (31.07.05 03:08) [25]

> А если вредный пользователь сотрет vcl, то программа вылетит
> при загрузке с ошибкой и не скачает уже никогда этот пакет

А если вредный пользователь сотрет DLL, то будет точно то же самое.

> А где экспортируются функции в этих пакетах?
> И как можно импортировать из них классы?

Как обычно, все просто объявляется в секциях interface модулей, которые входят в пакет. При статической загрузке пакета Ваша программа имеет полное право ссылаться на его модули в своих uses, при динамической используйте GetProcAddress.

> как самому написать пакет.

File - New - Package. Остальное как обычно - создаем в пакете юниты, в них пишем все, что нужно.


vers   (2005-07-31 03:08:00) [13]

А если вредный пользователь сотрет vcl, то программа вылетит при загрузке с ошибкой и не скачает уже никогда этот пакет...
А где экспортируются функции в этих пакетах? В основном файле пакета, как в dll, нельзя. И как можно импортировать из них классы? Видимо через GetClass? И вообще, где можно почитать о практической реализации пакетов? А то пока что все, что находил - это "что такое пакеты и для чего они нужны", а не "как самому написать пакет".


Юрий Зотов   (2005-07-31 02:29:00) [14]

> vers ©   (31.07.05 02:04) [23]

Зачем стирать из списка пакеты, которые программе нужны постоянно, без которых она просто не сможет работать? Например, пакеты VCL.

Не нужно их стирать, нужно просто поставить галочку. Компилятор сам все впишет и получится статическая загрузка этих пакетов - это как статическая линковка DLL. Что и нормально, раз эти пакеты все равно нужны всегда.

А динамически есть смысл загружать те пакеты, которые программе нужны не все время (загрузил - поработал - выгрузил). Либо пакеты с плагинами (какой надо - такой и загрузил). Функции таких пакетов вызываются по обычной схеме (GetProcAddress).


vers   (2005-07-31 02:04:00) [15]

Вот как раз об этом-то и хотел спросить: какая последовательность действий при динамической загрузке пакетов?
Поставить галочку "build with runtime packages", стереть оттуда все пакеты из списка и уже в программе перед Application.Initialize вписать LoadPackage?


Юрий Зотов   (2005-07-31 01:08:00) [16]

> vers ©   (31.07.05 00:40) [20]

Кроме того, пакет можно загрузить и самому (LoadPackage) - тогда можно явно указать и путь к нему.


Юрий Зотов   (2005-07-31 01:04:00) [17]

> vers ©   (31.07.05 00:40) [20]

Загружаемые пакеты ищутся по обычным правилам. Последовательность поиска есть в описании LoadLibrary.


vers   (2005-07-31 00:40:00) [18]

Подмена Application, Application.Handle и Screen не решали проблему. Она решилась только после того, как я поставил галочку "build with runtime packages" в приложении и в dll. Специально перенес программу на другой компьютер, на котором не установлена Delphi, для проверки (при этом пришлось еще захватить rtl и vcl пакеты).
При этом возникает другая проблема: разрабатываемые dll - plugin'ы для программы, подключаемые пользователем по мере надобности, возможно даже во время работы приложения. При этом (как раньше было) один plugin - одна dll. Сами файлы dll передаются по сети, используется свой протокол передачи. Перед подключением проверяется есть ли уже эта dll у пользователя и если есть, то импортируются несколько функций для определения имени и версии plugin'а, если они не совпадают, dll обновляется, иначе используется локально сохраненная dll. Но разные dll могут использовать одни и те же пакеты, следовательно нужно будет к каждому plugin'у приписать, какие пакеты он использует и проверять есть ли уже эти пакеты у пользователя. Но это уже дело техники.
Возник вопрос: а можно ли указать в программе путь, откуда будет загружаться пакет, или этот путь обязательно прописывать в переменную окружения?


Defunct   (2005-07-30 22:56:00) [19]

Юрий Зотов ©   (30.07.05 22:47) [17]

> Естественно. Он просто начинает работать с другим Self. Соответственно, и с другим Handle.

хм.. т.е. методы остаются теже, что имеются в TApplication DLL подменяются только поля и свойства. Верная несовместимость на будущее ;>


Юрий Зотов   (2005-07-30 22:52:00) [20]

> Defunct ©   (30.07.05 22:45) [16]

> я губоко сомневаюсь, что Вы хотя бы раз применили в своих
> программах подобный код:

Точно, не применял. И замену хэндла тоже не применял. Я вообще не применяю потенциально опасных вещей, чтобы потом не иметь с ними проблем. Тем не менее, в одном из проектов формы в DLL использовались ОЧЕНЬ активно (можно даже сказать, что на этом была построена идеология проекта). Просто все компилировалось с run-time пакетами - а потому все работало и без всяких трюков.


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо