要重现我的问题,请执行以下操作:
FormBorderStyle
设置为None
。在默认FormBorderStyle
设置中,MaximizeBox
属性为false将禁用 Windows + 向上全屏快捷方式。
如果FormBorderStyle
设置为None
Microsoft决定禁用除向上箭头之外的所有Windows +箭头键快捷键,然后禁用{{1}禁用属性。
这是一个小故障吗?任何简单方式禁用此快捷方式功能的方法是在所有其他FormBorderStyles 上禁用此方法吗?
答案 0 :(得分:7)
Windows通过调用SetWindowPos()来改变窗口的位置和大小。通过监听WM_WINDOWPOSCHANGING消息并覆盖设置,可以通知窗口。你可以做很多事情,比如通过根据自己的喜好调整大小和位置来保持操作意义。你可以通过打开NOSIZE和NOMOVE标志来完全阻止它。
将此代码粘贴到表单中:
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);
}
如果您想自己更改窗口,只需将AllowWindowChange字段暂时设置为true。
答案 1 :(得分:2)
覆盖ProcessCmdKey
(表单中的受保护方法)明确允许我们应用自定义挂钩并可以在您的方案中使用。这基本上允许我们覆盖内置击键处理。
注意:以下示例演示了如何处理不同击键或其组合的想法。现在,您可能需要微调以下代码以与您的方案一起工作。例如:当用户按下FormBorderStyle
箭头时,理想情况下更改Form Size
或LWin+Up
。
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);
}
}
已更新有关如何在您的案例Lwin
或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());
}
}
答案 2 :(得分:2)
捕获WM_GETMINMAXINFO消息,该消息允许您指定表单的最大大小和位置。从技术上讲,你的表单仍然会将状态更改为最大化,但它会显示相同,因为我们指定最大化的大小/位置与表单的正常状态相同:
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);
}
}
答案 3 :(得分:1)
检查此解决方案 - 它会通过API调用删除Maximize / Minimize / Titlebar / Border。
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();
}
}
这是按预期工作的。通过设置WindowState来最大化/最小化。
人们可以在消息来源中分析框架的作用以及它的“错误”(或不完全正确)。
编辑:我添加了样式值的调试输出。请在Form1构造函数中尝试以下命令序列:
MaximizeBox = false;
FormBorderStyle = FormBorderStyle.Sizable;
HideMinimizeAndMaximizeButtons();
FormBorderStyle = FormBorderStyle.None;
MaximizeBox = true;
MaximizeBox = false;
HideMinimizeAndMaximizeButtons();
FormBorderStyle = FormBorderStyle.None;
HideMinimizeAndMaximizeButtons();
您将看到,设置FormBorderStyle.None启用WS_MAXIMIZEBOX样式。这不能被另一个MaximizeBox = false
“纠正”。似乎有必要调用API函数。