はじめに
通常のプロパティでは閉じるボタンだけを無効化できないので、その対応です。
環境
- 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);
}
おわりに
まあまあ良く使うと思います。