扩展另一个应用程序的标题栏

Extend another application's title bar

我正在开发 open-source .NET clone (GitHub) of DeskPins by Elias Fotinis(直接从 Google 驱动器下载)。它的主要功能是让其他windowsalways-on-top。当它们位于顶部时,标题栏中会添加一个图钉图标,如下所示:

图钉图标在拖放过程中会随着window一起移动,看起来真的像是它的一部分。它甚至响应点击事件,取消总是在顶部状态并从显示中删除图标。

问题。是否可以在 C#(我假设是 p/invoke)中实现类似的东西?

研究

  1. 我试过运行这个项目。

这是一个WPF demo,应该是给标题栏添加一个自定义控件。似乎不适用于 Windows 7 x64。不确定是 OS 还是其他。问题 - z-order 不一致,标题栏也出现在其他 windows 之上,并且它不随 window 移动,它尝试了,但是有很多视觉伪像和闪烁。

  1. 尝试将此解决方案应用于 #1:

    • Attach form window to another window in C#

基本上用这种模式替换对 SetWindowLong 的相关调用:

SetWindowLong(guestHandle, GWL_STYLE, GetWindowLong(guestHandle, GWL_STYLE) | WS_CHILD);
SetParent(guestHandle, hostHandle);

此更改破坏了所有内容,因此标题栏中没有添加任何内容。可能是它不适用于标题栏,仅适用于表单的用户区域。

无论如何,如果有简单的解决方法,请分享您的智慧。如果没有,我将不胜感激任何提示 and/or 链接,以便我进一步研究该主题。

以下是我在 DeskPins 中的操作方法。

每个图钉都是一个弹出窗口 window,具有定义其形状的自定义 HRGN。我确实尝试过使用钩子将 DLL 注入进程并在标题上绘制,但这对我来说太混乱了。

DeskPins 使用 WS_POPUPWS_EX_TOPMOSTWS_EX_TOOLWINDOW 创建图钉,其中 0 作为 parent window。然后它立即向它发送一条消息 (WM_PIN_ASSIGNWND),传递要固定的目标 window 和以毫秒为单位的轮询速率。之后,pin 独立于 DeskPins 运行,它们只相互发送信息消息。

pin 通过将目标 window 设置为其 parent 来处理 WM_PIN_ASSIGNWND,使其成为 top-most 并启动轮询计时器。要设置 parent 它使用:

SetWindowLong(hPin, GWL_HWNDPARENT, (LONG)hPinned);

请注意,Microsoft 警告不要像这样设置 parent,而是建议使用 SetParent()。但是,SetParent() 会进行一些内部处理,这会阻止它跨进程工作。使用 SetWindowLong(GWL_HWNDPARENT) 本质上是在欺骗 window 经理接受它。这有点 hack,但是,嘿......它有效。

轮询计时器持续运行并测试目标 window 是否被销毁、隐藏、移动或其 WS_EX_TOPMOST 标志是否已更改并做出适当响应。