一、前言
.net框架是Windows應(yīng)用領(lǐng)域中一個(gè)非常新的技術(shù),可以肯定在未來(lái)的一段時(shí)間內(nèi),.NET應(yīng)用必須與現(xiàn)存的Windows技術(shù)交互作用。這種交互作用主要體現(xiàn)在兩個(gè)領(lǐng)域:COM和應(yīng)用編程接口(API)。為此,.NET框架在Windows API之上提供了一個(gè)OO層,但是有時(shí)候可能需要使用一個(gè).NET不可到達(dá)的API調(diào)用。在這種情況下,可以使用.NET平臺(tái)調(diào)用(P/Invoke)機(jī)制從.NET中調(diào)用C或C++函數(shù)。因?yàn)閃indows API函數(shù)在DLL中,所以,P/Invoke為從.NET代碼調(diào)用DLL中的C或C++函數(shù)提供了一種通用機(jī)制。
本文針對(duì)C#.NET中沒(méi)有提供直接的類似SystemMenu的屬性或類似GetSystemMenu的成員函數(shù)的實(shí)際,編寫了一個(gè)C#類SystemMenu,從而實(shí)現(xiàn)了傳統(tǒng)的對(duì)于系統(tǒng)菜單的操作,這是通過(guò)調(diào)用本地Windows API來(lái)完成的。
二、系統(tǒng)菜單簡(jiǎn)介
當(dāng)你單擊窗口圖標(biāo)或右擊窗口標(biāo)題欄時(shí)系統(tǒng)菜單即彈出。它包含當(dāng)前窗口的默認(rèn)行為。不同窗口的系統(tǒng)菜單看起來(lái)有些不同,如一個(gè)正常的窗口的系統(tǒng)菜單看起來(lái)與一個(gè)工具欄子對(duì)話框窗口的菜單就不一樣。
修改系統(tǒng)菜單的好處:
·添加應(yīng)用程序自己定義的菜單項(xiàng)。
·在WW被最小化時(shí),SS是一個(gè)很好的地方來(lái)放置動(dòng)作,可以被存取,因?yàn)镾S可以顯示,通過(guò)在任務(wù)欄窗口圖標(biāo)上單擊右鍵。
·使某菜單項(xiàng)失去能力,如從系統(tǒng)菜單中移去“化”,“最小化”“關(guān)閉”等。由于這種改動(dòng)還影響到窗口右上角的三個(gè)按鈕,所以這是一個(gè)使窗口右上角“X”失去能力的不錯(cuò)的辦法。
操縱系統(tǒng)菜單
通過(guò)調(diào)用 API函數(shù)GetSystemMenu,你就檢索到了系統(tǒng)菜單的一個(gè)拷貝。該函數(shù)的第二個(gè)參數(shù)指明是否你要復(fù)位系統(tǒng)菜單到它的缺省狀態(tài)。再加上另外幾個(gè)API菜單函數(shù)如AppendMenu, InsertMenu等,你就能實(shí)現(xiàn)對(duì)于系統(tǒng)菜單的靈活控制。
下面我僅簡(jiǎn)單介紹如何添加菜單項(xiàng)以及如何實(shí)現(xiàn)新項(xiàng)與用戶的交互。
三、SystemMenu 類介紹
SystemMenu類的實(shí)現(xiàn)使得整個(gè)系統(tǒng)菜單存取容易許多。你可以使用這個(gè)類來(lái)修改一個(gè)窗口的菜單。 通過(guò)調(diào)用靜態(tài)成員函數(shù)FromForm你得到一個(gè)對(duì)象,該函數(shù)要求一個(gè)Form對(duì)象或一個(gè)從Form繼承的類作為它的參數(shù)。然后它創(chuàng)建一個(gè)新的對(duì)象,當(dāng)然如果GetSystemMenu API調(diào)用失敗的話,將引發(fā)一個(gè)NoSystemMenuException例外。
注意,每一個(gè)Windows API菜單函數(shù)要求一個(gè)菜單句柄以利于操作。因?yàn)椴藛尉浔鷮?shí)際上是一個(gè)C++指針,所以在.NET中你要使用IntPtr來(lái)操作它。許多函數(shù)還需要一個(gè)位掩碼標(biāo)志來(lái)指明新菜單項(xiàng)的動(dòng)作或形式。幸運(yùn)的是,你不必象在VC++中那樣,通過(guò)某個(gè)頭文件的包含來(lái)使用一系列的位掩碼標(biāo)志定義,.NET中已經(jīng)提供了一個(gè)現(xiàn)成的公共枚舉類ItemFlags。下面對(duì)這個(gè)類的幾個(gè)重要成員作一說(shuō)明:
·mfString―― 告訴子系統(tǒng)將顯示由菜單項(xiàng)中的“Item”參數(shù)傳遞的字符串。
·mfSeparator――此時(shí) "ID" 與 "Item" 參數(shù)被忽略。
·MfBarBreak―― 當(dāng)用于菜單條時(shí),其功能與mfBreak一樣;當(dāng)用于下拉菜單,子菜單或快捷菜單時(shí),新的一列與舊有的一列由一線垂直線所隔開。
·MfBreak――把當(dāng)前項(xiàng)目放在一個(gè)新行(菜單條)或新的一列(下拉菜單,子菜單或快捷菜單)。
注意:如果指定多個(gè)標(biāo)志,應(yīng)該用位操作運(yùn)算符|(或)連接。例如:
//將創(chuàng)建一個(gè)菜單項(xiàng) "Test" ,且該項(xiàng)被選中(checked)
mySystemMenu.AppendMenu(myID, "Test", ItemFlags.mfString|ItemFlags.mfChecked);
“Item”參數(shù)指定了新項(xiàng)中要顯示的文本,其ID必須是的數(shù)字――用來(lái)標(biāo)志該菜單項(xiàng)。
注意:確保新項(xiàng)的ID大于0小于0XF000。因?yàn)榇笥诘扔?XF000的范圍為系統(tǒng)命令所保留使用。你也可以調(diào)用類SystemMenu的靜態(tài)方法VerifyItemID來(lái)核驗(yàn)是否你的ID正確。
另外,還有兩個(gè)需要解釋的常量:mfByCommand和mfByPosition。
第一,在缺省情況下,使用mfByCommand。第二,“Pos”的解釋依賴于這些標(biāo)志:如果你指定mfByCommand,“Pos”參數(shù)就是在新項(xiàng)目插入前項(xiàng)目的ID;如果你指定mfByPosition,“Pos”參數(shù)就是以0索引為開頭的新項(xiàng)的相對(duì)位置;如果是-1并且指定mfByPosition,該項(xiàng)目將被插入到最后。這也正是為什么AppendMenu()可以為InsertMenu()所取代的原因。
.net框架是Windows應(yīng)用領(lǐng)域中一個(gè)非常新的技術(shù),可以肯定在未來(lái)的一段時(shí)間內(nèi),.NET應(yīng)用必須與現(xiàn)存的Windows技術(shù)交互作用。這種交互作用主要體現(xiàn)在兩個(gè)領(lǐng)域:COM和應(yīng)用編程接口(API)。為此,.NET框架在Windows API之上提供了一個(gè)OO層,但是有時(shí)候可能需要使用一個(gè).NET不可到達(dá)的API調(diào)用。在這種情況下,可以使用.NET平臺(tái)調(diào)用(P/Invoke)機(jī)制從.NET中調(diào)用C或C++函數(shù)。因?yàn)閃indows API函數(shù)在DLL中,所以,P/Invoke為從.NET代碼調(diào)用DLL中的C或C++函數(shù)提供了一種通用機(jī)制。
本文針對(duì)C#.NET中沒(méi)有提供直接的類似SystemMenu的屬性或類似GetSystemMenu的成員函數(shù)的實(shí)際,編寫了一個(gè)C#類SystemMenu,從而實(shí)現(xiàn)了傳統(tǒng)的對(duì)于系統(tǒng)菜單的操作,這是通過(guò)調(diào)用本地Windows API來(lái)完成的。
二、系統(tǒng)菜單簡(jiǎn)介
當(dāng)你單擊窗口圖標(biāo)或右擊窗口標(biāo)題欄時(shí)系統(tǒng)菜單即彈出。它包含當(dāng)前窗口的默認(rèn)行為。不同窗口的系統(tǒng)菜單看起來(lái)有些不同,如一個(gè)正常的窗口的系統(tǒng)菜單看起來(lái)與一個(gè)工具欄子對(duì)話框窗口的菜單就不一樣。
修改系統(tǒng)菜單的好處:
·添加應(yīng)用程序自己定義的菜單項(xiàng)。
·在WW被最小化時(shí),SS是一個(gè)很好的地方來(lái)放置動(dòng)作,可以被存取,因?yàn)镾S可以顯示,通過(guò)在任務(wù)欄窗口圖標(biāo)上單擊右鍵。
·使某菜單項(xiàng)失去能力,如從系統(tǒng)菜單中移去“化”,“最小化”“關(guān)閉”等。由于這種改動(dòng)還影響到窗口右上角的三個(gè)按鈕,所以這是一個(gè)使窗口右上角“X”失去能力的不錯(cuò)的辦法。
操縱系統(tǒng)菜單
通過(guò)調(diào)用 API函數(shù)GetSystemMenu,你就檢索到了系統(tǒng)菜單的一個(gè)拷貝。該函數(shù)的第二個(gè)參數(shù)指明是否你要復(fù)位系統(tǒng)菜單到它的缺省狀態(tài)。再加上另外幾個(gè)API菜單函數(shù)如AppendMenu, InsertMenu等,你就能實(shí)現(xiàn)對(duì)于系統(tǒng)菜單的靈活控制。
下面我僅簡(jiǎn)單介紹如何添加菜單項(xiàng)以及如何實(shí)現(xiàn)新項(xiàng)與用戶的交互。
三、SystemMenu 類介紹
SystemMenu類的實(shí)現(xiàn)使得整個(gè)系統(tǒng)菜單存取容易許多。你可以使用這個(gè)類來(lái)修改一個(gè)窗口的菜單。 通過(guò)調(diào)用靜態(tài)成員函數(shù)FromForm你得到一個(gè)對(duì)象,該函數(shù)要求一個(gè)Form對(duì)象或一個(gè)從Form繼承的類作為它的參數(shù)。然后它創(chuàng)建一個(gè)新的對(duì)象,當(dāng)然如果GetSystemMenu API調(diào)用失敗的話,將引發(fā)一個(gè)NoSystemMenuException例外。
注意,每一個(gè)Windows API菜單函數(shù)要求一個(gè)菜單句柄以利于操作。因?yàn)椴藛尉浔鷮?shí)際上是一個(gè)C++指針,所以在.NET中你要使用IntPtr來(lái)操作它。許多函數(shù)還需要一個(gè)位掩碼標(biāo)志來(lái)指明新菜單項(xiàng)的動(dòng)作或形式。幸運(yùn)的是,你不必象在VC++中那樣,通過(guò)某個(gè)頭文件的包含來(lái)使用一系列的位掩碼標(biāo)志定義,.NET中已經(jīng)提供了一個(gè)現(xiàn)成的公共枚舉類ItemFlags。下面對(duì)這個(gè)類的幾個(gè)重要成員作一說(shuō)明:
·mfString―― 告訴子系統(tǒng)將顯示由菜單項(xiàng)中的“Item”參數(shù)傳遞的字符串。
·mfSeparator――此時(shí) "ID" 與 "Item" 參數(shù)被忽略。
·MfBarBreak―― 當(dāng)用于菜單條時(shí),其功能與mfBreak一樣;當(dāng)用于下拉菜單,子菜單或快捷菜單時(shí),新的一列與舊有的一列由一線垂直線所隔開。
·MfBreak――把當(dāng)前項(xiàng)目放在一個(gè)新行(菜單條)或新的一列(下拉菜單,子菜單或快捷菜單)。
注意:如果指定多個(gè)標(biāo)志,應(yīng)該用位操作運(yùn)算符|(或)連接。例如:
//將創(chuàng)建一個(gè)菜單項(xiàng) "Test" ,且該項(xiàng)被選中(checked)
mySystemMenu.AppendMenu(myID, "Test", ItemFlags.mfString|ItemFlags.mfChecked);
“Item”參數(shù)指定了新項(xiàng)中要顯示的文本,其ID必須是的數(shù)字――用來(lái)標(biāo)志該菜單項(xiàng)。
注意:確保新項(xiàng)的ID大于0小于0XF000。因?yàn)榇笥诘扔?XF000的范圍為系統(tǒng)命令所保留使用。你也可以調(diào)用類SystemMenu的靜態(tài)方法VerifyItemID來(lái)核驗(yàn)是否你的ID正確。
另外,還有兩個(gè)需要解釋的常量:mfByCommand和mfByPosition。
第一,在缺省情況下,使用mfByCommand。第二,“Pos”的解釋依賴于這些標(biāo)志:如果你指定mfByCommand,“Pos”參數(shù)就是在新項(xiàng)目插入前項(xiàng)目的ID;如果你指定mfByPosition,“Pos”參數(shù)就是以0索引為開頭的新項(xiàng)的相對(duì)位置;如果是-1并且指定mfByPosition,該項(xiàng)目將被插入到最后。這也正是為什么AppendMenu()可以為InsertMenu()所取代的原因。