如何用C#编程修改系统菜单

嘿,Philippe,至少在我有10年经验之前我不能称自己为C#专家,而且C#出现并不长。然而,我知道你的问题的答案:使用 GetSystemMenu。对,就如你在C++中一样。怎样做呢?自然是用 托管。

有时我感觉就像坏掉的唱片,因为如此多的C#问题,我都用相同的答案:托管。那是因为我得到的大部分问题都是 GUI 问题,并且 Windows 窗体目前只暴露基本的窗口子集。一旦你想做一些复杂的东西,你还必须返回到Win32®。幸运的是,Microsoft .NET Framework 托管服务使得它更容易。

如果有一种方法能用 Windows 窗体获得系统菜单,那么窗体类中就应该有一个类似SystemMenu的东西。啊哈,事实上没有这样的属性。 控件一般都用 Control.ContextMenu 得到上下文菜单,窗体用 Form.Menu 获得主菜单,但没有 SystemMenu 或是其它的属性 用 Menu 来直接存取系统菜单。这就是你要使用托管的原因。我写了一个小程序,SysMenu,来示范如何使用托管。Figure 5列出了代码。Figure 6为结果。

menu3_1
Figure 6 修改后的系统菜单

为使用GetSystemMenu API函数,首先声明托管方式, 用 DllImpor。. 对于SysMenu, 你实际上需要两个函数: GetSystemMenu 和 AppendMenu.

using System.Runtime.InteropServices;
public class Form1 : Form
{
    [DllImport("user32.dll")]
    private static extern IntPtr GetSystemMenu(IntPtr hwnd, int bRevert);
    [DllImport("user32.dll")]
    private static extern bool AppendMenu(IntPtr hMenu, MenuFlags uFlags, uint uIDNewItem, String lpNewItem);
}

你应该经常使用 IntPtr 来代替 HWNDs、HMENUs和其它类型的窗口句柄。对于 LPCTSTRs, 将参数声明为String类型。托管服务会在传给 Windows 之前将System::String自动转换为 LPCTSTR类型。对于 MenuFlags, 那是你必须自己定义的枚举:

public enum MenuFlags {
    MF_INSERT = 0x00000000,
    MF_CHANGE = 0x00000080,
    ooo // etc
}

你不一定非要用枚举,但用枚举更安全。MF_XXX 值来自 WinUser.h。最后, 你需要一个新的命令 ID。在SysMenu中,IDC_MYCOMMAND值为 100. 如果你使用的值小于0xF000, 你要保证不和SC_MINIMIZE, SC_MAXIMIZE 或其它内建的系统命令冲突。同时也必须确保不和你自己的主菜单命令冲突。有了这些定义之后, 你便可以开始添加菜单项。所有需要做的只是在你的窗体构造函数中添加很少的代码。首先是获得系统菜单:

// Get system menu
IntPtr hSysMenu = GetSystemMenu(this.Handle, 0);

随后是加入你的命令:

// Add separator and new command
AppendMenu(hSysMenu,MenuFlags.MF_SEPARATOR,0,null);
AppendMenu(hSysMenu,MenuFlags.MF_BYCOMMAND, IDC_MYCOMMAND, "Do you like interop?");

现在当用户在窗口标题栏点击系统菜单,你的新菜单将显示,如 Figure 6所示。只是为了好玩,我给了它一个复选标记。但用户调用你的命令时会发生什么呢?目前,什么也不会发生。为处理这个命令,你必须重写窗体的虚拟 WndProc 方法:

const int WM_SYSCOMMAND = 0x0112;
protected override void WndProc(ref Message msg)
{
    if (msg.Msg==WM_SYSCOMMAND) {
        if (msg.WParam.ToInt32() == IDC_MYCOMMAND) {
            // handle it!
            return;
        }
    }
    base.WndProc(ref msg);
}
Contributors: FHL