日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Visual Studio 2005 插件编程(代码行数统计插件)之一

發布時間:2023/12/31 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Visual Studio 2005 插件编程(代码行数统计插件)之一 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原文:http://www.codeproject.com/useritems/LineCounterAddin.asp

注意:1.本文中的提到的“外接程序”等同與“插件程序”

2.本文提供的源碼是在原作的基礎上有過修改。

代碼行數統計器(二):http://sifang2004.cnblogs.com/archive/2006/06/26/436178.html


代碼行數統計器(一)

--Visual Studio 2005插件開發

???????? 前段日子也寫篇關于開發Visual Studio 2005插件的文章,《Visual Studio 2005 開發VB.NET-C#語言轉換插件》,對這個也產生了點興趣,后又在codeproject上看到了這篇文章,開發一個可以統計整個項目代碼行數的插件,覺得還是挺不錯的,準備介紹給E文不是很好的朋友,當然沒有必要對文章進行整體翻譯,只要達到我們學習的目的就行了,而且代碼也是經過我做了些修改(我現在還有點納悶,為什么他的源碼編譯后可以正常運行,我是修改了幾個小時才能讓它正確運行的,特別是在中文環境中,需要修改的地方更多),如果你覺得本文讓你受益,那就向原著致以謝意吧!

背景

?????? 其實這種統計工程中各個文件及其整體的代碼行數的插件在WndTabs.com已經出現很久了,只是直到現在它還沒有出現支持VS2005的插件,那插件的運行效果顯示如下:

?



這插件的用處不用我說了,也許你說你用不上,但有的卻是喜歡至極了。

???????? 下面就是本文要完成的插件,運行后的效果圖:



是不是覺得更加漂亮點呢,至于功能,基本上差不多,如果你還需要更多的功能,完全可以自己去擴展,沒有看本文之前,也許還一頭霧水,但看完本文,你就有點蠢蠢欲動了。

Visual Studio自動化和擴展

?????? Visual Studio最大的特性之一就是其擴展性,對此我們中很多人應該都有所了解。Visual Studio 提供了三種不同級別的擴展:宏、外接程序和向導(就是我們本文中到的插件程序)以及 Visual Studio行業合作伙伴 (VSIP) 計劃。

???????? 若要創建自動化應用程序(如外接程序),則必須執行一些步驟獲取對自動化成員的訪問權。首先必須引用必需的自動化程序集,然后必須獲取對頂級對象 DTE2 的引用。

Visual Studio .NET 2002 Visual Studio .NET 2003 中,所有的核心自動化項均位于名為 EnvDTE 的程序集中,并且其最高分層對象為 DTE 對象。該對象是所有核心自動化對象、集合及其成員的父對象。DTE2 是從 DTE 派生的。

對于 Visual Studio 2005,只對這些核心自動化對象、集合及成員的一部分進行添加和更新。所有新的更新功能都位于名為 EnvDTE80 的程序集中(EnvDTE 8.0 版),而不會更新現有的程序集和危及現有外接程序和自動化項目的向后兼容性。EnvDTE80 中大多數更新的函數保留與早期版本相同的名稱,但是在函數名后加上數字 2。例如,在新版本中,TaskItems 集合名為 TaskItems2Solution 對象名為 Solution2。由于新成員比早期版本的功能更強健,并且包含最新功能,因此推薦在編寫新的自動化應用程序時使用新對象和新集合。

雖然新項位于 EnvDTE80 中,但是大多數核心自動化功能仍然位于 EnvDTE 中。因此,在編寫新的自動化應用程序(如外接程序)時,一定要引用 EnvDTE EnvDTE80 兩者。另外,如果使用 EnvDTE 程序集中的成員,也必須設置對 DTE 對象和 DTE2 對象的引用。這使您可以訪問所有的項。

???????? 外接程序是一些可以為您節省時間和精力的應用程序,可附加到 Visual Studio 集成開發環境 (IDE) 中使用。外接程序是 COM 對象,它們實現 IDTExtensibility2 接口,并通過 EnvDTE EnvDTE80 程序集中包含的核心自動化對象模型與 IDE 通信。工具欄模型包含在 Microsoft.VisualStudio.CommandBars 中。

??? 使用到的主要對象就是DTE對象,利用它我們能編程控制在Visual Studio中的任何東西,從工具欄,裝卸工具窗口,甚至編輯文件和初始化編譯。

?

創建一個插件工程

??????
???????? Visual Studio 2005
插件能使用任何編程語言寫,當你在運行Add-In向導(也就是插件工程向導)時,你可以選擇使用何種語言編寫,向導還會向你顯示其它的選項,具體每個選項的含義與作用,請參考MSDN,我只列舉如下(外接程序就是本文所說的插件):



1.???????????????

創建一個新的 Visual Studio 外接程序項目。這會啟動“外接程序向導”。

該項目類型位于“其他項目類型”下的“擴展性”文件夾中。

2.??????????????? 在“選擇編程語言”頁選擇一種語言。

這使您可以選擇將用來編寫外接程序的編程語言。

3.??????????????? 在“選擇應用程序宿主”頁選擇一個或多個應用程序,如 Visual Studio

這使您可以選擇需要的應用程序以便創建外接程序后可在其中運行該外接程序,如 Visual Studio Visual Studio“宏 IDE”。

4.??????????????? 在“輸入名稱和說明”頁中輸入外接程序的名稱和說明。

創建外接程序后,此名稱和說明顯示在“外接程序管理器”對話框的“可用外接程序”列表中,它告訴用戶外接程序的用途和工作方式等。

5.??????????????? 在“選擇外接程序選項”頁可以指定:

2??????? 是否希望外接程序顯示在“工具”菜單中。

2??????? 希望啟動外接程序的時間。

2??????? 外接程序是否不使用模型用戶界面 (UI),以便可以和命令行生成一起安全地使用。

此頁使您可以指定外接程序的某些行為選項。

6.??????????????? 在“選擇‘幫助’中的‘關于’信息”頁指定是否要將外接程序的信息顯示在 Visual Studio“幫助”中的“關于”窗口中,如果是這樣,就會顯示所需信息。

可以添加到 Visual Studio“幫助”中的“關于”窗口的信息包括版本號、支持詳細信息和授權數據等。

完成步驟 1 - 6 后,選定的選項會顯示在“摘要”頁中。

7.??????????????? 選擇“完成”創建外接程序。

現在,您已經擁有了一個功能齊全的基本外接程序。若要使外接程序能夠執行一些有用的操作,則必須添加相應代碼。

?

根據Add-In Wizard”創建一個外接程序,它具有全面的功能,但是只有基本框架,創建完該程序后可立即運行它。向導會自動生成一個Connect.cs文件,這個文件就是任何Visual Studio插件的起動點,它實現了一些關鍵接口,例如IDTExtensibility2, IDTCommandTarget,在幾個關鍵方法中提供一些啟動代碼,最重要的一個方法就是OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)當啟動一個插件時,第一個調用的方法就是它,你可以在其中增加一些初始化代碼,以及一些技術性的處理代碼,只要這些是工作在Visual Studio自動模型所公開的范圍之內。通常,該方法被插件向導生成的代碼填充,它實現你當時所做出的選擇(例如,增加一個工具菜單項)。

???????? Onconnection方法中許多代碼都有很好注釋說明,我們就不詳細解釋了,首先我們要注意的這三行代碼:

_applicationObject = (DTE2)application;

_addInInstance = (AddIn)addInInst;

if (connectMode == ext_ConnectMode.ext_cm_AfterStartup || connectMode == ext_ConnectMode.ext_cm_Startup)

第一行就是緩存一個DTE對象,這是在Visual Studio啟動插件時由它提供的,第二行就是緩存插件自己的一個實例,在你的編寫的插件代碼中你將會經常調用它,第三行是一個if語句,當插件啟動后,涉及到的條件的處理,Visual Studio通常會兩次啟動插件,一次就是設置自己的UI,如菜單項,菜單欄按鈕等等;另外,當插件真正運行后,插件被再次啟動,這可以發生在兩種不同情況下(第一是當VS啟動后自動運行,或者是在VS啟動后通過其它進程來運行)。If語句中兩個條件含義你可以參照下表:

成員名稱

說明

ext_cm_AfterStartup

外接程序是在 Visual Studio 啟動后加載的。?

ext_cm_CommandLine

外接程序是從命令行加載的。?

ext_cm_External

外接程序是由外部客戶端加載的。(Visual Studio 不再使用此設置。)?

ext_cm_Solution

外接程序是在解決方案中加載的。?

ext_cm_Startup

外接程序是在 Visual Studio 啟動時加載的。?

ext_cm_UISetup

外接程序是為用戶界面設置而加載的。?

枚舉ext_ConnectMode的成員?

??? OnConnection方法中的其它代碼都有注釋,根據你當初在向導中做出的選擇,代碼會有所不同,對于該Line Counter插件來說,我們去掉了所有的自動生成的代碼,完全用自己寫的代碼代替了,如果你希望跟著本文聽我解釋如果創建一個工具欄插件,那么按如下設置創建一個新的工程:

工程名稱:LineCounterAddin

語言:c#

插件名稱:Line Counter

插件描述:Line Counter 2005 - Source Code Line Counter

其它選項:默認

工程創建后,添加如下引用:

System.Drawing
System.Windows.Forms

最后,添加一個用戶控件LineCounterBrowser,該用戶控件是本插件的主要的交換接口,它就像普通的Widows Form那樣工作,當然這不是本文討論的重點,你可以下載源碼,從源碼中查看該用戶控件的詳細細節,現在,我們向新的用戶控件中加入下面的代碼:

private DTE2 m_dte;??????????????????????

public DTE2 DTE

{

set

{

???? ???? m_dte = value;

}

}

暫時在用戶控件代碼中我們不需要任何其它東西,這個屬性以及相應的變量為我們提供了一種從Connect類向我們的UI類傳遞DTE對象引用的方法。我們在Connect類的OnConnection方法中設定該屬性,OnConnection方法中的全部代碼就如下面的,已經注釋的非常清楚,在這我就不做深入解釋了。

public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)

??????? {

??????????? // Cache the DTE and add-in instance objects

??????????? _applicationObject = (DTE2)application;

??????????? _addInInstance = (AddIn)addInInst;

?

??????????? // Only execute the startup code if the connection mode is a startup mode

??????????? if (connectMode == ext_ConnectMode.ext_cm_AfterStartup || connectMode == ext_ConnectMode.ext_cm_Startup)

??????????? {

??????????????? try

??????????????? {

??????????????????? // Declare variables

??????????????????? string ctrlProgID, guidStr;

??????????????????? EnvDTE80.Windows2 toolWins;

??????????????????? object objTemp = null;

?

??????????????????? // The Control ProgID for the user control

??????????????????? ctrlProgID = "LineCounterAddin.LineCounterBrowser";

?

??????????????????? // This guid must be unique for each different tool window,

??????????????????? // but you may use the same guid for the same tool window.

??????????????????? // This guid can be used for indexing the windows collection,

??????????????????? // for example: applicationObject.Windows.Item(guidstr)

??????????????????? guidStr = "{2C73C576-6153-4a2d-82FE-9D54F4B6AD09}";

?

??? ??????????????? // Get the executing assembly...

??????????????????? System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();

?

??????????????????? // Get Visual Studio's global collection of tool windows...

??????????????????? toolWins = (Windows2)_applicationObject.Windows;

?

??????????????????? // Create a new tool window, embedding the LineCounterBrowser control inside it...

??????????????????? m_toolWin = toolWins.CreateToolWindow2(_addInInstance, asm.Location, ctrlProgID, "Line Counter", guidStr, ref objTemp);

?

??????????????????? // Pass the DTE object to the user control...

??????????????????? LineCounterBrowser browser = (LineCounterBrowser)objTemp;

??????????????????? browser.DTE = _applicationObject;

?

??????????????????? // and set the tool windows default size...

??????????????????? m_toolWin.Visible = true;?????? // MUST make tool window visible before using any methods or properties,

??????????????????? // otherwise exceptions will occurr.

??????????????????? //toolWin.Height = 400;

??????????????????? //toolWin.Width = 600;

??????????????? }

??????????????? catch (Exception ex)

??????????????? {

??????????????????? Debug.WriteLine(ex.Message);

??????????????????? Debug.WriteLine(ex.StackTrace);

??????????????? }

??????????? }

?

??????????? // Create the menu item and toolbar for starting the line counter

??????????? if (connectMode == ext_ConnectMode.ext_cm_UISetup)

??????????? {

??????????????? try

??????????????? {

??????????????????? // Get the command bars collection, and find the MenuBar command bar

??????????????????? CommandBars cmdBars = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars);

??????????????????? CommandBar menuBar = cmdBars["MenuBar"];

?

??????????????????? // Add command to 'Tools' menu

??????????????????? CommandBarPopup toolsPopup = (CommandBarPopup)menuBar.Controls["Tools"];

??????????????????? AddPopupCommand(toolsPopup, "LineCounterAddin", "Line Counter 2005", "Display the Line Counter 2005 window.", 1);

?

??????????????????? // Add new command bar with button

??????????????????? CommandBar buttonBar = AddCommandBar("LineCounterAddinToolbar", MsoBarPosition.msoBarFloating);

??????????????????? AddToolbarCommand(buttonBar, "LineCounterAddinButton", "Line Counter 2005", "Display the Line Counter 2005 window.", 1);

??????????????? }

????????? ??????catch (Exception ex)

??????????????? {

??????????????????? string error = ex.Message;

??????????????? }

??????????? }

??????? }

Visual Studio的執行期間的不同點,OnConnection方法會運行幾次,我們關注的是方法被調用的可能原因中的兩個,其一是UI Setpup,另外就是Startup,當因為UI Setpup OnConnection方法被調用時,為了這個插件,我們想用一個菜單項以及菜單欄按鈕更新Visual Studio的用戶接口,我們是在OnConnection方法中的第二個if語句中完成的。當OnConnection方法因為Startup(有兩種不同的方法-當VS啟動時,VS啟動后)調用時我們顯示我們的插件。

???????? 當執行UI Setup時,我們已經創建了幾個private輔助方法來簡化處理,下面,你能發現不少方法能幫助你在Visual Studio中建立新的CommandBar,還可以向這些CommandBar中添加命令。這些方法還包含向菜單中添加菜單項,這些方法也都注釋得非常清楚了。關于這些方法,要注意的一件事情就是他們認為你的插件項目中有一個包含你所有你希望為你命令使用的圖片(包括菜單項以及你工具條上的按鈕。等下我就解釋如何添加自定義的圖標。

/// <summary>

??????? /// Add a command bar to the VS2005 interface.

??????? /// </summary>

??????? /// <param name="name">The name of the command bar</param>

??????? /// <param name="position">Initial command bar positioning</param>

??????? /// <returns></returns>

??????? private CommandBar AddCommandBar(string name, MsoBarPosition position)

??????? {

??????????? // Get the command bars collection

??????????? CommandBars cmdBars = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars);

??????????? CommandBar bar = null;

?

??????????? try

??????????? {

??????????????? try

??????????????? {

??????????????????? // Create the new CommandBar

??????????????????? bar = cmdBars.Add(name, position, false, false);

??????????????? }

??????????????? catch (ArgumentException)

??????????????? {

??????????????????? // Try to find an existing CommandBar

??????????????????? bar = cmdBars[name];

??????????????? }

??????????? }

??????????? catch

??????????? {

??????????? }

?

??????????? return bar;

??????? }

?

??????? /// <summary>

??????? /// Add a menu to the VS2005 interface.

??????? /// </summary>

??????? /// <param name="name">The name of the menu</param>

??????? /// <returns></returns>

??????? private CommandBar AddCommandMenu(string name)

??????? {

??????????? // Get the command bars collection

??????????? CommandBars cmdBars = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars);

??????????? CommandBar menu = null;

?

??????????? try

??????????? {

??????????????? try

??????????????? {

??????????????????? // Create the new CommandBar

??????????????????? menu = cmdBars.Add(name, MsoBarPosition.msoBarPopup, false, false);

??????????????? }

??????????????? catch (ArgumentException)

??????????????? {

??????????????????? // Try to find an existing CommandBar

??????????????????? menu = cmdBars[name];

??????????????? }

??????????? }

??????????? catch

??????????? {

??????????? }

?

??????????? return menu;

??????? }

?

??????? /// <summary>

??????? /// Add a command to a popup menu in VS2005.

??????? /// </summary>

??????? /// <param name="popup">The popup menu to add the command to.</param>

??????? /// <param name="name">The name of the new command.</param>

??????? /// <param name="label">The text label of the command.</param>

??????? /// <param name="ttip">The tooltip for the command.</param>

??????? /// <param name="iconIdx">The icon index, which should match the resource ID in the add-ins resource assembly.</param>

??????? private void AddPopupCommand(CommandBarPopup popup, string name, string label, string ttip, int iconIdx)

??????? {

??????????? // Do not try to add commands to a null menu

??????????? if (popup == null)

??????????????? return;

?

??????????? // Get commands collection

??????????? Commands2 commands = (Commands2)_applicationObject.Commands;

??????????? object[] contextGUIDS = new object[] { };

?

??????????? try

??????????? {

??????????????? // Add command

??????????????? Command command = commands.AddNamedCommand2(_addInInstance, name, label, ttip, false, iconIdx, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

??????????????? if ((command != null) && (popup != null))

??????????????? {

??????????????????? command.AddControl(popup.CommandBar, 1);

??????????????? }

??????????? }

??????????? catch (ArgumentException)

??????????? {

??????????????? // Command already exists, so ignore

??????????? }

??????? }

?

??????? /// <summary>

??????? /// Add a command to a toolbar in VS2005.

??????? /// </summary>

??????? /// <param name="bar">The bar to add the command to.</param>

??????? /// <param name="name">The name of the new command.</param>

??????? /// <param name="label">The text label of the command.</param>

??????? /// <param name="ttip">The tooltip for the command.</param>

??????? /// <param name="iconIdx">The icon index, which should match the resource ID in the add-ins resource assembly.</param>

??????? private void AddToolbarCommand(CommandBar bar, string name, string label, string ttip, int iconIdx)

??????? {

??????????? // Do not try to add commands to a null bar

??????????? if (bar == null)

??????????????? return;

?

??????????? // Get commands collection

??????????? Commands2 commands = (Commands2)_applicationObject.Commands;

??????????? object[] contextGUIDS = new object[] { };

?

??????????? try

??????????? {

??????????????? // Add command

??????????????? Command command = commands.AddNamedCommand2(_addInInstance, name, label, ttip, false, iconIdx, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePict, vsCommandControlType.vsCommandControlTypeButton);

??????????????? if (command != null && bar != null)

??????????????? {

??????????????????? command.AddControl(bar, 1);

??????????????? }

??????????? }

??????????? catch (ArgumentException)

??????????? {

??????????????? // Command already exists, so ignore

??????????? }

??????? }

現在我們有了必要的代碼,讓插件正確地集成到Visual Studio用戶接口中去的代碼,并當得到請求時顯示插件,我們需要增加命令處理,在插件中處理命令是一件相當簡單的事情,這個 IDTCommandTarget接口,我們的Connect 類實現了它,提供了一些必要的方法從Visual Studio中正確地處理命令。你將需要根據下面的代碼更新QueryStatusExec 方法,下面的代碼的含義是,當它的菜單項或者工具條按鈕被點擊后顯示出Line Counter插件。

?

public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)

??????? {

??????????? if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)

??????????? {

??????????????? // Respond only if the command name is for our menu item or toolbar button

??????????????? if (commandName == "LineCounterAddin.Connect.LineCounterAddin" || commandName == "LineCounterAddin.Connect.LineCounterAddinButton")

??????????????? {

??????????????????? // Disable the button if the Line Counter window is already visible

??????????????????? if (m_toolWin.Visible)

??????????????????? {

??????????????????????? // Set status to supported, but not enabled

??????????????????????? status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported;

??????????????????? }

??????????????????? else

??????????????????? {

??????????????????????? // Set status to supported and eneabled

??????????????????????? status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;

??????????????????? }

??????????????????? return;

??????????????? }

??????????? }

??????? }

?

??????? public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)

??????? {

??????????? handled = false;

??????????? if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)

??????????? {

??????????????? // Respond only if the command name is for our menu item or toolbar button

??????????????? if (commandName == "LineCounterAddin.Connect.LineCounterAddin" || commandName == "LineCounterAddin.Connect.LineCounterAddinButton")

??????????????? {

??????????????????? // Only display the add-in if it is not already visible

??????????????????? if (m_toolWin != null && m_toolWin.Visible == false)

??????????????????? {

??????????????????????? m_toolWin.Visible = true;

??????????????????? }

?

??????????????????? handled = true;

??????????????????? return;

??????????????? }

??????? ??? }

??????? }

???????? 隨著OnConnection方法的完成,你就已經建立了一個漂浮工具窗口的插件,完整的用戶控件能讓你計算你的解決方案中總共的代碼行數,各個工程的代碼行數,以及各個文件的代碼行數。


代碼行數統計器(二):http://sifang2004.cnblogs.com/archive/2006/06/26/436178.html

總結

以上是生活随笔為你收集整理的Visual Studio 2005 插件编程(代码行数统计插件)之一的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。