Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 全局钩子线程占用太多CPU,如何修复?_Delphi - Fatal编程技术网

Delphi 全局钩子线程占用太多CPU,如何修复?

Delphi 全局钩子线程占用太多CPU,如何修复?,delphi,Delphi,下面的全局钩子线程占用了太多CPU,除非我在那里添加睡眠(10), 除了睡眠(10毫秒)还有其他解决方案吗?对于我的应用程序的性能来说,睡眠看起来不是一个最佳的解决方案。如果我加了太多的睡眠,它不是也会减慢鼠标的速度吗 procedure THookThread.Execute; begin hookhandle := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseHook, Hinstance, 0); while

下面的全局钩子线程占用了太多CPU,除非我在那里添加睡眠(10), 除了睡眠(10毫秒)还有其他解决方案吗?对于我的应用程序的性能来说,睡眠看起来不是一个最佳的解决方案。如果我加了太多的睡眠,它不是也会减慢鼠标的速度吗

  procedure THookThread.Execute;
    begin
      hookhandle := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseHook, Hinstance, 0);

     while not Terminated do
      begin    
        MessageLoop;
      //  Sleep(10);
      end;

      UnHookWindowsHookEx(hookhandle);
      hookhandle := 0;

    end;

procedure THookThread.MessageLoop;
var
  msg: TMsg;
begin
  while PeekMessage(msg, 0, 0, 0, PM_NOREMOVE) do
  begin
    TranslateMessage(msg);
    DispatchMessage(msg);
  end;
end;

您的消息循环是一个忙循环。您应该使用
GetMessage
而不是
PeekMessage
。这是因为
GetMessage
阻塞,直到消息添加到队列中


您在注释中注意到,
GetMessage
阻塞了终止代码。通过在终止后向线程发送消息来处理该问题。
WM_NULL
作为常规唤醒,或
WM_QUIT
作为退出消息循环的显式指令

试试类似的方法:

procedure THookThread.Execute;
var
  msg: TMsg;
  ret: LongInt;
begin
  //create the message queue...
  PeekMessage(msg, 0, WM_USER, WM_USER, PM_NOREMOVE);

  hookhandle := SetWindowsHookEx(WH_MOUSE_LL, @LowLevelMouseHook, Hinstance, 0);
  if hookhandle = 0 then RaiseLastOSError; 

  try
    while GetMessage(msg, 0, 0, 0) and (not Terminated) do
    begin
      TranslateMessage(msg);
      DispatchMessage(msg);
    end;
  finally
    UnHookWindowsHookEx(hookhandle);
    hookhandle := 0;
  end;
end;

procedure THookThread.Stop;
begin
  Terminate;
  PostThreadMessage(ThreadID, WM_QUIT, 0, 0);
end;

10毫秒延迟背后有什么原因吗?通常,放弃当前时间片是通过
Sleep(0)
完成的。使用Yield而不是Sleep(0)也可以。线程的用途是什么?你怎么把钩子放在一条线里了?为什么不直接用
GetMessage
而不是
PeekMessage
?前者自然会阻塞,直到有消息可用,绕过繁忙的循环和相关的高CPU使用率。这不是对你问题的回答,但我强烈建议你寻找一个能满足你需要的组件,而不是重新发明这个轮子。我自己在感谢方面也有很好的经验,GetMessage()从性能的角度来看是非常好的,但是有一个主要的问题,线程不能用这个来终止!当我调用Terminate时,似乎没有出现“Terminate”;-“需要使用GetMessage”-这不是强制性的,
WaitMessage
可用于在
PeekMessage
返回false时阻止。@Sertac是的,需要太强烈。也就是说,等待/偷看很难成为首选。@Tom所以不要使用Terminate。。。您有一个消息循环,请改为发布一条消息。谢谢您的帮助,代码现在可以运行了。但是,我要感谢有完整代码的,很抱歉。您可以安全地将GetMessage返回值视为BOOL。在本例中,
BOOL
LongBool
的别名,它将-1视为True。如果
GetMessage()
返回-1,并且您使用
while-GetMessage()
循环,则它不会在失败时中断。甚至MSDN也在
GetMessage()
文档中解释了这个特定条件,并说不要这样编写代码。因此,显式检查-1(特别是因为我无论如何都要调用
raiselastserror()
,因为
GetLastError()
GetMessage()
返回-1时报告错误代码)。例如,如果hWnd是无效的窗口句柄或lpMsg是无效的指针,则函数将失败。这两种情况在这里都不可能发生,因此返回值永远不会为-1。雷蒙德解释说:利用这一点,你可以大大简化代码。我原以为你会很高兴了解这一点,而不是不屑一顾。我知道我很感激你多次教我一些东西。我以前读过那篇文章,这次我只是不记得那个特别的细节。我不经常编写消息循环,当我这样做时,我通常不会对它们使用
GetMessage()