Создание MainForm в TThread

У меня есть приложение Delphi 2010, которое экспортирует DLL и имеет заголовок library. Он создает свою MainForm в TThread, например:

var
  ActiveThread: TActive;
  
type
  TActive= class(TThread)
  protected
    procedure Execute; override;
  end;

procedure TActive.Execute;
begin
      Application.Initialize;
      Application.CreateForm(MyForm, form);
      Application.Run;
end;

begin
  ActiveThread := TActive.Create(true);
  ActiveThread.FreeOnTerminate := true;
  ActiveThread.Resume;
end.

Всякий раз, когда я загружаю эту DLL через функцию LoadLibrary, приложение работает нормально. (Очевидно, он использует поток, который я передал LoadLibrary, в качестве основного потока и не имеет проблем)

Но если я попытаюсь экспортировать эту DLL в настоящий EXE-файл, изменив сгенерированный вывод в «Параметры» -> «Приложение. и изменить заголовок с library на program, а затем построить его и выполнить выходной EXE вместо загрузки DLL через Windows API, приложение зависает при попытке создать форму, особенно в Application.CreateForm(MyForm, form);. Если я удаляю инициализацию приложения из потока и помещаю ее в основную процедуру, она работает нормально.

Форма, которую я пытаюсь отобразить, - это просто пустая форма. Любые идеи?


person Gege GMF    schedule 17.02.2021    source источник


Ответы (1)


При компиляции этого кода как program во время выполнения он попытается завершить себя при достижении end., даже до того, как рабочий поток сможет запуститься, что может (и вероятно) произойти после уничтожения объекта Application. Вам придется подождать, пока рабочий поток завершит свою работу, прежде чем разрешить выход из программы, например:

program MyProgram;

uses
  Classes, Forms, MyForm;

type
  TActive = class(TThread)
  protected
    procedure Execute; override;
  end;

procedure TActive.Execute;
begin
  Application.Initialize;
  Application.CreateForm(TMyForm, MyForm);
  Application.Run;
end;

var
  ActiveThread: TActive;
begin
  ActiveThread := TActive.Create(False);
  ActiveThread.WaitFor;
  ActiveThread.Free;
end.

Но на самом деле нет веской причины когда-либо использовать такой рабочий поток, это сводит на нет всю цель использования потока, поэтому вы можете просто избавиться от него вообще:

program MyProgram;

uses
  Forms, MyForm;

begin
  Application.Initialize;
  Application.CreateForm(TMyForm, MyForm);
  Application.Run;
end.

С другой стороны, если вы пытаетесь использовать общий код между проектами program и library, вы можете обернуть код Application внутри функции и позволить проекту решать, какой поток вызывает функцию, например:

unit MyApp;

interface

procedure RunMyApp;

implementation

uses
  Forms, MyForm;

procedure RunMyApp;
begin
  Application.Initialize;
  Application.CreateForm(TMyForm, MyForm);
  Application.Run;
end;

end.
program MyProgram;

uses
  MyApp;

begin
  RunMyApp;
end.
library MyLibrary

uses
  Classes, MyApp;
  
type
  TActive = class(TThread)
  protected
    procedure Execute; override;
  end;

procedure TActive.Execute;
begin
  RunMyApp;
end;

var
  ActiveThread: TActive;
begin
  ActiveThread := TActive.Create(True);
  ActiveThread.FreeOnTerminate := True;
  ActiveThread.Resume;
end.
person Remy Lebeau    schedule 17.02.2021