深爱那片海 发表于 2015-1-16 22:36:29

ASP.NET网页编程之C#+Windows API利用体系菜单

J2EE比较成熟一点,一些比较出名的企业应用软件都是基于J2EE的。以后的发展就不好说了。不过java比较烦,学.net的话,微软把很多工具都封装好了,学起来可能容易一点。window|菜单<P>  1、媒介

  本文针对C#.NET中没有供应间接的相似SystemMenu的属性或相似GetSystemMenu的成员函数的情形,经由过程挪用WindowsAPI计划了一个C#类SystemMenu,从而完成了传统的关于体系菜单的操纵。

  2、体系菜单简介

  当你单击窗口图标或右击窗口题目栏时体系菜单即弹出。它包括以后窗口的默许举动。分歧窗口的体系菜单看起来有些分歧,如一个一般窗口的体系菜单看起来与一个工具栏子对话框窗口的菜单就纷歧样。

  修正体系菜单的优点:

  ・增加使用程序本人界说的菜单项。

  ・在WW被最小化时,SS是一个很好的中央来安排举措,能够被存取,由于SS能够显现,经由过程在义务栏窗口图标上单击右键。

  ・使某菜单项得到才能,如从体系菜单中移往“最年夜化”,“最小化”“封闭”等。因为这类修改还影响到窗口右上角的三个按钮,以是这是一个使窗口右上角“X”得到才能的不错的举措。

  利用体系菜单

  经由过程挪用API函数GetSystemMenu,你就检索到了体系菜单的一个拷贝。该函数的第二个参数指明是不是你要复位体系菜单到它的缺省形态。再加上别的几个API菜单函数如AppendMenu,InsertMenu等,你就可以完成关于体系菜单的天真把持。

  上面我仅复杂先容怎样增加菜单项和怎样完成新项与用户的交互。

  3、SystemMenu类先容

  SystemMenu类的完成使得全部体系菜单存取变得十分简单。你可使用这个类来修正一个窗口的菜单。经由过程挪用静态成员函数FromForm你失掉一个工具,该函数请求一个Form工具或一个从Form承继的类作为它的参数。然后它创立一个新的工具,固然假如GetSystemMenuAPI挪用失利的话,将激发一个NoSystemMenuException破例。

  注重,每个WindowsAPI菜单函数请求一个菜单句柄以利于操纵。由于菜单句柄实践上是一个C++指针,以是在.NET中你要利用IntPtr来操纵它。很多函数还必要一个位掩码标记来指明新菜单项的举措或情势。侥幸的是,你不用象在VC++中那样,经由过程某个头文件的包括来利用一系列的位掩码标记界说,.NET中已供应了一个现成的大众列举类ItemFlags。上面对这个类的几个主要成员作一申明:

  ・mfStringDD告知子体系将显现由菜单项中的“Item”参数传送的字符串。

  ・mfSeparatorDD此时"ID"与"Item"参数被疏忽。

  ・MfBarBreakDD当用于菜单条时,其功效与mfBreak一样;当用于下拉菜单,子菜单或快速菜单时,新的一列与旧有的一列由一线垂直线所离隔。

  ・MfBreakDD把以后项目放在一个新行(菜单条)或新的一列(下拉菜单,子菜单或快速菜单)。

  注重:假如指定多个标记,应当用位操纵运算符|(或)毗连。比方:

//将创立一个菜单项"Test",且该项被选中(checked)

mySystemMenu.AppendMenu(myID,"Test",ItemFlags.mfString|ItemFlags.mfChecked);
  “Item”参数指定了新项中要显现的文本,其ID必需是独一的数字DD用来标记该菜单项。

  注重:确保新项的ID年夜于0小于0XF000。由于年夜于即是0XF000的局限为体系命令所保存利用。你也能够挪用类SystemMenu的静态办法VerifyItemID来核验是不是你的ID准确。

  别的,另有两个必要注释的常量:mfByCommand和mfByPosition。

  第一,在缺省情形下,利用mfByCommand。第二,“Pos”的注释依附于这些标记:假如你指定mfByCommand,“Pos”参数就是在新项目拔出前项目标ID;假如你指定mfByPosition,“Pos”参数就是以0索引为开首的新项的绝对地位;假如是-1而且指定mfByPosition,该项目将被拔出到最初。这也恰是为何AppendMenu()能够为InsertMenu()所代替的缘故原由。
<P>  4、SystemMenu类代码剖析

usingSystem;
usingSystem.Windows.Forms;
usingSystem.Diagnostics;
usingSystem.Runtime.InteropServices;

publicclassNoSystemMenuException:System.Exception
{}

//这些值来自于MSDN

publicenumItemFlags
{
 //Theitem...
 mfUnchecked=0x00000000,//...isnotchecked
 mfString=0x00000000,//...containsastringaslabel
 mfDisabled=0x00000002,//...isdisabled
 mfGrayed=0x00000001,//...isgrayed
 mfChecked=0x00000008,//...ischecked
 mfPopup=0x00000010,//...Isapopupmenu.Passthe

 //menuhandleofthepopup
 //menuintotheIDparameter.

 mfBarBreak=0x00000020,//...isabarbreak
 mfBreak=0x00000040,//...isabreak
 mfByPosition=0x00000400,//...isidentifiedbytheposition
 mfByCommand=0x00000000,//...isidentifiedbyitsID
 mfSeparator=0x00000800//...isaseperator(Stringand

 //IDparametersareignored).
}

publicenumWindowMessages
{
 wmSysCommand=0x0112
}

//
///匡助完成操纵体系菜单的类的界说
///.

//注重:用P/Invoke挪用静态链接库中非托管函数时,应实行以下步骤:
//1,定位包括该函数的DLL。
//2,把该DLL库装载进内存。
//3,找到行将挪用的函数地点,并将一切的现场压进仓库。
//4,挪用函数。
//

publicclassSystemMenu
{
 //提醒:C#把函数声明为内部的,并且利用属性DllImport来指定DLL
 //和任何其他大概必要的参数。
 //起首,我们必要GetSystemMenu()函数
 //注重这个函数没有Unicode版本

[DllImport("USER32",EntryPoint="GetSystemMenu",SetLastError=true,
CharSet=CharSet.Unicode,ExactSpelling=true,
CallingConvention=CallingConvention.Winapi)]

privatestaticexternIntPtrapiGetSystemMenu(IntPtrWindowHandle,intbReset);
 //还必要AppendMenu()。既然.NET利用Unicode,
 //我们应当拔取它的Unicode版本。

 [DllImport("USER32",EntryPoint="AppendMenuW",SetLastError=true,
 CharSet=CharSet.Unicode,ExactSpelling=true,
 CallingConvention=CallingConvention.Winapi)]

 privatestaticexternintapiAppendMenu(IntPtrMenuHandle,intFlags,intNewID,StringItem);

 //还大概必要InsertMenu()

 [DllImport("USER32",EntryPoint="InsertMenuW",SetLastError=true,
CharSet=CharSet.Unicode,ExactSpelling=true,
CallingConvention=CallingConvention.Winapi)]

privatestaticexternintapiInsertMenu(IntPtrhMenu,intPosition,intFlags,intNewId,StringItem);
privateIntPtrm_SysMenu=IntPtr.Zero;//体系菜单句柄

publicSystemMenu()
{}

//在给定的地位(以0为索引入手下手值)拔出一个分开条

publicboolInsertSeparator(intPos)
{
 return(InsertMenu(Pos,ItemFlags.mfSeparator|ItemFlags.mfByPosition,0,""));
}

//简化的InsertMenu(),条件DDPos参数是一个0开首的绝对索引地位

publicboolInsertMenu(intPos,intID,StringItem)
{
 return(InsertMenu(Pos,ItemFlags.mfByPosition|ItemFlags.mfString,ID,Item));
}

//在给定地位拔出一个菜单项。详细拔出的地位取决于Flags

publicboolInsertMenu(intPos,ItemFlagsFlags,intID,StringItem)
{
 return(apiInsertMenu(m_SysMenu,Pos,(Int32)Flags,ID,Item)==0);
}

//增加一个分开条

publicboolAppendSeparator()
{
 returnAppendMenu(0,"",ItemFlags.mfSeparator);
}

//利用ItemFlags.mfString作为缺省值

publicboolAppendMenu(intID,StringItem)
{
 returnAppendMenu(ID,Item,ItemFlags.mfString);
}

//被代替的函数

publicboolAppendMenu(intID,StringItem,ItemFlagsFlags)
{
 return(apiAppendMenu(m_SysMenu,(int)Flags,ID,Item)==0);
}

//从一个Form工具检索一个新工具

publicstaticSystemMenuFromForm(FormFrm)
{
 SystemMenucSysMenu=newSystemMenu();
 cSysMenu.m_SysMenu=apiGetSystemMenu(Frm.Handle,0);
 if(cSysMenu.m_SysMenu==IntPtr.Zero)
 {//一旦失利,激发一个非常
  thrownewNoSystemMenuException();
 }
 returncSysMenu;
}

//以后窗口菜单复原publicstaticvoidResetSystemMenu(FormFrm)

{
 apiGetSystemMenu(Frm.Handle,1);
}

//反省是不是一个给定的ID在体系菜单ID局限以内

publicstaticboolVerifyItemID(intID)
{
 return(bool)(ID<0xF000&&ID>0);
}
}
  你可使用静态办法ResetSystemMenu把窗口的体系菜单设置为本来形态DD这在使用程序碰到毛病或没有准确修正菜单时是很有效的。

  5、利用SystemMenu类

//SystemMenu工具

privateSystemMenum_SystemMenu=null;

//ID常数界说

privateconstintm_AboutID=0x100;

privateconstintm_ResetID=0x101;



privatevoidfrmMain_Load(objectsender,System.EventArgse)

{

try

{

m_SystemMenu=SystemMenu.FromForm(this);

//增加一个separator...

m_SystemMenu.AppendSeparator();

//增加"关于"菜单项

m_SystemMenu.AppendMenu(m_AboutID,"关于");

//在菜单顶部加上"复位"菜单项

m_SystemMenu.InsertSeparator(0);

m_SystemMenu.InsertMenu(0,m_ResetID,"复位体系菜单");

}

catch(NoSystemMenuException/*err*/)

{

//创建你的毛病处置器

}

}
  6、检测自界说的菜单项是不是被点击

  这是较难完成的部分。由于你必需重载你的从Form或Control承继类的WndProc成员函数。你能够如许完成:

protectedoverridevoidWndProc(refMessagemsg)
{
 base.WndProc(refmsg);
}
  注重,必需挪用基类的WndProc完成;不然,不克不及一般事情。

  如今,我们来剖析一下怎样重载WndProc。起首应当截获WM_SYSCOMMAND动静。当用户点击体系菜单的某一项大概选择“最年夜化”按钮,“最小化”按钮大概“封闭”按钮时,我们要检索该动静。出格注重,动静工具的WParam参数恰好包括了被点击菜单项的ID。因而我们能够完成以下重载:

protectedoverridevoidWndProc(refMessagemsg)
{
 //经由过程截取WM_SYSCOMMAND动静并举行处置
 //注重,动静WM_SYSCOMMAND被界说在WindowMessages列举类中
 //动静的WParam参数包括点击的项的ID
 //该值与经由过程下面类的InsertMenu()或AppendMenu()成员函数传送的一样

 if(msg.Msg==(int)WindowMessages.wmSysCommand)
 {
  switch(msg.WParam.ToInt32())
  {
   casem_ResetID://reset菜单项的ID
   {
    if(MessageBox.Show(this,"        Areyousure?","Question",MessageBoxButtons.YesNo)==
DialogResult.Yes)
    {//复位体系菜单
     SystemMenu.ResetSystemMenu(this);
    }
   }break;
   casem_AboutID:
   {//“关于”菜单项
    MessageBox.Show(this,"朱先中

"+"e-mail:sdmyzxz@163.com","关于");
   }break;
   //这里能够针对别的的菜单项计划处置历程
  }
 }
 //挪用基类函数
 base.WndProc(refmsg);
}
  7、总结

  完成上述方针的另外一个大概的办法是,经由过程创立一个事务OnSysCommand并当动静WM_SYSCOMMAND传来时激活它,然后把属性WParam传送给该事务的句柄。读者能够自行编程考证。

  总之,本文经由过程一个复杂的体系菜单修正例子,剖析了用C#利用.NET平台挪用机制来挪用DLL中的非托管函数的基础步骤及注重事项。另,所附源程在Windows2000Server/VS.NET2003下调试经由过程。感觉很多控件都必须自己去写代码;用了WebMatrix感觉也不是很好,毕竟没有很强的WYSIWYG效果。现在就不知道如何是好了。

若天明 发表于 2015-1-19 18:21:36

是指转换后的Servlet程序代码的行数。这给调试代码带来一定困难。所以,在排除错误时,可以采取分段排除的方法(在可能出错的代码前后输出一些字符串,用字符串是否被输出来确定代码段从哪里开始出错)。

再见西城 发表于 2015-1-27 21:45:20

对于中小项目来说.net技术是完全可以胜任,但为什么现在大型公司或网站都选择php或java呢?就是因为微软不够开放,没有提供从硬件到应用服务器再到业务应用的整套解决方案。

第二个灵魂 发表于 2015-2-5 11:40:54

我的意思是.net好用,从功能上来说比JAVA强还是很明显的。

因胸联盟 发表于 2015-2-11 14:40:23

同时也感谢博客园给我们这个平台,也感谢博客园的编辑们做成专题引来这么多高人指点。

愤怒的大鸟 发表于 2015-3-2 14:26:02

是指转换后的Servlet程序代码的行数。这给调试代码带来一定困难。所以,在排除错误时,可以采取分段排除的方法(在可能出错的代码前后输出一些字符串,用字符串是否被输出来确定代码段从哪里开始出错)。

莫相离 发表于 2015-3-11 04:09:46

ASP在执行的时候,是由IIS调用程序引擎,解释执行嵌在HTML中的ASP代码,最终将结果和原来的HTML一同送往客户端。

爱飞 发表于 2015-3-17 20:35:02

JSP/Servlet虽然在国内目前的应用并不广泛,但是其前途不可限量。

活着的死人 发表于 2015-3-25 00:25:10

现在的ASP.net分为两个版本:1.1和2.0Asp.net1.1用VS2003(visualstudio2003)编程。Asp.net2.0用VS2005(visualstudio2005)编程。现在一般开发用的是VS2003。
页: [1]
查看完整版本: ASP.NET网页编程之C#+Windows API利用体系菜单