以前用VS一直不知道自定义工具这家伙是干什么用的,后来渐渐明白是用来生成代码的。现在一个项目需要将一个自定义格式的XML转换为代码,就想到要自己做一个自定义工具来生成代码,于是找了网上一些资料,终于开发成功。
第一步,编写代码
在VS里创建一个类库,这与一般的过程没什么两样,然后需要添加两个DLL的引用,一个是Microsoft.VisualStudio.Shell.Interop.DLL,另一个是Microsoft.VisualStudio.Shell.DLL。但奇怪的是,这两个DLL并没有出现在添加引用的对话框里,我找了很久,最后还是直接从GAC的目录里复制出来的。
接下来,创建一个类,这个类需要实现IVsSingleFileGenerator接口。关于接口的详细说明,请参考MSDN。这个接口有两个成员,一个是DefaultExtension,用来获取所生成文件的扩展名,另一个是Generate,就是需要实现代码生成的地方了。来看一下我的测试代码,这些代码是从Code Project上复制过来的。
View Code
稍微解释一下,这个生成器的作用就是将源文件的行数写入到一个文本文件中。来看Generate方法的实现,首先从源文件中分析出行数,但我们无法将这个信息以传统的.net方式写入输出文件中,而是要通过Marshal与非托管的VS交换数据。这就需要把行数转换成字符串后获得相应的字节数组,再将这个字节数组写入到从系统分配来的COM任务内存中。所分配的内存不需要我们去释放,VS会替我们搞定的。(其实COM我并不懂,照样做准没错就是了)
第二步,准备程序集
因为自定义工具必须是一个COM组件,所以还需要把DLL设置为COM可见,这个很容易,在Properties目录的AssemblyInfo.cs中,把ComVisible的参数改为true。然后为刚才的LineCountGenerator加上一个GuidAttribute就可以了。
程序必须要放在GAC里才能被VS直接调用,而程序集必须要进行签名才能放入GAC,所以我们还得为DLL进行签名。只需要在项目的属性里做一个简单的设置就可以了,当然不嫌麻烦的话也可以用sn.exe。
接下来,编译后,打开VS的命令提示符,然后转到程序集所在的目录,分别用regasm和gacutil对所生成的DLL进行注册。
第三步,让VS知道
VS通过注册表存放自定义工具的信息,位置在:
32位:HKLM\Software\Microsoft\VisualStudio\版本\Generators\语言
64位:HKLM\Software\Wow6432Node\Microsoft\VisualStudio\版本\Generators\语言
其中,版本就你当前所使用的VS的版本号,2010是10.0,2008是9.0。语言就是程序开发语言的GUID,对于C#来说,是{FAE04EC1-301F-11D3-BF4B-00C04F79EFBC}。
通过注册表编辑器打开后,你会看到下面已经有一些自定义工具了,不解析,照葫芦画瓢就可以了。
第四步,使用自定义工具
到此为止,自定义工具已经搞定,接下来就是使用它了。很简单,在解决方案浏览器中某个文件的属性里,在自定义工具一栏中输入工具的名称就可以了。不要问我应该输入什么内容,折腾了老半天你应该知道的。 输入之后敲回车,你会发现加号下面多了一个文件,哈哈,这就是我们的代码生成。
因为时间关系,我没有将整个过程写得很细致,考虑到有这种需求的人应该有一定的基础,所以我就省点口水了,呵呵。下面列出几篇参考文章,有不明白的地方可以去看看,我也是从这里面学出来的。
http://www.codeproject.com/Articles/31257/Custom-Tools-Explained
http://msdn.microsoft.com/en-us/library/bb166817.aspx
http://www.drewnoakes.com/snippets/WritingACustomCodeGeneratorToolForVisualStudio/
这些年我收集的GDI+代码
本作者,在工作之中收集了大量的GDI代码,在此与大家分享。愿意建立良好的学习交流的平台。
图形类所在的命名空间:
各个命名空间的主要功能如下:
System.Drawing:提供了对GDI+基本图形功能的访问的类;
System.Drawing.Imaging:提供高级GDI+图像处理功能的类;
System.Drawing.Text:提供高级GDI+排版功能,该命名空间中的类允许用户创建和使用多种字体的类
图一、命名空间
下面演示如何用GDI+画一条直线
图二、画一条线
窗体重绘问题
图三、重新绘制
图四、使笔画出的线变粗
图五、我画得矩形
六、填充矩形,无缝连接
七、我画的无籽西瓜
下一篇内容,我将介绍如何用GDI+制作验证码,敬请期待!
作者近期文章:
实现一个小的通信功能:客户端向服务端提交数据,然后服务端回执数据。
一、新建一个控制台应用程序:Client。
二、新建一个控制台应用程序:Server。
先后运行服务端和客户端程序。执行结果如下:
三、可以进一步的完善功能:如可以让客户端每5秒钟向客户端提交一次数据。
这样只需要对程序进行一些修改:在客户端增加一个定时器,在程序运行后,每5秒钟向服务端提交一次当前时间。(在Client运行期间,Server端必须保持运行状态)
在服务端接收和回执部分代码上添加一个while循环语句:
四、再次先后运行Server和Client。运行结果如下: