12

要重现我的问题,请执行以下操作:

  1. 在 C# 中创建一个新的 Windows 窗体应用程序。
  2. 在 Form1 的属性窗口中设置FormBorderStyleNone.
  3. 启动程序并按Windows+ Up
  4. 现在你被困在全屏中。

在默认FormBorderStyle设置中,该MaximizeBox属性为 false 将禁用Windows+Up全屏快捷方式。

如果FormBorderStyle设置为NoneMicrosoft 决定禁用除向上箭头之外的所有 Windows+箭头键快捷键,然后禁用该MaximizeBox属性的禁用是个好主意。

这是一个故障吗?有什么简单的方法可以禁用此快捷方式功能,就像在所有其他 FormBorderStyles 上禁用它一样

4

4 回答 4

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。

于 2013-06-08T20:35:08.180 回答
2

显式地覆盖ProcessCmdKey(Form 中的受保护方法)允许我们应用自定义钩子并且可以在您的场景中使用。这实质上允许我们覆盖内置的击键处理。

注意以下示例演示了如何处理不同击键或组合击键的想法。现在,您可能需要微调以下代码以适应您的场景。例如:理想情况下,在用户按下箭头时更改FormBorderStyle或。Form SizeLWin+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);
   }
}

更新了如何在您的情况下禁用 windows 键LwinRWin

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());
        }


    }
于 2013-06-05T05:35:47.983 回答
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);
    }

}
于 2013-06-05T05:45:58.023 回答
1

检查此解决方案 - 它通过 API 调用删除最大化/最小化/标题栏/边框。

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 函数。

于 2013-06-08T18:59:33.967 回答