在上一个项目中由于修改代码 里面的添加/删除/修改的注释都有规范,因此做了一个注释的第三方dll小插件。效果不错,被日本Nes要去全面推广让其他协力公司都用。
因此提取出来发给大家。先上代码。在Vs2012里面。我试了下没成功,因此先发代码。稍后我整合打包传上来了。
VS 创建外接程序 参考链接
http://technet.microsoft.com/zh-tw/library/90855k9f
http://technet.microsoft.com/zh-cn/library/ms165621
http://technet.microsoft.com/zh-cn/library/7k3w6w59
http://www.cnblogs.com/Reborn/archive/2010/02/04/1664010.html C#利用外接程序生成解决方案
http://technet.microsoft.com/zh-cn/magazine/ms228771%28VS.90%29.aspx 如何:在外接程序按钮上显示自定义图标
Connect.cs 最重要的类。注释的方法都在里面
/// <summary>用于实现外接程序的对象。</summary>
public class Connect : IDTExtensibility2, IDTCommandTarget
{
/// <summary>实现外接程序对象的构造函数。请将您的初始化代码置于此方法内。</summary>
public Connect()
{
}
/// <summary>实现 IDTExtensibility2 接口的 OnConnection 方法。接收正在加载外接程序的通知。</summary>
/// <param term='application'>宿主应用程序的根对象。</param>
/// <param term='connectMode'>描述外接程序的加载方式。</param>
/// <param term='addInInst'>表示此外接程序的对象。</param>
/// <seealso class='IDTExtensibility2' />
public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
{
_applicationObject = (DTE2)application;
_addInInstance = (AddIn)addInInst;
if (connectMode == ext_ConnectMode.ext_cm_UISetup)
{
object[] contextGUIDS = new object[] { };
Commands2 commands = (Commands2)_applicationObject.Commands;
string toolsMenuName;
try
{
// 添加在菜单栏里面
// CommandBar.resx.
ResourceManager resourceManager = new ResourceManager("StarkingCommentTool.CommandBar", Assembly.GetExecutingAssembly());
CultureInfo cultureInfo = new System.Globalization.CultureInfo(_applicationObject.LocaleID);
string resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "Tools");
toolsMenuName = resourceManager.GetString(resourceName);
}
catch
{
toolsMenuName = "Tools";
}
//将此命令置于“工具”菜单上。
//查找 MenuBar 命令栏,该命令栏是容纳所有主菜单项的顶级命令栏:
Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];
//在 MenuBar 命令栏上查找“工具”命令栏:
CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;
//如果希望添加多个由您的外接程序处理的命令,可以重复此 try/catch 块,
// 只需确保更新 QueryStatus/Exec 方法,使其包含新的命令名。
try
{
//将一个命令添加到 Commands 集合:
Command commandA = commands.AddNamedCommand2(_addInInstance, "Add", "Add", "Add Comment", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
Command commandD = commands.AddNamedCommand2(_addInInstance, "Del", "Del", "Delete Comment", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
Command commandC = commands.AddNamedCommand2(_addInInstance, "Chg", "Chg", "Change Comment", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported + (int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
//将对应于该命令的控件添加到“工具”菜单:
if ((commandA != null) && (commandD != null) && (commandC != null) && (toolsPopup != null))
{
commandA.AddControl(toolsPopup.CommandBar, 1);
commandD.AddControl(toolsPopup.CommandBar, 1);
commandC.AddControl(toolsPopup.CommandBar, 1);
}
}
catch (System.ArgumentException)
{
//如果出现此异常,原因很可能是由于具有该名称的命令
// 已存在。如果确实如此,则无需重新创建此命令,并且
// 可以放心忽略此异常。
}
}
}
/// <summary>实现 IDTExtensibility2 接口的 OnDisconnection 方法。接收正在卸载外接程序的通知。</summary>
/// <param term='disconnectMode'>描述外接程序的卸载方式。</param>
/// <param term='custom'>特定于宿主应用程序的参数数组。</param>
/// <seealso class='IDTExtensibility2' />
public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom)
{
}
/// <summary>实现 IDTExtensibility2 接口的 OnAddInsUpdate 方法。当外接程序集合已发生更改时接收通知。</summary>
/// <param term='custom'>特定于宿主应用程序的参数数组。</param>
/// <seealso class='IDTExtensibility2' />
public void OnAddInsUpdate(ref Array custom)
{
}
/// <summary>实现 IDTExtensibility2 接口的 OnStartupComplete 方法。接收宿主应用程序已完成加载的通知。</summary>
/// <param term='custom'>特定于宿主应用程序的参数数组。</param>
/// <seealso class='IDTExtensibility2' />
public void OnStartupComplete(ref Array custom)
{
ReadConf();
}
/// <summary>实现 IDTExtensibility2 接口的 OnBeginShutdown 方法。接收正在卸载宿主应用程序的通知。</summary>
/// <param term='custom'>特定于宿主应用程序的参数数组。</param>
/// <seealso class='IDTExtensibility2' />
public void OnBeginShutdown(ref Array custom)
{
}
/// <summary>实现 IDTCommandTarget 接口的 QueryStatus 方法。此方法在更新该命令的可用性时调用</summary>
/// <param term='commandName'>要确定其状态的命令的名称。</param>
/// <param term='neededText'>该命令所需的文本。</param>
/// <param term='status'>该命令在用户界面中的状态。</param>
/// <param term='commandText'>neededText 参数所要求的文本。</param>
/// <seealso class='Exec' />
public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
{
if (neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
{
switch (commandName)
{
case "StarkingCommentTool.Connect.Add":
goto case "StarkingCommentTool.Connect.Chg";
case "StarkingCommentTool.Connect.Del":
goto case "StarkingCommentTool.Connect.Chg";
case "StarkingCommentTool.Connect.Chg":
status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported | vsCommandStatus.vsCommandStatusEnabled;
return;
}
}
}
private DTE2 _applicationObject;
private AddIn _addInInstance;
private string _add1 = "";//before add
private string _add2 = "";//after add
private string _del1 = "";//before del
private string _del2 = "";//after del
private string _changeBefore1 = "";//change before
private string _changeAfter2 = "";//change after
private string _changeDel = "";// comment ///
private bool _autoCopy = true;//复制
private void ReadConf()
{
try
{
string strPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + @"\Visual Studio 2012\Addins\StarkingCommentTool.conf";
string strUserName = Environment.UserName;
string strDateFormat = "yyyy.MM.dd";
string strAddFormatA = "NES Add {0} {1}";
string strAddFormatB = "NES Add {0} {1}";
string strDelFormatA = "NES Del {0} {1}";
string strDelFormatB = "NES Del {0} {1}";
string strCgAFormatB = "NES Change After {0} {1}";
string strCgBFormatA = "NES Change Before {0} {1}";
string strAllA = "";
string strAllB = "";
string strAddA = "";
string strAddB = "";
string strDelA = "";
string strDelB = "";
string strCgAB = "";
string strCgBA = "";
string strComm = "";
if (!File.Exists(strPath))
{
System.Windows.Forms.MessageBox.Show("Starking_comment_tool can't read config file \rplease check it exist!", "Starking_comment_tool Error");
}
else
{
XmlDocument xd = new XmlDocument();
xd.Load(strPath);
XmlNode root = xd.ChildNodes[1];
//取出XML配置文件里面的自定义内容
strAddFormatA = root.SelectSingleNode("/config/before/add").InnerText;
strDelFormatA = root.SelectSingleNode("/config/before/del").InnerText;
strCgBFormatA = root.SelectSingleNode("/config/before/changeBefore").InnerText;
strAddFormatB = root.SelectSingleNode("/config/after/add").InnerText;
strDelFormatB = root.SelectSingleNode("/config/after/del").InnerText;
strCgAFormatB = root.SelectSingleNode("/config/after/changeAfter").InnerText;
strComm = root.SelectSingleNode("/config/comment").InnerText + " ";
_changeDel = strComm;
strDateFormat = root.SelectSingleNode("/config/dateFormat").InnerText + " ";
//
//取出XML配置文件节点other里面的自定义内容
strAllA = root.SelectSingleNode("/config/other/before/all").InnerText;
strAddA = root.SelectSingleNode("/config/other/before/add").InnerText;
strDelA = root.SelectSingleNode("/config/other/before/del").InnerText;
strCgBA = root.SelectSingleNode("/config/other/before/changeBefore").InnerText;
strAllB = root.SelectSingleNode("/config/other/after/all").InnerText;
strAddB = root.SelectSingleNode("/config/other/after/add").InnerText;
strDelB = root.SelectSingleNode("/config/other/after/del").InnerText;
strCgAB = root.SelectSingleNode("/config/other/after/changeAfter").InnerText;
string strAutoCopy = root.SelectSingleNode("/config/changeAutoCopy").InnerText;
bool.TryParse(strAutoCopy, out _autoCopy);
}
string strDate = DateTime.Now.ToString(strDateFormat);
//add
_add1 = strComm + string.Format(strAddFormatA, strDate, strUserName) + strAddA + strAllA + Environment.NewLine;
_add2 = strComm + string.Format(strAddFormatB, strDate, strUserName) + strAddB + strAllB + Environment.NewLine;
//change
_changeBefore1 = strComm + string.Format(strCgBFormatA, strDate, strUserName) + strCgBA + strAllA + Environment.NewLine;
_changeAfter2 = strComm + string.Format(strCgAFormatB, strDate, strUserName) + strCgAB + strAllB + Environment.NewLine;
//delete
_del1 = strComm + string.Format(strDelFormatA, strDate, strUserName) + strDelA + strAllA + Environment.NewLine;
_del2 = strComm + string.Format(strDelFormatB, strDate, strUserName) + strDelB + strAllB + Environment.NewLine;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
}
/// <summary>实现 IDTCommandTarget 接口的 Exec 方法。此方法在调用该命令时调用。</summary>
/// <param term='commandName'>要执行的命令的名称。</param>
/// <param term='executeOption'>描述该命令应如何运行。</param>
/// <param term='varIn'>从调用方传递到命令处理程序的参数。</param>
/// <param term='varOut'>从命令处理程序传递到调用方的参数。</param>
/// <param term='handled'>通知调用方此命令是否已被处理。</param>
/// <seealso class='Exec' />
public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
handled = false;
if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
{
switch (commandName)
{
#region//StarkingCommentTool.Connect.Add
case "StarkingCommentTool.Connect.Add":
TextSelection ts = _applicationObject.ActiveDocument.Selection as TextSelection;
int TopLine = ts.TopPoint.Line;
int ButtomLine = ts.BottomPoint.Line;
bool ButtomAtStartOfLine = ts.BottomPoint.AtStartOfLine;
int startLine = 0;
int endLine = 0;
if (TopLine == ButtomLine)
{
ts.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, false);
ts.Insert(_add1, 0);
ts.SmartFormat();
ts.LineDown(false, 1);
ts.StartOfLine(vsStartOfLineOptions.vsStartOfLineOptionsFirstColumn, false);
ts.Insert(_add2, 0);
ts.SmartFormat();
ts.GotoLine(TopLine + 2, false);
}
else
{
if (ts.TopPoint.AtEndOfLine)
{
ts.GotoLine(TopLine + 1, false);
ts.Insert(_add1, 0);
}
else
{
ts.GotoLine(TopLine, false);
ts.Insert(_add1, 0);
}
ts.SmartFormat();
if (ButtomAtStartOfLine)
{
ts.GotoLine(ButtomLine + 1, false);
ts.Insert(_add2, 0);
}
else
{
ts.GotoLine(ButtomLine + 2, false);
ts.Insert(_add2, 0);
}
ts.SmartFormat();
}
handled = true;
return;
#endregion
#region//StarkingCommentTool.Connect.Del
case "StarkingCommentTool.Connect.Del":
ts = _applicationObject.ActiveDocument.Selection as TextSelection;
TopLine = ts.TopPoint.Line;
ButtomLine = ts.BottomPoint.Line;
ButtomAtStartOfLine = ts.BottomPoint.AtStartOfLine;
// Area Delete
if (ts.TopPoint.AtEndOfLine)
{
ts.GotoLine(TopLine + 1, false);
startLine = TopLine + 2;
ts.Insert(_del1, 0);
}
else
{
ts.GotoLine(TopLine, false);
startLine = TopLine + 1;
ts.Insert(_del1, 0);
}
if (ButtomAtStartOfLine)
{
ts.GotoLine(ButtomLine + 1, false);
endLine = ButtomLine;
ts.Insert(_del2, 0);
}
else
{
ts.GotoLine(ButtomLine + 2, false);
endLine = ButtomLine + 1;
ts.Insert(_del2, 0);
}
for (int line = startLine; line < endLine + 1; line++)
{
ts.GotoLine(line, false);
ts.SelectLine();
if (ts.Text.Contains(" ") || ts.Text.Contains("{") || ts.Text.Contains("}") || ts.Text.Contains("//") || !ts.Text.Contains("///") || !ts.Text.Contains("#region") || !ts.Text.Contains("#endregion"))
{
ts.Insert(ts.Text.TrimStart(" ".ToCharArray()), 0);
}
if (ts.Text.Contains(" ") || ts.Text.Contains("{") || ts.Text.Contains("}") || ts.Text.Contains("//") || !ts.Text.Contains("///") || !ts.Text.Contains("#region") || !ts.Text.Contains("#endregion"))
{
ts.Insert(_changeDel + ts.Text.TrimStart(" ".ToCharArray()), 0);
}
}
//缩放注释到多少列 start==>end
ts.GotoLine(TopLine, false);
//计算选中的行数来进行注释
if (TopLine == ButtomLine)
{ //单行删除注释
ts.LineDown(true, ButtomLine + 3 - TopLine);
}
else
{ //多行删除注释
ts.LineDown(true, ButtomLine + (endLine + 1 - startLine) - TopLine);
}
ts.SmartFormat();
handled = true;
return;
#endregion
#region//StarkingCommentTool.Connect.Chg
case "StarkingCommentTool.Connect.Chg":
ts = _applicationObject.ActiveDocument.Selection as TextSelection;
TopLine = ts.TopPoint.Line;
ButtomLine = ts.BottomPoint.Line;
ButtomAtStartOfLine = ts.BottomPoint.AtStartOfLine;
int intCount = ts.TextRanges.Count;
if (TopLine == ButtomLine)//单行变更
{
ts.GotoLine(TopLine, false);
ts.SelectLine();
//选中要变化的内容
string strText = string.Empty;
if (ts.Text.Contains(" ") || ts.Text.Contains("{") || ts.Text.Contains("}") || ts.Text.Contains("//") || !ts.Text.Contains("///") || !ts.Text.Contains("#region") || !ts.Text.Contains("#endregion"))
{
strText = ts.Text.TrimStart(" ".ToCharArray());
}
if (ts.Text.Contains(" ") || ts.Text.Contains("{") || ts.Text.Contains("}") || ts.Text.Contains("//") || !ts.Text.Contains("///") || !ts.Text.Contains("#region") || !ts.Text.Contains("#endregion"))
{
strText = ts.Text.TrimStart(" ".ToCharArray());
}
string strText2 = _changeBefore1 + _changeDel + strText.Replace(" ", "");
//复制要变更的内容
if (_autoCopy)
strText2 += strText;
else
strText2 += Environment.NewLine;
strText2 += _changeAfter2;
//插入变更内容
ts.Insert(strText2, 0);
ts.GotoLine(TopLine, false);
//单行删除注释
ts.LineDown(true, ButtomLine + 4 - TopLine);
ts.SmartFormat();
}
else//多行内容变更
{
if (!ts.TopPoint.AtEndOfLine && !ButtomAtStartOfLine)
{
intCount++;
}
if (ts.TopPoint.AtEndOfLine)
{
ts.GotoLine(TopLine + 1, false);
startLine = TopLine + 2;
ts.Insert(_changeBefore1, 0);
}
else
{
ts.GotoLine(TopLine, false);
startLine = TopLine + 1;
ts.Insert(_changeBefore1, 0);
}
if (ButtomAtStartOfLine)
{
ts.GotoLine(ButtomLine + 1, false);
endLine = ButtomLine;
}
else
{
ts.GotoLine(ButtomLine + 2, false);
endLine = ButtomLine + 1;
}
//存放选中变化的内容
StringBuilder sb = new StringBuilder();
if (_autoCopy)
{
for (int line = startLine; line < endLine + 1; line++)
{
ts.GotoLine(line, false);
ts.SelectLine();
sb.Append(ts.Text);
}
}
//循环注释掉选中的内容
for (int line = startLine; line < endLine + 1; line++)
{
ts.GotoLine(line, false);
ts.SelectLine();
if (ts.Text.Contains(" ") || ts.Text.Contains("{") || ts.Text.Contains("}") || ts.Text.Contains("//") || !ts.Text.Contains("///") || !ts.Text.Contains("#region") || !ts.Text.Contains("#endregion"))
{
ts.Insert(ts.Text.TrimStart(" ".ToCharArray()), 0);
}
if (ts.Text.Contains(" ") || ts.Text.Contains("{") || ts.Text.Contains("}") || ts.Text.Contains("//") || !ts.Text.Contains("///") || !ts.Text.Contains("#region") || !ts.Text.Contains("#endregion"))
{
ts.Insert(_changeDel + ts.Text.TrimStart(" ".ToCharArray()), 0);
}
}
//复制选中的内容到计算好的行数中
ts.GotoLine(endLine + 1, false);
if (_autoCopy)
{
ts.Insert(sb.ToString(), 0);
ts.GotoLine(endLine + intCount, false);
}
else
{
ts.NewLine(1);
}
//插入注释结束语句
ts.Insert(_changeAfter2, 0);
ts.GotoLine(TopLine, false);
//计算行数光标停止在最后一行+1行
ts.LineDown(true, (endLine + intCount + 1) - TopLine);
ts.SmartFormat();
}
handled = true;
return;
#endregion
}
}
}
}
StarkingCommentTool.AddIn 创建自动产生的里面放外接程序的信息
<?xml version="1.0" encoding="UTF-16" standalone="no"?>
<Extensibility xmlns="http://schemas.microsoft.com/AutomationExtensibility">
<HostApplication>
<Name>Microsoft Visual Studio</Name>
<Version>11.0</Version>
</HostApplication>
<Addin>
<FriendlyName>StarkingCommentTool</FriendlyName>
<Description>C# VC VB.NET JS 注释工具</Description>
<Assembly>StarkingCommentTool.dll</Assembly>
<FullClassName>StarkingCommentTool.Connect</FullClassName>
<LoadBehavior>5</LoadBehavior>
<CommandPreload>1</CommandPreload>
<CommandLineSafe>1</CommandLineSafe>
</Addin>
</Extensibility>
StarkingCommentTool.conf 配置文件 你可以配置成自己想要的注释风格
<?xml version="1.0" encoding="utf-8" ?>
<config>
<!--
add: 追加
del: 削除
changeAfter: 変更前
changeBefore: 変更後
{0}: 时间格式化
NOTE: 请不要删除此文件中的注释(重要都是配置节点)
-->
<before>
<!-- 変更前的应用 -->
<add>{0}1处System对应 INSERT START</add>
<del>{0}1处System对应 DELETE START</del>
<changeBefore>{0}1处System对应 UPDATE START</changeBefore>
</before>
<after>
<!-- 変更后的应用 -->
<add>{0}1处System对应 INSERT END</add>
<del>{0}1处System对应 DELETE END</del>
<changeAfter>{0}1处System对应 UPDATE END</changeAfter>
</after>
<!-- dateFormat:日期格式化
例:
日付 2012年12月25日
dateFormat: yyyy.MM.dd
注释中的格式为中 2012.12.25 。
-->
<dateFormat>yy/MM/dd</dateFormat>
<other>
<!--
all: 追加,削除,変更前,変更后等最后要追加的文字。
add: 追加后最后要追加的文字。
del: 削除后最后要追加的文字。
changeAfter: 修改前最后要追加的文字。
changeBefore: 修改后変最后要追加的文字。
all的优先级是最低的
例如 other中, 如果添加了all和add的場合, 那么注释中就会显示other.add other.all的样子。
-->
<before>
<all></all>
<add></add>
<del></del>
<changeBefore></changeBefore>
</before>
<after>
<all></all>
<add></add>
<del></del>
<changeAfter></changeAfter>
</after>
</other>
<!-- 修改的内容是否复制-->
<changeAutoCopy>True</changeAutoCopy>
<!-- 注释
VB: '
C#: ///
-->
<comment>///</comment>
</config>
先贴出代码,稍后我整理测试完毕打包上传。