Multithreading 当线程调用Delphi XE2 GetTextExtentPoint32时失败

Multithreading 当线程调用Delphi XE2 GetTextExtentPoint32时失败,multithreading,delphi,delphi-xe2,Multithreading,Delphi,Delphi Xe2,此简单示例在双击按钮1时引发异常(无效参数) 您可能需要多次单击才能获取消息 这个代码有什么问题 type TForm2 = class(TForm) Button1: TButton; procedure Button1Click(Sender: TObject); end; TTestThread = class(TThread) protected procedure Execute; override; end; var Form2:

此简单示例在双击按钮1时引发异常(无效参数)

您可能需要多次单击才能获取消息

这个代码有什么问题

type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  end;

  TTestThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.Button1Click(Sender: TObject);
var MyThread : TTestThread;
begin
  MyThread:=TTestThread.Create(true);
  MyThread.FreeOnTerminate:=True;
  MyThread.Priority:=tpHighest;
  MyThread.Resume;
end;

{ TTestThread }

procedure TTestThread.Execute;
var len : integer;
begin
 len := Form2.Canvas.TextWidth('test');
 if (len=0) then
  Raise Exception.Create(SysErrorMessage(GetLastError));
end;

end.

Windows GUI函数具有线程关联性。此约束将传递给VCL。这意味着您只能从主GUI线程访问VCL例程

在您的代码中,您通过从除主GUI线程之外的线程调用
Form2.Canvas.TextWidth
打破了这一规则。当该代码映射到Win32时,它最终使用与调用者的不同线程关联的设备上下文调用
GetTextExtentPoint32
。那是违反规定的


解决办法是遵守规则。仅从主GUI线程调用VCL函数。

Windows GUI函数具有线程关联性。此约束将传递给VCL。这意味着您只能从主GUI线程访问VCL例程

在您的代码中,您通过从除主GUI线程之外的线程调用
Form2.Canvas.TextWidth
打破了这一规则。当该代码映射到Win32时,它最终使用与调用者的不同线程关联的设备上下文调用
GetTextExtentPoint32
。那是违反规定的


解决办法是遵守规则。只能从主GUI线程调用VCL函数。

关于Delphi线程、VCL和TThread文档,甚至是由
File->New->Other->TThread单元创建的
shell代码的每一篇文章都告诉人们“除非使用Synchronize,否则不要从线程访问可视化组件”,并且没有人愿意阅读它,并且问了同样的问题:“为什么当我从它里面访问可视化控件时,我的线程不能正常工作?”每一篇关于Delphi线程、VCL和TThread文档,甚至是由
File->New->Other->TThread单元创建的
TThread
shell代码的帖子都告诉人们“除非使用同步,否则不要从线程访问可视组件”,没有人会费心阅读它,并问同样的问题:“为什么当我从线程中访问可视控件时,我的线程不能正常工作?”+1正确,这是正确的。+1正确,这是正确的。