我从delphi应用程序调用CreateThread它似乎工作,但是我得到系统错误:代码1400,窗口句柄无效。
代码如下:
procedure TForm1.SyncFile;
var
thr: THandle;
thrID: DWORD;
begin
thr := CreateThread(nil, 0, @sync, nil, 0, thrID);
if (thr = 0) then
ShowMessage('Error creating thread');
end;
procedure sync;
begin
Connect;
Application.ProcessMessages;
SyncText;
Disconnect;
ExitThread(0);
end;
我尝试使用form1.syncfile中的TerminateThread()但是nop。也尝试使用CloseHandle(thr),但也没有解决方案。我尝试了Delphi TThread,但没有解决方案。
我做错了什么?代码表示赞赏。
答案 0 :(得分:3)
除了主要的GUI线程之外,不应该在任何线程中执行对TForm(或调用Application.ProcessMessages)有效的操作。 Windows消息泵期望所有窗口操作都在创建窗口的线程上完成,而不是其他线程。
尝试将“工作”推送到后台线程,但将GUI调用留在主线程上。
答案 1 :(得分:1)
线程函数的签名错误。它需要与文档中描述的匹配。
此外,您不应直接调用CreateThread。请改为调用BeginThread。它会正确地将您的程序标记为多线程,以便内存管理器知道对所有进一步的分配操作使用适当的保护。
这完全独立于你在线程中做的任何事情。当我们达到目标时,还有其他问题。一个是你调用Application.ProcessMessages。消息队列属于特定线程。 Application对象假定它正在处理主VCL线程的消息队列。当您调用ProcessMessages时,您正在使用VCL线程处理代码来处理不同线程的消息队列,然后代码对其处理的队列所做的所有假设都是错误的。如果要在工作线程中处理消息,则需要自己编写消息处理代码。首先阅读GetMessage,PeekMessage和DispatchMessage。 (即使您没有使用多个线程,Application.ProcessMessages的存在也表明程序存在设计问题。线程只是复合它。)
您无需致电ExitThread。如果你的线程例程是一个类似于它应该的函数,那么你可以像任何普通函数一样返回一个值。
你还没有说 where 你得到“无效窗口句柄”异常。如果你在ProcessMessages调用中得到它,那么这可能就是问题所在。但是如果你在其他一个函数中遇到错误,比如Connect或SyncText,那么你也需要看看那里。也许您正在访问不再存在的窗口的属性,或者您正在使用未初始化的变量。
答案 2 :(得分:1)
Windows API禁止线程直接使用已创建(并“属于”)另一个线程的窗口句柄。
对此的一个例外是消息传递系统 - 对于线程将消息发布或发送到另一个线程拥有的窗口句柄,它是完全有效的(实际上是预期的)。实际上,这是确保线程之间同步通信的最简单,最基本的机制之一(利用UI元素所有者线程消息队列)
线程中的任何代码都会尝试使用它没有创建的窗口句柄(除了通过消息传递),这可能会导致此错误(实际上,违规的WinAPI调用将失败,您只会看到如果调用后跟错误检查引发相应异常的代码,则会出现此错误。
由于Delphi应用程序中的GUI对象是在主线程的上下文中创建的(除非你已经跳过了一些严肃的箍以在其他线程中创建UI元素),因此线程中任何试图与Delphi交互的代码UI元素极有可能与WinAPI的这种架构特性相悖。
正如其他人所说,最简单的方法是确保在线程中只执行非UI代码。