Draw Custom Buttons on Windows Vista/7 Aero Titlebar

后端 未结 3 1321
暗喜
暗喜 2020-12-14 23:26

I found this question on StackOverflow. Basically, the user wanted to draw custom buttons on the titlebar.

I tried the code and realised it works in vista/7 only whe

相关标签:
3条回答
  • 2020-12-15 00:03

    As long as you're willing to redraw the entire title-bar contents, then you can use the DWM API's DwmExtendFrameIntoClientArea method, which involves setting your window to have no titlebar, allowing the DWM to draw its glass into your usable area to create a new space that looks like the titlebar but is in fact in your client area, so that you can draw buttons onto it.

    The downside of this method is that you'll have to make the standard buttons if you want them. Minimize, Maximize and Close are no problem to recreate (though you'll find that the maximize button is a togglebutton with appearance based on the state), but you might find you have issue with recreating the top-left corner button. You'll also have to redraw your title, of course, but I can't imagine you'll have any issue with that.

    As for reading the current theme's data back to restyle your buttons as theirs, I'm sorry but I don't know anything about that. My suggestion would be to use transparency when building your buttons onto the titlebar, and to use translucent glow-effects, etcetera. That way you'll be able to retain the glass background, and simply modify its appearance by overlaying a translucent colour. Also, if you do it this way, then the shifting specular highlights on the glass will move naturally, whereas if you simply got their theme colours you'd find either that you didn't get access to their reflections or that they recreated afresh within the space of your buttons. Just my two cents, of course - if you can find a way to do your theme colours etcetera, by all means.

    There's one caveat to this though - there's another StackOverflow thread (http://stackoverflow.com/questions/2666979/net-framework-4-0-and-drawing-on-aero-glass-issue/4656182#4656182) which is describing an issue with the DWM API DwmExtendFrameIntoClientArea method, so if I were you, I'd read through that before trying this solution.

    0 讨论(0)
  • 2020-12-15 00:08

    I did some research into this as I implemented this too in my own multi-monitor solution. The way DisplayFusion and TeamViewer implemented this is overlaying a custom form over the desired window containing the buttons. You can use Spy++ to confirm this.

    This is the general idea:

    1. Write a DLL hook for getting notified when a window is created, removed, activated, repositioned or resized.
    2. Make a transparant form using transparancy key or using this alpha-PNG and GDI+ solution and simulate the button(s) by painting it your own.
    3. On window creation/removal you show/hide your titlebarbutton form for the desired window(s).
    4. On window resize/reposition messages you realign your titlebarbutton form.
    5. On window activation you set the Z position of the window so that it is on top of the desired window.

    Getting and setting the Z position through the GetWindow and SetWindowPos API's.
    Be aware that the DLL must be written in a native language. However you van use something like this to work around that problem: Using Window Messages to Implement Global System Hooks in C#

    And here is my result:

    enter image description here

    0 讨论(0)
  • 2020-12-15 00:09

    Ok, system hooks are the direct approach for getting information on changed window positions and Jelle's proposal with transparent form is very good. But you can use a less invasive method to get information on Desktop windows by using user32.dll

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

    The window handles you can get using 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);
    

    An example for this you can get from the thread getting-a-list-of-all-applications-in-c-sharp

    0 讨论(0)
提交回复
热议问题