トップ回答者
閉じるボタンを無効にしたい

質問
回答
-
以下を読む限り、ちょっと難しそうですね。
Disable/hide minimize button
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=930576&SiteID=1 -
従来のハンドルフックを使用してですが、閉じるボタンを無効&グレー化することが出来ました。
既にどこかで出てるかもしれませんが、ソース置いておきます。
~【以下ソースコード】~
public partial class Window1 : Window
{
[DllImport("user32.dll")]
private static extern Window1 GetSystemMenu(Window1 hWnd, bool bRevert);
[DllImport("user32.dll")]
private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
private const uint MF_BYCOMMAND = 0x00000000;
private const uint MF_GRAYED = 0x00000001;
private const uint MF_ENABLED = 0x00000000;
private const uint SC_CLOSE = 0xF060;
private const int WM_SHOWWINDOW = 0x00000018;
private const int WM_SYSCOMMAND = 0x112;
private const int WM_CLOSE = 0x10;private HwndSource hwndSource = null;
public Window1()
{
InitializeComponent();
}protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)
{
hwndSource.AddHook(new HwndSourceHook(this.hwndSourceHook));
}
}
private IntPtr hwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SHOWWINDOW)
{
IntPtr hMenu = GetSystemMenu(hwnd, false);
if (hMenu != IntPtr.Zero)
{
EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
}
}
else if (msg == WM_SYSCOMMAND && (wParam.ToInt32() & 0xFFF0) == SC_CLOSE)
{
handled = true;
}
return IntPtr.Zero;
}
} -
hwndsource は,プライベートメンバとしてメソッドから出して,
Window1 が閉じる前にちゃんと RemoveHook() しておいた方が(フック云々をきれいに終えるというより,
HwndSourceのインスタンスがローカル変数でも,
弱参照の関係でずっと残る仕組みになっているので,
Window1インスタンスのwndprocへの参照をHwndSourceのインスタンスから取り除いておいた方が)
コード的には安全側に倒れるんじゃないかと思います。MSDNブログのコードでも後始末をやってないので,なくてもいいのかもしれませんが...
あと,
HwndSource hwndSource = (HwndSource)PresentationSource.FromVisual(this);
if (hwndSource != null)って,
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)ですよね。
すべての返信
-
XBAP などの部分信頼で動くアプリとの関係で,
Windowクラスとは別のクラスを仲介する形にしたんじゃないですかね。
(例えば,下の FromHwnd などで (CAS で) UI Permission が必要になるなど)System.Windows.Interop 名前空間の
・ WindowInteropHelper (このコンストラクタにWPFのWindowインスタンスを渡してハンドルを取得できます。で,HwndSource.FromHwnd に Handle を渡して HwndSource もしくは,いきなり HwndSource.FromVisual で)
・ HwndSource (AddHook, RemoveHook, 弱参照の関係で OnClosedで Dispose もしておいた方が無難かも)
などのクラスを介してやるんじゃないかと思います。
(いわゆる従来のフックしてウィンドウメッセージを横取りする形)ひょっとしたら,簡単にやれる方法もあるのかもしれませんが。
cf. フックする場所ですが,
http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=1390791&SiteID=7
のようにするか,OnSourceInitialized をオーバーライドするか。
-
ご返信ありがとうございます。
稍丼 さんからの引用 System.Windows.Interop 名前空間の
・ WindowInteropHelper (このコンストラクタにWPFのWindowインスタンスを渡してハンドルを取得できます。で,HwndSource.FromHwnd に Handle を渡して HwndSource もしくは,いきなり HwndSource.FromVisual で)
・ HwndSource (AddHook, RemoveHook, 弱参照の関係で OnClosedで Dispose もしておいた方が無難かも)
などのクラスを介してやるんじゃないかと思います。
(いわゆる従来のフックしてウィンドウメッセージを横取りする形)ひょっとしたら,簡単にやれる方法もあるのかもしれませんが。
cf. フックする場所ですが,
http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=1390791&SiteID=7
のようにするか,OnSourceInitialized をオーバーライドするか。
提示していただいたURLを参考にしてみました。
[×]ボタンを押してもウィンドウが閉じなくなったのですが、無効になっていません。
やはり、無効にするにはAPI関数を使うしかないのでしょうか。
-----[ 以下ソースコード ]-------------------------------------------------------------------------------------------
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();}
protected override void OnSourceInitialized(EventArgs e)
{
HwndSource hwndSource = (HwndSource)PresentationSource.FromVisual(this);
hwndSource.AddHook(Hook);base.OnSourceInitialized(e);
}
private const int WM_SYSCOMMAND = 0x112;
private const int SC_CLOSE = 0xF060;private static IntPtr Hook(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;
}
} -
以下を読む限り、ちょっと難しそうですね。
Disable/hide minimize button
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=930576&SiteID=1 -
trapemiya様、稍丼様ご回答ありがとうござます。
trapemiya さんからの引用 以下を読む限り、ちょっと難しそうですね。
Disable/hide minimize button
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=930576&SiteID=1上記URL内にあったブログhttp://pavanpodila.spaces.live.com/のサンプルを見ました。
WPFのWindowクラスは、やはり継承されるクラスがWinFormとは違うので、単純にオーバーライドするだけでは難しいようですね。サンプルのようにオリジナルでタイトルバーごとオーナードローすれば大丈夫そうですが、まだまだWPFに未熟なので今回はもう少し様子を見てみます。
-
従来のハンドルフックを使用してですが、閉じるボタンを無効&グレー化することが出来ました。
既にどこかで出てるかもしれませんが、ソース置いておきます。
~【以下ソースコード】~
public partial class Window1 : Window
{
[DllImport("user32.dll")]
private static extern Window1 GetSystemMenu(Window1 hWnd, bool bRevert);
[DllImport("user32.dll")]
private static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
private const uint MF_BYCOMMAND = 0x00000000;
private const uint MF_GRAYED = 0x00000001;
private const uint MF_ENABLED = 0x00000000;
private const uint SC_CLOSE = 0xF060;
private const int WM_SHOWWINDOW = 0x00000018;
private const int WM_SYSCOMMAND = 0x112;
private const int WM_CLOSE = 0x10;private HwndSource hwndSource = null;
public Window1()
{
InitializeComponent();
}protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)
{
hwndSource.AddHook(new HwndSourceHook(this.hwndSourceHook));
}
}
private IntPtr hwndSourceHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
if (msg == WM_SHOWWINDOW)
{
IntPtr hMenu = GetSystemMenu(hwnd, false);
if (hMenu != IntPtr.Zero)
{
EnableMenuItem(hMenu, SC_CLOSE, MF_BYCOMMAND | MF_GRAYED);
}
}
else if (msg == WM_SYSCOMMAND && (wParam.ToInt32() & 0xFFF0) == SC_CLOSE)
{
handled = true;
}
return IntPtr.Zero;
}
} -
hwndsource は,プライベートメンバとしてメソッドから出して,
Window1 が閉じる前にちゃんと RemoveHook() しておいた方が(フック云々をきれいに終えるというより,
HwndSourceのインスタンスがローカル変数でも,
弱参照の関係でずっと残る仕組みになっているので,
Window1インスタンスのwndprocへの参照をHwndSourceのインスタンスから取り除いておいた方が)
コード的には安全側に倒れるんじゃないかと思います。MSDNブログのコードでも後始末をやってないので,なくてもいいのかもしれませんが...
あと,
HwndSource hwndSource = (HwndSource)PresentationSource.FromVisual(this);
if (hwndSource != null)って,
HwndSource hwndSource = PresentationSource.FromVisual(this) as HwndSource;
if (hwndSource != null)ですよね。