如何通过代码打开窗口的系统菜单?

时间:2020-03-06 14:47:13  来源:igfitidea点击:

我有一个CWinForms无边界窗口,为此我重写WndProc并处理WM_NCHITTEST消息。对于该表格的区域,我的命中测试函数将返回HTSYSMENU。双击该区域将成功关闭该窗体,但是右键单击它不会显示窗口的系统菜单,也不会在任务栏中右键单击窗口名称时显示该菜单。

此表单使用以下样式:

this.SetStyle( ControlStyles.AllPaintingInWmPaint, true );
this.SetStyle( ControlStyles.UserPaint, true );
this.SetStyle( ControlStyles.OptimizedDoubleBuffer, true );
this.SetStyle( ControlStyles.ResizeRedraw, true );

并具有以下非默认属性值:

this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
this.KeyPreview = true;
this.MaximizeBox = false;
this.MinimizeBox = false;

我已经尝试处理WM_NCRBUTTONDOWN和WM_NCRBUTTONUP,并发送WM_GETSYSMENU消息,但是它没有用。

解决方案

我的应用程序具有相同的属性,并且右键单击也不起作用,所以这不是问题,这似乎是Windows窗体在没有边框时进行响应的方式。

如果将边框设置为正常值,则可以在任务栏等中单击鼠标右键。

要右键单击其他控件,我们需要设置ContextMenuStrip并提供"菜单"。但是我不确定如果没有边框,是否可以使用。我一直无法使其工作。

如果我没记错的话,无边界窗口会被标记为不提供系统菜单,并且不会出现在任务栏中。

任何给定的窗口没有边框并且不会出现在任务栏中的事实是在窗口上设置样式标志的结果。可以使用GetWindowLong和SetWindowLong API调用来设置这些特定的样式标志。但是,我们必须要小心,因为某些样式无法配合使用。

这些年来,我已经编写了许多自定义控件,并且我一直在不断哄骗窗口以使其成为最初不想要的东西。例如,我编写了自己的下拉控件,其中需要一个窗口来充当弹出窗口而不激活窗口。以下代码将执行此操作。请注意,代码显示在OnHandleCreated事件处理程序中。这是因为在设置了句柄之后就需要更改标志,这表明Windows已经设置了它认为标志应具有的功能。

protected override void OnHandleCreated(EventArgs e) {
    uint dwWindowProperty;

    User32.SetParent( this.Handle, IntPtr.Zero );

    dwWindowProperty = User32.GetWindowLong( this.Handle, User32.GWL.EXSTYLE );
    dwWindowProperty = dwWindowProperty | (uint)User32.WSEX.TOOLWINDOW | (uint)User32.WSEX.NOACTIVATE;
    User32.SetWindowLong( this.Handle, User32.GWL.EXSTYLE, dwWindowProperty );

    dwWindowProperty = User32.GetWindowLong( this.Handle, User32.GWL.STYLE );
    dwWindowProperty = ( dwWindowProperty & ~(uint)User32.WS.CHILD ) | (uint)User32.WS.POPUP; 
    User32.SetWindowLong( this.Handle, User32.GWL.STYLE, dwWindowProperty );
    base.OnHandleCreated (e);
}

//this is a fragment of my User32 library wrapper needed for the previous code segment.
class User32 { 

    [DllImport("user32.dll", CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall )]
    public  static extern int SetWindowLong( IntPtr hWnd, User32.GWL gwlIndex, uint dwNewLong); 

    [DllImport("user32.dll", CharSet=CharSet.Auto, CallingConvention=CallingConvention.StdCall )]
    public static extern uint GetWindowLong( IntPtr hWnd, User32.GWL gwlIndex );

    [FlagsAttribute] 
    public enum WS: uint { 
        POPUP        = 0x80000000,
        CHILD        = 0x40000000,
    }

    public enum GWL {
        STYLE = -16,
        EXSTYLE = -20
    }

    [FlagsAttribute]
    public enum WSEX: uint {
        TOP = 0x0,
        TOPMOST = 0x8,
        TOOLWINDOW = 0x80,
        NOACTIVATE = 0x08000000,
    }
}

不幸的是,如果不使用Caption样式,则无法设置SysMenu样式,因此我不能说这是否是实现中的问题。

我们可以在这两个链接处签出原始样式列表和扩展样式列表。
http://msdn.microsoft.com/zh-CN/library/ms632600(VS.85).aspx

http://msdn.microsoft.com/zh-CN/library/ms632680(VS.85).aspx

protected override void WndProc( ref System.Windows.Forms.Message m )
    { // RightClickMenu
        if ( m.Msg == 0x313 )
        {
            this.contextMenuStrip1.Show(this, this.PointToClient(new Point(m.LParam.ToInt32())));
        }}

这将检测到在应用程序任务栏"区域"上的右键单击。

也许会有所帮助吗?