简体   繁体   English

线程调用时,Delphi XE2 GetTextExtentPoint32失败

[英]Delphi XE2 GetTextExtentPoint32 fails when called by a thread

This simple example raise exception (invalid parameter) when double clicking on Button1. 双击Button1时,此简单示例引发异常(无效参数)。

You may have to click several times to get the message. 您可能必须单击几次以获取消息。

What is wrong with this code ? 此代码有什么问题?

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 functions have thread affinity. Windows GUI函数具有线程关联性。 This constraint is passed on to the VCL. 该约束传递给VCL。 Which means that you can only access VCL routines from the main GUI thread. 这意味着您只能从主GUI线程访问VCL例程。

In your code you have broken this rule by calling Form2.Canvas.TextWidth from a thread other than the main GUI thread. 在您的代码中,通过从主GUI线程以外的线程调用Form2.Canvas.TextWidth打破了此规则。 When that code is mapped down to Win32 it ends up calling GetTextExtentPoint32 with a device context that is associated with a different thread from the caller. 当该代码向下映射到Win32时,它最终使用与调用方的不同线程关联的设备上下文调用GetTextExtentPoint32 That's against the rules. 这是违反规则的。

The solution is to abide by the rules. 解决的办法是遵守规则。 Only call VCL functions from the main GUI thread. 仅从主GUI线程调用VCL函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM