скрыть

скрыть

  Форум  

Delphi FAQ - Часто задаваемые вопросы

| Базы данных | Графика и Игры | Интернет и Сети | Компоненты и Классы | Мультимедиа |
| ОС и Железо | Программа и Интерфейс | Рабочий стол | Синтаксис | Технологии | Файловая система |



Google  
 

О загрузке дочерней формы (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. Но что делать! Или так или пакеты. Вообще говоря в наше время гигабайтов и Wi n2K спорить о сотне килобайт просто скучно.

Для дех, у кого не вышло: я написал и скомпилировал тестовый пример (Delphi 2). Он работает. Все возможности MDI сохраняются, вроде menu-merging, меню Window и Caption в главной форме. Тексты и скомпилированное приложение прилагаются.

Напоследок. Я не претендую на полное исследование темы. Возможно в других версиях Дельфи есть и другие необходимые глобальные обьекты. Возможно, если формы будут использовать печать, то необходимо передать таким-же образом и объект Printer, однако это сам и можете проверить. Стоит посмотреть, чем занимается delphimm.dll, ведь она устраивает общий менеджер памяти, может и еще чего интересное делает. Удачи всем.






Copyright © 2004-2016 "Delphi Sources". Delphi World FAQ




Группа ВКонтакте   Ссылка на Twitter   Группа на Facebook