To reproduce my problem please do the following:
FormBorderSt
Check this solution - it removes Maximize/Minimize/Titlebar/Border by API calls.
public partial class Form1 : Form
{
// import necessary API functions to get and set Windows styles for P/Invoke
[DllImport("user32.dll")]
internal extern static int SetWindowLong(IntPtr hwnd, int index, int value);
[DllImport("user32.dll")]
internal extern static int GetWindowLong(IntPtr hwnd, int index);
// define constants like they are named in SDK in order to make source more readable
const int GWL_STYLE = -16;
const int GWL_EXSTYLE = -20;
const int WS_MINIMIZEBOX = 0x00020000;
const int WS_MAXIMIZEBOX = 0x00010000;
const int WS_CAPTION = 0x00C00000;
const int WS_THICKFRAME = 0x00040000;
const int WS_EX_DLGMODALFRAME = 0x00000001;
const int WS_EX_CLIENTEDGE = 0x00000200;
const int WS_EX_STATICEDGE = 0x00020000;
// this replaces MinimizeBox=false and MaximizeBox=false
void HideMinimizeAndMaximizeButtons()
{
// read current style
int style = GetWindowLong(Handle, GWL_STYLE);
Debug.WriteLine("0x{0:X}", style);
// update style - remove flags for MinimizeBox and MaximizeBox
style = style & ~WS_MINIMIZEBOX & ~WS_MAXIMIZEBOX;
Debug.WriteLine("0x{0:X}", style);
SetWindowLong(Handle, GWL_STYLE, style);
}
// part of removing the whole border
void HideTitleBar()
{
// read current style
int style = GetWindowLong(Handle, GWL_STYLE);
Debug.WriteLine("0x{0:X}", style);
// update style - remove flag for caption
style = style & ~WS_CAPTION;
Debug.WriteLine("0x{0:X}", style);
SetWindowLong(Handle, GWL_STYLE, style);
}
// hide the border
void HideBorder()
{
// read current style
int style = GetWindowLong(Handle, GWL_STYLE);
Debug.WriteLine("0x{0:X}", style);
// update style - remove flag for border (could use WS_SIZEBOX which is the very same flag (see MSDN)
style = style & ~WS_THICKFRAME;
Debug.WriteLine("0x{0:X}", style);
SetWindowLong(Handle, GWL_STYLE, style);
// read current extended style
style = GetWindowLong(Handle, GWL_EXSTYLE);
Debug.WriteLine("0x{0:X}", style);
// update style by removing some additional border styles -
// may not be necessary, when current border style is not something exotic,
// i.e. as long as it "normal"
style = style & ~WS_EX_DLGMODALFRAME & ~WS_EX_CLIENTEDGE & ~WS_EX_STATICEDGE;
Debug.WriteLine("0x{0:X}", style);
SetWindowLong(Handle, GWL_EXSTYLE, style);
}
public Form1()
{
InitializeComponent();
// hide those unwanted properties - you can try to leave out one or another to see what it does
HideMinimizeAndMaximizeButtons();
HideTitleBar();
HideBorder();
}
}
This works as intended. Maximizing/minimizing by setting WindowState works as well.
One could analyze in sources what the framework does and what it does "wrong" (or not quite correct).
Edit: I added debug output of the style values. Please try this sequence of commands in Form1 constructor:
MaximizeBox = false;
FormBorderStyle = FormBorderStyle.Sizable;
HideMinimizeAndMaximizeButtons();
FormBorderStyle = FormBorderStyle.None;
MaximizeBox = true;
MaximizeBox = false;
HideMinimizeAndMaximizeButtons();
FormBorderStyle = FormBorderStyle.None;
HideMinimizeAndMaximizeButtons();
You'll see, that setting FormBorderStyle.None enables the WS_MAXIMIZEBOX style. This cannot be "corrected" by another MaximizeBox = false
. It seems it's necessary to call API functions.
Overriding the ProcessCmdKey
(protected method in Form) explicitly allow us to apply custom hook and can be used in your scenario. This essentially allow us to override built-in keystroke handling.
Note: Following example demonstrate the idea of how to handle different keystroke or combination of it. Now, you probably need to fine tune the following code to work inline with your scenario. Eg: Ideally changing the FormBorderStyle
or Form Size
when user press the LWin+Up
arrow.
public partial class Form1 : Form
{
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == (Keys.LWin | Keys.Up))//Left windows key + up arrow
{
FormBorderStyle = FormBorderStyle.FixedDialog;
return true;
}
if (keyData == Keys.Escape) //Form will call its close method when we click Escape.
Close();
return base.ProcessCmdKey(ref msg, keyData);
}
}
Updated on How to disable windows Key in your case Lwin
or RWin
public partial class Form1 : Form
{
// Structure contain information about low-level keyboard input event
[StructLayout(LayoutKind.Sequential)]
private struct KBDLLHOOKSTRUCT
{
public Keys key;
public int scanCode;
public int flags;
public int time;
public IntPtr extra;
}
//System level functions to be used for hook and unhook keyboard input
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int id, LowLevelKeyboardProc callback, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hook);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hook, int nCode, IntPtr wp, IntPtr lp);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string name);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern short GetAsyncKeyState(Keys key);
//Declaring Global objects
private IntPtr ptrHook;
private LowLevelKeyboardProc objKeyboardProcess;
public Form1()
{
ProcessModule objCurrentModule = Process.GetCurrentProcess().MainModule;
objKeyboardProcess = new LowLevelKeyboardProc(captureKey);
ptrHook = SetWindowsHookEx(13, objKeyboardProcess, GetModuleHandle(objCurrentModule.ModuleName), 0);
InitializeComponent();
}
private IntPtr captureKey(int nCode, IntPtr wp, IntPtr lp)
{
if (nCode >= 0)
{
KBDLLHOOKSTRUCT objKeyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lp, typeof(KBDLLHOOKSTRUCT));
if (objKeyInfo.key == Keys.RWin || objKeyInfo.key == Keys.LWin) // Disabling Windows keys
{
return (IntPtr)1;
}
}
return CallNextHookEx(ptrHook, nCode, wp, lp);
}
private void Form1_KeyPress(object sender, KeyPressEventArgs e)
{
MessageBox.Show(e.KeyChar.ToString());
}
}
Trap the WM_GETMINMAXINFO message which will allow you to specify the maximized size and location of your form. Technically your form will still change state to Maximized, but it will appear the same since we specify the maximized size/position to be the same as the normal state of the form:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
public struct POINTAPI
{
public Int32 X;
public Int32 Y;
}
public struct MINMAXINFO
{
public POINTAPI ptReserved;
public POINTAPI ptMaxSize;
public POINTAPI ptMaxPosition;
public POINTAPI ptMinTrackSize;
public POINTAPI ptMaxTrackSize;
}
public const Int32 WM_GETMINMAXINFO = 0x24;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_GETMINMAXINFO:
MINMAXINFO mmi = (MINMAXINFO)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(MINMAXINFO));
mmi.ptMaxSize.X = this.Width;
mmi.ptMaxSize.Y = this.Height;
mmi.ptMaxPosition.X = this.Location.X;
mmi.ptMaxPosition.Y = this.Location.Y;
System.Runtime.InteropServices.Marshal.StructureToPtr(mmi, m.LParam, true);
break;
}
base.WndProc(ref m);
}
}
Windows does this by calling SetWindowPos() to change the position and size of the window. A window can be notified about this by listening for the WM_WINDOWPOSCHANGING message and override the settings. Lots of things you can do, like still giving the operation a meaning by adjusting the size and position to your liking. You completely prevent it by turning on the NOSIZE and NOMOVE flags.
Paste this code into your form:
private bool AllowWindowChange;
private struct WINDOWPOS {
public IntPtr hwnd, hwndInsertAfter;
public int x, y, cx, cy;
public int flags;
}
protected override void WndProc(ref Message m) {
// Trap WM_WINDOWPOSCHANGING
if (m.Msg == 0x46 && !AllowWindowChange) {
var wpos = (WINDOWPOS)System.Runtime.InteropServices.Marshal.PtrToStructure(m.LParam, typeof(WINDOWPOS));
wpos.flags |= 0x03; // Turn on SWP_NOSIZE | SWP_NOMOVE
System.Runtime.InteropServices.Marshal.StructureToPtr(wpos, m.LParam, false);
}
base.WndProc(ref m);
}
When you want to change the window yourself, simply set the AllowWindowChange field temporarily to true.