菜单枚举记

菜单

菜单枚举记

 

有一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 ystem\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

OpenFile()

10001

CloseFile()

10002

 

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

时间: 2024-08-01 22:03:49

菜单枚举记的相关文章

Win8.1开始菜单软件8StartButton体验记

1Win8.1开始菜单:支持Metro的开始菜单 尽管Win8已经发布很长时间,但还是有不少人钟情于传统开始菜单,这其中Start8.StartIsBack等一大批开始菜单找回软件功不可没.不过令人大跌眼镜的是,自从进入Win8.1时代,很多经典的开始菜单找回软件已经无法继续使用(如Start8),越来越同质化的软件设计也逐渐让人腻歪.不过自从笔者无意间结识一款小众新秀8StartButton后忽然发现,其实好的东西总是有的,只不过自己没发现罢了! 软件名称: 8StartButton 软件版本

前端MVC变形记

背景: MVC是一种架构设计模式,它通过关注点分离鼓励改进应用程序组织.在过去,MVC被大量用于构建桌面和服务器端应用程序,如今Web应用程序的开发已经越来越向传统应用软件开发靠拢,Web和应用之间的界限也进一步模糊.传统编程语言中的设计模式也在慢慢地融入Web前端开发.由于前端开发的环境特性,在经典MVC模式上也引申出了诸多MV*模式,被实现到各个Javascript框架中都有多少的衍变.在研究MV*模式和各框架的过程中,却是"剪不断.理还乱": 为什么每个地方讲的MVC都不太一样?

AVEVA .Net 菜单自定义

AVEVA .Net 菜单自定义 AVEVA .Net Command and Menu Customisation eryar@163.com   摘要Abstract:以一个具体实例详细介绍AVEVA .Net中自定义菜单的原理及方法.掌握了自定义菜单的方法就可以对二次开发的程序进行分类和整理,便于用户使用. 关键字Key words:AVEVA .Net.Addin Commands.Menu Customisation.PDMS.二次开发   一.概述 Introduction 通过<A

jsp从数据库取得数据作为下拉菜单选项的实现

js|菜单|数据|数据库|下拉     用jsp进行web开发时,很多场合要用到下拉菜单.几个月前,我还做过,可到了今天有忘了.找了好久才又做出来,今天特意把它记下来. <select   name="sortname" >   <%     while(iterator.hasNext()){  String name = ((Sort)iterator.next()).getName();  %>   <option  name="sortn

J2SE 5.0实例---枚举

j2se 枚举在过去,我们必须用整型常数代替枚举,随着J2SE 5.0的发布,这样的方法终于一去不复返了. 一个简单的枚举类型定义如下: public enum Weather {      SUNNY,RAINY,CLOUDY } 枚举可以用在switch语句中: Weather weather=Weather.CLOUDY;      switch(weather)      {      case SUNNY:             System.out.println("It's su

Internet Explorer 编程简述(八)实现浏览历史菜单

编程|菜单 关键字:ITravelLogStg, IEnumTravelLogEntry, ITravelLogEntry 1.概述 Internet Explorer的浏览历史菜单在4.0版本开始出现,但直到5.5之前,微软都未公布用于访问浏览历史的COM接口,如今已是IE6.0大行其道的年代,用于访问浏览历史的接口也早已公布多时,本文的目的则是试图抛砖引玉,简单介绍用于访问浏览历史的Travel Log接口,并用一个小小的类CIETravelLog来实现对Travel Log的封装. 2.I

C#+Windows API操纵系统菜单

window|菜单 一.前言 本文针对C#.NET中没有提供直接的类似SystemMenu的属性或类似GetSystemMenu的成员函数的情况,通过调用Windows API设计了一个C#类SystemMenu,从而实现了传统的对于系统菜单的操作. 二.系统菜单简介 当你单击窗口图标或右击窗口标题栏时系统菜单即弹出.它包含当前窗口的默认行为.不同窗口的系统菜单看起来有些不同,如一个正常窗口的系统菜单看起来与一个工具栏子对话框窗口的菜单就不一样. 修改系统菜单的好处: ·添加应用程序自己定义的菜

跟我学做树型菜单(三)

菜单 续上篇 上一篇中我们已经在网页中实现了动态的菜单.我们使用的是JS脚本来实现的.但是菜单的内容是手工写的,现在我们要用ASP程序来从数据库中读出这些数据,并在程序中生成这些菜单. 一.用递归的方式生成菜单 在讲到从数据库中读取数据并生成菜单的时候,我们先来回忆一下第一篇中提到的数据库结构.数据表(treemenu)中,我们记录了每个菜单的父菜单的ID,如果这ID是0,那么它就是根菜单:并且记录了每个菜单的子菜单的个数:chi_id 也就是说对于任意一个菜单,我们都可以用select * f

FLASH MX 2004右键菜单秀

菜单|右键 在FLASH MX的时代,大家就希望能在自己的作品中放入自定义右键菜单,现在FLASH升级到了2004,终于可以放上自己的右键菜单秀一下了:P(这对于游戏编写者--尤其是RPG游戏编写者来说,手中无疑又多了把利剑) 在2004中,主要使用ContextMenu类与ContextMenuItem类来对右键菜单进行控制.ContextMenu对象可以附加到特定的按钮(使用Button类的menu属性来实现).影片剪辑(使用MovieClip类的menu属性来实现)或文本字段(使用Text