【问题标题】:Draw Custom Buttons on Windows Vista/7 Aero Titlebar在 Windows Vista/7 Aero 标题栏上绘制自定义按钮
【发布时间】:2011-05-06 07:06:05
【问题描述】:

我在StackOverflow 上发现了这个问题。基本上,用户想要在标题栏上绘制自定义按钮。

我尝试了代码并意识到它仅在禁用 Aero 时才能在 vista/7 中工作。我的问题是,有没有办法在标题栏上绘制自定义按钮同时 aero 启用?

另外,有什么方法可以从当前主题中读取信息,这样我就可以设置按钮的样式以匹配现有的按钮。


更新

这是我的电脑截图,展示了上述概念。安装 DisplayFusion 后,我得到了额外的标题栏按钮。

而且我知道 DisplayFusion 是一个 .NET 程序,因为它在 .NET Reflector 中打开。不利的一面是程序被混淆了。不像我想反编译程序或任何东西;我只想在标题栏上添加一个按钮来执行其他操作(例如最小化到系统托盘)。
下面是截图,证明该程序是一个 .NET 应用程序。

【问题讨论】:

  • 忘记这个,它不再起作用了。
  • 我知道这是可能的,因为有一个名为 Display Fusion 的多显示器应用程序可以做到这一点。我知道这是一个 .NET 应用程序,因为我使用 Lutz Roeder 的 .NET Reflector 来查看它。

标签: c# vb.net winapi windows-vista titlebar


【解决方案1】:

只要您愿意重绘整个标题栏内容,那么您可以使用 DWM API 的 DwmExtendFrameIntoClientArea 方法,该方法涉及将您的窗口设置为没有标题栏,从而允许 DWM 将其玻璃绘制到您的可用区域创建一个看起来像标题栏但实际上在您的客户区中的新空间,以便您可以在其上绘制按钮。

这种方法的缺点是,如果需要,您必须制作标准按钮。最小化、最大化和关闭重新创建没有问题(尽管您会发现最大化按钮是一个切换按钮,其外观基于状态),但您可能会发现重新创建左上角按钮有问题。当然,您还必须重新绘制标题,但我无法想象您对此会有任何问题。

至于读取当前主题的数据以将您的按钮重新设计为他们的,我很抱歉,但我对此一无所知。我的建议是在标题栏上构建按钮时使用透明度,并使用半透明发光效果等。这样您就可以保留玻璃背景,并通过覆盖半透明颜色来简单地修改其外观。此外,如果你这样做,那么玻璃上不断变化的镜面高光会自然移动,而如果你只是获得它们的主题颜色,你会发现要么你无法访问它们的反射,要么它们在内部重新创建按钮的空间。当然,只是我的两分钱——如果你能找到一种方法来制作你的主题颜色等等,无论如何。

对此有一个警告 - 还有另一个 StackOverflow 线程 (http://stackoverflow.com/questions/2666979/net-framework-4-0-and-drawing-on-aero-glass-issue/4656182#4656182 ) 描述了 DWM API DwmExtendFrameIntoClientArea 方法的问题,所以如果我是你,我会在尝试此解决方案之前通读该问题。

【讨论】:

    【解决方案2】:

    我对此进行了一些研究,因为我也在自己的多显示器解决方案中实现了这一点。 DisplayFusion 和 TeamViewer 实现这一点的方式是在包含按钮的所需窗口上覆盖自定义表单。您可以使用 Spy++ 来确认这一点。

    这是一般的想法:

    1. 编写一个 DLL 挂钩,以便在创建、删除、激活、重新定位或调整窗口大小时获得通知。
    2. 使用透明键或alpha-PNG and GDI+ solution 制作透明表单,并通过自己绘制来模拟按钮。
    3. 在创建/删除窗口时,您可以显示/隐藏所需窗口的标题栏按钮表单。
    4. 在窗口调整大小/重新定位消息时,您需要重新调整标题栏按钮表单。
    5. 在窗口激活时,您设置窗口的 Z 位置,使其位于所需窗口的顶部。

    通过GetWindowSetWindowPos API 获取和设置 Z 位置。
    请注意,DLL 必须以本地语言编写。但是,您可以使用类似的方法来解决该问题: Using Window Messages to Implement Global System Hooks in C#

    这是我的结果:

    【讨论】:

    • 您的解决方案看起来很有希望。我想出了如何创建透明表单并检测窗口的打开、移动和关闭。我想知道的是您如何创建空白主题按钮,以便我可以自己绘制。如果可能,您能否上传您的解决方案?
    • 您能否发布一些代码来展示您如何在屏幕截图中创建标题栏按钮?
    • @Jelle Vergeer 请考虑为“结果”的源代码添加链接,我需要这个解决方案... +1
    • 我会写一篇关于 CodeProject 的文章,它是如何组合在一起的,但可能需要一些时间,因为我现在没有太多空闲时间..
    【解决方案3】:

    好的,系统挂钩是获取更改窗口位置信息的直接方法,Jelle's 透明形式的提案非常好。但是您可以使用侵入性较小的方法通过 user32.dll 获取有关桌面窗口的信息

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool GetWindowRect(HandleRef hWnd, out RECT lpRect);
    

    您可以使用 EnumDesktopWindows 获得的窗口句柄

    [DllImport("user32.dll", EntryPoint = "EnumDesktopWindows", 
    ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EnumDesktopWindows(IntPtr hDesktop, EnumDelegate lpEnumCallbackFunction, IntPtr lParam);
    

    你可以从线程getting-a-list-of-all-applications-in-c-sharp获得一个例子

    【讨论】:

      猜你喜欢
      • 2010-11-13
      • 1970-01-01
      • 1970-01-01
      • 2016-03-22
      • 2010-09-11
      • 1970-01-01
      • 2019-05-05
      • 2011-12-08
      • 2011-05-14
      相关资源
      最近更新 更多