在Windows Vista / 7 Aero Titlebar上绘制自定义按钮

时间:2010-11-07 13:18:40

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

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

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

此外,有没有办法从当前主题中读取信息,所以我可以设置我的按钮样式以匹配现有的按钮。


更新

以下是我的计算机的屏幕截图,展示了上述概念。安装DisplayFusion后,我得到了额外的标题栏按钮 Notepad2 showing additional buttons.

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

3 个答案:

答案 0 :(得分:4)

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

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

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

虽然有一点需要注意 - 还有另一个StackOverflow线程(http://stackoverflow.com/questions/2666979/net-framework-4-0-and-drawing-on-aero-glass-issue/4656182#4656182 )这是描述DWM API DwmExtendFrameIntoClientArea方法的一个问题,所以如果我是你,我会在尝试这个解决方案之前仔细阅读。

答案 1 :(得分:4)

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

这是一般的想法:

  1. 编写DLL挂钩,以便在创建,删除,激活,重新定位或调整窗口大小时收到通知。
  2. 使用透明度密钥或使用此alpha-PNG and GDI+ solution创建透明表单,并通过自己绘制按钮来模拟按钮。
  3. 在创建/删除窗口时,显示/隐藏所需窗口的标题栏按钮形式。
  4. 在窗口调整大小/重新定位消息时,您需要重新标记标题栏按钮形式。
  5. 在窗口激活时,您可以设置窗口的Z位置,使其位于所需窗口的顶部。
  6. 通过GetWindowSetWindowPos API获取并设置Z位置 请注意,DLL必须使用本机语言编写。但是,你使用这样的东西来解决这个问题: Using Window Messages to Implement Global System Hooks in C#

    这是我的结果:

    enter image description here

答案 2 :(得分:0)

好的,系统挂钩是获取有关已更改窗口位置信息的直接方法,而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

获取此示例