用C#和本地Win API操縱系統(tǒng)菜單.doc_第1頁
用C#和本地Win API操縱系統(tǒng)菜單.doc_第2頁
用C#和本地Win API操縱系統(tǒng)菜單.doc_第3頁
用C#和本地Win API操縱系統(tǒng)菜單.doc_第4頁
用C#和本地Win API操縱系統(tǒng)菜單.doc_第5頁
已閱讀5頁,還剩7頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

一、前言.NET框架是Windows應(yīng)用領(lǐng)域中一個非常新的技術(shù),可以肯定在未來的一段時間內(nèi),.NET應(yīng)用必須與現(xiàn)存的Windows技術(shù)交互作用。這種交互作用主要體現(xiàn)在兩個領(lǐng)域:COM和應(yīng)用編程接口(API)。為此,.NET框架在WindowsAPI之上提供了一個OO層,但是有時候可能需要使用一個.NET不可到達(dá)的API調(diào)用。在這種情況下,可以使用.NET平臺調(diào)用(P/Invoke)機(jī)制從.NET中調(diào)用C或C+函數(shù)。因?yàn)閃indowsAPI函數(shù)在DLL中,所以,P/Invoke為從.NET代碼調(diào)用DLL中的C或C+函數(shù)提供了一種通用機(jī)制。 本文針對C.NET中沒有提供直接的類似SystemMenu的屬性或類似GetSystemMenu的成員函數(shù)的實(shí)際,編寫了一個C類SystemMenu,從而實(shí)現(xiàn)了傳統(tǒng)的對于系統(tǒng)菜單的操作,這是通過調(diào)用本地Windows API來完成的。二、系統(tǒng)菜單簡介當(dāng)你單擊窗口圖標(biāo)或右擊窗口標(biāo)題欄時系統(tǒng)菜單即彈出。它包含當(dāng)前窗口的默認(rèn)行為。不同窗口的系統(tǒng)菜單看起來有些不同,如一個正常的窗口的系統(tǒng)菜單看起來與一個工具欄子對話框窗口的菜單就不一樣。修改系統(tǒng)菜單的好處:添加應(yīng)用程序自己定義的菜單項(xiàng)。 在WW被最小化時,SS是一個很好的地方來放置動作,可以被存取,因?yàn)镾S可以顯示,通過在任務(wù)欄窗口圖標(biāo)上單擊右鍵。使某菜單項(xiàng)失去能力,如從系統(tǒng)菜單中移去“最大化”,“最小化”“關(guān)閉”等。由于這種改動還影響到窗口右上角的三個按鈕,所以這是一個使窗口右上角“X”失去能力的不錯的辦法。操縱系統(tǒng)菜單通過調(diào)用 API函數(shù)GetSystemMenu,你就檢索到了系統(tǒng)菜單的一個拷貝。該函數(shù)的第二個參數(shù)指明是否你要復(fù)位系統(tǒng)菜單到它的缺省狀態(tài)。再加上另外幾個API菜單函數(shù)如AppendMenu, InsertMenu等,你就能實(shí)現(xiàn)對于系統(tǒng)菜單的靈活控制。下面我僅簡單介紹如何添加菜單項(xiàng)以及如何實(shí)現(xiàn)新項(xiàng)與用戶的交互。 三、SystemMenu 類介紹SystemMenu類的實(shí)現(xiàn)使得整個系統(tǒng)菜單存取容易許多。你可以使用這個類來修改一個窗口的菜單。 通過調(diào)用靜態(tài)成員函數(shù)FromForm你得到一個對象,該函數(shù)要求一個Form對象或一個從Form繼承的類作為它的參數(shù)。然后它創(chuàng)建一個新的對象,當(dāng)然如果GetSystemMenu API調(diào)用失敗的話,將引發(fā)一個NoSystemMenuException例外。注意,每一個Windows API菜單函數(shù)要求一個菜單句柄以利于操作。因?yàn)椴藛尉浔鷮?shí)際上是一個C+指針,所以在.NET中你要使用IntPtr來操作它。許多函數(shù)還需要一個位掩碼標(biāo)志來指明新菜單項(xiàng)的動作或形式。幸運(yùn)的是,你不必象在VC+中那樣,通過某個頭文件的包含來使用一系列的位掩碼標(biāo)志定義,.NET中已經(jīng)提供了一個現(xiàn)成的公共枚舉類ItemFlags。下面對這個類的幾個重要成員作一說明:mfString 告訴子系統(tǒng)將顯示由菜單項(xiàng)中的“Item”參數(shù)傳遞的字符串。mfSeparator此時 ID 與 Item 參數(shù)被忽略。MfBarBreak 當(dāng)用于菜單條時,其功能與mfBreak一樣;當(dāng)用于下拉菜單,子菜單或快捷菜單時,新的一列與舊有的一列由一線垂直線所隔開。 MfBreak把當(dāng)前項(xiàng)目放在一個新行(菜單條)或新的一列(下拉菜單,子菜單或快捷菜單)。 注意:如果指定多個標(biāo)志,應(yīng)該用位操作運(yùn)算符(或)連接。例如:/將創(chuàng)建一個菜單項(xiàng) Test ,且該項(xiàng)被選中(checked)mySystemMenu.AppendMenu(myID, Test, ItemFlags.mfString|ItemFlags.mfChecked);“Item”參數(shù)指定了新項(xiàng)中要顯示的文本,其ID必須是唯一的數(shù)字用來標(biāo)志該菜單項(xiàng)。注意:確保新項(xiàng)的ID大于0小于0XF000。因?yàn)榇笥诘扔?XF000的范圍為系統(tǒng)命令所保留使用。你也可以調(diào)用類SystemMenu的靜態(tài)方法VerifyItemID來核驗(yàn)是否你的ID正確。另外,還有兩個需要解釋的常量:mfByCommand和mfByPosition。 第一,在缺省情況下,使用mfByCommand。第二,“Pos”的解釋依賴于這些標(biāo)志:如果你指定mfByCommand,“Pos”參數(shù)就是在新項(xiàng)目插入前項(xiàng)目的ID;如果你指定mfByPosition,“Pos”參數(shù)就是以0索引為開頭的新項(xiàng)的相對位置;如果是-1并且指定mfByPosition,該項(xiàng)目將被插入到最后。這也正是為什么AppendMenu()可以為InsertMenu()所取代的原因。四、SystemMenu 類代碼分析using System;using System.Windows.Forms;using System.Diagnostics;using System.Runtime.InteropServices;public class NoSystemMenuException : System.Exception/這些值來自于MSDNpublic enum ItemFlags/ The item .mfUnchecked = 0x00000000, / . is not checkedmfString = 0x00000000, / . contains a string as labelmfDisabled = 0x00000002, / . is disabledmfGrayed = 0x00000001, / . is grayedmfChecked = 0x00000008, / . is checkedmfPopup = 0x00000010, / . Is a popup menu. Pass the/ menu handle of the popup/ menu into the ID parameter.mfBarBreak = 0x00000020, / . is a bar breakmfBreak = 0x00000040, / . is a breakmfByPosition = 0x00000400, / . is identified by the positionmfByCommand = 0x00000000, / . is identified by its IDmfSeparator = 0x00000800 / . is a seperator (String and/ ID parameters are ignored).public enum WindowMessageswmSysCommand = 0x0112/ 幫助實(shí)現(xiàn)操作系統(tǒng)菜單的類的定義/./注意:用P/Invoke調(diào)用動態(tài)鏈接庫中非托管函數(shù)時,應(yīng)執(zhí)行如下步驟:/1,定位包含該函數(shù)的DLL。/2,把該DLL庫裝載入內(nèi)存。/3,找到即將調(diào)用的函數(shù)地址,并將所有的現(xiàn)場壓入堆棧。/4,調(diào)用函數(shù)。/public class SystemMenu/ 提示:C把函數(shù)聲明為外部的,而且使用屬性DllImport來指定DLL /和任何其他可能需要的參數(shù)。/ 首先,我們需要GetSystemMenu() 函數(shù)/ 注意這個函數(shù)沒有Unicode 版本DllImport(USER32, EntryPoint=GetSystemMenu, SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.Winapi)private static extern IntPtr apiGetSystemMenu(IntPtr WindowHandle,int bReset);/ 還需要AppendMenu()。 既然 .NET 使用Unicode,/ 我們應(yīng)該選取它的Unicode版本。DllImport(USER32, EntryPoint=AppendMenuW, SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.Winapi)private static extern int apiAppendMenu( IntPtr MenuHandle, int Flags,int NewID, String Item );/還可能需要InsertMenu()DllImport(USER32, EntryPoint=InsertMenuW, SetLastError=true,CharSet=CharSet.Unicode, ExactSpelling=true,CallingConvention=CallingConvention.Winapi)private static extern int apiInsertMenu ( IntPtr hMenu, int Position,int Flags, int NewId,String Item );private IntPtr m_SysMenu = IntPtr.Zero; / 系統(tǒng)菜單句柄public SystemMenu( )/ 在給定的位置(以0為索引開始值)插入一個分隔條public bool InsertSeparator ( int Pos )return ( InsertMenu(Pos, ItemFlags.mfSeparator |ItemFlags.mfByPosition, 0, ) );/ 簡化的InsertMenu(),前提Pos參數(shù)是一個0開頭的相對索引位置public bool InsertMenu ( int Pos, int ID, String Item )return ( InsertMenu(Pos, ItemFlags.mfByPosition |ItemFlags.mfString, ID, Item) );/ 在給定位置插入一個菜單項(xiàng)。具體插入的位置取決于Flags public bool InsertMenu ( int Pos, ItemFlags Flags, int ID, String Item )return ( apiInsertMenu(m_SysMenu, Pos, (Int32)Flags, ID, Item) = 0);/ 添加一個分隔條public bool AppendSeparator ( )return AppendMenu(0, , ItemFlags.mfSeparator);/ 使用ItemFlags.mfString 作為缺省值public bool AppendMenu ( int ID, String Item )return AppendMenu(ID, Item, ItemFlags.mfString);/ 被取代的函數(shù)public bool AppendMenu ( int ID, String Item, ItemFlags Flags )return ( apiAppendMenu(m_SysMenu, (int)Flags, ID, Item) = 0 );/從一個Form對象檢索一個新對象 public static SystemMenu FromForm ( Form Frm )SystemMenu cSysMenu = new SystemMenu();cSysMenu.m_SysMenu = apiGetSystemMenu(Frm.Handle, 0);if ( cSysMenu.m_SysMenu = IntPtr.Zero )/ 一旦失敗,引發(fā)一個異常throw new NoSystemMenuException();return cSysMenu;/ 當(dāng)前窗口菜單還原 public static void ResetSystemMenu ( Form Frm )apiGetSystemMenu(Frm.Handle, 1);/ 檢查是否一個給定的ID在系統(tǒng)菜單ID范圍之內(nèi)public static bool VerifyItemID ( int ID )return (bool)( ID 0 );你可以使用靜態(tài)方法ResetSystemMenu把窗口的系統(tǒng)菜單設(shè)置為原來狀態(tài)這在應(yīng)用程序遇到錯誤或沒有正確修改菜單時是很有用的。五、使用SystemMenu類/ SystemMenu 對象private SystemMenu m_SystemMenu = null;/ ID 常數(shù)定義private const int m_AboutID = 0x100;private const int m_ResetID = 0x101;private void frmMain_Load(object sender, System.EventArgs e)trym_SystemMenu = SystemMenu.FromForm(this);/ 添加一個separator .m_SystemMenu.AppendSeparator();/ 添加關(guān)于 菜單項(xiàng)m_SystemMenu.AppendMenu(m_AboutID, 關(guān)于);/ 在菜單頂部加上復(fù)位菜單項(xiàng)m_SystemMenu.InsertSeparator(0);m_SystemMenu.InsertMenu(0, m_ResetID, 復(fù)位系統(tǒng)菜單);catch ( NoSystemMenuException /* err */ )/ 建立你的錯誤處理器六、檢測自定義的菜單項(xiàng)是否被點(diǎn)擊這是較難實(shí)現(xiàn)的部分。因?yàn)槟惚仨氈剌d你的從Form或Control繼承類的WndProc成員函數(shù)。你可以這樣實(shí)現(xiàn):protected override void WndProc ( ref Message msg )base.WndProc(ref msg);注意,必須調(diào)用基類的WndProc實(shí)現(xiàn);否則,不能正常工作。 現(xiàn)在,我們來分析一下如何重載WndProc。首先應(yīng)該截獲WM_SYSCOMMAND消息。當(dāng)用戶點(diǎn)擊系統(tǒng)菜單的某一項(xiàng)或者選擇“最大化”按鈕,“最小化”按鈕或者“關(guān)閉”按鈕時,我們要檢索該消息。特別注意,消息對象的WParam參數(shù)正好包含了被點(diǎn)擊菜單項(xiàng)的ID。于是我們可以實(shí)現(xiàn)如下重載:protected override void WndProc ( ref Message msg )/ 通過截取WM_SYSCOMMAND消息并進(jìn)行處理/ 注意,消息WM_SYSCOMMAND被定義在WindowMe

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論