所以,我的目标是在另一个线程中启动一个函数。此外,我需要从新线程访问其他vcl组件。到目前为止,这是我的代码:
procedure TForm1.StartButtonClick(Sender: TObject);
var
thread1: integer;
id1: longword;
begin
thread1 := beginthread(nil,0,Addr(Tform1.fetchingdata),nil,0,id1);
closehandle(thread1);
end;
procedure TForm1.FetchingData;
var
...
begin
Idhttp1.IOHandler := IdSSLIOHandlerSocketOpenSSL1; //<- error
idhttp1.Request.ContentType := 'application/x-www-form-urlencoded';
我的程序挂起并且我收到错误:00154E53模块my.exe中的异常EAccessViolation。模块“my.exe”中地址00554E53的访问冲突。读取地址00000398。
提前致谢。
答案 0 :(得分:9)
AV的原因是您将TForm
方法的地址传递给期望TThreadFunc
的函数(请参阅documentation of System.BeginThread()
)。像这样使用Addr()
是防止编译器指出你的错误的好方法。
您需要做的是编写一个具有正确签名的包装函数,将表单实例作为参数传递,并从该函数调用表单上的方法。
但是不要去那里,要么将代码写为TThread
的后代,要么(最好)使用更高级别的包装,如AsyncCalls或Omni Thread Library。并确保您不访问主线程中的VCL组件,创建并释放工作线程中所需的组件。
答案 1 :(得分:5)
只能从主线程访问VCL(Gui组件)。其他线程需要主线程来访问VCL。
答案 2 :(得分:0)
如果你使用Delphi或Lazarus,你可以尝试使用常规的TThread。
type
TSeparateThread = class(TThread)
private
protected
public
constructor Create(IfSuspend: Boolean);
proceedure Execute; override;
// variables to fill go here
// s : String;
// i : Integer;
// etc...
end;
constructor TSeparateThread.Create(IfSuspend: Boolean);
begin
inherited Create(IfSuspend);
end;
procedure TSeparateThread.Execute;
begin
// This is where you will do things with those variables and then pass them back.
YourMainUnitOrForm.PublicVariableOf := s[i];
// passes position 0 of s to PublicVariableOf in your Main Thread
end;
调用新线程的步骤如下:
with TSeparateThread.Create(true) do
begin
// This is where you fill those variables passed to the new Thread
s := 'from main program';
i := 0;
// etc...
Resume;
//Will Start the Execution of the New Thread with the variables filled.
end;