[英]Why are Maximize/Minimize events causing the Close Button to be re-enabled after disabling it?
我使用P / Invoke調用GetSystemMenu和EnableMenuItem(win32api)來禁用關閉功能。 但是,在最小化或最大化我的Windows窗體應用程序后,將重新啟用該按鈕。
顯然,最小化或最大化會導致行為,但如何? 我不知道在哪里可以防止這種行為。
我應該阻止最大化和最小化行為,還是IP /調用呼叫的方式有什么特別的錯誤? 加載應用程序(主窗體)后,我會通過單擊按鈕調用靜態方法。
class PInvoke
{
// P/Invoke signatures
[DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[DllImport("user32.dll")]
static extern bool EnableMenuItem(IntPtr hMenu, uint uIDEnableItem, uint uEnable);
// SysCommand (WM_SYSCOMMAND) constant
internal const UInt32 SC_CLOSE = 0xF060;
// Constants used with Add/Check/EnableMenuItem
internal const UInt32 MF_BYCOMMAND = 0x00000000;
internal const UInt32 MF_ENABLED = 0x00000000;
internal const UInt32 MF_GRAYED = 0x00000001;
internal const UInt32 MF_DISABLED = 0x00000002;
/// <summary>
/// Sets the state of the Close (X) button and the System Menu close functionality.
/// </summary>
/// <param name="window">Window or Form</param>
/// <param name="bEnabled">Enabled state</param>
public static void EnableCloseButton(IWin32Window window, bool bEnabled)
{
IntPtr hSystemMenu = GetSystemMenu(window.Handle, false);
EnableMenuItem(hSystemMenu, SC_CLOSE, MF_BYCOMMAND | (bEnabled ? MF_ENABLED : MF_GRAYED));
}
}
接受的答案確實提出了問題的可能解決方法(以及我多次使用過的問題),但它根本沒有回答最初提出的問題:
在使用
GetSystemMenu
和EnableMenuItem
API函數禁用關閉按鈕之后,最大化或最小化窗體的原因是什么/為什么導致關閉按鈕重新啟用?
在發現這種看似無法解釋的行為之后,我在完全沒有結果的Google搜索過程中得出了這個問題。 找不到實際解釋行為的答案,
我被迫采取了一些自己的挖掘方式。
作為參考,請注意原始問題中顯示的完全相同的代碼在本機Win32應用程序中正常工作。 重新啟用“關閉”菜單項似乎僅限於WinForms應用程序。
研究System.Windows.Forms.Form
類的源代碼揭示了一個有趣的實現細節: .NET Framework設計者顯然決定每次窗體的WindowState
更改時調整窗體的系統菜單 ,其中包括最大化和最小化由系統。
具體來說,名稱為AdjustSystemMenu
方法有兩種,它們負責響應這些事件而改變系統菜單(並弄亂你自己可能做過的任何自定義)。 如果您有興趣檢查代碼(我已經放棄了這里為了Mono等項目的參與者而放棄了這些代碼),請獲取.NET Reflector的免費副本。
我不完全確定為什么做出這個決定,但至少我現在已經解釋了。
我有同樣的要求。 嘗試了幾種方法來禁用關閉菜單選項然后刪除並嘗試重新創建它(正確)后,我發現了來自Microsoft http://support.microsoft.com/kb/184686的這個黑客攻擊。
奇跡般有效。 它仍然是一個黑客,但它的工作原理。
這是我原來的(松散)C#轉換
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern int GetMenuItemCount(IntPtr hMenu);
[System.Runtime.InteropServices.DllImport("user32.dll")]
static extern bool DrawMenuBar(IntPtr hWnd);
public static void EnableCloseButton(Form frm, bool enabled) {
IntPtr hMenu;
int n;
hMenu = GetSystemMenu(frm.Handle, false);
if (hMenu != IntPtr.Zero) {
n = GetMenuItemCount(hMenu);
if (n > 0) {
if (enabled) {
EnableClose(frm);
}
else {
DisableClose(frm);
}
SendMessage(frm.Handle, WM_NCACTIVATE, (IntPtr)1, (IntPtr)0);
DrawMenuBar(frm.Handle);
Application.DoEvents();
}
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MENUITEMINFO {
public uint cbSize;
public uint fMask;
public uint fType;
public uint fState;
public int wID;
public int hSubMenu;
public int hbmpChecked;
public int hbmpUnchecked;
public int dwItemData;
public string dwTypeData;
public uint cch;
// public int hbmpItem;
}
internal const UInt32 SC_CLOSE = 0xF060;
//SetMenuItemInfo fMask constants.
const UInt32 MIIM_STATE = 0x1;
const UInt32 MIIM_ID = 0x2;
//'SetMenuItemInfo fState constants.
const UInt32 MFS_ENABLED = 0x0;
const UInt32 MFS_GRAYED = 0x3;
const UInt32 MFS_CHECKED = 0x8;
internal const int MFS_DEFAULT = 0x1000;
[DllImport("user32.dll")]
static extern bool SetMenuItemInfo(IntPtr hMenu, int uItem, bool fByPosition, [In] ref MENUITEMINFO lpmii);
[DllImport("user32.dll")]
static extern bool GetMenuItemInfo(IntPtr hMenu, int uItem, bool fByPosition, ref MENUITEMINFO lpmii);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
private const UInt32 WM_NCACTIVATE = 0x0086;
private static void DisableClose(Form frm) {
IntPtr hMenu;
int n;
hMenu = GetSystemMenu(frm.Handle, false);
if (hMenu != IntPtr.Zero) {
MENUITEMINFO mif = new MENUITEMINFO();
mif.cbSize = (uint)Marshal.SizeOf(typeof(MENUITEMINFO));
mif.fMask = MIIM_ID | MIIM_STATE;
mif.fType = 0;
mif.dwTypeData = null;
bool a = GetMenuItemInfo(hMenu, (int)SC_CLOSE, false, ref mif);
mif.fState = MFS_GRAYED;
SetMenuItemInfo(hMenu, (int)SC_CLOSE, false, ref mif);
SendMessage(frm.Handle, WM_NCACTIVATE, (IntPtr)1, (IntPtr)0);
mif.wID = -10;
mif.fState = MFS_GRAYED;
SetMenuItemInfo(hMenu, (int)SC_CLOSE, false, ref mif);
}
}
private static void EnableClose(Form frm) {
IntPtr hMenu;
int n;
hMenu = GetSystemMenu(frm.Handle, false);
if (hMenu != IntPtr.Zero) {
MENUITEMINFO mif = new MENUITEMINFO();
mif.cbSize = (uint)Marshal.SizeOf(typeof(MENUITEMINFO));
mif.fMask = MIIM_ID | MIIM_STATE;
mif.fType = 0;
mif.dwTypeData = null;
bool a = GetMenuItemInfo(hMenu, -10, false, ref mif);
mif.wID = (int)SC_CLOSE;
SetMenuItemInfo(hMenu, -10, false, ref mif);
SendMessage(frm.Handle, WM_NCACTIVATE, (IntPtr)1, (IntPtr)0);
mif.fState = MFS_ENABLED;
SetMenuItemInfo(hMenu, (int)SC_CLOSE, false, ref mif);
SendMessage(frm.Handle, WM_NCACTIVATE, (IntPtr)1, (IntPtr)0);
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.