選單列舉記 (轉)

worldblog發表於2008-01-28
選單列舉記 (轉)[@more@]

選單列舉記

 :namespace prefix = o ns = "urn:schemas--com::office" />

有一MDI應用,現假設要列舉出其能夠得到命令響應所有選單項的內容:如命令ID,資源名稱,所在(子)選單的控制程式碼等,並對之進行操作。本文對此略述一二,未達意處,望各位海涵之外,以我之深度,唯與諸位共勉而已。

1、  我的迷惑

這幾天修煉English Help,悟得些許正果,希望得與世人共超,尚不知是否有效,但為之而已。言歸正傳:

選單項可以是選單,反之亦然,此時選單被稱為子選單;如果選單項不是選單,則它便是’純選單項’。以前我以為選單中每一項都是選單,我的思維中因此不再有選單項的定義。可能這是個菜鳥級問題,但也可能您尚不甚解,那您不妨紙上談兵一番,將最簡單的選單畫上一畫,再琢磨琢磨。

2、  選單列舉演算法

A、 選單抽象結構之一(樹型抽象):

ectratio="t">

  現在要訪問到這棵’樹’的所有葉結點並處理之,方法如B所述。

 

B、 列舉演算法(深度遍歷,C++語法)

1.  )求得當前結點的子結點數c;

2.  )迴圈查詢當前結點的I (0<=I

若該子結點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

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文字,兩者略有不同,以資參考。

  下面對上述程式碼中用到的 及 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; //而不一定要是’√’或空白

  D    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 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:windowssystemuser32.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 unableItem, 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.CODE=-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 ( 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


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10752043/viewspace-998631/,如需轉載,請註明出處,否則將追究法律責任。

相關文章