gpt4 book ai didi

multithreading - 具有隐藏窗口的线程的线程消息循环?

转载 作者:行者123 更新时间:2023-12-03 14:56:55 28 4
gpt4 key购买 nike

我有一个 Delphi 6 应用程序,它有一个线程专用于与使用 SendMessage() 和 WM_COPYDATA 消息与外部程序交互的外部应用程序进行通信。因此,我使用 AllocateHWND() 创建一个隐藏窗口来满足该需要,因为由于 SendMessage() 函数仅接受窗口句柄而不接受线程 ID,因此线程消息队列将无法工作。我不确定要在线程 Execute() 方法中放入什么内容。

我假设如果我使用 GetMessage() 循环或创建一个带有 WaitFor*() 函数调用的循环,线程将阻塞,因此线程的 WndProc() 将永远不会处理来自的 SendMessage() 消息国外的节目对吧?如果是这样,放入 Execute() 循环的正确代码是什么,该循环不会不必要地消耗 CPU 周期,但一旦收到 WM_QUIT 消息就会退出?如有必要,我总是可以使用 Sleep() 进行循环,但我想知道是否有更好的方法。

最佳答案

AllocateHWnd()(更具体地说,MakeObjectInstance())不是线程安全的,因此您必须小心使用它。最好直接使用 CreatWindow/Ex() (或者使用 AllocateHWnd() 的线程安全版本,例如 DSiAllocateHwnd()

无论如何,HWND 都与创建它的线程上下文相关联,因此您必须在 Execute() 内创建和销毁 HWND 方法,不在线程的构造函数/析构函数中。此外,即使 SendMessage() 用于向您发送消息,它们也来自另一个进程,因此在其拥有之前,它们不会被您的 HWND 处理线程执行消息检索操作,因此线程需要自己的消息循环。

您的 Execute() 方法应如下所示:

procedure TMyThread.Execute;
var
Message: TMsg;
begin
FWnd := ...; // create the HWND and tie it to WndProc()...
try
while not Terminated do
begin
if MsgWaitForMultipleObjects(0, nil^, False, 1000, QS_ALLINPUT) = WAIT_OBJECT_0 then
begin
while PeekMessage(Message, 0, 0, 0, PM_REMOVE) do
begin
TranslateMessage(Message);
DispatchMessage(Message);
end;
end;
end;
finally
// destroy FWnd...
end;
end;

procedure TMyThread.WndProc(var Message: TMessage);
begin
if Message.Msg = WM_COPYDATA then
begin
...
Message.Result := ...;
end else
Message.Result := DefWindowProc(FWnd, Message.Msg, Message.WParam, Message.LParam);
end;

或者:

// In Delphi XE2, a virtual TerminatedSet() method was added to TThread,
// which is called when TThread.Terminate() is called. In earlier versions,
// use a custom method instead...

type
TMyThread = class(TThread)
private
procedure Execute; override;
{$IF RTLVersion >= 23}
procedure TerminatedSet; override;
{$IFEND}
public
{$IF RTLVersion < 23}
procedure Terminate; reintroduce;
{$IFEND}
end;

procedure TMyThread.Execute;
var
Message: TMsg;
begin
FWnd := ...; // create the HWND and tie it to WndProc()...
try
while not Terminated do
begin
if WaitMessage then
begin
while PeekMessage(Message, 0, 0, 0, PM_REMOVE) do
begin
if Message.Msg = WM_QUIT then Break;
TranslateMessage(Message);
DispatchMessage(Message);
end;
end;
end;
finally
// destroy FWnd...
end;
end;

{$IF RTLVersion < 23}
procedure TMyThread.Terminate;
begin
inherited Terminate;
PostThreadMessage(ThreadID, WM_QUIT, 0, 0);
end;
{$ELSE}
procedure TMyThread.TerminatedSet;
begin
PostThreadMessage(ThreadID, WM_QUIT, 0, 0);
end;
{$IFEND}

关于multithreading - 具有隐藏窗口的线程的线程消息循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7700410/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com