代码改变世界

定制Paste from Visual Studio插件(上)

2009-12-16 10:56 by Jeffrey Zhao, ... 阅读, ... 评论, 收藏, 编辑

我在上一篇文章里谈了我常用Paste from Visual Studio(下文称VSPaste)的插件,这大大方便了我写博客时贴代码的工作。不过今天早上有朋友在我博客后面留言说:“VSPaste没法显示行号,不知大家有没有办法解决?”其实这点很容易,写个小程序,把VSPaste生成的HTML再进行一番处理不就可以了嘛。不过最方便的做法还是让VSPaste直接生成带行号的代码块,不是吗?那么,我们就来自己动手丰衣足食解决这个问题吧。

这个问题说简单不简单,说复杂不复杂。其“不简单”之处在于VSPaste是不提供源代码的。而“不复杂”又在于……您一会儿就明白了。那么我们就开始吧,别担心,我和您一样不知道Windows Live Writer的插件体系。不过这不影响我们用正常的推理逻辑来解决问题。

了解VSPaste

第一步自然是要了解VSPaste插件,而这唯一的途径便是它的分发版本。您可以下载到VSPaste.msi文件,安装后就可以使用这个插件了。这个插件的部署原理很简单,只是在Windows Live Writer安装目录(如C:\Program Files\Windows Live\Writer\)的Plugins文件夹下放一个dll而已(话说这么容易的方式,为什么就非要提供一个安装文件?这么做很专业吗?),于是我们用.NET Refactor便可以打开这个文件一看究竟。

我相信您也会和我一样首先关注VSPaste类。于是我们查看打开它的CreateContent方法:

public class VSPaste
{
    public override DialogResult CreateContent(
        IWin32Window dialogOwner,
        ref string newContent)
    {
        try
        {
            if (Clipboard.ContainsData(DataFormats.Rtf))
            {
                newContent =
                    "<pre class=\"code\">" + 
                    Undent(
                        HTMLRootProcessor.FromRTF(
                            (string)Clipboard.GetData(DataFormats.Rtf))) + 
                    "</pre><a href=\"http://11011.net/software/vspaste\"></a>";
                return DialogResult.OK;
            }
        }
        catch
        {
            MessageBox.Show(
                "VS Paste could not convert that content.",
                "VS Paste Problem",
                MessageBoxButtons.OK,
                MessageBoxIcon.Hand);
        }

        return DialogResult.Cancel;
    }

    ...
}

几乎没有比这再简单的逻辑了:我们在Visual Studio里复制了一段代码之后,这段文字会被保存为RTF格式,程序将其取出之后,再把它转化为HTML,最后在前后再加上些标签就行了。

尝试解决方案

VSPaste的难点其实是RTF到HTML的转化工作——这从来就是个难题,虽然已经有无数人投身于此。其实在一开始,我也并不想着要“修改”VSPaste,看到CreateContent这点代码相信您也觉得重新写一个更为简单。但是,打开HTMLRootProcessor.FromRTF方法之后我便放弃了,因为实在太复杂。然后我在网上找了找RTF转HTML的类库,还是找不到立即可可用的,于是最后还是下定决心从VSPaste入手。

如果要修改VSPaste,最方便的做法自然是将一个程序集的C#代码导出,而不少.NET Reflector的插件可以轻易完成这个工作。不过,您再回去看看程序集里的成员,就会发现其实这点并不容易。因为……编译后自动生成的一些类和成员,并无法再重新用C#编译器编译通过(主要是命名方面的问题)。不过可能经过简单的修改就行了,但我不知道——而且我们其实只要改一点点逻辑就行了,我不想搞那么复杂。既然如此,那么我们还是从IL入手吧。

别怕,我也不会IL。

要获得VSPaste程序集的IL,自然需要用到ildasm.exe,如下:

ildasm VSPaste.dll /output:VSPaste.il

于是我们就得到了VSPaste.il文件,您可以用某个文本编辑器打开,然后搜索CreateContent便可以定位到这个方法:

.method public hidebysig virtual instance valuetype [System....
        CreateContent(class [System.Windows.Forms]System.Win...
                      string& newContent) cil managed...
{
  // Code size       101 (0x65)
  .maxstack  4
  .locals init (valuetype [System.Windows.Forms]System.Windo...
           bool V_1)
  IL_0000:  nop
  .try
  {
    IL_0001:  nop
    IL_0002:  ldsfld     string [System.Windows.Forms]System...
    IL_0007:  call       bool [System.Windows.Forms]System.W...
    IL_000c:  ldc.i4.0
    IL_000d:  ceq
    IL_000f:  stloc.1
    IL_0010:  ldloc.1
    IL_0011:  brtrue.s   IL_0042
    ...
    IL_0029:  call       string HTMLRootProcessor::FromRTF(string)
    IL_002e:  call       string VSPaste.VSPaste::Undent(string)
    IL_0033:  ldstr      "</pre><a href=\"http://11011.net/software/vspaste\"></a>"
    IL_0038:  call       string [mscorlib]System.String::Concat(string,
                                                              string,
                                                              string)
    ...

好一堆“乱码”,不过其中可以定位到某些关键字符串,例如上面那行链接。那么我们先做一个尝试,把它去除如何?于是我们把不动其他内容,只是把那行代码修改成:

IL_0033:  ldstr      "</pre>"

OK,保存,然后使用ilasm.exe将其编译成VSPaste2.dll文件:

...>ilasm VSPaste.il /output:VSPaste2.dll /dll

Microsoft (R) .NET Framework IL Assembler.  Version 2.0.50727.4016
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling 'VSPaste.il'  to DLL --> 'VSPaste2.dll'
Source file is ANSI

Assembled method VoidProcessor::Open
Assembled method VoidProcessor::Close
...
Class 7
Class 8
Class 9
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Operation completed successfully

好,关闭Windows Live Writer,再将VSPaste2.dll文件复制到Plugins目录下,然后重新打开Windows Live Writer,使用一下,是不是很有效?

谁说一定要学习IL才能摆弄这些,是不?

相关文章

使用Live Messenger联系我