前言
在VS概覽中,我們簡單回顧了一下VS的歷史。本文將通過兩個簡單的例子來說明Macro 和Add-In的開發。通過Macro我們把VS中的一些重復操作錄制下來,之後可以多次運行, 節省時間並保持好的心情;通過Add-In,我們可以自己動手來為VS添加新的功能,擴展了 VS就意味著擴展了我們自己。
VS 2008擴展方式一覽
在上篇VS概覽中提到了擴展VS有三種主要的方式:Macro、Add-In和VsPackage。事實 上,還有更多的選擇,這裡先簡單列一下:
Macro
Add-In
VsPackage
VS Shell
Domain Specific Language Tool
Visualizer
Code Snippet
Project/Item Template
MSBuild
甚至External Tools(菜單Tools->External Tools)也可看作是一種擴展方式, 我們可以將外部工具添加到VS菜單中,這樣使用起來會更方便一點。之前曾寫過關於VS中 的模板和Code Snippet的隨筆,它們屬於比較簡單的擴展方式了。
在本文中將簡單介紹一下Macro和Add-In的用法,它們可以訪問共同的API,既然這樣 ,了解一下Macro對Add-In的開發也會有幫助,然後就正式步入Add-In的開發。之後對於 其它的擴展方式也會盡量多介紹一點。
開發第一個Macro
作為程序員,我們在編寫代碼的時候害怕重復,它的危害人人知曉。另一方面,對於 某些操作,如果經常重復進行也會讓人厭煩,Macro此時也許能幫得上忙。
Macro一般翻譯為宏,它的一個含義是“大量使用的”,這個詞對於我們Windows平台 下的開發人員來說應當不陌生,在Word和Excel中都有它的身影。宏的作用是將我們在VS 中的一些重復操作錄制下來,之後可以多次運行,也就可以節省很多時間,心情也會因此 變得好一點。
在VS中,宏可以用兩種方式來創建,一是錄制,二是手工編寫代碼。可以想見的是, 第一種方式更為簡單,第二種方式則更為靈活、強大。需要注意的是,當前只能用VB.NET 來開發宏。
以前我曾用VBA開發過簡單的Excel自動化,當時如果某些操作不知如何用代碼表示, 就錄制一個宏,看看它生成的代碼。VS中的宏與此類似,這也是為什麼我說對Add-In開發 也有幫助了。我們可以將前面說的兩種方式結合起來使用,看看下面的例子。
1)Macro Explorer
通過菜單Tools -> Macros -> Macro Explorer(快捷鍵Alt+F8)打開Macro Explorer:
它的結構看起來有點像Solution Explorer。在Macros上點擊右鍵,選擇New Macro Project...,我這裡把宏命名為FirstMacro,將其設置為錄制項目:
2)錄制宏
現在可以進行錄制了,按下Ctrl+Shift+R,這時會出現一個小工具欄,可以暫停、停 止或取消一次錄制(如果某些操作不想錄制,就可以將它暫停)。然後執行以下操作:
按下Ctrl+F打開Find and Replace對話框
輸入":a+"(含引號),查找范圍為Current Document,然後選擇使用正則表達式
點擊Find Next
按下Ctrl+Shift+R停止錄制
3)運行宏
這個簡單的宏可以用來查找當前文檔內硬編碼的字符串。按下Alt+F8打開Macro Explorer,可以看到新錄制的宏TemporaryMacro:
通過右鍵菜單運行它,怎麼樣,是不是很方便涅?現在打開另一個文件,再次運行宏 。奇怪的是,還是在剛才的那個文件內查找!看來剛才在錄制的時候把文件名也錄制進去 了,這時我們利用第二種方式:手工編寫代碼。
4)修改宏
參考上圖,在TemporaryMacro上點擊右鍵,對它進行編輯。在新打開的Macro IDE內可 以看到如下代碼:
VB.NET Code
Sub TemporaryMacro()
DTE.ExecuteCommand("Edit.Find")
DTE.Windows.Item("ListViewSample.cs").Activate()
DTE.Find.FindWhat = """:a+"""
DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument
DTE.Find.MatchCase = False
DTE.Find.MatchWholeWord = False
DTE.Find.Backwards = False
DTE.Find.MatchInHiddenText = True
DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxRegExpr
DTE.Find.Action = vsFindAction.vsFindActionFind
If (DTE.Find.Execute() = vsFindResult.vsFindResultNotFound) Then
Throw New System.Exception ("vsFindResultNotFound")
End If
End Sub
果然,這裡包含了剛才打開的文件名,把這一行注釋掉。另外最後的異常信息也不喜 歡,改成"Sorry, I cannot find it:("。
VB.NET Code
Sub TemporaryMacro()
DTE.ExecuteCommand("Edit.Find")
'DTE.Windows.Item("ListViewSample.cs").Activate()
DTE.Find.FindWhat = """:a+"""
DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument
DTE.Find.MatchCase = False
DTE.Find.MatchWholeWord = False
DTE.Find.Backwards = False
DTE.Find.MatchInHiddenText = True
DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxRegExpr
DTE.Find.Action = vsFindAction.vsFindActionFind
If (DTE.Find.Execute() = vsFindResult.vsFindResultNotFound) Then
Throw New System.Exception("Sorry, I cannot find it:(")
End If
End Sub
這樣使用起來就沒問題了。
通過這個小例子我們應當對Macro的用法有基本的了解了。不僅可以編寫有用的宏,還 可以通過宏來幫助編寫Add-In,比如通過上面的代碼,我們就可以知道如何打開查找和替 換對話框了。下面再來編寫我們的第一個Add-In。
開發第一個Add-In
相信有很多人用過Add-In(一般譯作插件,這裡保留不譯),常見的如DPack、 TestDriven.NET、GhostDoc等等,這些我都曾經介紹過(至於ReSharper、Visual Assist X等很棒的Add-In,沒錢買,又不願用破解版,故沒有嘗試)。Add-In與VS環境完全集成 ,可以為VS添加新的功能。
Add-In可與宏訪問相同的API,但是VS處理起來有所不同。宏是可被VS運行的源代碼, 但沒有集成到IDE中,它不被編譯為程序集,要分發宏只能使用源代碼。而Add-In呢,會 被編譯為dll,然後VS啟動時加載它,這樣它就與IDE集成在了一起,部署的時候不需要源 代碼。另一個區別是,當前只能用VB.NET開發宏,而對於Add-In來說,任何.NET下的語言 都可以使用,如C#、VB.NET和VC(理論上來說F#當然也可以,但還沒做過嘗試)。
Add-In可以操作解決方案、項目、文件、編輯器,也可以操作VS中的各個工具窗口。 可以說,它是擴展VS的一種比較專業的方式。下面來看看如何開發我們的第一個Add-In, 它的功能是向編輯器內插入當前的日期,不管怎樣,還是有一點點用處。
1)Add-In Wizard
新建一個項目:
在Other Project Types->Extensibility中可以看到Add-In項目模板,項目名稱設 置為FirstAddin,OK。出現歡迎界面,點擊Next,進入向導第一步,選擇一種語言,如C# ,點擊Next進入第二步。
這裡可以選擇Add-In運行的宿主環境,只保留VS 2008,Next進入第三步,設置Add-In 的名稱和描述信息,進入第四步:
選中第一個選項,這樣VS會在Tools菜單中添加一個新菜單項,剩下的部分一路Next下 去即可。最後VS會創建一個新的項目,其中包含了Connect.cs文件,這就是今後我們的主 戰場了。
打開Connect.cs,如果這是你的Add-In初體驗,也許會覺得代碼有些奇怪,進而感覺 有些慌亂,不用擔心,很快你就會熟悉它了。找到OnConnection方法,Add-In就是在這裡 加載,搜索文本"commands.AddNamedCommand2"(大約在77行),這一行創建了一個新的 菜單項,將其AddNameCommand2的第二、三個參數都改為"InsertDate"。將QueryStatus和 Exec方法稍作修改:
C# Code - QueryStatus 和 Exec方法
public void QueryStatus(string commandName, )
{
if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
{
if (commandName == "FirstAddin.Connect.InsertDate")
{
status = (vsCommandStatus) vsCommandStatus.vsCommandStatusSupported|vsCommandStatus.vsCommandStatusEnable d;
return;
}
}
}
public void Exec(string commandName, )
{
handled = false;
if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
if (commandName == "FirstAddin.Connect.InsertDate")
{
TextSelection selectedText = _applicationObject.ActiveDocument.Selection as TextSelection;
selectedText.Text = DateTime.Now.ToShortDateString();
handled = true;
return;
}
}
}
按下F5進行調試,此時打開一個新的IDE窗口,在新的窗口中可以測試Add-In的功能, 隨便打開一個解決方案,然後打開一個代碼文件,查看Tools菜單:
點擊新菜單項,看看編輯器內是不是插入了當前日期?注意,這個菜單項只有在調試 的時候才會出現。
好,我們第一個Add-In也創建成功了。它頗為簡陋,而且菜單項放在編輯器的上下文 菜單中會更好,這裡先放一放,在後面的文章中我會對此作出修改。
可以在這裡下載代碼。第一次使用Google Code,感覺很不錯。
我們身在何處
本文將通過兩個例子說明了Macro和Add-In的開發。希望這些能讓你對兩者有個基本的 認識。在隨後的隨筆中,我將對Add-In展開詳細的介紹。