How can I open a window's system menu by code? - winforms

I have a C# WinForms borderless window, for which I override WndProc and handle the WM_NCHITTEST message. For an area of that form, my hit test function returns HTSYSMENU. Double-clicking that area successfully closes the form, but right-clicking it does not show the window's system menu, nor does it show up when right-clicking the window's name in the taskbar.
This form uses these styles:
this.SetStyle( ControlStyles.AllPaintingInWmPaint, true );
this.SetStyle( ControlStyles.UserPaint, true );
this.SetStyle( ControlStyles.OptimizedDoubleBuffer, true );
this.SetStyle( ControlStyles.ResizeRedraw, true );
And has these non-default property values:
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.KeyPreview = true;
this.MaximizeBox = false;
this.MinimizeBox = false;
I've tried handling WM_NCRBUTTONDOWN and WM_NCRBUTTONUP, and send the WM_GETSYSMENU message, but it didn't work.

A borderless window, if I am not mistaken, is flagged such that it offers no system menu, and that it does not appear in the taskbar.
The fact that any given window does not have a border and does not appear in the taskbar is the result of the style flags set on the window. These particular Style flags can be set using the GetWindowLong and SetWindowLong API calls. However you have to be careful as certain styles just don't work together.
I have written a number of custom controls over the years and I am constantly coaxing windows to become something they weren't originally intended to be.
For example I have written my own dropdown control where I needed a window to behave as a popup and not to activate.
The following code will do that. Note that the code appears in the OnHandleCreated event handler. This is because the flags need to be changed just after the handle is setup which indicates that Windows has already set what it thinks the flags should be.
using System.Runtime.InteropServices;
protected override void OnHandleCreated(EventArgs e) {
uint dwWindowProperty;
User32.SetParent(this.Handle, IntPtr.Zero);
dwWindowProperty = User32.GetWindowLong( this.Handle, User32.GWL.EXSTYLE );
dwWindowProperty = dwWindowProperty | (uint)User32.WSEX.TOOLWINDOW | (uint)User32.WSEX.NOACTIVATE;
User32.SetWindowLong( this.Handle, User32.GWL.EXSTYLE, dwWindowProperty );
dwWindowProperty = User32.GetWindowLong( this.Handle, User32.GWL.STYLE );
dwWindowProperty = ( dwWindowProperty & ~(uint)User32.WS.CHILD ) | (uint)User32.WS.POPUP;
User32.SetWindowLong( this.Handle, User32.GWL.STYLE, dwWindowProperty );
base.OnHandleCreated (e);
}
//this is a fragment of my User32 library wrapper needed for the previous code segment.
class User32
{
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);
[DllImport("user32.dll", CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall )]
public static extern int SetWindowLong( IntPtr hWnd, User32.GWL gwlIndex, uint dwNewLong);
[DllImport("user32.dll", CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall )]
public static extern uint GetWindowLong( IntPtr hWnd, User32.GWL gwlIndex );
[FlagsAttribute]
public enum WS: uint {
POPUP = 0x80000000,
CHILD = 0x40000000,
}
public enum GWL {
STYLE = -16,
EXSTYLE = -20
}
[FlagsAttribute]
public enum WSEX: uint {
TOP = 0x0,
TOPMOST = 0x8,
TOOLWINDOW = 0x80,
NOACTIVATE = 0x08000000,
}
}
Unfortunately the SysMenu style cannot be set without using the Caption style, so I can't say if this is a problem in your implementation.
You can check out the original style list and the extend style list at these two links:
Window Styles
CreateWindowEx

I have the same properties in my application and Right click doesn't work either, so this is not your problem, it appears to be the way windows forms respond when they have no border.
If you set your border to the normal value, you will be able to have right click in the taskbar and such.
For right click on other controls, you'll need to set the ContextMenuStrip and provide your "menu". But I'm not sure if this works when you have it without border. I have been unable to make it work.

protected override void WndProc( ref System.Windows.Forms.Message m )
{ // RightClickMenu
if ( m.Msg == 0x313 )
{
this.contextMenuStrip1.Show(this, this.PointToClient(new Point(m.LParam.ToInt32())));
}}
This detects rightclick on the applications taskbar "area"..
maybe it will help ?

Related

Activate WPF Window without losing focus on previous application/window

I have a WPF window in application which I Activate on some specific scenarios by calling MainView.Activate(); and MainView.BringIntoView(); method. it also sets focus on this 'MainView' window.
But my requirement is this window should not get Focus. i.e. my cursor should still remain on previous application(notepad,word etc..)
I tried using MainView.ShowActivated="False" but it didn't work.
Do I need to use HwndSource as mentioned here or what?
Code I have used after Kent's help (Its working only if Window is minimized):
IntPtr HWND_TOPMOST = new IntPtr(-1);
const short SWP_NOMOVE = 0X2;
const short SWP_NOSIZE = 1;
const short SWP_NOZORDER = 0X4;
const int SWP_SHOWWINDOW = 0x0040;
Process[] processes = Process.GetProcesses(".");
foreach (var process in processes)
{
IntPtr handle = process.MainWindowHandle;
if (handle != IntPtr.Zero)
{
SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_SHOWWINDOW);
}
}
I Have Win32 helper class for such situation here is listing for your case
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
namespace your.namespace {
public static class Win32 {
public static void ShowWindowNoActive( Window window) {
var hwnd = (HwndSource.FromVisual(window) as HwndSource).Handle;
ShowWindow(hwnd, ShowWindowCommands.SW_SHOWNOACTIVATE);
}
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, ShowWindowCommands nCmdShow);
private enum ShowWindowCommands : int {
SW_SHOWNOACTIVATE = 4
}
}
}
Let's call the window that you want to show without focus: YourWindow. Add the following code:
YourWindow.ShowActivated = false;
YourWindow.Owner = TheOtherWindowThatWillStilHaveFocus;
First line you can also set from XAML.
In my recent blog post, I use SetWindowPos to bring a window to the front of the z-order without giving it focus. I don't believe WPF has an in-built means of achieving the same without p/invoke.
I needed to solve a similar problem and got it to work by setting Window.ShowActivate=false and then using Window.Show rather than Window.Activate. Perhaps this will work for you. I have not yet needed to use BringIntoView because my window is newly created and appears on top of other windows by default.

WPF: Non focusable window

I am developing WPF Touch Screen Keyboard.
I need to know how is it possible to make main window non focusable, so other windows will be receiving the input when I click on virtual keyboard buttons.
Simple applying "Focusable="False"" to the main window and all child controls doesn't work.
I think there is a clickable attribute you can set to false which stops the form receiving click messages.
Problem was solved by using Popup instead of Window, which not grab the focus, when you click on it.
From here: https://social.msdn.microsoft.com/Forums/vstudio/en-US/41ca3605-247c-4c5b-ac5d-74ce5abd7b92/making-a-window-invisible-to-mouse-events-ishittestvisiblefalse-not-working?forum=wpf
I've figured out how to do this. The key being the WS_EX_TRANSPARENT flag for the window's extended style.You can set the topmost property like you normally would, then this code takes care of making the window transparent to mouse clicks:
Code Snippet
public const int WS_EX_TRANSPARENT = 0x00000020;
public const int GWL_EXSTYLE = (-20);
[DllImport("user32.dll")]
public static extern int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
public static extern int SetWindowLong(IntPtr hwnd, int index, int newStyle);
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
// Get this window's handle
IntPtr hwnd = new WindowInteropHelper(this).Handle;
// Change the extended window style to include WS_EX_TRANSPARENT
int extendedStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, extendedStyle | WS_EX_TRANSPARENT);
}

Some questions about focus on WPF

I've a little problem about focus on WPF.
I whant to create a window, always on top, and that never get the focus (even if we click on it).
Here's my solution :
public partial class SkinWindow : Window
{
public SkinWindow()
{
InitializeComponent();
Loaded += ( object sender, RoutedEventArgs e ) => SetNoActiveWindow();
}
private void SetNoActiveWindow()
{
WindowInteropHelper helper = new WindowInteropHelper( this );
SetWindowLong( helper.Handle, GWL_EXSTYLE, WS_EX_NOACTIVATE );
LockSetForegroundWindow( LSFW_LOCK );
}
const int GWL_EXSTYLE = -20;
const int WS_EX_NOACTIVATE = 134217728;
const int LSFW_LOCK = 1;
[DllImport( "user32" )]
public static extern bool LockSetForegroundWindow( uint UINT );
[DllImport( "user32" )]
public static extern IntPtr SetWindowLong( IntPtr hWnd, int nIndex, int dwNewLong );
}
First problem : It's works, but I've to select an other window to "remove" the focus of my application (after the focus is not gave again, even if I click on my window).
Second problem : When I move or resize the window, the modifications happens when I drop the window.
Do you have any ideas / links / docs ?
Thank you :)
You might want to have a look at this SO post: Make a form not focusable in C#. The answer is specific to Windows Forms. However, the main part is done using Win32 functions, so maybe you can get some ideas from there...

Custom draw Aero title bar without extending into client area

My WinForms application has the standard Aero glass appearance on Vista/Windows 7.
I want to custom draw the window title bar so it retains the Aero glass appearance with the glass min/max/close buttons but without the title text and window icon. I have tried this by overriding WM_NCPAINT but overriding this event always causes the glass to be removed.
Does anyone know how to override WM_NCPAINT with glass in place in order to effectively draw over the glass area correctly?
I don't have a solution involving WM_NCPAINT, but I have a solution that does what you want it to do, and perhaps cleaner than the WM_NCPAINT-version would be.
First define this class. You'll use its types and functions to achieve your desired functionality:
internal class NonClientRegionAPI
{
[DllImport( "DwmApi.dll" )]
public static extern void DwmIsCompositionEnabled( ref bool pfEnabled );
[StructLayout( LayoutKind.Sequential )]
public struct WTA_OPTIONS
{
public WTNCA dwFlags;
public WTNCA dwMask;
}
[Flags]
public enum WTNCA : uint
{
NODRAWCAPTION = 1,
NODRAWICON = 2,
NOSYSMENU = 4,
NOMIRRORHELP = 8,
VALIDBITS = NODRAWCAPTION | NODRAWICON | NOSYSMENU | NOMIRRORHELP
}
public enum WINDOWTHEMEATTRIBUTETYPE : uint
{
/// <summary>Non-client area window attributes will be set.</summary>
WTA_NONCLIENT = 1,
}
[DllImport( "uxtheme.dll" )]
public static extern int SetWindowThemeAttribute(
IntPtr hWnd,
WINDOWTHEMEATTRIBUTETYPE wtype,
ref WTA_OPTIONS attributes,
uint size );
}
Next, in your form, you simply do this:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// Set your options. We want no icon and no caption.
SetWindowThemeAttributes( NonClientRegionAPI.WTNCA.NODRAWCAPTION | NonClientRegionAPI.WTNCA.NODRAWICON );
}
private void SetWindowThemeAttributes( NonClientRegionAPI.WTNCA attributes )
{
// This tests that the OS will support what we want to do. Will be false on Windows XP and earlier,
// as well as on Vista and 7 with Aero Glass disabled.
bool hasComposition = false;
NonClientRegionAPI.DwmIsCompositionEnabled( ref hasComposition );
if( !hasComposition )
return;
NonClientRegionAPI.WTA_OPTIONS options = new NonClientRegionAPI.WTA_OPTIONS();
options.dwFlags = attributes;
options.dwMask = NonClientRegionAPI.WTNCA.VALIDBITS;
// The SetWindowThemeAttribute API call takes care of everything
NonClientRegionAPI.SetWindowThemeAttribute(
this.Handle,
NonClientRegionAPI.WINDOWTHEMEATTRIBUTETYPE.WTA_NONCLIENT,
ref options,
(uint)Marshal.SizeOf( typeof( NonClientRegionAPI.WTA_OPTIONS ) ) );
}
}
Here's the result:
http://img708.imageshack.us/img708/1972/noiconnocaptionform.png
I normally make a base class that implements Form with all my funky extended behavior and then let my actual forms implement that base class, but if you only need it for one Form, just put it all in there.

How to remove minimize and maximize buttons from a resizable window?

WPF doesn't provide the ability to have a window that allows resize but doesn't have maximize or minimize buttons. I'd like to able to make such a window so I can have resizable dialog boxes.
I'm aware the solution will mean using pinvoke but I'm not sure what to call and how. A search of pinvoke.net didn't turn up any thing that jumped out at me as what I needed, mainly I'm sure because Windows Forms does provide the CanMinimize and CanMaximize properties on its windows.
Could someone point me towards or provide code (C# preferred) on how to do this?
I've stolen some code I found on the MSDN forums and made an extension method on the Window class, like this:
internal static class WindowExtensions
{
// from winuser.h
private const int GWL_STYLE = -16,
WS_MAXIMIZEBOX = 0x10000,
WS_MINIMIZEBOX = 0x20000;
[DllImport("user32.dll")]
extern private static int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
extern private static int SetWindowLong(IntPtr hwnd, int index, int value);
internal static void HideMinimizeAndMaximizeButtons(this Window window)
{
IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
var currentStyle = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, (currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX));
}
}
The only other thing to remember is that for some reason this doesn't work from a window's constructor. I got around that by chucking this into the constructor:
this.SourceInitialized += (x, y) =>
{
this.HideMinimizeAndMaximizeButtons();
};
One way is to set your ResizeMode="NoResize". It will behave like this.
Don't know if this works for your req. visually.. This is
<Window x:Class="DataBinding.MyWindow" ...Title="MyWindow" Height="300" Width="300"
WindowStyle="ToolWindow" ResizeMode="CanResizeWithGrip">
If anyone use Devexpress window (DXWindow) accepted answer doesn't work. One ugly approach is
public partial class MyAwesomeWindow : DXWindow
{
public MyAwesomeWIndow()
{
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
// hides maximize button
Button button = (Button)DevExpress.Xpf.Core.Native.LayoutHelper.FindElementByName(this, DXWindow.ButtonParts.PART_Maximize.ToString());
button.IsHitTestVisible = false;
button.Opacity = 0;
// hides minimize button
button = (Button)DevExpress.Xpf.Core.Native.LayoutHelper.FindElementByName(this, DXWindow.ButtonParts.PART_Minimize.ToString());
button.IsHitTestVisible = false;
button.Opacity = 0;
// hides close button
button = (Button)DevExpress.Xpf.Core.Native.LayoutHelper.FindElementByName(this, DXWindow.ButtonParts.PART_CloseButton.ToString());
button.IsHitTestVisible = false;
button.Opacity = 0;
}
}
Here's a solution I'm using. Note that maximize button is still displayed.
Markup:
<Window x:Class="Example"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Example"
StateChanged="Window_StateChanged">
Code behind:
// Disable maximizing this window
private void Window_StateChanged(object sender, EventArgs e)
{
if (this.WindowState == WindowState.Maximized)
this.WindowState = WindowState.Normal;
}
This variant of the solution proposed by #MattHamilton can (and must) be called in the constructor of the Window. The trick is to subscribe a delegate to the SourceInitialized event within the extension method.
private const int GWL_STYLE = -16, WS_MAXIMIZEBOX = 0x10000, WS_MINIMIZEBOX = 0x20000;
[DllImport("user32.dll")]
extern private static int GetWindowLong(IntPtr hwnd, int index);
[DllImport("user32.dll")]
extern private static int SetWindowLong(IntPtr hwnd, int index, int value);
/// <summary>
/// Hides the Minimize and Maximize buttons in a Window. Must be called in the constructor.
/// </summary>
/// <param name="window">The Window whose Minimize/Maximize buttons will be hidden.</param>
public static void HideMinimizeAndMaximizeButtons(this Window window)
{
window.SourceInitialized += (s, e) => {
IntPtr hwnd = new System.Windows.Interop.WindowInteropHelper(window).Handle;
int currentStyle = GetWindowLong(hwnd, GWL_STYLE);
SetWindowLong(hwnd, GWL_STYLE, currentStyle & ~WS_MAXIMIZEBOX & ~WS_MINIMIZEBOX);
};
}
You can set the ResizeMode="NoResize" of the window if you want to remove Minimize and Maximize button
Just use
WindowStyle="ToolWindow"
It hides the maximize and minimize buttons, but the window can still be resized by dragging the window borders and minimize using the hide button in the bottom right corner of the taskbar.
https://learn.microsoft.com/en-us/dotnet/api/system.windows.window.windowstyle?view=windowsdesktop-6.0

Resources