CSDN首页 空间 新闻 论坛 Blog 下载 读书 网摘 搜索 .NET Java 视频 接项目 求职 在线学习 买书 程序员 通知
山寨机中的战斗机! 程序优化工程师到底对IT界有没有贡献
CSDN社区
搜索 收藏 打印 关闭
CSDN社区 >  .NET技术 >  非技术区

想写个代码生成器嵌入到 vs 2003. 请高人指点一下.

楼主CtrlT( 我自由!我变坏! )2005-06-02 15:31:34 在 .NET技术 / 非技术区 提问

 
  每天都在写重复的存盘存盘….也够有火气的了…  
   
   
  想用C#写个比如像vs   2003里的菜单或工具条的插件   嵌入到   vs   2003.      
   
  这样的话可以跟据要求的不同自动产生一些代码,减轻大伙的工作量.    
   
  但不知如何下手呀.        
  问题点数:94、回复次数:6Top

1 楼JasonHeung(拥有一切不过就这样笑着哭)回复于 2005-06-02 15:50:08 得分 80

VS   2003   IDE插件开发指南                  
  作者   sema            
  2005-04-15   10:03      
  Visual   Studio.NET插件能做很多事情,例如:  
  1、       编写如CodeRush一样的开发环境代码辅助工具  
  2、       编写如CodeSmith这样的代码模板工具  
  3、       编写代码生成器,根据自定义的一些条件自动生成代码。如现在比较流行的一些代码生成工具,如果和开发环境集成,使用起来应该会更加方便。  
  4、       编写如DataSetPryer这样的调试工具,可以在调试时查看DataSet的内容。  
  5、       甚至还可以在VS.NET里集成Google搜索引擎,或将MSN集成到VS.NET。  
  这里不再一一列举,总而言之,凡是可以和Visual   Studio.NET开发环境相关的,都能以插件的形式进行。  
  开发VS.NET插件,目前有两种形式:一是利用VS向导生成的VS外接程序;二是利用微软的VSIP开发包(Visual   Studio   Industry   Partner:微软合作伙伴计划)。本文讨论的是第一种方法。  
   
    二、                           程序框架概述  
  在Visual   Studio.NET中选择”新建项目à其他项目à扩展性项目àVisual   Studio.NET外接程序”,按照向导生成代码,最后会生成两个工程文件,一个是外接程序项目,一个是外接程序安装项目。可以在外接程序项目里看到生成的项目文件中有个connect.cs文件,该文件有以下几个部分:  
   
   
  1、       类的继承接口及其常量定义  
   
  [GuidAttribute("952A6CFF-8516-4DA0-B0BA-519CB9614525"),   ProgId("STDTools.Connect")]  
  public   class   Connect   :   Object,   Extensibility.IDTExtensibility2,   IDTCommandTarget  
  {…}  
  Connect类主要从两个接口继承,一个是Extensibility.IDTExtensibility2接口,该接口主要定义了下面几个方法:  
  OnAddInsUpdate   方法:在环境中加载或卸载外接程序时发生。  
  OnBeginShutdown   方法:正在关闭环境时发生。  
  OnConnection   方法:将外接程序加载到环境中时发生。  
  OnDisconnection   方法:当从环境中卸载外接程序时发生。  
  OnStartupComplete   方法:环境启动完毕时发生。  
   
   
  IDTCommandTarget接口则定义了以下两个方法  
  Exec   方法:在VS开发环境中选择了某个外接菜单命令时被VS环境所调用。    
  QueryStatus方法:当VS环境要显示外接菜单时调用该方法查询菜单的状态。  
  该方法返回指定的已命名命令的当前状态,无论此命令是启用、禁用还是隐藏  
   
   
  2、       OnConnection()函数:  
  本事件处理函数是在插件被加载时发生,一般用于做一些初始化工作,如创建菜单等。该函数的传入参数如下:  
  object   application:定义了IDE自动化对象  
  Extensibility.ext_ConnectMode   connectMode:连接模式,指明了插件当前的连接模式  
  ext_cm_AfterStartup   外接程序是在应用程序启动后加载的,或是通过将相应   AddIn   对象的   Connect   属性设置为   True   加载的。    
  ext_cm_Startup   外接程序是在启动时加载的。    
  ext_cm_UISetup   外接程序自安装后首次被启动。  
   
   
  3、       OnDisconnection()函数:系统卸载插件时被调用  
  本事件处理函数是在插件被卸载时发生,其传入参数如下  
  Extensibility.ext_DisconnectMode   disconnectMode:  
  ext_dm_HostShutdown:外接程序是在开发环境关闭时卸载的。    
  ext_dm_UserClosed:外接程序是在用户清除“外接程序管理器”对话框中该外接程序的复选框时卸载的    
  ext_dm_UISetupComplete:外接程序是在环境安装完成后和在   OnConnection   方法返回后卸载的。    
   
   
  4、       QueryStatus()函数:    
  系统查询菜单状态  
   
   
  5、       Exec()函数:  
  在VS开发环境中选择了某个外接菜单命令时被VS环境所调用,在这里可以编写自己的响应代码,例如运行自己的程序或弹出某个窗口。  
   
   
  三、                           处理菜单  
  在OnConnect方法中可以进行一系列初始化工作,其中之一就是生成菜单  
   
   
  1、       添加菜单条菜单和工具条菜单  
   
   
  applicationObject   =   (_DTE)application;  
  addInInstance   =   (AddIn)addInInst;  
  if(connectMode   ==   Extensibility.ext_ConnectMode.ext_cm_UISetup  
  ||   connectMode   ==   Extensibility.ext_ConnectMode.ext_cm_Startup)  
  {//         如果是安装状态或是插件刚被启动的状态,则创建菜单  
  object   []contextGUIDS   =   new   object[]   {   };    
     
   
  //获取IDE环境的Command集合和CommandBar集合   Commands   commands   =   applicationObject.Commands;  
  _CommandBars   commandBars   =   applicationObject.CommandBars;  
   
  try  
  {  
  //菜单条对象和工具条对象都是CommandBar类型  
  CommandBar   menuObj,toolbarObj;  
  //生成新的子菜单对象,将会被插入到菜单条和工具条对象上  
  Command   commandObj   =   commands.AddNamedCommand(addInInstance,  
    "PublishUserManage",  
    "添加用户管理代码",    
  "添加用户管理的代码",    
  true,  
  127,    
  ref   contextGUIDS,   (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled  
  );  
  #region    
  这里有几点要说明:  
            1、菜单图片:  
  以上的参数中的true,bool   MSOButton参数为true,意味着该菜单命令的图片是来源于Office资源库,则后面的int   Bitmap(位图ID号)则指明了是哪个图片。如何知道哪个ID号对应哪个图片?可以从微软的页面上下载一个用VBA写的工具,该工具列举出了所有的图片资源(附录工具中已经包含FaceID.xls)。  
  以上的参数中的true(bool   MSOButton),意味着该菜单命令的图片是来源于Office资源库,则后面的127(int   Bitmap--位图ID号)则指明了是哪个图片。如何知道哪个ID号对应哪个图片?可以从微软的页面上下载一个用VBA写的工具,该工具列举出了所有的图片资源(附录工具中已经包含FaceID.xls)。  
  如果不想用Microsoft   Office自带的图片资源,则需要先在自己的解决方案中添加一个MFC   DLL的工程,然后在其中加入图片资源;然后将MSOButton设为False,将Bitmap位图ID设为该资源文件中图片资源的ID号,然后还要在安装程序里添加一个文件夹,同时添加注册表项。具体过程就不再多说了,可以看参考资料  
  2、菜单项的名称  
  函数的第二项参数string   Name(本例中是”PublishUserManage”),系统在生成菜单对象时会自动在Name前面添加本插件的ProgID代表的字符串作为菜单对象的全名。后面在根据名称检索该菜单对象时,需要用全名,本例中应该是”STDTools.Connect.PublishUserManage”;  
  */  
  #endregion    
  //添加主菜单  
  CommandBarButton   buttonObj;  
  //创建主菜单项和工具条  
  menuObj   =   (CommandBar)   applicationObject.Commands.AddCommandBar("代码生成(&C)"   ,    
      vsCommandBarType.vsCommandBarTypeMenu,    
      applicationObject.CommandBars["MenuBar"],10);  
  toolbarObj   =   (CommandBar)   applicationObject.Commands.AddCommandBar(  
                                  "CodeTools(&C)",  
  vsCommandBarType.vsCommandBarTypeToolbar,  
  null,  
  -1);  
  toolbarObj.Position   =   Microsoft.Office.Core.MsoBarPosition.msoBarTop;  
  //增加子菜单  
  //将子菜单加入主菜单和工具条  
  buttonObj   =   (CommandBarButton)   commandObj.AddControl(menuObj,   menuObj.Controls.Count   +   1);  
  buttonObj   =   (CommandBarButton)   commandObj.AddControl(toolbarObj,   toolbarObj.Controls.Count   +   1);  
  buttonObj.Style   =   MsoButtonStyle.msoButtonIcon;  
  //将子菜单加入Project的右键菜单  
  CommandBar   projBar   =   this.applicationObject.CommandBars["Project"];  
  commandObj.AddControl(projBar,1);  
  }  
  catch(System.Exception   ex)  
  {  
  string   error   =   ex.Message;  
  }  
   
   
  2、       添加右键弹出快捷菜单  
   
  除了上面在VS开发环境中添加常规菜单外,还允许用户为开发环境添加一些右键弹出菜单项。下面代码是为代码编辑窗口添加右键弹出菜单。  
                          //检索代码编辑窗口右键弹出菜单的工具条  
  CommandBar   projBar   =   this.applicationObject.CommandBars["Code   Window"];  
  //将自己的菜单项加入工具条  
                          commandObj.AddControl(projBar,1);  
  如果想在鼠标右键点击“解决方案资源管理器”中的某项目结点时弹出的菜单条中添加自己的菜单项,则只需把上面的"Code   Window"改成"Project"即可。如何知道是"Code   Window"或"Project"这个没有什么资料说明,但是也很简单,只要编写一个插件程序,列举出所有的菜单条对象就行了。幸好笔者已经做了这件事情,把所有的菜单条对象的名称都列在附录的CommandBar_Names.txt文件里了,你所要做的就是根据名称去猜哪个是你所需要的菜单条了。  
   
   
  3、       卸载菜单  
   
   
  为什么需要卸载菜单?  
  因为如果在你的插件中没有处理卸载菜单,则用户通过“工具à外接程序管理器”暂时关闭了你的插件,或者是通过添加/删除程序卸载了你的插件时,菜单项依然存在,但是却已经不能执行命令,这是不合理的。  
  卸载菜单是在OnDisconnection方法中实现的,具体可参见下载资源里的STDTool里的Connect.cs文件中的OnDisconnection方法。在该方法中的代码比较简单,先判断是不是VS环境正在关闭或用户通过外接程序暂停了插件,然后查找到子菜单项并删除,再查找到主菜单项和工具条项,从系统菜单集合里移除掉这些命令条对象。  
   
   
  4、       确定菜单状态  
   
   
  菜单显示时有一项比较重要的工作,就是根据应用环境的不同,菜单对象的显示状态也在不断变化。也即可用,禁用,不显示。每当VS集成环境要显示一个插件的菜单时,它会调用QueryStatus()方法查询该菜单应该显示的状态。具体代码可参见下载资源里的STDTool里的Connect.cs文件中的QueryStatus方法,该方法先预设菜单项状态为受支持状态(vsCommandStatusSupported,如果不受支持,则菜单不会显示),然后判断条件满足的情况下添加菜单为可用状态(vsCommandStatusEnabled),如果不满足条件,则菜单为禁用状态。  
   
  Top

2 楼JasonHeung(拥有一切不过就这样笑着哭)回复于 2005-06-02 15:50:19 得分 0

 
  5、       执行菜单命令  
   
   
  当用户选择插件的菜单项时,集成环境会调用Exec()方法,具体代码可参见下载资源里的STDTool里的Connect.cs文件中的Exec方法,该方法查询被执行的菜单的名称是本插件所期望的名称,则执行一段代码,如显示窗口等。执行成功,则设置handled为true,告诉集成环境已经成功执行命令。  
   
   
  四、                           使用窗口  
   
   
  1、       使用WinForm窗口  
   
  在VS.NET中显示WinForm窗口非常容易,和平常编写WinForm程序没什么两样,步骤如下:    
  l                     在项目里添加一个WinForm窗体  
  l                     修改WinForm窗体的构造函数  
  将VS环境的根对象DTE对象传入,以便在WinForm中可以操纵开发环境  
                      public   class   MyForm   :   System.Windows.Forms.Form  
                      {                  
  private   EnvDTE.DTE   applicationObject;  
  …  
                    public   MyForm(EnvDTE.DTE   applicationObject)  
                    {  
                              InitializeComponent();  
                              this.applicationObject   =   applicationObject;  
                              …  
                      }  
   
   
  l                     在Connect文件的Exec函数里生成并显示WinForm窗体。  
                              MyForm   form   =   new   MyForm(this.applicationObject.DTE);  
                              form.ShowDialog();  
  注意:这里的this.applicationObject是_DTE接口指针,它的一个成员DTE成员才是DTE对象,不能直接用类型转换如(DTE)   this.applicationObject  
   
   
  2、       使用工具窗口  
   
   
  VS.NET的工具窗口指的是类似“解决方案资源管理器”,“类视图”,“工具箱”这样停靠在上下左右侧边的窗口。而如代码编辑窗口这样的窗口,需要用VSIP进行开发,外接程序插件是没有办法开发这类窗口的。  
  根据MSDN里的资料,如果要开发侧边工具窗口,是件非常繁琐的事情。因为VS.NET是基于COM开发的,所以开发出来的侧边工具窗口也需要实现一系列接口,也就是说,不能直接使用.NET程序集。幸而已经有人做了这件事情  
  (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/vstchFAQAboutVSNETAutomation.asp),  
  开发了一个将.NET用户控件包装成COM组件的容器VSUserControlHostLib,使得我们只需要开发出.NET用户控件,就可以将其嵌入到VS集成环境里了  
  开发步骤:    
  1、       生成Addin项目  
  2、       在项目中添加VSUserControlHost.dll引用  
  3、       在Connect.cs文件的OnConnection方法中添加显示窗口的代码  
  下面是代码示例:(添加在OnConnect方法中)  
  //GUID串可以用VS开发环境里菜单命令“工具à创建GUID”弹出的对话框创建  
                    string   guidstr   =   "{65FADCBF-63D2-448b-8A4B-393D7E751345}";  
                    object   objTemp   =   null;  
                    VSUserControlHostLib.IVSUserControlHostCtl   objControl   =   null;  
                    //这里先生成容器窗口,返回的控件对象在objTemp里  
                    windowExplorer   =   applicationObject.Windows.CreateToolWindow(  
  addInInstance,    
  "VSUserControlHost.VSUserControlHostCtl",    
  "菜单浏览器",    
  guidstr,    
  ref   objTemp);  
                    //使用容器窗口时,必须在调用该容器控件前设置其为可见,否者将会不能正常显示  
                    windowExplorer.Visible   =   true;  
                    windowExplorer.IsFloating   =   false;  
                    //将返回的工具窗口转换为容器对象  
                    objControl   =   (VSUserControlHostLib.IVSUserControlHostCtl)objTemp;  
                    System.Reflection.Assembly   asm   =   System.Reflection.Assembly.GetExecutingAssembly();  
                    //用容器对象包含用户控件,  
                    menuExplorer   =   (MenuExplore)objControl.HostUserControl(asm.Location,  
  "MenuBrowser.MenuExplore");  
                    //设置窗口的图标  
  //windowExplorer.SetTabPicture(…)  
                              //将DTE对象赋给窗口  
  menuExplorer.Application   =   applicationObject;  
   
   
  说明:    
  l                     生成工具窗口:  
  以上代码先用CreateToolWindow函数生成工具窗口,工具窗口里承载的VSUserControlHost.VSUserControlHostCtl类型控件由objTemp对象返回  
  l                     设置可见性:  
  将工具窗口设置为可见,非浮动  
  l                     获取IVSUserControlHostCtl接口:  
  将返回的工具窗口中承载的控件对象objTemp转换为IVSUserControlHostCtl接口类型,并赋给objControl对象  
  l                     加载用户控件:  
  用objControl的HostUserControl方法加载指定程序集的指定用户控件对象,上面代码中因为MenuBrowser.MenuExplore类是在插件项目的程序集里,所以用System.Reflection.Assembly.GetExecutingAssembly()方法获取当前程序集位置。如果用户控件是在其他程序集里,需要根据实际情况指定程序集位置  
   
   
  4、       最后还应该在OnDisconnection方法里关闭窗口  
  if(windowExplorer!=   null)  
  {  
            windowExplorer.Visible   =   false;  
  }  
   
   
  五、                           操纵VS开发环境  
   
   
  VS.NET自动化模型涉及的面太广,本文只针对一些专题加以说明。  
  1、       利用代码模型浏览代码  
  l                     获取代码模型对象  
  //获取当前正活动的文档  
            Document   activeDocument   =   applicationObject.ActiveDocument;  
  //获取代码模型对象,  
  //请自行判断activeDocument,ProjectItem,FileCodeModel以及CodeElements是否不为空  
  CodeElements   codeElements   =   activeDocument.ProjectItem.FileCodeModel.CodeElements;  
  //检索代码元素  
            foreach(CodeElement   ce   in   codeElements)  
            {  
                    result.AddRange(getCodeElements(ce));  
            }  
  说明:  
  上面的代码先从DTE对象(也即VS自动模型的根对象)获得当前正活动的文档对象  
  然后再根据文档对象获取和它关联的项目元素,这里的ProjectItem其实就是在解决方案资源管理器下面的项目文件夹对应的子项。可以是各种类型,如文件,文件夹等  
  再从项目元素获得关联的文件代码模型  
  根据文件代码模型获取其代码元素的集合CodeElementCollection,代码元素的父类为CodeElement,下面派生出许多的子类,代表具体的代码元素,分别有:  
  CodeNamespace、CodeClass、CodeInterface、CodeFunction  
  CodeProperty、CodeVariable、CodeDelegate、CodeStruct、CodeEnum  
  代表着命名空间、类、接口、函数、属性、变量、委托、结构、枚举等类型的代码元素,某个CodeElement具体是何类型,可以根据CodeElement.   vsCMElement枚举类型来判断,然后再显式转换成具体的子类即可  
  但是更进一步的代码元素,如函数体内的语句,好像还没有看到有方法检索。不过也可以利用一些其它的方法,比如CodeRush的程序集里面提供了一个StructuralParser程序集,用于C#的代码分析。如果谁有兴趣可以研究研究  
   
   
  l                     根据具体类型检索代码元素  
  具体可参见下载资源包里的MenuBrowser的getCodeElements方法,这里不多作解释  
  2、       操纵解决方案及其项目文档  
  l                     获取当前被选中的项目  
  下面代码演示了鼠标点击一个项目,或项目中的子项时,如何得到该项目对象  
  public   Project   GetSelectedProject()  
  {  
            Project   project   =   null;  
            //从被选中对象中获取工程对象  
            EnvDTE.SelectedItem   item   =   Application.SelectedItems.Item(1);  
            if(item.Project   !=   null)  
            {//被选中的就是项目本生  
                    project   =   item.Project;  
            }  
            else  
            {//被选中的是项目下的子项  
                    project   =   item.ProjectItem.ProjectItems.ContainingProject;  
            }  
            return   project;  
  }  
  l                     获取当前项目的所在目录  
  private   string   GetSelectedProjectPath()  
  {  
                    string   path   =   "";  
            //获取被选中的工程  
                    Project   project   =   GetSelectedProject();  
                    if(project   !=   null)  
                    {  
                    //全名包括*.csproj这样的文件命  
                                        path   =   project.FullName;  
                    }  
            //去掉工程的文件名  
                    path   =   Path.GetDirectoryName(path);  
                    return   path;  
  }  
  l                     将文件加入工程中  
  //获取被选中的工程  
  Project   project   =   this.GetSelectedProject();  
  //将文件夹下的文件加入工程  
  project.ProjectItems.AddFromDirectory(sdir);  
  //将单个文件加入工程  
  project.ProjectItems.AddFromFile(nfile);  
  l                     向项目中加入程序集引用  
  using   VSLangProj;  
  private   void   AddReference(string   assembly)  
  {  
                    Project   project   =   GetSelectedProject();  
                    VSProject   vsproject   =   null;  
                    if   (project.Kind   ==   PrjKind.prjKindCSharpProject)  
                    {  
                    //工程类型为C#工程,将project的Object成员转换为VSProject对象  
                                        vsproject   =   project.Object   as   VSProject;  
                    }  
                    if(vsproject   !=   null)  
                    {  
                      //获取C#工程的引用集  
                                        VSLangProj.References   refers   =   vsproject.References;  
                                        if(refers   !=   null)  
                                        {  
                              //将程序集引用添加到工程中  
                                                          refers.Add(assembly);  
                                        }  
                    }  
  }  
  3、       在代码编辑窗口操纵代码  
  这里不再详述,只是列出网上的资源,大家可以自行参考  
   
   
  六、                           参考资料  
  http://www.knowdotnet.com/add-insmacros.html  
  msdn帮助目录:Visual   Studio   .NET-->使用   Visual   Studio   .NET   进行开发-->参考-->自动化与扩展性参考-->公共环境对象模型  
   
   
   
   
    Happy   Everyday    
   
  Top

3 楼CtrlT( 我自由!我变坏! )回复于 2005-06-02 15:58:24 得分 0

 
  非常感謝樓上的...    
  Top

4 楼rrjsh(rrjsh)回复于 2005-06-02 16:18:50 得分 10

我写了个代码生成工具,很管用,有空可以交流下,适用于多种场合,本人的QQ是 312912745Top

5 楼fuxia(双子星)回复于 2005-06-02 18:07:52 得分 2

OoTop

6 楼singedcat(以夢為馬)回复于 2005-06-02 18:44:19 得分 2

oTop

相关问题

  • 请朋友门指点,Asp2005 页面里的 窗体生成器 里的代码去哪找!
  • 谁有词法生成器?
  • 下拉菜单生成器???
  • 关于代码生成器
  • 关于类生成器和数据读写生成器的???
  • 类似WINZIP的密码生成器
  • 密码生成器的问题
  • 属性生成器里的URL多参???
  • 求一主键代码生成器
  • 有没有VB.NET的代码生成器?

关键词

  • .net
  • c#
  • vs.net
  • 代码
  • 函数
  • 卸载
  • vs
  • 项目
  • 文件
  • 菜单

得分解答快速导航

  • 帖主:CtrlT
  • JasonHeung
  • rrjsh
  • fuxia
  • singedcat

相关链接

  • CSDN .NET频道
  • .NET类图书
  • C#类图书
  • .NET类源码下载

广告也精彩

反馈

请通过下述方式给我们反馈
反馈
提问
网站简介|广告服务|VIP资费标准|银行汇款帐号|网站地图|帮助|联系方式|诚聘英才|English|问题报告
北京创新乐知广告有限公司 版权所有, 京 ICP 证 070598 号
世纪乐知(北京)网络技术有限公司 提供技术支持
Copyright © 2000-2008, CSDN.NET, All Rights Reserved
GongshangLogo