嘿,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为结果。

如何用C#编程修改系统菜单?_开发语言


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);
 }