用C#和本地Windows API操纵系统菜单(2)

    技术2022-05-11  110

    四、SystemMenu 类代码分析 using System;using System.Windows.Forms;using System.Diagnostics;using System.Runtime.InteropServices;public class NoSystemMenuException : System.Exception{}//这些值来自于MSDNpublic enum ItemFlags{  // The item ...  mfUnchecked = 0x00000000, // ... is not checked  mfString = 0x00000000, // ... contains a string as label  mfDisabled = 0x00000002, // ... is disabled  mfGrayed = 0x00000001, // ... is grayed  mfChecked = 0x00000008, // ... is checked  mfPopup = 0x00000010, // ... Is a popup menu. Pass the  // menu handle of the popup  // menu into the ID parameter.  mfBarBreak = 0x00000020, // ... is a bar break  mfBreak = 0x00000040, // ... is a break  mfByPosition = 0x00000400, // ... is identified by the position  mfByCommand = 0x00000000, // ... is identified by its ID  mfSeparator = 0x00000800 // ... is a seperator (String and  // ID parameters are ignored).}public enum WindowMessages{  wmSysCommand = 0x0112}//// 帮助实现操作系统菜单的类的定义///.//注意:用P/Invoke调用动态链接库中非托管函数时,应执行如下步骤://1,定位包含该函数的DLL。//2,把该DLL库装载入内存。//3,找到即将调用的函数地址,并将所有的现场压入堆栈。//4,调用函数。//public class SystemMenu{  // 提示:C#把函数声明为外部的,而且使用属性DllImport来指定DLL   //和任何其他可能需要的参数。  // 首先,我们需要GetSystemMenu() 函数  // 注意这个函数没有Unicode 版本[DllImport("USER32", EntryPoint="GetSystemMenu", SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.Winapi)]private static extern IntPtr apiGetSystemMenu(IntPtr WindowHandle,int bReset);// 还需要AppendMenu()。 既然 .NET 使用Unicode,// 我们应该选取它的Unicode版本。[DllImport("USER32", EntryPoint="AppendMenuW", SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.Winapi)]private static extern int apiAppendMenu( IntPtr MenuHandle, int Flags,int NewID, String Item );//还可能需要InsertMenu()[DllImport("USER32", EntryPoint="InsertMenuW", SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.Winapi)]private static extern int apiInsertMenu ( IntPtr hMenu, int Position,int Flags, int NewId,String Item );private IntPtr m_SysMenu = IntPtr.Zero; // 系统菜单句柄public SystemMenu( ){}// 在给定的位置(以0为索引开始值)插入一个分隔条public bool InsertSeparator ( int Pos ){  return ( InsertMenu(Pos, ItemFlags.mfSeparator |ItemFlags.mfByPosition, 0, "") );}// 简化的InsertMenu(),前提――Pos参数是一个0开头的相对索引位置public bool InsertMenu ( int Pos, int ID, String Item ){  return ( InsertMenu(Pos, ItemFlags.mfByPosition |ItemFlags.mfString, ID, Item) );}// 在给定位置插入一个菜单项。具体插入的位置取决于Flags public bool InsertMenu ( int Pos, ItemFlags Flags, int ID, String Item ){  return ( apiInsertMenu(m_SysMenu, Pos, (Int32)Flags, ID, Item) == 0);}// 添加一个分隔条public bool AppendSeparator ( ){  return AppendMenu(0, "", ItemFlags.mfSeparator);}// 使用ItemFlags.mfString 作为缺省值public bool AppendMenu ( int ID, String Item ){  return AppendMenu(ID, Item, ItemFlags.mfString);}// 被取代的函数public bool AppendMenu ( int ID, String Item, ItemFlags Flags ){  return ( apiAppendMenu(m_SysMenu, (int)Flags, ID, Item) == 0 );}//从一个Form对象检索一个新对象 public static SystemMenu FromForm ( Form Frm ){  SystemMenu cSysMenu = new SystemMenu();  cSysMenu.m_SysMenu = apiGetSystemMenu(Frm.Handle, 0);  if ( cSysMenu.m_SysMenu == IntPtr.Zero )  {   // 一旦失败,引发一个异常   throw new NoSystemMenuException();  }  return cSysMenu;}// 当前窗口菜单还原 public static void ResetSystemMenu ( Form Frm ){  apiGetSystemMenu(Frm.Handle, 1);}// 检查是否一个给定的ID在系统菜单ID范围之内public static bool VerifyItemID ( int ID ){  return (bool)( ID < 0xF000 && ID > 0 );}}    你可以使用静态方法ResetSystemMenu把窗口的系统菜单设置为原来状态――这在应用程序遇到错误或没有正确修改菜单时是很有用的。    五、使用SystemMenu类 // SystemMenu 对象private SystemMenu m_SystemMenu = null;// ID 常数定义private const int m_AboutID = 0x100;private const int m_ResetID = 0x101;private void frmMain_Load(object sender, System.EventArgs e){  try  {   m_SystemMenu = SystemMenu.FromForm(this);   // 添加一个separator ...   m_SystemMenu.AppendSeparator();   // 添加"关于" 菜单项   m_SystemMenu.AppendMenu(m_AboutID, "关于");   // 在菜单顶部加上"复位"菜单项   m_SystemMenu.InsertSeparator(0);   m_SystemMenu.InsertMenu(0, m_ResetID, "复位系统菜单");  }  catch ( NoSystemMenuException /* err */ )  {   // 建立你的错误处理器  }}

    最新回复(0)