菜单枚举记

类别:数据库 点击:0 评论:0 推荐:

菜单枚举记

 

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

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

本文地址:http://com.8s8s.com/it/it21483.htm