Delphi XE2 GetTextExtentPoint32在被线程调用时失败

时间:2012-10-01 11:13:04

标签: multithreading delphi delphi-xe2

这个简单的例子在双击Button1时引发异常(无效参数)。

您可能需要多次点击才能收到消息。

此代码有什么问题?

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.

1 个答案:

答案 0 :(得分:5)

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

在您的代码中,您通过从主GUI线程以外的线程调用Form2.Canvas.TextWidth来破坏此规则。当该代码被映射到Win32时,它最终使用与来自调用者的不同线程相关联的设备上下文调用GetTextExtentPoint32。那是违反规则的。

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