2012-10-01 71 views
0

這個簡單的示例在雙擊Button1時引發異常(無效參數)。Delphi XE2 GetTextExtentPoint32在線程調用時失敗

您可能需要點擊幾次以獲取消息。

什麼是錯的代碼?

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. 
+2

關於Delphi線程,VCL和TThread文檔,甚至是由'File-> New-> Other-> TThread Unit'創建的'TThread' shell代碼的每一篇文章都告訴人們:「不要從線程,除非你使用Synchronize「,並且沒有人討厭它,並且詢問同樣的問題:」爲什麼當我從內部訪問可視化控件時,我的線程沒有正常工作?「 –

回答

5

Windows圖形用戶界面的功能有螺紋的親和力。這個約束被傳遞給VCL。這意味着您只能從主GUI線程訪問VCL例程。

在你的代碼中,你通過調用主GUI線程以外的線程調用Form2.Canvas.TextWidth來打破這條規則。當代碼被映射到Win32時,它最終會調用GetTextExtentPoint32,其中的設備上下文與來自調用者的不同線程相關聯。這違反了規則。

解決方案是遵守規則。只從主GUI線程調用VCL函數。

+0

+1正確,這裏是[文檔](http://msdn.microsoft.com/en-us/library/windows/desktop/ms684256(v = vs.85).aspx)。 –