Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

This article is a Private article. Only a writer and users who know the URL can access it.
Please change open range to public in publish setting if you want to share this article with other users.

WPF タイトルバーの閉じるボタンを無効化する方法

0
Posted at

はじめに

通常のプロパティでは閉じるボタンだけを無効化できないので、その対応です。

環境

  • Visual Studio Community 2022
  • .NET 8.0

ソース

閉じるボタンだけでなく、最大化や最小化も制御できます。

WindowButtonDisabler.cs
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;

namespace Utilities;

/// <summary>
/// ウィンドウの最大化・最小化・閉じるボタンを無効化する機能を提供します。
/// </summary>
public static class WindowButtonDisabler
{
    [DllImport("user32.dll", EntryPoint = "GetWindowLong")]
    private static extern int GetWindowLong(IntPtr hWnd, int nIndex);

    [DllImport("user32.dll", EntryPoint = "SetWindowLong")]
    private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);

    [DllImport("user32.dll")]
    private static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);

    [DllImport("user32.dll")]
    private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);

    private const int GWL_STYLE = -16;
    private const int WM_SYSCOMMAND = 0x112;
    private const int WS_MAXIMIZEBOX = 0x10000;
    private const int WS_MINIMIZEBOX = 0x20000;
    private const uint MF_BYCOMMAND = 0x00000000;
    private const uint MF_GRAYED = 0x00000001;
    private const uint SC_CLOSE = 0xF060;

    /// <summary>
    /// 指定したウィンドウの最大化・最小化・閉じるボタンを無効化します。
    /// </summary>
    public static void Apply(Window window, bool disableMaximize = false, bool disableMinimize = false, bool disableClose = false)
    {
        // ウィンドウハンドルを取得する。
        var handle = new WindowInteropHelper(window).Handle;
        if (handle == IntPtr.Zero)
        {
            return;
        }

        // 現在のウィンドウスタイルを取得する。
        var style = GetWindowLong(handle, GWL_STYLE);

        // 最大化ボタンを無効化する。
        if (disableMaximize)
        {
            style &= ~WS_MAXIMIZEBOX;
        }

        // 最小化ボタンを無効化する。
        if (disableMinimize)
        {
            style &= ~WS_MINIMIZEBOX;
        }

        // 変更したスタイルをウィンドウに適用する。
        _ = SetWindowLong(handle, GWL_STYLE, (int)style);

        // 閉じるボタンを無効化する。
        if (disableClose)
        {
            // システムメニューの閉じるボタンを無効化する。
            var hMenu = GetSystemMenu(handle, false);
            if (hMenu != IntPtr.Zero)
            {
                EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
            }

            // Alt + F4 やタイトルバーの閉じるボタンなどを無効化する。
            if (PresentationSource.FromVisual(window) is HwndSource hwndSource)
            {
                hwndSource.AddHook(delegate (IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
                {
                    if (msg == WM_SYSCOMMAND && (wParam.ToInt32() & 0xFFF0) == SC_CLOSE)
                    {
                        handled = true;
                    }

                    return IntPtr.Zero;
                });
            }
        }
    }
}

使い方

MainWindow の OnSourceInitialized イベントで適用します。

MainWindow.cs
protected override void OnSourceInitialized(EventArgs e)
{
    base.OnSourceInitialized(e);
    WindowButtonDisabler.Apply(this, disableClose: true);
}

おわりに

まあまあ良く使うと思います。

0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?