【问题标题】:Intercepting and hiding a window before it appears在窗口出现之前拦截并隐藏它
【发布时间】:2011-05-19 20:50:03
【问题描述】:

我正在为应用程序开发一个(进程中)插件,作为我插件的一部分,我想用我自己的替换应用程序的工具提示。但是,我没有可用的 API 来执行此操作,因此我决定使用低级。

我知道工具提示的窗口类,但问题是,如何检测它正在创建以及之后如何关闭它?

到目前为止,这是我想做的事情:

  1. 在 WM_CREATE 上创建系统范围的挂钩
  2. 当被捕获时,检查 WM_CREATE 目标的类和进程
  3. 验证它确实是我关心的窗口:
    • 如果进程是我的插件所在的进程
    • 如果类的类型正确
    • 如果正确的应用程序是焦点(在多个应用程序的情况下)
  4. 向创建的窗口发送 WM_DESTROY 并在其位置创建我自己的窗口

听起来怎么样?假设确实没有 API 来处理工具提示,有没有更简单的方法来满足我的需要?

谢谢!

P.S 标记为 C++/C#,因为我打算用这两种语言编写它(C++ 用于系统范围的挂钩,C# 用于其他所有语言)

【问题讨论】:

  • 工具提示通常是通过为每个顶级父窗口创建并保留 一个 工具提示窗口来完成的。然后在需要时调整并显示该工具提示窗口,并在不需要时隐藏。因此,您需要跟踪窗口何时显示,而不是创建时间,并且您显然不想销毁它(您可能会隐藏它)。
  • @Leo:感谢您的评论。这可能是非常正确的。

标签: c# c++ windows message-queue subclass


【解决方案1】:

这行不通。考虑您正在替换工具提示的应用程序的视图,并假设您可以告诉它销毁窗口。当应用程序决定它需要关闭工具提示时会发生什么?它没有你的新窗口的句柄,它有你已经销毁的旧窗口的句柄。是时候出错了。

如果您希望它顺利工作,您的插件系统需要明确支持替换工具提示。也许插件框架的可选部分可以是 RequestTooltip 函数。如果它不存在,或者返回 null,或者其他什么,则使用默认工具提示,否则使用插件提供的。

【讨论】:

  • 关于第一部分。没错,它比这更复杂 - 我需要自己开始跟踪鼠标来隐藏我自己的窗口。原始应用程序将无法为我隐藏工具提示,但是,我不明白为什么它会导致问题。例如,如果销毁“旧”工具提示有问题,我可以尝试隐藏它,然后销毁就可以正常工作(事实上,我什至可以挂钩旧工具提示的销毁以隐藏我的新工具提示)。
  • 关于第二个问题:恐怕应用程序没有 API 来查询是否存在工具提示,所以我根本做不到 =\
【解决方案2】:

如果您知道要阻止的窗口的类型,您可以简单地将其子类化并在您自己的WndProc 中处理销毁。在工具提示类上使用GetClassLongPtr()GCL_WNDPROC,使用SetClassLongPtr()GCL_WNDPROC 设置您自己的WndProc 并让它在WM_CREATE 上调用DestroyWindow(),其余的调用旧的WndProc。 .

【讨论】:

  • 我很困惑... GetClassLongPtr() 需要一个 HWND,但在工具提示的情况下,它尚未创建。你是说我可以使用 GetClassLongPtr()/SetClassLongPtr() 子类化一个还不存在的窗口?
  • 是的,您需要先创建一个虚拟工具提示窗口并使用它。
  • @kichik:有趣...如果我这样做,该类窗口的所有未来实例都将使用该 MessagePump?
  • 确实如此。虽然这不是 MessagePump 的问题,而是 WndProc 的问题。您还可以使用 GetClassInfoEx()、UnregisterClass() 和 RegisterClassEx() 重新注册该类。
  • @kichik:这似乎工作得很好,而且比挂钩容易得多。谢谢!
猜你喜欢
  • 2011-07-04
  • 1970-01-01
  • 2013-12-25
  • 2017-02-25
  • 1970-01-01
  • 2014-09-09
  • 1970-01-01
  • 2022-11-01
  • 2016-10-27
相关资源
最近更新 更多