| | | | |
Алексей Еремеев дата публикации 07-08-2000 00:00 О загрузке дочерней формы (MDIChild) из DLL.
Данную статью меня заставило написать огромное количество вопросов в Круглом Столе
(а теперь еще и в Подводных Камнях) насчет размещения дочерней формы в библиотеке DLL. Честно
говоря, у меня никогда не возникало такой необходимости и я обходился простым приложением. Но
масса вопросов без ответа посадило меня за кнопки вечерком. Говорят, что те ответы, которые,
тем не менее, присутствуют, не работающие. И проверять мне их совсем не хотелось. Я решил
начать решать проблему с нуля.
Поначалу я решил досконально разобраться в работе TForm и TApplication дабы точно
представлять себе, как эти оболочки взаимодействуют с Windows, но потом понял, что ковыряться
в сотнях строк исходников мне совсем неохота. Я просто посмотрел и увидел, что кроме,
собственно handl-ов эти компоненты оперируют со своими всяческими внутренними служебными
списками (обычно TList) и передачей хэндла тут не обойдешься. Для работы форм необходимы оба
глобальных (для программы) объекта: и TApplication и TScreen. Подгружаемая DLL, если
использует разного рода формы и контролы их тоже создает. Но они другие! В смысле другие
instances, которые и знать не знают о таких-же объектах в главном приложении. Но они есть и
убивать их тоже не хочется (мало-ли чего случится, если убить объект TApplication, даже в
DLL). Поэтому решение пришло следующее. Создаем в нашей DLL две служебные функции, функцию
вызова нашей дочерней формы и две переменные (пишу StdCall потому что всегда DLL-ки так
оформляю, это удобно):
var
DLLApp: TApplication;
DLLScr: TScreen;
procedure InitPlugin(App, Scr: integer); StdCall;
begin
DLLScr := Screen;
Screen := TScreen(Scr);
DLLApp := Application;
Application := TApplication(App);
end;
procedure DonePlugin; StdCall;
begin
Screen := DLLScr;
Application := DLLApp;
end;
function CreateMDI: integer; StdCall;
begin
Result := integer(TfrmMyChildForm.Create(Application));
end;
exports
InitPlugin,
DonePlugin,
CreateMDI;
|
|
Итак, в начале программы я открываю библиотеку (LoadLibrary), получаю функции
(GetProcAddress) и инициализируюплагин (InitPlugin(integer(Application), integer(Screen))),
передавая ему ссылки на объекты Application и Screen и они сохраняются в переменных внутри
DLL. По окончании работы я его деинициализирую (DonePlugin), восстанавливая для dll-ки его
объекты (для корректной деинициализации этих самых внутренних TApplication и TScreen), потом
выгружаю библотеку (FreeLibrary). Функция создания дочернего окна возвращает объект формы (а
по сути указатель) и с ним можно работать, либо используя переменную - родителя (TForm
например) или абстрактный класс с которого наследуется форма в DLL (MyForm :=
TForm(CreateMDI)).
Неприятности такого похода состоят в том, что разные инструменты разработки (и даже
разные версии одной и той же среды) могут быть (скорее всего, но я не проверял) несовместимы.
Т.е. DLL с формой, изготовленной в одной версии Дельфи может не работать с приложением,
скомпилированным в другой. Ведь внутренние структуры объектов и таблицы методов могут не
совпадать. Но это не слишком дорого. Есть еще проблема дублирования кода VCL. Но что делать!
Или так или пакеты. Вообще говоря в наше время гигабайтов и Win2K спорить о сотне килобайт
просто скучно.
Для дех, у кого не вышло: я написал и скомпилировал тестовый пример (Delphi 2). Он
работает. Все возможности MDI сохраняются, вроде menu-merging, меню Window и Caption в
главной форме. Тексты и скомпилированное приложение прилагаются.
Напоследок. Я не претендую на полное исследование темы. Возможно в других версиях
Дельфи есть и другие необходимые глобальные обьекты. Возможно, если формы будут использовать
печать, то необходимо передать таким-же образом и объект Printer, однако это сами можете
проверить. Стоит посмотреть, чем занимается delphimm.dll, ведь она устраивает общий менеджер
памяти, может и еще чего интересное делает. Удачи всем.
Скачать проект Test_MD.zip (198 K)
[TList] [TForm] [TApplication] [TScreen] [Размещение форм в DLL] [MDI-интерфейс]
Обсуждение материала [ 15-01-2009 04:35 ] 33 сообщения |
|