在 TThread 上创建 MainForm
Creating MainForm on a TThread
我有一个 Delphi 2010 应用程序,它导出一个 DLL 并具有 library
header。它在 TThread 中创建其 MainForm,如下所示:
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.
每当我通过 LoadLibrary
函数加载这个 DLL 时,应用程序运行良好。 (显然它使用我传递给 LoadLibrary
的线程作为主线程并且没有问题)
但是,如果我尝试通过更改选项 -> 应用程序中生成的输出,将此 DLL 导出到实际的 EXE。并将 header 从 library
更改为 program
然后构建它并执行输出 EXE 而不是通过 windows api 加载 DLL,应用程序挂起尝试创建表单时,特别是在 Application.CreateForm(MyForm, form);
。如果我从线程中删除应用程序初始化并将其放在主例程中,它运行得很好。
我要呈现的表单只是一个空表单。有什么想法吗?
将此代码编译为 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.
我有一个 Delphi 2010 应用程序,它导出一个 DLL 并具有 library
header。它在 TThread 中创建其 MainForm,如下所示:
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.
每当我通过 LoadLibrary
函数加载这个 DLL 时,应用程序运行良好。 (显然它使用我传递给 LoadLibrary
的线程作为主线程并且没有问题)
但是,如果我尝试通过更改选项 -> 应用程序中生成的输出,将此 DLL 导出到实际的 EXE。并将 header 从 library
更改为 program
然后构建它并执行输出 EXE 而不是通过 windows api 加载 DLL,应用程序挂起尝试创建表单时,特别是在 Application.CreateForm(MyForm, form);
。如果我从线程中删除应用程序初始化并将其放在主例程中,它运行得很好。
我要呈现的表单只是一个空表单。有什么想法吗?
将此代码编译为 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.