VsSingleFileGenerator插件创建,安装和使用

    相信很多用过VS朋友都会发现一个问题,就是当编写一个XML或一个资源文件的时候VS会为该文件同时生成个类文件;其实我们也可以针对某种文件来实现自定义的生成效果,这种插件就是VS提供给相关文件的自定义工具功能(Custom Tools);下面将为大家介绍如何构造一个VsSingleFileGenerator插件,制作安装发布和在VS中使用.

编写插件

首先要知道的编写这样一个插件需要什么,其实这东西在Google一搜应该就有不少资料和相关sample,直接拿下来看下基本知道原来.编写这样一个插件所需要用到的是一个接口IVsSingleFileGenerator,对于这个接口的详细介绍可以通过MSDN了解.下面看一下实现这接口后的对象代码是怎样的

ContractedBlock.gif ExpandedBlockStart.gif View Code
  1 /// <summary>
2 ///
3 /// </summary>
4 [Guid("F9135C1D-E958-485b-95B9-0233E63930ED")]
5 public class InterfaceToModel : IVsSingleFileGenerator, VSOLE::IObjectWithSite
6 {
7 private CodeDomProvider codeProvider;
8
9 private string codeFileNameSpace;
10 private string codeFilePath;
11
12 private object site;
13
14 private IVsGeneratorProgress codeGeneratorProgress;
15
16 public CodeDomProvider CodeProvider
17 {
18 get
19 {
20 if (this.codeProvider == null)
21 {
22 codeProvider = CodeDomProvider.CreateProvider("C#");
23 }
24
25 return this.codeProvider;
26 }
27
28 set
29 {
30 if (value == null)
31 {
32 throw new ArgumentNullException();
33 }
34
35 this.codeProvider = value;
36 }
37 }
38
39 #region IVsSingleFileGenerator Members
40
41 public int DefaultExtension(out string ext)
42 {
43 string defExt;
44 ext = string.Empty;
45
46 defExt = this.CodeProvider.FileExtension;
47
48 if (((defExt != null) && (defExt.Length > 0)) && (defExt[0] != '.'))
49 {
50 defExt = "." + defExt;
51 }
52
53 if (!string.IsNullOrEmpty(defExt))
54 {
55 ext = ".Model" + defExt;
56 }
57
58 return 0;
59 }
60
61 public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] pbstrOutputFileContents, out uint pbstrOutputFileContentSize, IVsGeneratorProgress pGenerateProgress)
62 {
63 if (bstrInputFileContents == null)
64 {
65 throw new ArgumentNullException(bstrInputFileContents);
66 }
67
68 this.codeFilePath = wszInputFilePath;
69 this.codeFileNameSpace = wszDefaultNamespace;
70 this.codeGeneratorProgress = pGenerateProgress;
71
72 byte[] generatedStuff = this.GenerateCode(wszInputFilePath, bstrInputFileContents);
73
74 if (generatedStuff == null)
75 {
76 pbstrOutputFileContents[0] = IntPtr.Zero;
77 pbstrOutputFileContentSize = 0;
78 }
79 else
80 {
81 pbstrOutputFileContents[0] = Marshal.AllocCoTaskMem(generatedStuff.Length);
82 Marshal.Copy(generatedStuff, 0, pbstrOutputFileContents[0], generatedStuff.Length);
83 pbstrOutputFileContentSize = (uint)generatedStuff.Length;
84 }
85 return 0;
86 }
87 #endregion
88
89 #region IObjectWithSite Members
90
91 public void GetSite(ref Guid riid, out IntPtr ppvSite)
92 {
93 if (this.site == null)
94 {
95 throw new Win32Exception(-2147467259);
96 }
97
98 IntPtr objectPointer = Marshal.GetIUnknownForObject(this.site);
99
100 try
101 {
102 Marshal.QueryInterface(objectPointer, ref riid, out ppvSite);
103 if (ppvSite == IntPtr.Zero)
104 {
105 throw new Win32Exception(-2147467262);
106 }
107 }
108 finally
109 {
110 if (objectPointer != IntPtr.Zero)
111 {
112 Marshal.Release(objectPointer);
113 objectPointer = IntPtr.Zero;
114 }
115 }
116 }
117
118 public void SetSite(object pUnkSite)
119 {
120 this.site = pUnkSite;
121 this.codeProvider = null;
122 }
123
124 #endregion
125
126 #region Private Methods
127 protected byte[] GenerateCode(string inputFileName, string inputFileContent)
128 {
129 using (System.IO.FileStream stream =System.IO.File.Open(inputFileName, FileMode.Open, FileAccess.Read))
130 {
131 Smark.Data.InterfaceToModelGenerator.GenerateCode gc
132 = new GenerateCode();
133 return StreamToBytes(gc.Builder(stream));
134 }
135
136 }
137
138 protected byte[] StreamToBytes(Stream stream)
139 {
140 if (stream.Length == 0)
141 {
142 return new byte[0];
143 }
144
145 long pos = stream.Position;
146
147 stream.Position = 0;
148
149 byte[] buffer = new byte[(int)stream.Length];
150 stream.Read(buffer, 0, buffer.Length);
151
152 stream.Position = pos;
153 return buffer;
154 }
155
156 private void ThrowOnFailure(int hr)
157 {
158 if ((hr < 0))
159 {
160 Marshal.ThrowExceptionForHR(hr);
161 }
162 }
163 #endregion
164 }

其实整个类的实现都比较简单,主要有两个方法是需要我们去关注分别是:

 public int DefaultExtension(out string ext)

这个方法主要是描述生成文件的默认后缀扩展名

public int Generate(string wszInputFilePath, string bstrInputFileContents, string wszDefaultNamespace, IntPtr[] pbstrOutputFileContents, out uint pbstrOutputFileContentSize, IVsGeneratorProgress pGenerateProgress)

 这个方法比重要,主要是获取当前文件路径,名称空间,输出文件内容等相关信息;并根据根据这些信息按实际需要生成相关文件内容输出给相关参数.

byte[] generatedStuff = this.GenerateCode(wszInputFilePath, bstrInputFileContents);

if (generatedStuff == null)
{
pbstrOutputFileContents[0] = IntPtr.Zero;
pbstrOutputFileContentSize = 0;
}
else
{
pbstrOutputFileContents[0] = Marshal.AllocCoTaskMem(generatedStuff.Length);
Marshal.Copy(generatedStuff, 0, pbstrOutputFileContents[0], generatedStuff.Length);
pbstrOutputFileContentSize = (uint)generatedStuff.Length;
}
return 0;
 从上面代码可以看到,Generate方法内部所做的事情就是根据需要生成一个文件内容generatedStuff,并根据generatedStuff数据情况进行参数更新,告诉VS如何处理.

     大概看一下this.GenerateCode方法做得是什么:

protected byte[] GenerateCode(string inputFileName, string inputFileContent)
{
using (System.IO.FileStream stream =System.IO.File.Open(inputFileName, FileMode.Open, FileAccess.Read))
{
Smark.Data.InterfaceToModelGenerator.GenerateCode gc
= new GenerateCode();
return StreamToBytes(gc.Builder(stream));
}

}
public System.IO.Stream Builder(System.IO.Stream stream)
{
System.IO.StringWriter sw = new System.IO.StringWriter();
Console.SetOut(sw);
Console.SetError(sw);
CSharpParser p = new CSharpParser(null, stream, null);
System.IO.Stream result = new System.IO.MemoryStream();
System.IO.StreamWriter writer = new System.IO.StreamWriter(result, Encoding.UTF8);
int errno = p.parse();
if (errno > 0)
{
writer.Write(sw.ToString());
}
CodeCompileUnit unit = p.Builder.CurrCompileUnit;

if (unit != null)
{
try
{
Microsoft.CSharp.CSharpCodeProvider csp = new Microsoft.CSharp.CSharpCodeProvider();
foreach (string assembly in unit.ReferencedAssemblies)
{
mEntityUnit.ReferencedAssemblies.Add(assembly);
}

foreach (CodeNamespace cn in unit.Namespaces)
{
BuilderNameSpace(cn);
}
csp.GenerateCodeFromCompileUnit(mEntityUnit, writer, new CodeGeneratorOptions());
writer.Flush();
}
catch (Exception e_)
{
writer.WriteLine(e_.Message + e_.StackTrace);
}
}
return result;

}

其实就是生成文件内容并返回相关流数据

 制作安装

     插件使用必须要把相关类信息注册到win注册表中让vs可以识别,还要把类生成的程序集部署到全局程序集中,这样做的前提就是要给程序集签名并发为相关类生成uid标识(对于这些详细信息可以通过MSDN了解).以上工作其实可以手动去做自行导入注册表和copy文件到全局目录中;这种做法确实比较山寨,我们可以创建一个安装项目,生成相关安装程序自动地完成这些事情.

 首先把需要的DLL添加到GAC中 

然后针对不同VS需要的版本构造相关的注册信息,也可以通过现有的注册项文件导入

以上工作都做好后,直接编译生成安装文件包就OK了.

使用插件

 其实插件使用也很简单,只需要在文件属性的自定义工具处理,填写插件制定的名称就行了

插件源码

http://smark.codeplex.com/

转载于:https://www.cnblogs.com/smark/archive/2011/10/13/2210432.html

将整个页面存档到一个HTML文件中 SingleFile也可以用来替代快照/截图/捕获页面扩展。 1-说明: - 等待页面完全加载:您可能需要向下滚动整个页面并悬停动态文档元素(例如“翻转”图像)以确保所有元素都已加载 - 点击Chrome工具栏中的SingleFile图标(或按Ctrl Shift S)以启动页面处理 - 等到保存标题出现在页面顶部 - 点击横幅链接将页面保存在默认的下载文件夹中 补充笔记: - 在安装过程中,扩展会要求您安装SingleFile Core”,按照安装说明或从这里下载:https://chrome.google.com/webstore/detail/jemlklgaibiijojffihnhieihhagocma - 您可以使用上下文菜单处理整个页面(“处理页面”),页面的选定部分(“处理选择”)或框架(“处理框架”) - 从SingleFile版本0.3.0开始,默认行为是显示一个横幅,它允许您轻松地将页面保存到Downloads目录中。要使用Chrome文件 - >另存为...对话框并将文件保存到选定位置,请取消选择页面中的“显示保存横幅”和“显示保存通知”(右键单击单个文件图标,选择选项)。 2 - 一般说明 - 保存的文件与Firefox,Opera,Safari,Konqueror兼容,部分与Internet Explorer 8兼容(请参阅帮助页面)*不安装任何扩展名* - SingleFile使用“数据URI”方案将图像和帧内容嵌入到页面中:生成的格式不是MHT / MHTML。 - 右键单击​​SingleFile图标并选择“Options”打开选项页面 3 - 更多信息 有关选项,技术说明和已知问题的更多详细信息,请参阅选项页面中的扩展帮助。 >>您想在查看保存的页面时打开原始页面吗?尝试“打开单个文件的原始” >> https://chrome.google.com/webstore/detail/ofpgbbdbebphacpiilccacdhjnehlhia >>您是否在寻找高级档案管理员?尝试“PageArchiver” >> https://chrome.google.com/webstore/detail/ihkkeoeinpbomhnpkmmkpggkaefincbn >>你想保存一个zip文件中的多个标签?试试“ZipTabs” >> https://chrome.google.com/webstore/detail/ccnanbffbfbcgfmmkgejodommhidpjba 4 - 问题 如果您发现一个未知的问题(即冻结过程,额外保存的文件,空白或更改的文档,标签崩溃...): - 检查SingleFile帮助页面中的已知问题 - 在SingleFile选项页面中重置选项 - 如果选项重置不起作用,请尝试取消选中“显示保存通知”和“显示保存横幅”,并确保后台进程未被选中(您需要使用Chrome“另存为”对话框来保存页面)。 - 禁用所有其他分机,查看是否有冲突 - 如果发生冲突,请尝试确定哪个分机(S) - 用一个简短的描述报告问题,描述如何重现它,Chrome版本,操作系统名称和版本: https://github.com/gildas-lormeau/SingleFile/issues 建议欢迎:) 支持语言:Deutsch,English,Français,español,polski,русский,中文 (简体),中文 (繁體),日本語
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值