梦想与现实的落差,就是我们离成功的距离!!

博客园 首页 新随笔 联系 订阅 管理

源码:http://www.cnblogs.com/Files/sifang2004/PasteAsCS.rar

Visual Studio插件开发

――VB.NET-C# 语言转换插件

我前段时间在《程序员》上看到一篇肖文编译的文章,说的是C#-VB 语言转换的一个Visual Studio2005 插件,当时也没有在意,因为我用的是C# ,一般情况下不会用到C#-VB 的插件。最近在网上找了些源码,比较短的那种,完成某种小功能的,但有的是VB.net 的,要么自己改成c# ,要么去一些转换网站,都觉得不是很方便。于是也有种想法了,何不依样画葫芦,来一个VB-C# 的插件呢,虽然技术含量不多,但也好了解下Visual Studio2005 中的插件开发是怎么回事了。

首先,我肯定不是自己写转换代码,那我做不到,网上基于Web 的代码转换器不少,我们可以随便找几个来用就行了,http://www.carlosag.net/Tools/CodeTranslator/Default.aspx 就是不错的一个,两种语言互转。另外就是这个http://www.kamalpatel.net/ ,其实,在我在《程序员》上看到肖文编译的那篇文章的时候,只有C#-VB 的转换,没有VB-C# 的,我当时就想,你怎么可能只支持一种呢,果不然,今天我上该网站时,它就已经出现了新的功能VB-C# 的,

看到没有,的确是新增的。但是我今天点了该链接,暂时还有点问题,估计很快就会好的了。所以比较遗憾,我没有测试它了。

创建转换器

转换器其实就是使用的上述的网站的转换器。我们可以多找几个这样的网站,这样如果一个网站暂时不可用时,或者你觉得某个网站的转换器给出的转换后的代码不是太好的时候,你就可选择其它的。也正是基于这个原因,我们为了以后能加入新的转换器,所以还是先定义一个接口为妙:

interface IConvertCode

{

string Convert(string vbCode);

string ConvertName

{

get;

}

}

代码1 :接口

Convert 方法把vb.net 的代码看成是字符串,返回的c# 代码也是字符串。ConvertName 属性返回的是转换器的名称,这样就方便选择自己喜欢的转换器。

第一个实现该接口的就是该http://www.kamalpatel.net/ 网站上的,也就是Kamal Patel 的"VB.NET to C# ", 该网站的这个功能是基于web 服务的,那就很简单了,我们就在项目中引用web 服务就OK 了。这里注意的是,因为我上面说了该功能是新增的,我写该文章的时候也用不了,它是基于web 服务的,所以它的web 服务地址我也找不到,所以现在我在代码中用的是它的"C# to VB.NET "的服务,如果什么时候它的"VB.NET to C# "可以用了,就可以很方便简单修改下就可以了。

class KPConvert : IConvertCode

{

public string Convert(string vbCode)

{

ConvertCSharp2VBService convert = new ConvertCSharp2VBService();

return convert.Execute(vbCode);

}

public string ConvertName

{

get

{

return "Kamal Patel's Converter";

}

}

}

代码2 :调用web 服务

看看就明白了,这是把C# 代码转为VB.NET 的,所以到时http://www.kamalpatel.net/ 网站上VB.NET C# 的功能正常之后,你就去上面找到对象的web 服务地址,在项目中引用,在改下该类中的相关代码就可以了。

另外一个很著名的工具就是Carlos Aguilar Mares 的基于ajax 的代码转换器,http://www.carlosag.net/Tools/CodeTranslator/Default.aspx 这是它的网站,它早就实现了C# VB.NET 之间的互转功能。它这儿,代码是以表单域集合传给carlosag.net/Tools/CodeTranslator/translate.ashx 。代码3 就是它的实现:

class CAConvert : IConvertCode

{

public string Convert(string vbCode)

{

NameValueCollection formFields = new NameValueCollection();

formFields.Add("code", vbCode);

formFields.Add("Language", "VB");

formFields.Add("DestinationLanguage", "C#");

WebClient client = new WebClient();

return Encoding.ASCII.GetString(client.UploadValues("http://www.carlosag.net/Tools/CodeTranslator/translate.ashx", "post", formFields));

}

public string ConvertName

{

get

{

return "Carlos Aguilar's Converter";

}

}

}

代码3 :使用基于表单的转换器

创建插件工程

现在就要为Visual Studio 2005 创建插件了。我们可以在解决方案里,添加一个新的插件工程来创建插件,这在扩展(Extensibility )项目里,已经含有预制的模板(注意:我看代码量不多,又比较简单所以我的源码是把转换代码和插件工程混在一起了,应该是把转换的单独建立一个工程,再插件一个工程,这样就比较清楚点




2. 创建插件工程

这个向导让你很轻松就帮你建好了该插件工程。与Visual Studio 2003 不一样,Visual Studio 2005 的插件工程包含可以将插件正确连接到开发环境的基本代码。这个插件类实现了IExtensiblity2 接口,它可以使Visual Studio 与插件进行通信。要注意的一些关键方法是,

Onconnection QueryStatus

其实你这时就可以按F5 启动项目了,但是插件默认是在"Tools "菜单中的,我要把它放在Edit 菜单的Paste 项之后,这就得改Onconnection 方法了,这个你用默认的文件跟我的这个文件比较后,你就应该明白很多东西了。

对这个方法有些重要的修改之处。首先,这个工程包含了一个含有多种语言的顶级Visual Studio 菜单项,名为CommandBar 的文本文件。下面这行代码就是定位一个双字节母语名称的菜单项。

editMenuName = resourceManager.GetString(resourceName);

如果是设置为U.S.English 的计算机上运行,它会在CommandBar.resx 文件中查找名为enEdit 的源字符串,如果是简体中文的,它就会找zh-CHSEdit 的源字符串。

需要详细的了解修改之处,你必须仔细看下修改后的Onconnection 方法了。

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 editMenuName;

try

{

ResourceManager resourceManager = new ResourceManager("PasteAsCSharp.CommandBar", Assembly.GetExecutingAssembly());

CultureInfo cultureInfo = new System.Globalization.CultureInfo(_applicationObject.LocaleID);

string resourceName = string.Empty;

if (cultureInfo.Name == "zh")

{

resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "-CHSEdit");

}

else

{

resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "Edit");

}

editMenuName = resourceManager.GetString(resourceName);

}

catch

{

editMenuName = "Edit";

}

Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];

CommandBarControl editControl = menuBarCommandBar.Controls[editMenuName];

CommandBarPopup editPopup = (CommandBarPopup)editControl;

try

{

Command command = commands.AddNamedCommand2(_addInInstance, "PasteAsCSharp", "Paste as CSharp", "Executes the command for PasteAsCSharp", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

if((command != null) && (editPopup != null))

{

command.AddControl(editPopup.CommandBar, 12);

}

}

catch(System.ArgumentException)

{

}

}

}

代码3 :修改后的Onconnection 方法。

这里请稍微注意一点,

if (cultureInfo.Name == "zh")

{

resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "-CHSEdit");

}

else

{

resourceName = String.Concat(cultureInfo.TwoLetterISOLanguageName, "Edit");

}

按理来所,这里根本就不要这么写的,就用else 里面代码就可以了,但是在我前段时间的中文版的Visual Studio 2005 就有问题,因为简体中文是zh-CHS ,这样它加上"Edit "就是正确的了,zh-CHSEdit, 但我的却是"zh ",所以加上"Edit "后,就成了"zhEdit ",这样就定位不到正确的资源了,如果你不知道我在说什么,你看看CommandBar.resx 文件就明白了

下面的代码定位实际的菜单对象:

CommandBarControl editControl = menuBarCommandBar.Controls[editMenuName];

CommandBarPopup editPopup = (CommandBarPopup)editControl;

一旦菜单栏定位好了,新的Paste as CSharp 菜单就能被添加进来。这一步可以通过创建一个Command 对象来实现,然后把Command 添加进菜单就可以了。

这里要注意的是,AddNameCommand2 这个方法的第二参数不能随便改动的,第三个是可以改动,它是显示在菜单项上的文本。

Command command = commands.AddNamedCommand2(_addInInstance, "PasteAsCSharp", "Paste as CSharp", "Executes the command for PasteAsCSharp", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);

command.AddControl(editPopup.CommandBar, 12);

这样把Command 添加在菜单里位置为12 的地方,恰好在Paste 菜单之后。




还有要保证插件在只有当活动文档的后缀名为
.cs 时才是可以使用的。

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

{

if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)

{

if(commandName == "PasteAsCSharp.Connect.PasteAsCSharp")

{

if (_applicationObject.ActiveDocument != null && _applicationObject.ActiveDocument.FullName.ToLower().EndsWith(".cs"))

{

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

return;

}

}

}

}

代码5: 插件可用控制

到此为止,我们还需要做的是编写插件的Exec 方法,实际执行代码转换并把结果粘贴到编辑器中。

转换窗体

其实这已经是比较简单的部分了。看下界面就知道个八九不离十了。何况有源码呢,只说下那个"转换后格式化"的ChecBox 控件, 其实也特简单,选中它后,在把代码粘贴入编辑器后,接着执行Edit.FormatDocument 命令格式化文档。就相当于在Visual Studio 2005 中按下"Ctl+E" ,然后再按"D", 应该都用过这个功能吧,平常,我们看到,源文件中的大括号似乎对应的不是很整齐了,我们不就用该功能自动调整下吗。



3: 转换界面

还是看下比较重要的Exec 方法吧:

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

{

handled = false;

if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)

{

if(commandName == "PasteAsCSharp.Connect.PasteAsCSharp")

{

ConvertForm f = new ConvertForm();

if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)

{

TextSelection textSelection = (TextSelection)_applicationObject.ActiveDocument.Selection;

textSelection.Insert(f.CSCode, 0);

}

if (f.IfFormat)

{

_applicationObject.ExecuteCommand("Edit.FormatDocument", "");

}

handled = true;

return;

}

}

}

插件程序注册

创建了外接程序后,必须先在 Visual Studio 注册此外接程序,才可以在外接程序管理器中激活它。在 Visual Studio 的先前版本中,这是通过使用注册表项实现的,但目前是通过使用 XML 文件实现的。 在创建该插件工程的时候,就自动在

\Documents and Settings\All Users\My Documents\Visual Studio 2005\Addins

- -

\Documents and Settings\<user name>\My Documents\Visual Studio 2005\Addins)

创建一个.Addin文件,你在工程中可以看到的:

<?xml version="1.0" encoding="UTF-16" standalone="no"?>

<Extensibility xmlns="http://schemas.microsoft.com/AutomationExtensibility">

<HostApplication>

<Name>Microsoft Visual Studio</Name>

<Version>8.0</Version>

</HostApplication>

<Addin>

<FriendlyName>PasteAsCSharp</FriendlyName>

<Description>Paste As CSharp</Description>

<Assembly>D:\Visual Studio 2005 Projects\PasteAsCS\PasteAsCSharp\bin\PasteAsCSharp.dll</Assembly>

<FullClassName>PasteAsCSharp.Connect</FullClassName>

<LoadBehavior>1</LoadBehavior>

<CommandPreload>1</CommandPreload>

<CommandLineSafe>0</CommandLineSafe>

</Addin>

</Extensibility>

该文件根据你当时创建插件工程时的不同选项,会稍有不同,有了这个文件,部署就基本搞定了。 这种简化的注册方法允许对托管代码插件程序采用 XCopy 式的安装方法。如果将所有文件放入正确的位置,插件程序就可以正常运行。此外,这种方法使用带有注释的 XML 来定义插件程序的注册设置,使信息变得比注册表项更易于理解和编辑。( 如果想了解更多,请查看msnd ,你装的是中文版的msdn 的话,就查"外接程序注册"等相关内容,msdn 中把插件程序称之为"外接程序"

结论

Visual Studio 2005 创建插件非常简单(我也是比较菜的,但也没有碰到什么大问题,由此可见,的确不难哦),首先,它会生成将插件置于Visual Studio 菜单中的基本代码。然后,通过F5 键,包含插件的Visual Studio 测试用例就可以运行。是就调试就比较简单了。

我根据前人写的这个插件是否有用,本人也不太清楚,但对我还是有点用的。我的写的代码扩展性也许不是太好,这就需要各位字节改进了,我只是抛砖引玉了

posted on 2006-06-09 15:50  叶漂  阅读(7320)  评论(3编辑  收藏  举报