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?
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.