




已阅读5页,还剩3页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
用c#和本地win api操纵系统菜单doc文档可能在WAP端浏览体验不佳。建议您优先选择TXT,或下载源文件到本机查看。 一,前言 .NET 框架是 Windows 应用领域中一个非常新的技术, 可以肯定在未来的一段时间内, .NET 应用必须与现存的 Windows 技术交互作用. 这种交互作用主要体现在两个领域:COM 和应用编程接口(API).为此,.NET 框架在 Windows API 之上提供了一个 OO 层,但是有时候 可能需要使用一个.NET 不可到达的 API 调用.在这种情况下,可以使用.NET 平台调用(P/Invoke)机制从.NET 中调用 C 或 C+函数.因 为 Windows API 函数在 DLL 中,所以,P/Invoke 为从.NET 代码调用 DLL 中的 C 或 C+函数提供了一种通用机制. 本文针对 C#.NET 中没有提供直接的类似 SystemMenu 的属性或类似 GetSystemMenu 的成员函数的实际,编写了一个 C#类 SystemMenu,从而实现了传统的对于系统菜单的操作,这是通过调用本地 Windows API 来完成的. 二,系统菜单简介 当你单击窗口图标或右击窗口标题栏时系统菜单即弹出.它包含当前窗口的默认行为.不同窗口的系统菜单看起来有些不同,如一 个正常的窗口的系统菜单看起来与一个工具栏子对话框窗口的菜单就不一样. 修改系统菜单的好处: 添加应用程序自己定义的菜单项. 在 WW 被最小化时,SS 是一个很好的地方来放置动作,可以被存取,因为 SS 可以显示,通过在任务栏窗口图标上单击右键. 使某菜单项失去能力,如从系统菜单中移去最大化,最小化关闭等.由于这种改动还影响到窗口右上角的三个按钮, 所以这是一个使窗口右上角X失去能力的不错的办法. 操纵系统菜单 通过调用 API 函数 GetSystemMenu,你就检索到了系统菜单的一个拷贝.该函数的第二个参数指明是否你要复位系统菜单到它的缺 省状态.再加上另外几个 API 菜单函数如 AppendMenu, InsertMenu 等,你就能实现对于系统菜单的灵活控制. 下面我仅简单介绍如何添加菜单项以及如何实现新项与用户的交互. 三,SystemMenu 类介绍 SystemMenu 类的实现使得整个系统菜单存取容易许多. 你可以使用这个类来修改一个窗口的菜单. 通过调用静态成员函数 FromForm 你得到一个对象,该函数要求一个 Form 对象或一个从 Form 继承的类作为它的参数.然后它创建一个新的对象,当然如果 GetSystemMenu API 调用失败的话,将引发一个 NoSystemMenuException 例外. 注意,每一个 Windows API 菜单函数要求一个菜单句柄以利于操作.因为菜单句柄实际上是一个 C+指针,所以在.NET 中你要使用 IntPtr 来操作它.许多函数还需要一个位掩码标志来指明新菜单项的动作或形式.幸运的是,你不必象在 VC+中那样,通过某个头文件 的包含来使用一系列的位掩码标志定义,.NET 中已经提供了一个现成的公共枚举类 ItemFlags.下面对这个类的几个重要成员作一说明: mfString 告诉子系统将显示由菜单项中的Item参数传递的字符串. mfSeparator此时 ID 与 Item 参数被忽略. MfBarBreak 当用于菜单条时,其功能与 mfBreak 一样;当用于下拉菜单,子菜单或快捷菜单时,新的一列与旧有的一列由一 线垂直线所隔开. MfBreak把当前项目放在一个新行(菜单条)或新的一列(下拉菜单,子菜单或快捷菜单). 注意:如果指定多个标志,应该用位操作运算符|(或)连接.例如: /将创建一个菜单项 Test ,且该项被选中(checked) mySystemMenu.AppendMenu(myID, Test, ItemFlags.mfString|ItemFlags.mfChecked); Item参数指定了新项中要显示的文本,其 ID 必须是唯一的数字用来标志该菜单项. 注意:确保新项的 ID 大于 0 小于 0XF000.因为大于等于 0XF000 的范围为系统命令所保留使用.你也可以调用类 SystemMenu 的静 态方法 VerifyItemID 来核验是否你的 ID 正确. 另外,还有两个需要解释的常量:mfByCommand 和 mfByPosition. 第一,在缺省情况下,使用 mfByCommand.第二,Pos的解释依赖于这些标志:如果你指定 mfByCommand,Pos参数就是在新 项目插入前项目的 ID; 如果你指定 mfByPosition, Pos参数就是以 0 索引为开头的新项的相对位置; 如果是-1 并且指定 mfByPosition, 该项目将被插入到最后.这也正是为什么 AppendMenu()可以为 InsertMenu()所取代的原因. 四,SystemMenu 类代码分析 using System; using System.Windows.Forms; using System.Diagnostics; using System.Runtime.InteropServices; public class NoSystemMenuException : System.Exception /这些值来自于 MSDN public 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 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 */ ) / 建立你的错误处理器 六,检测自定义的菜单项是否被点击 这是较难实现的部分.因为你必须重载你的从 Form 或 Control 继承类的 WndProc 成员函数.你可以这样实现: protected override void WndProc ( ref Message msg ) base.WndProc(ref msg); 注意,必须调用基类的 WndProc 实现;否则,不能正常工作. 现在,我们来分析一下如何重载 WndProc.首先应该截获 WM_SYSCOMMAND 消息.当用户点击系统菜单的某一项或者选择最大化 按钮,最小化按钮或者关闭按钮时,我们要检索该消息.特别注意,消息对象的 WParam 参数正好包含了被点击菜单项的 ID. 于是我们可以实现如下重载: protected override void WndProc ( ref Message msg ) / 通过截取 WM_SYSCOMMAND 消息并进行处理 / 注意,消息 WM_SYSCOMMAND 被定义在 WindowMes
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 木材加工过程中的能耗分析与节能考核试卷
- 疫病防控监测设备使用与维护考核试卷
- 羽绒制品企业人力资源绩效管理考核试卷
- 舞台灯光设备的人机工程学考量考核试卷
- 英语电影分析与讨论考核试卷
- 石棉制品生产过程中的环境保护考核试卷
- 羽绒加工企业生产安全应急预案考核试卷
- 纸质文具行业市场前景与消费趋势预测方法考核试卷
- 天然气开采业的社会经济效益评估与分析考核试卷
- 石材表面装饰工艺探讨考核试卷
- 2025-2030工程塑料行业市场深度分析及发展策略研究报告
- 2025-2030中国涂料设备行业市场发展趋势与前景展望战略研究报告
- 锌银电池的资料
- 七人学生小品《如此课堂》剧本台词手稿
- RFJ05-2009-DQ人民防空工程电气大样图集
- 毕业设计(论文)-纯电动汽车电池管理系统(bms)管理资料
- 医疗机构消毒技术规范(2023年版)
- 农户贷款管理办法银监发〔2012〕50号
- 儿科-补液-液体疗法课件
- 优生优育TORCH检测临床意义与临床咨询课件
- 《踏雪寻梅》合唱谱
评论
0/150
提交评论