3

I have a Delphi 2010 application that exports a DLL and has the library header. It creates its MainForm in a TThread, like so:

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.

Whenever I load this DLL through the LoadLibrary function, the application runs fine. (Apparently it uses the thread that I passed to LoadLibrary as the main thread and has no issues)

But if I attempt to export this DLL to an actual EXE, by changing the generated output in Options -> Application. and changing the header from library to program and then build it and execute the output EXE instead of loading the DLL through the windows api, the application hangs when attempting to create the form, specifically at Application.CreateForm(MyForm, form);. If I remove the Application initialization from the thread and place it on the main routine, it runs just fine.

The form I'm trying to render is just an empty form. Any ideas?

Gege GMF
  • 55
  • 5

1 Answers1

4

When compiling this code as a program, at runtime it will try to terminate itself when end. is reached, before the worker thread even has a chance to run, which could possibly (and likely) happen after the Application object has been destroyed. You would have to wait for the worker thread to finish its work before letting the program exit, eg:

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.

But, there is really no good reason to ever use a worker thread like this, this defeats the whole purpose of using a thread, so you may as well just get rid of it altogether:

program MyProgram;

uses
  Forms, MyForm;

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

On the other hand, if you are trying to share common code between program and library projects, then you can wrap the Application code inside of a function and let the project decide which thread calls the function, eg:

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.
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770