即在程序标题栏上右键时弹出的菜单
此菜单会根据窗体的状态而不同,如最大化状态时则如上图
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); } }
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
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; } } } }
汗...这么一个功能就这么多代码