Могу ли я гарантировать выполнение пользовательского кода завершения ПОСЛЕ уничтожения формы?

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

Вот упрощенный пример файла.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Форм.

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

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

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

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

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

Спасибо

2 ответа

Решение

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

Единственная форма, которая должна принадлежать 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. Поскольку это явно исполняемый файл, система все равно их выгружает. Зачем тебе это нужно?

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

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

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