gpt4 book ai didi

multithreading - 如何终止具有单独消息循环的线程?

转载 作者:行者123 更新时间:2023-12-03 15:21:18 29 4
gpt4 key购买 nike

我正在为 SetWindowsHookEx API 编写一个实用程序单元。

要使用它,我希望有一个像这样的界面:

var
Thread: TKeyboardHookThread;
begin
Thread := TKeyboardHookThread.Create(SomeForm.Handle, SomeMessageNumber);
try
Thread.Resume;
SomeForm.ShowModal;
finally
Thread.Free; // <-- Application hangs here
end;
end;

在我当前的 TKeyboardHookThread 实现中,我无法使线程正确退出。

代码是:

  TKeyboardHookThread = class(TThread)
private
class var
FCreated : Boolean;
FKeyReceiverWindowHandle : HWND;
FMessage : Cardinal;
FHiddenWindow : TForm;
public
constructor Create(AKeyReceiverWindowHandle: HWND; AMessage: Cardinal);
destructor Destroy; override;
procedure Execute; override;
end;

function HookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
S: KBDLLHOOKSTRUCT;
begin
if nCode < 0 then begin
Result := CallNextHookEx(0, nCode, wParam, lParam)
end else begin
S := PKBDLLHOOKSTRUCT(lParam)^;
PostMessage(TKeyboardHookThread.FKeyReceiverWindowHandle, TKeyboardHookThread.FMessage, S.vkCode, 0);
Result := CallNextHookEx(0, nCode, wParam, lParam);
end;
end;

constructor TKeyboardHookThread.Create(AKeyReceiverWindowHandle: HWND;
AMessage: Cardinal);
begin
if TKeyboardHookThread.FCreated then begin
raise Exception.Create('Only one keyboard hook supported');
end;
inherited Create('KeyboardHook', True);
FKeyReceiverWindowHandle := AKeyReceiverWindowHandle;
FMessage := AMessage;
TKeyboardHookThread.FCreated := True;
end;

destructor TKeyboardHookThread.Destroy;
begin
PostMessage(FHiddenWindow.Handle, WM_QUIT, 0, 0);
inherited;
end;

procedure TKeyboardHookThread.Execute;
var
m: tagMSG;
hook: HHOOK;
begin
hook := SetWindowsHookEx(WH_KEYBOARD_LL, @HookProc, HInstance, 0);
try
FHiddenWindow := TForm.Create(nil);
try
while GetMessage(m, 0, 0, 0) do begin
TranslateMessage(m);
DispatchMessage(m);
end;
finally
FHiddenWindow.Free;
end;
finally
UnhookWindowsHookEx(hook);
end;
end;

AFAICS 仅当线程中存在消息循环时才会调用 Hook 过程。问题是我不知道如何正确退出这个消息循环。

我尝试使用属于该线程的隐藏 TForm 来执行此操作,但消息循环不会处理我发送到该窗体的窗口句柄的消息。

如何正确执行此操作,以便消息循环在线程关闭时终止?

编辑:我现在使用的解决方案如下所示(并且工作起来就像一个魅力):

  TKeyboardHookThread = class(TThread)
private
class var
FCreated : Boolean;
FKeyReceiverWindowHandle : HWND;
FMessage : Cardinal;
public
constructor Create(AKeyReceiverWindowHandle: HWND; AMessage: Cardinal);
destructor Destroy; override;
procedure Execute; override;
end;

function HookProc(nCode: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
S: KBDLLHOOKSTRUCT;
begin
if nCode < 0 then begin
Result := CallNextHookEx(0, nCode, wParam, lParam)
end else begin
S := PKBDLLHOOKSTRUCT(lParam)^;
PostMessage(TKeyboardHookThread.FKeyReceiverWindowHandle, TKeyboardHookThread.FMessage, S.vkCode, 0);
Result := CallNextHookEx(0, nCode, wParam, lParam);
end;
end;

constructor TKeyboardHookThread.Create(AKeyReceiverWindowHandle: HWND;
AMessage: Cardinal);
begin
if TKeyboardHookThread.FCreated then begin
raise Exception.Create('Only one keyboard hook supported');
end;
inherited Create('KeyboardHook', True);
FKeyReceiverWindowHandle := AKeyReceiverWindowHandle;
FMessage := AMessage;
TKeyboardHookThread.FCreated := True;
end;

destructor TKeyboardHookThread.Destroy;
begin
PostThreadMessage(ThreadId, WM_QUIT, 0, 0);
inherited;
end;

procedure TKeyboardHookThread.Execute;
var
m: tagMSG;
hook: HHOOK;
begin
hook := SetWindowsHookEx(WH_KEYBOARD_LL, @HookProc, HInstance, 0);
try
while GetMessage(m, 0, 0, 0) do begin
TranslateMessage(m);
DispatchMessage(m);
end;
finally
UnhookWindowsHookEx(hook);
end;
end;

最佳答案

您需要将 WM_QUIT 消息发送到该线程的消息队列以退出该线程。 GetMessage如果从队列中提取的消息是 WM_QUIT,则返回 false,因此它将在收到该消息后退出循环。

为此,请使用 PostThreadMessage函数将WM_QUIT消息直接发送到线程的消息队列。例如:

PostThreadMessage(Thread.Handle, WM_QUIT, 0, 0);

关于multithreading - 如何终止具有单独消息循环的线程?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10415481/

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