2013-09-10 2 views
4

У меня многопоточное приложение со многими формами, но мне нужно создать экземпляр некоторых классов и вызвать некоторые элементы инициализации перед созданием форм. Конечно, мне нужно выполнить соответствующий код завершения.Могу ли я гарантировать выполнение пользовательского кода для окончательной доработки ПОСЛЕ уничтожения формы?

Вот упрощенный пример .dpr файла:

begin // .dpr project file 
    LoadDlls; 
    try 
    Config := TConfig.Create; 
    try 
     Application.Initialize; 
     Application.Title := 'Foo'; 
     Application.CreateForm(TMainForm, MainForm); 
     Application.CreateForm(TOtherForm, OtherForm); 
     //...other forms... 
     Application.Run; 
    finally 
     Config.Free; 
    end; 
    finally 
    UnloadDlls; 
    end; 
end; 

Проблема здесь состоит в том, что код внутри finally блоков получить выполняется перед OnDestroy/destructor с моих форм. Выдается ясно смотрит на finalization секции Form блока:

finalization 
    if Application <> nil then DoneApplication; 

И DoneApplication звонки Application.DestroyComponents, которые эффективно высвобождает все Application «S принадлежат формы.

Итак, формы, созданные с помощью Application.CreateForm, будут уничтожены после любого кода внутри основного блока begin..end.

То, что я хочу, что после того, как Application.Run все формы будут уничтожены, так что их OnDestroy обработчики событий могут видеть Config объект и внешние функции, определенные в моих библиотек DLL. То же самое, если возникает исключение. Но я также хочу иметь обработку исключений стандартного приложения, если Config.Free или UnlodDlls рейз (приложение должно все еще существовать).

Обратите внимание, что:

  • Я предпочел бы не использовать finalization блок (? Бы это было возможно в .dpr), чтобы сохранить код понятнее и Отладка;
  • На данный момент я предпочитаю не менять слишком много кода (например, динамически создавать формы)

Я думаю, что самое простое решение явно вызвать Application.DestroyComponents после Application.Run. Как вы думаете, есть ли какие-то недостатки? Есть ли более элегантное решение?

Спасибо

ответ

6

чистый способ добиться того, что вы хотите, чтобы контролировать разрушение форм.

Единственная форма, которая должна принадлежать Application, является вашей основной формой. Это должно быть так, потому что первая форма, созданная вызовом Application.CreateForm, обозначена как основная форма. Итак, мой совет заключается в том, что вы должны сделать один звонок и один звонок только до Application.CreateForm, чтобы создать основную форму. Для всех ваших других форм создайте их, вызвав их конструкторы. Пусть остальные формы принадлежат основной форме. Когда пришло время закрыть, уничтожьте основную форму и пусть она возьмет с собой все принадлежащие ему формы.

Вы можете написать свой код .dpr так:

begin 
    LoadDlls; 
    try 
    Config := TConfig.Create; 
    try 
     Application.Initialize; 
     Application.Title := 'Foo'; 
     Application.CreateForm(TMainForm, MainForm); 
     try 
     OtherForm := TOtherForm.Create(MainForm); 
     YetAnotherForm := TYetAnotherForm.Create(MainForm); 
     Application.Run; 
     finally 
     FreeAndNil(MainForm); 
     // will destroy the other forms since they are owned by the main form 
     end; 
    finally 
     Config.Free; 
    end; 
    finally 
    UnloadDlls; 
    end; 
end; 

Еще один момент, чтобы сделать то, что, возможно, вам не нужно выгружать библиотеки DLL. Так как это явно исполняемый файл, система все равно выгрузит их. Зачем вам это нужно?

+0

Спасибо, я вижу вашу точку зрения. Я хотел бы сделать это изменение как «шаг 2», потому что ему нужно изменить мнение всех членов команды ;-) На данный момент я должен гарантировать, что если кто-то добавит форму «стандартный способ», это будет правильно обработано. Почему не 'Application.DestroyComponents'? Что касается DLL, вы правы, но в «LoadDlls» есть другие структуры, которые я хочу правильно освободить, чтобы уловить некоторые утечки памяти в главном коде. – yankee

+0

Система восстановит память при завершении процесса. Вы не можете течь в этот момент. Вероятно, вы достаточно безопасны для вызова 'DestroyComponents' в этот момент. Я бы сделал это правильно, если бы был вами, но тогда я не знаю, какое влияние у вас есть в вашей команде! –

+0

вы меня убедили ;-) – yankee

4

Другим вариантом является то, что ваши формы неявно ссылаются на глобальную конфигурацию.
Сделать явную зависимость явной, указав каждую форму своей ссылкой на интерфейс IConfig.
Когда RefCount экземпляра, на который ссылается, падает до нуля (после того, как все формы, которые его используют, были уничтожены), он может саморазрушиться.

Задание зависимости формы (и другого объекта) от конфигурации явно предоставит другие преимущества.

  • Испытание будет намного проще.
  • Формы, которые не нуждаются в IConfig, не будут иметь зависимости, и это будет неважно.
  • Таким образом, эти формы будут легко (и, очевидно,) перемещаться в другие приложения с несколько иной структурой.
+0

Я тоже подойду к этому варианту, это очень интересно. – yankee

Смежные вопросы