Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 在具有此窗体句柄的窗体/框架的OnCreate中启动线程_Delphi - Fatal编程技术网

Delphi 在具有此窗体句柄的窗体/框架的OnCreate中启动线程

Delphi 在具有此窗体句柄的窗体/框架的OnCreate中启动线程,delphi,Delphi,我有一个我不知道如何解决的问题 我尝试在OnCreate事件中启动一个线程,或者在创建TFrame之后,当它的父线程仍然是nil时启动一个线程。创建线程时,我会向它传递一个窗口句柄,但窗口的地址会在例如OnShow事件之后更改 procedure Form1.OnCreate(Sender: TObject); begin TCustomThread.Create(Self); Label1.Caption := IntToStr(Self.Handle); //for example

我有一个我不知道如何解决的问题

我尝试在
OnCreate
事件中启动一个线程,或者在创建
TFrame
之后,当它的
父线程仍然是
nil
时启动一个线程。创建线程时,我会向它传递一个窗口句柄,但窗口的地址会在例如
OnShow
事件之后更改

procedure Form1.OnCreate(Sender: TObject);
begin
  TCustomThread.Create(Self);
  Label1.Caption := IntToStr(Self.Handle); //for example 10203040 
end;

procedure Form1.ButtonOnClick;
begin
  Label1.Caption := IntToStr(Self.Handle); //i give 342545454 not 10203040 
end;

procedure Form1.FromThread(var Msg: TMessage); message WM_TheardComplete;
begin
  {do something}
end;

constructor TCustomThread.Create(AWinControl: TWinControl);
begin
  inherited Create(False);
  FWinControl := AWinControl;
  FreeOnTerminate := True;
end;

procedure TCustomThread.Execute;
begin
   {do something}
   PostMessage(FWinControl.Handle, WM_TheardComplete, 0, 0); //Handle 10203040
end;

我可以使用什么参数启动线程,以便它以后可以向此对象发送消息?

TWinControl.Handle属性不是线程安全的。VCL可以并且确实在控件的生命周期内动态地重新创建控件的窗口,甚至多次。但更重要的是,windows具有线程关联性,其中对给定窗口的消息检索和处理仅在创建窗口的线程中起作用。使用控件的
Handle
属性的工作线程会导致争用条件,如果您不小心,该争用条件实际上会导致工作线程捕获控件窗口的所有权,从而使控件在主UI线程中完全无用

如果需要为工作线程提供一个向其发布/发送消息的窗口,请为该线程提供一个VCL不会破坏的持久窗口(无需您通知),例如使用、使用其事件处理已发布消息或使用其方法处理已发送消息,例如:

procedure Form1.OnCreate(发送方:TObject);
开始
Application.OnMessage:=AppMessage;
TCustomThread.Create(Application.Handle);
结束;
程序表1.OnDestroy(发送方:ToObject);
开始
Application.OnMessage:=nil;
结束;
过程Form1.AppMessage(var-Msg:tagMSG;var-Handled:Boolean);
开始
如果Msg.message=WM\u TheardComplete,则
开始
已处理:=真;
{做点什么}
结束;
结束;
构造函数TCustomThread.Create(AWnd:HWND);
开始
继承创建(False);
FWnd:=有芒;
FreeOnTerminate:=真;
结束;
过程TCustomThread.Execute;
开始
{做点什么}
PostMessage(FWnd,WM_TheardComplete,0,0);
结束;
或者更好,使用VCL功能创建的新专用窗口,例如:

procedure Form1.OnCreate(发送方:TObject);
开始
ThreadWnd:=AllocateHWnd(ThreadWndProc);
TCustomThread.Create(ThreadWnd);
结束;
程序表1.OnDestroy(发送方:ToObject);
开始
解除分配HWND(螺纹WND);
结束;
过程表单1.ThreadWndProc(变量消息:TMessage);
开始
如果Message.Msg=WM\u theard完成,则
开始
{做点什么}
结束其他
Message.Result:=DefWindowProc(ThreadWnd,Message.Msg,Message.WParam,Message.LParam);
结束;
构造函数TCustomThread.Create(AWnd:HWND);
开始
继承创建(False);
FWnd:=有芒;
FreeOnTerminate:=真;
结束;
过程TCustomThread.Execute;
开始
{做点什么}
PostMessage(FWnd,WM_TheardComplete,0,0);
结束;
但是,在您介绍的示例中,我建议使用一种完全不同的方法,而不是在线程执行结束时发送消息—使用
TThread.OnTerminate
事件,该事件已与主线程同步,例如:

procedure Form1.OnCreate(发送方:TObject);
变量
线程:TCustomThread;
开始
线程:=TCustomThread.Create;
Thread.OnTerminate:=ThreadFinished;
Thread.Start;//或在旧版本中恢复()
结束;
程序格式1.螺纹加工(发送方:TObject);
开始
{做点什么}
结束;
构造函数TCustomThread.Create;
开始
继承创建(True);
FreeOnTerminate:=真;
结束;
过程TCustomThread.Execute;
开始
{做点什么}
结束;

另一方面,在Delphi的现代版本中,考虑使用,例如:

procedure Form1.OnCreate(发送方:TObject);
变量
线程:TThread;
开始
线程:=TThread.CreateAnonymousThread(
程序
开始
{做点什么}
结束
);
Thread.OnTerminate:=ThreadFinished;
线程。开始;
结束;
程序格式1.螺纹加工(发送方:TObject);
开始
{做点什么}
结束;
甚至:

procedure Form1.OnCreate(发送方:TObject);
开始
TThread.CreateAnonymousThread(
程序
开始
尝试
{做点什么}
最后
TThread.Queue(nil,
程序
开始
{做点什么}
结束
);
结束;
结束
).开始;
结束;

挑剔:句柄不是地址。这很正常。VCL有时会重新创建窗口。不要让线程引用窗口句柄。让它参考表格。然后使用
TThread.Queue
发布消息。尝试解决问题,而不是解决问题。:)为什么需要表单句柄?我知道你需要它来传递一些信息。由于引用实际窗口的句柄有时会重新创建,因此它在线程中无效。要解决此问题,可以创建一个新的控制柄以绑定到实际窗口。将不会重新创建该句柄。使用System.Classes.AllocateHwnd。