This simple example raise exception (invalid parameter) when double clicking on 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. This constraint is passed on to the VCL. Which means that you can only access VCL routines from the main GUI thread.
In your code you have broken this rule by calling Form2.Canvas.TextWidth
from a thread other than the main GUI thread. 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. That's against the rules.
The solution is to abide by the rules. Only call VCL functions from the main GUI thread.