国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 開(kāi)發(fā) > 綜合 > 正文

C#+Windows API操縱系統(tǒng)菜單

2024-07-21 02:29:23
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友

  一、前言

  本文針對(duì)c#.net中沒(méi)有提供直接的類(lèi)似systemmenu的屬性或類(lèi)似getsystemmenu的成員函數(shù)的情況,通過(guò)調(diào)用windows api設(shè)計(jì)了一個(gè)c#類(lèi)systemmenu,從而實(shí)現(xiàn)了傳統(tǒng)的對(duì)于系統(tǒng)菜單的操作。

  二、系統(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ì)話(huà)框窗口的菜單就不一樣。

  修改系統(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)與用戶(hù)的交互。

  三、systemmenu 類(lèi)介紹

  systemmenu類(lèi)的實(shí)現(xiàn)使得整個(gè)系統(tǒng)菜單存取變得非常容易。你可以使用這個(gè)類(lèi)來(lái)修改一個(gè)窗口的菜單。 通過(guò)調(diào)用靜態(tài)成員函數(shù)fromform你得到一個(gè)對(duì)象,該函數(shù)要求一個(gè)form對(duì)象或一個(gè)從form繼承的類(lèi)作為它的參數(shù)。然后它創(chuàng)建一個(gè)新的對(duì)象,當(dāng)然如果getsystemmenu api調(diào)用失敗的話(huà),將引發(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)成的公共枚舉類(lèi)itemflags。下面對(duì)這個(gè)類(lèi)的幾個(gè)重要成員作一說(shuō)明:

  ·mfstring―― 告訴子系統(tǒng)將顯示由菜單項(xiàng)中的“item”參數(shù)傳遞的字符串。

  ·mfseparator――此時(shí) "id" 與 "item" 參數(shù)被忽略。

  ·mfbarbreak―― 當(dāng)用于菜單條時(shí),其功能與mfbreak一樣;當(dāng)用于下拉菜單,子菜單或快捷菜單時(shí),新的一列與舊有的一列由一線(xiàn)垂直線(xiàn)所隔開(kāi)。

  ·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)用類(lèi)systemmenu的靜態(tài)方法verifyitemid來(lái)核驗(yàn)是否你的id正確。

  另外,還有兩個(gè)需要解釋的常量:mfbycommand和mfbyposition。

  第一,在缺省情況下,使用mfbycommand。第二,“pos”的解釋依賴(lài)于這些標(biāo)志:如果你指定mfbycommand,“pos”參數(shù)就是在新項(xiàng)目插入前項(xiàng)目的id;如果你指定mfbyposition,“pos”參數(shù)就是以0索引為開(kāi)頭的新項(xiàng)的相對(duì)位置;如果是-1并且指定mfbyposition,該項(xiàng)目將被插入到最后。這也正是為什么appendmenu()可以為insertmenu()所取代的原因。

  四、systemmenu 類(lèi)代碼分析

using system;
using system.windows.forms;
using system.diagnostics;
using system.runtime.interopservices;

public class nosystemmenuexception : system.exception
{}

//這些值來(lái)自于msdn

public enum itemflags
{
 // the item ...
 mfunchecked = 0x00000000, // ... is not checked
 mfstring = 0x00000000, // ... contains a string as label
 mfdisabled = 0x00000002, // ... is disabled
 mfgrayed = 0x00000001, // ... is grayed
 mfchecked = 0x00000008, // ... is checked
 mfpopup = 0x00000010, // ... is a popup menu. pass the

 // menu handle of the popup
 // menu into the id parameter.

 mfbarbreak = 0x00000020, // ... is a bar break
 mfbreak = 0x00000040, // ... is a break
 mfbyposition = 0x00000400, // ... is identified by the position
 mfbycommand = 0x00000000, // ... is identified by its id
 mfseparator = 0x00000800 // ... is a seperator (string and

 // id parameters are ignored).
}

public enum windowmessages
{
 wmsyscommand = 0x0112
}

//
/// 幫助實(shí)現(xiàn)操作系統(tǒng)菜單的類(lèi)的定義
///.

//注意:用p/invoke調(diào)用動(dòng)態(tài)鏈接庫(kù)中非托管函數(shù)時(shí),應(yīng)執(zhí)行如下步驟:
//1,定位包含該函數(shù)的dll。
//2,把該dll庫(kù)裝載入內(nèi)存。
//3,找到即將調(diào)用的函數(shù)地址,并將所有的現(xiàn)場(chǎng)壓入堆棧。
//4,調(diào)用函數(shù)。
//

public class systemmenu
{
 // 提示:c#把函數(shù)聲明為外部的,而且使用屬性dllimport來(lái)指定dll
 //和任何其他可能需要的參數(shù)。
 // 首先,我們需要getsystemmenu() 函數(shù)
 // 注意這個(gè)函數(shù)沒(méi)有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為索引開(kāi)始值)插入一個(gè)分隔條

public bool insertseparator ( int pos )
{
 return ( insertmenu(pos, itemflags.mfseparator |itemflags.mfbyposition, 0, "") );
}

// 簡(jiǎn)化的insertmenu(),前提――pos參數(shù)是一個(gè)0開(kāi)頭的相對(duì)索引位置

public bool insertmenu ( int pos, int id, string item )
{
 return ( insertmenu(pos, itemflags.mfbyposition |itemflags.mfstring, id, item) );
}

// 在給定位置插入一個(gè)菜單項(xiàng)。具體插入的位置取決于flags

public bool insertmenu ( int pos, itemflags flags, int id, string item )
{
 return ( apiinsertmenu(m_sysmenu, pos, (int32)flags, id, item) == 0);
}

// 添加一個(gè)分隔條

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 );
}

//從一個(gè)form對(duì)象檢索一個(gè)新對(duì)象

public static systemmenu fromform ( form frm )
{
 systemmenu csysmenu = new systemmenu();
 csysmenu.m_sysmenu = apigetsystemmenu(frm.handle, 0);
 if ( csysmenu.m_sysmenu == intptr.zero )
 { // 一旦失敗,引發(fā)一個(gè)異常
  throw new nosystemmenuexception();
 }
 return csysmenu;
}

// 當(dāng)前窗口菜單還原 public static void resetsystemmenu ( form frm )

{
 apigetsystemmenu(frm.handle, 1);
}

// 檢查是否一個(gè)給定的id在系統(tǒng)菜單id范圍之內(nèi)

public static bool verifyitemid ( int id )
{
 return (bool)( id < 0xf000 && id > 0 );
}
}

  你可以使用靜態(tài)方法resetsystemmenu把窗口的系統(tǒng)菜單設(shè)置為原來(lái)狀態(tài)――這在應(yīng)用程序遇到錯(cuò)誤或沒(méi)有正確修改菜單時(shí)是很有用的。

  五、使用systemmenu類(lèi)

// systemmenu 對(duì)象

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)

{

try

{

m_systemmenu = systemmenu.fromform(this);

// 添加一個(gè)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 */ )

{

// 建立你的錯(cuò)誤處理器

}

}

  六、檢測(cè)自定義的菜單項(xiàng)是否被點(diǎn)擊

  這是較難實(shí)現(xiàn)的部分。因?yàn)槟惚仨氈剌d你的從form或control繼承類(lèi)的wndproc成員函數(shù)。你可以這樣實(shí)現(xiàn):

protected override void wndproc ( ref message msg )
{
 base.wndproc(ref msg);
}

  注意,必須調(diào)用基類(lèi)的wndproc實(shí)現(xiàn);否則,不能正常工作。

  現(xiàn)在,我們來(lái)分析一下如何重載wndproc。首先應(yīng)該截獲wm_syscommand消息。當(dāng)用戶(hù)點(diǎn)擊系統(tǒng)菜單的某一項(xiàng)或者選擇“最大化”按鈕,“最小化”按鈕或者“關(guān)閉”按鈕時(shí),我們要檢索該消息。特別注意,消息對(duì)象的wparam參數(shù)正好包含了被點(diǎn)擊菜單項(xiàng)的id。于是我們可以實(shí)現(xiàn)如下重載:

protected override void wndproc ( ref message msg )
{
 // 通過(guò)截取wm_syscommand消息并進(jìn)行處理
 // 注意,消息wm_syscommand被定義在windowmessages枚舉類(lèi)中
 // 消息的wparam參數(shù)包含點(diǎn)擊的項(xiàng)的id
 // 該值與通過(guò)上面類(lèi)的insertmenu()或appendmenu()成員函數(shù)傳遞的一樣

 if ( msg.msg == (int)windowmessages.wmsyscommand )
 {
  switch ( msg.wparam.toint32() )
  {
   case m_resetid: // reset菜單項(xiàng)的id
   {
    if ( messagebox.show(this, "/tare you sure?","question", messageboxbuttons.yesno) ==
dialogresult.yes )
    { // 復(fù)位系統(tǒng)菜單
     systemmenu.resetsystemmenu(this);
    }
   } break;
   case m_aboutid:
   { // “關(guān)于”菜單項(xiàng)
    messagebox.show(this, "作者: 朱先中 /n/n "+"e-mail: [email protected]", "關(guān)于");
   } break;
   // 這里可以針對(duì)另外的菜單項(xiàng)設(shè)計(jì)處理過(guò)程
  }
 }
 // 調(diào)用基類(lèi)函數(shù)
 base.wndproc(ref msg);
}

  七、總結(jié)

  實(shí)現(xiàn)上述目標(biāo)的另一個(gè)可能的方法是,通過(guò)創(chuàng)建一個(gè)事件onsyscommand并當(dāng)消息wm_syscommand傳來(lái)時(shí)激活它,然后把屬性wparam傳遞給該事件的句柄。讀者可以自行編程驗(yàn)證。

  總之,本文通過(guò)一個(gè)簡(jiǎn)單的系統(tǒng)菜單修改例子,分析了用c#使用.net平臺(tái)調(diào)用機(jī)制來(lái)調(diào)用dll中的非托管函數(shù)的基本步驟及注意事項(xiàng)。另,所附源程在windows2000 server/ vs .net2003下調(diào)試通過(guò)。
發(fā)表評(píng)論 共有條評(píng)論
用戶(hù)名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 宜宾市| 达日县| 新绛县| 东乡| 濮阳市| 玉龙| 油尖旺区| 宜阳县| 中阳县| 大邑县| 灯塔市| 通许县| 保靖县| 六枝特区| 大港区| 治多县| 大渡口区| 土默特右旗| 秦皇岛市| 大石桥市| 奈曼旗| 昆明市| 集贤县| 鄂托克前旗| 武定县| 阳信县| 麻阳| 友谊县| 原阳县| 湖南省| 万宁市| 寿宁县| 宁乡县| 建德市| 乌鲁木齐县| 泰和县| 陵水| 虎林市| 双鸭山市| 江津市| 通城县|