![]() |
|
||||||||||||||
| | 网站首页 | 数据库教程 | web编程 | 服务器 | 程序设计 | | ||
|
||
|
||||||||||||
| 菜单枚举记 | ||||||||||||
作者:佚名 文章来源:不详 点击数: 更新时间:2007-8-16 ![]() |
||||||||||||
|
菜单枚举记 有一MDI应用程序,现假设要枚举出其能够得到系统命令响应所有菜单项的内容:如命令ID,资源名称,所在(子)菜单的句柄等,并对之进行操作。本文对此略述一二,未达意处,望各位海涵之外,以我之深度,唯与诸位共勉而已。 1、 我的迷惑 这几天修炼English Help,悟得些许正果,希望得与世人共超,尚不知是否有效,但为之而已。言归正传: 菜单项可以是菜单,反之亦然,此时菜单被称为子菜单;如果菜单项不是菜单,则它便是’纯菜单项’。以前我以为菜单中每一项都是菜单,我的思维中因此不再有菜单项的定义。可能这是个菜鸟级问题,但也可能您尚不甚解,那您不妨纸上谈兵一番,将最简单的菜单画上一画,再琢磨琢磨。 2、 菜单枚举算法 A、 菜单抽象结构之一(树型抽象): 现在要访问到这棵’树’的所有叶结点并处理之,方法如B所述。 B、 枚举算法(深度遍历,C++语法) 1. )求得当前结点的子结点数c; 2. )循环查询当前结点的I (0<=I<c)子结点信息: 若该子结点I无下级子结点,则子结点I为叶结点,按需处理后,作I=I+1,重复此步骤; 否则子结点I为分枝结点,置下级子结点为当前结点,转向1; 3.)遍历完毕。 int FindMenuItem(HMENU hmenu)//参数hmenu为分支结点资源标识 { int i,c; long res; char* s=new char[33]; MENUITEMINFO mii; mii.cbSize=sizeof(MENUITEMINFO); mii.fMask=MIIM_DATA|MIIM_ID|MIIM_SUBMENU|MIIM_TYPE|MIIM_STATE|MIIM_CHECKMARKS; mii.dwTypeData=s; c=GetMenuItemCount(hmenu);//获取当前菜单所有的菜单项数目 for(i=0;i<c;i++) { mii.cch=32;//注意哦! res=GetMenuItemInfo(hmenu,i,true,&mii); if (res==0 ) {delete s;return -1;} //如果获取菜单信息失败 if (mii.hSubMenu==NULL)// { //若该菜单项非子菜单,则在此作相应处理 } else { //若该菜单项为子菜单,则如此处理 res=FindMenuItem(mii.hSubMenu);//直接递归调用 if(res==-1){delete s;return -1;} } } delete s; return 0; } int EnumMenuEndItems(HWND hwnd)//开始遍历窗口菜单项。参数hwnd为菜单所在的窗体。 { HMENU hmenu=GetMenu(hwnd); if(hmenu==NULL) return –1; return FindMenuItem(hmenu); } 注: 此处代码仅仅描述算法。若应用到它处,根据不同的需要,Function的返回值和结点处理代码理所当然要发生改变。 附录2为上述代码的PB文本,两者略有不同,以资参考。 下面对上述代码中用到的Windows api 及 struct稍作解说。 3、 在的所用开发工具中Declare 如下Windows API及相关Struct (标准格式): HMENU GetMenu( HWND hWnd);//返回值:hWnd所关联的窗口的菜单句柄 HMENU GetSubMenu(HMENU hMenu,int nPos);//返回值:hMenu所关联的菜单中第nPos项的子菜单句柄 int GetMenuItemCount(HMENU hMenu ); //返回值:hMenu所关联的菜单中的菜单项数目 BOOL WINAPI GetMenuItemInfo ( HMENU hMenu, UINT uItem, BOOL fByPosition, //该参数确定uItem为当前菜单项的命令标识还是在所属菜单中的排序位置号 LPMENUITEMINFO lpmii); BOOL DrawMenuBar(HWND hWnd ); //重绘hWnd所关联的窗口的菜单 typedef struct tagMENUITEMINFO { UINT cbSize; //本结构体物理大小,以byte为单位,其值实际上为48 UINT fMask; //确定想要查询或设置菜单项的哪能些内容 UINT fType; //菜单格式类型 UINT fState;// 菜单状态:Enabled、Disabled or Grayed UINT wID; //命令标识符 HMENU hSubMenu; //子菜单句柄,若无子菜单则为NULL HBITMAP hbmpChecked; //根据这两个域值,可以自定义菜单项被选定时的标记, HBITMAP hbmpUnchecked; //而不一定要是’√’或空白 DWORD dwItemData;//由English翻译为:应用程序定义的与菜单项相关的值(我也不明白) LPTSTR dwTypeData; //菜单资源内容指针,指向String or BitMap or SEPARATOR资源 UINT cch; //若菜单项为MFT_STRING类型,则此项为dwTypeData长度 HBITMAP hbmpItem;//在调试程序时发现有此一项 } MENUITEMINFO, FAR *LPMENUITEMINFO; 参考资料: MSDN98(MicroSoft) MS SDK Help Files\Win32 Developer’s References(Inprise/Borland) (附录1为上述API在PB中的Declare文本) 与Menu操作相关的Windows API Functions还比较多,可适度参考,动态库:USER32.DLL。 4、 其它: a、.我在PB7中调用这些Windows功能,但在调试至GetMenuItemInfo时,单步运行却停滞不前,约 30小时后,我进行了如下操作: a1、打开一Dos窗口,运行TDump c:\windows\system\user32.dll>user32.txt(Tdump.exe为Inprise公司的应用程序) a2、回到Windows中,以记事本打开user32.txt,发现其中并无GetMenuItemInfo,但有GetMenuItemInfoA,若在VB中调用过WIN API,则可猜测此为何物。 a3、将GetMenuItemInfo改写(或Alias)成GetMenuItemInfoA,便OK 了! b、菜单项命令标识符作用 在调用GetMenuItemInfoA之后,其值保存在MENUITEMINFO::wID中。 设现在获得一菜单项信息存储于MENUITEMINFO型结构体mii中,其部分内容为: mii.cbsize=48 mii.dwTypeData=”打开文件” mii.wID=10001 mii.fState=Enabled mii.fType=MFT_STRING
wID=10001 C、在上述GetMenuItemInfoA调用时,需对MENUITEMINFO的如下域赋值: MENUITEMINFO::cbSize MENUITEMINFO::fMask MENUITEMINFO::dwTypeData MENUITEMINFO:: cch 其中MENUITEMINFO::fMask可为如下常数值的组合(在相关资料中很难查到这些常数数值) MIIM_STATE (= 1) MIIM_ID (= 2) MIIM_SUBMENU (= 4) MIIM_CHECKMARKS (= 8) MIIM_TYPE (=16) MIIM_DATA (=32)
附: 1、 相关API及结构体在PB中的Declare Function Long GetMenu(long hWnd ) LIBRARY "USER32.DLL" Function Long GetSubMenu(long hMenu,long nPos) LIBRARY "USER32.DLL" Function Long GetMenuItemCount(long hMenu) LIBRARY "USER32.DLL" Function Long EnableMenuItem(long hMenu,Ulong uIDEnableItem, Ulong uEnable)LIBRARY "USER32.DLL" Function Long GetMenuItemInfoA(long hMenu, Ulong uItem, long fByPosition,ref MENUITEMINFO mii)LIBRARY "USER32.DLL" Function Long DrawMenuBar(long hwnd) LIBRARY "USER32.DLL" global type menuiteminfo from structure unsignedlong cbsize unsignedlong fmask unsignedlong ftype unsignedlong fstate unsignedlong wid long hsubmenu long hbmpchecked long hbmpunchecked long dwitemdata string dwtypedata unsignedlong cch long hbmpitem end type 2、PB代码,根据需要,不同于C++代码(节选,有修改) Public Function Int EnumMenuEndItems (long hwnd,int ins_upd) long hm constant int ins=0 if hwnd=0 or isnull(hwnd) then return 0 hm=GetMenu(handle(wmdi)) if ins_upd=ins then delete from sec_fun using trans; IF TRANS.SQLCODE=-1 THEN goto error end if if ismenu(hm)=0 then return -1 if fun(hm,ins_upd) =-1 then goto error IF TRANS.SQLCODE=-1 THEN goto error COMMIT USING TRANS; delete from sec_auth where id_fun not in (select id_fun from sec_fun) using trans;//对 if trans.sqlcode=-1 and ins_upd=ins then messagebox("","某些操作可能不再存在,但用户仍然拥有该项操作权限,请手动删除!") return 0 error: ROLLBACK USING TRANS; RETURN –1 End Fuction Private Function Int FindMenuItem (HMENU hmenu,int ins_upd ) //ins=0 //upd=1 int i,c long hm,res menuiteminfo mii mii.cbsize=48 mii.fmask=54 MII.FTYPE=0 c=getmenuitemcount(hmenu) for i=0 to c -1 mii.dwtypedata=" " mii.cch=63 if not isvalid(mii) then return -1 res=GetMenuItemInfoA(hmenu,i,255,mii) if res=0 then continue IF MII.HSUBMENU=0 THEN IF NOT ISNULL(MII.DWTYPEDATA) THEN choose case ins_upd case 0 insert into sec_fun(id_fun,des_fun,HANDLE) values (:mii.wid,:mii.dwTypeData,:hmenu) USING TRANS;//保存’纯’菜单项的信息 IF TRANS.SQLCODE=-1 THEN return -1 case 1 update sec_fun set HANDLE=:hmenu where id_fun=:mii.wid USING TRANS; IF TRANS.SQLCODE=-1 THEN return -2 end choose ELSE CONTINUE END IF ELSE res= FindMenuItem (MII.HSUBMENU,ins_upd) if res<>0 then return res END IF NEXT return 0 End Function
|
||||||||||||
| 文章录入:admin 责任编辑:admin | ||||||||||||
| 【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口】 | ||||||||||||
| 网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!) |
| | 设为首页 | 加入收藏 | 联系站长 | 友情链接 | 版权申明 | 网站公告 | 网站地图 | 管理登录 | | |||
|