I've seen that some apps (maybe not .NET apps) that have an extra button on the left from the minimize button on the form's title bar? How can I achieve this in C#?
Title bars contain at least three small buttons that minimize, maximize or restore, and close the window associated with the title bar. Title bars also contain a context-sensitive Help button.
The title bar has just the three buttons to minimize, maximize and restore windows. However, you can add new buttons to the window title bars in Windows 10 with the eXtra Buttons software.
In addition, the Title Bar has the three buttons familiar to Windows ® users: Minimize, Maximize, and Close.
UPDATE: Added a solution that will work with Aero enabled for Windows Vista and Windows 7
The non-client area of a window interaction is managed by a series of non-client specfic messages. For example WM_NCPAINT message is sent to the window procedure to paint the non-client area.
I have never done this from .NET, but I suspect you can overide the WndProc and handle the WM_NC* messages to achieve what you want.
Update: Since I never tried this from .NET I got a few minutes and thought I would give it a quick try.
Trying this on Windows 7, I found that I needed to disable the Themes for the Window if I wanted to OS to do the base rendering of the non-client area. So here is a short test. I used GetWindowDC to get the DC of the entire window rather than GetDCEx, that was just because I could interop that from memory and did not have lookup all the flag constants for GetDcEx. And of course the code could do with more error checking.
using System; using System.Drawing; using System.Windows.Forms; using System.Runtime.InteropServices; namespace WindowsFormsApplication1 { public partial class CustomBorderForm : Form { const int WM_NCPAINT = 0x85; [DllImport("user32.dll", SetLastError = true)] public static extern IntPtr GetWindowDC(IntPtr hwnd); [DllImport("user32.dll", SetLastError = true)] public static extern int ReleaseDC(IntPtr hwnd, IntPtr hdc); [DllImport("user32.dll", SetLastError = true)] public static extern void DisableProcessWindowsGhosting(); [DllImport("UxTheme.dll", SetLastError = true, CharSet = CharSet.Unicode)] public static extern IntPtr SetWindowTheme(IntPtr hwnd, string pszSubAppName, string pszSubIdList); public CustomBorderForm() { // This could be called from main. DisableProcessWindowsGhosting(); InitializeComponent(); } protected override void OnHandleCreated(EventArgs e) { SetWindowTheme(this.Handle, "", ""); base.OnHandleCreated(e); } protected override void WndProc(ref Message m) { base.WndProc(ref m); switch (m.Msg) { case WM_NCPAINT: { IntPtr hdc = GetWindowDC(m.HWnd); using (Graphics g = Graphics.FromHdc(hdc)) { g.FillEllipse(Brushes.Red, new Rectangle((Width-20)/2, 8, 20, 20)); } ReleaseDC(m.HWnd, hdc); } break; } } } }
Btw. I called DisableProcessWindowsGhosting
, this will stop the OS from drawing the non-client area if the application takes too long to respond to windows messages. If you do not do this, then in some situations the border will be renderd but your adornments will not be shown. So that depends on your requirements it that is right for you or not.
Prompted by the comment from @TheCodeKing, I thought I would take another look at this. It turns out this can be done in a fully documented way while supporting Aero. But it is not for the faint of heart. I will not provide a complete solution here, there are still some kinks to workout, but it does the basics.
This code/solution is based off the Win32 example which can be found at the following location http://msdn.microsoft.com/en-us/library/bb688195(VS.85).aspx
In principal what you need to do is the following.
The above steps will give you a windows with the standard glass frame excluding the system menu (Window Icon) and the title. The minimize, maximize and close buttons will still be drawn and will work. What you will not be able to do is drag or resize the window, this is because the frame is not really there, remember the client area covers the whole window, we have just asked the OS to draw the frame onto the client area.
Now you can draw on the window as normal, even on top of the frame. You can even put controls in the caption area.
Finally, allow the DWM to handle hit-testing for you, by calling DwmDefWindowProc from your WndProc
(before you've processed it). It returns a boolean indicating whether the DWM handled the message for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With