Приложение застряло в полноэкранном режиме?

Чтобы воспроизвести мою проблему, выполните следующие действия:

  • Создайте новое приложение Windows Form на С#.
  • В окне свойств Form1 установите FormBorderStyle в None.
  • Запустите программу и нажмите Windows + Up.
  • Теперь вы застряли в полноэкранном режиме.

В настройке по умолчанию FormBorderStyle свойство MaximizeBox на false отключит ярлык Windows + Up полноэкранного режима.

Если для параметра FormBorderStyle установлено значение None, Microsoft решила, что было бы неплохо отключить все ярлыки клавиш со стрелками Windows +, за исключением стрелки вверх, а затем отключить отключение свойства MaximizeBox.

Это глюк? Любой простой способ отключить эту функцию быстрого доступа тем же способом, который отключен для всех других форм FormBorderStyles?

Ответ 1

Проверьте это решение - он удаляет Maximize/Minimize/Titlebar/Border по вызовам 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.

Ответ 2

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.

Ответ 3

Переопределение 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);
   }
}

Обновлено о том, как отключить Windows Ключ в вашем случае 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());
        }


    }

Ответ 4

Отсканируйте сообщение WM_GETMINMAXINFO, которое позволит вам указать максимальный размер и местоположение вашей формы. Технически ваша форма все равно изменит состояние на Maximized, но будет выглядеть так же, поскольку мы указываем максимальный размер/положение как то же самое, что и нормальное состояние формы:

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

}