Win32 Api(显示程序系统菜单)

程序系统菜单的动态更新与操作
本文详细介绍了如何在程序中实现系统菜单的动态更新与操作,包括获取系统菜单、显示菜单、根据窗体状态调整菜单选项以及更新菜单状态等功能。

image
即在程序标题栏上右键时弹出的菜单
此菜单会根据窗体的状态而不同,如最大化状态时则如上图

1.GetSystemMenu
The GetSystemMenu function allows the application to access the window menu (also known as the system menu or the control menu) for copying and modifying.

[DllImport("User32.dll")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, [MarshalAs(UnmanagedType.Bool)]bool bRevert);

如果bRevert为false,则会拷贝一份菜单,这就意味着菜单状态全部回到了初始化,true则使用程序系统菜单

2.TrackPopupMenuEx
参考
http://baike.baidu.com/view/1080153.htm?fr=ala0_1
The TrackPopupMenuEx function displays a shortcut menu at the specified location and tracks the selection of items on the shortcut menu. The shortcut menu can appear anywhere on the screen.
当获取了系统菜单句柄,可以调用此方法显示程序系统菜单

3.菜单按下后发送消息(WM_SYSCOMMAND)
在PopupMenu消失后发送消息以触发菜单按下后的事件(接受事件)

测试

private void Button_Click(object sender, RoutedEventArgs e)
{
    ShowSystemMenu(new Point(this.Left+this.Width,this.Top));
}

public void ShowSystemMenu(Point physicalScreenLocation)
{
    const uint TPM_RETURNCMD = 0x0100;
    const uint TPM_LEFTBUTTON = 0x0;

    if (this.GetHandle() == IntPtr.Zero)
    {
        return;
    }

    IntPtr hmenu = NativeMethods.GetSystemMenu(this.GetHandle(), false);

    uint cmd = NativeMethods.TrackPopupMenuEx(hmenu, TPM_LEFTBUTTON | TPM_RETURNCMD, 
        (int)physicalScreenLocation.X, (int)physicalScreenLocation.Y, this.GetHandle(), IntPtr.Zero);
    if (0 != cmd)
    {
        NativeMethods.PostMessage(this.GetHandle(), NativeMethods.WM_SYSCOMMAND, new IntPtr(cmd), IntPtr.Zero);
    }
}

在按钮点击后,显示菜单
image


4.根据状态动态更新(EnableMenuItem)

[DllImport("user32.dll", EntryPoint = "EnableMenuItem")]
public static extern int EnableMenuItem(IntPtr hMenu, int uIDEnableItem, uint uEnable);


由于以上菜单是拷贝的,所以菜单状态回到了初始化,可以根据当前窗体状态动态更新
(1)GetWindowLongPtr
首先获取窗体偏移量信息,获取当前窗体的样式信息,并判断当前窗体状态

[DllImport("user32.dll", EntryPoint = "GetWindowLong")]
static extern Int32 GetWindowLongPtr32(IntPtr hWnd, int nIndex);

(2)根据不同状态更新菜单

[DllImport("user32.dll", EntryPoint = "EnableMenuItem")]
public static extern int EnableMenuItem(IntPtr hMenu, int uIDEnableItem, uint uEnable);
系统菜单命令Id
image

private void UpdateSystemMenu(WindowState? assumeState)
       {
           const uint mfEnabled = NativeMethods.MF_ENABLED | NativeMethods.MF_BYCOMMAND;
           const uint mfDisabled = NativeMethods.MF_GRAYED | NativeMethods.MF_DISABLED | NativeMethods.MF_BYCOMMAND;

           WindowState state = assumeState ?? GetHwndState();

           if (null != assumeState)
           {
             
               IntPtr hmenu = NativeMethods.GetSystemMenu(this.GetHandle(), false);
               if (IntPtr.Zero != hmenu)
               {
                   var dwStyle = NativeMethods.GetWindowLongPtr(this.GetHandle(), NativeMethods.GWL_STYLE).ToInt32();

                   bool canMinimize = IsFlagSet((int)dwStyle, (int)NativeMethods.WS_MINIMIZEBOX);
                   bool canMaximize = IsFlagSet((int)dwStyle, (int)NativeMethods.WS_MAXIMIZEBOX);
                   bool canSize = IsFlagSet((int)dwStyle, (int)NativeMethods.WS_THICKFRAME);

                   switch (state)
                   {
                       case WindowState.Maximized:
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_RESTORE, mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MOVE, mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_SIZE, mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MINIMIZE, canMinimize ? mfEnabled : mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MAXIMIZE, mfDisabled);
                           break;
                       case WindowState.Minimized:
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_RESTORE, mfEnabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MOVE, mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_SIZE, mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MINIMIZE, mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MAXIMIZE, canMaximize ? mfEnabled : mfDisabled);
                           break;
                       default:
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_RESTORE, mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MOVE, mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_SIZE, canSize ? mfEnabled : mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MINIMIZE, canMinimize ? mfEnabled : mfDisabled);
                           NativeMethods.EnableMenuItem(hmenu, NativeMethods.SC_MAXIMIZE, canMaximize ? mfEnabled : mfDisabled);
                           break;
                   }
               }

             
           }
       }

汗...这么一个功能就这么多代码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值