应用程序卡在全屏?

时间:2013-06-05 05:00:02

标签: c# winforms

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

  1. 使用C#创建新的Windows窗体应用程序。
  2. 在Form1的“属性”窗口中,将FormBorderStyle设置为None
  3. 启动程序并按 Windows + Up
  4. 现在你陷入了全屏。
  5. 在默认FormBorderStyle设置中,MaximizeBox属性为false将禁用 Windows + 向上全屏快捷方式。

    如果FormBorderStyle设置为None Microsoft决定禁用除向上箭头之外的所有Windows +箭头键快捷键,然后禁用{{1}禁用属性。

    这是一个小故障吗?任何简单方式禁用此快捷方式功能的方法是在所有其他FormBorderStyles 上禁用此方法吗?

4 个答案:

答案 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 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);
   }
}

已更新有关如何在您的案例LwinRWin

中停用Windows密钥
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函数。