Visual Studio Package 插件开发(Visual Studio SDK)
liuian 2025-07-23 16:11 19 浏览
背景
这段时间公司新做了一个支付系统,里面有N个后台服务,每次有更新修改,拷贝打包发布包“不亦乐乎”。。。于是我想要不要自己定制个打包插件。
部分朋友可能会认为,有现成的可以去找一个,干嘛不用持续集成工具啊。
1、公司没用,也不打算用
2、自己想折腾下,好奇
因此主要是分享这次的学习过程和结果。
涉及知识点
大概构想下,选择需要打包的项目-重新编译-拷贝生成文件到指定目录-OK,剩下就是交给测试去做了。
1、Visual Studio Package 初步使用
2、.Net 执行Dos命令
3、MSBuild简单运用
4、File.Copy的使用
下载安装
Visual Studio 2013 SDK包的下载地址:
http://www.microsoft.com/en-us/download/details.aspx?id=40758&
fa43d42b-25b5-4a42-fe9b-1634f450f5ee=True
完毕后,在新建项目-C#-扩展性,可以见到Visual Studio Package模板选项(见下图)
第一个vs插件程序
下一步,勾选Menu Command;下一步,修改Command Name;下一步,取消单元测试,Finish。恭喜,您的第一个插件程序就这么诞生了。
编译后,到生成目录下,执行.vsix文件,安装完后,重启VS,点击[工具]就会见到您的插件工具。同时你也可以在扩展与更新界面进行对您的插件进行卸载。
项目文件简介
初建项目,有很多文件,有几个下面是需要了解一下的。
1、PackingTools.vsct
2、PackingToolsPackage.cs
3、
source.extension.vsixmanifest
PackingTools.vsct
vsct是个Xml文件,它用来对插件按钮进行配置的。
Group是组节点,项目初建,它的Parent为IDM_VS_MENU_TOOLS,对于这个我们可以查看 您的vs安装目录\Visual Studio2013\VSSDK\VisualStudioIntegration\Common\Inc\vsshlids.h,打开文件,我们可以看到除IDM_VS_MENU_TOOLS以外还有IDM_VS_MENU_ADDINS、IDM_VS_MENU_HELP等等,我们尝试改成IDM_VS_MENU_HELP。
Buttons节点下,可以添加多个Button信息,我们尝试添加一个Button进去,同时GuidSymbol加多一个IDSymbol进去。修改对应新按钮的id 和 priority。
我们启动F5,调试看看,插件按钮位置变了,也是我们第一次修改了按钮布局。
PackingToolsPackage.cs
插件程序的入口,我们细看代码,发现在Initialize方法里,就对批量打包这个按钮进行事件绑定,我们尝试一下,把MenuItemCallback里的逻辑删了,展示一个wpf窗体出来。
添加新建项-添加wpf窗体后,需要在项目里新引用一个System.Xaml.dll才能编译通过。
接着,我们在PackingToolsPackage.cs的MenuItemCallback的方法里写new MainWindow().Show(),F5运行->点击批量打包,则会弹出下图。
主界面就这么出来了,当然,你可以单例一个窗体,不用new。。。
source.extension.vsixmanifest
对Visual Studio 扩展的配置,如:文件模板,项目工程模板,依赖程序集,Visual Studio 工具包logo,VS安装的版本等等。
读取已打开的项目信息
这个其实并没什么特别难的逻辑,只是开始找资料花了一些时间,直接上代码。
1 private void MenuItemCallback(object sender, EventArgs e)
2 {
3 IVsSolution pSolution = GetService(typeof(SVsSolution)) as IVsSolution;
4
5 if (pSolution != null)
6 {
7 var projectArray = new string[10];
8 uint aa;
9 //通过这个方法取到打开解决方案的项目信息
10 pSolution.GetProjectFilesInSolution((uint)__VSGETPROJFILESFLAGS.GPFF_SKIPUNLOADEDPROJECTS,
11 (uint)__VSGETPROJFILESFLAGS.GPFF_SKIPUNLOADEDPROJECTS, projectArray, out aa);
12
13 //转换信息,让girdView展示
14 var projectList =
15 projectArray.ToList()
16 .Where(a => a.Contains(".csproj")).Select(a => new ProjectList
17 {
18 Name = Path.GetFileNameWithoutExtension(a),
19 Path = a
20 }).ToList();
21
22 MainForm.GetInstance(projectList).Show();
23 }
24 }
对于IVsSolution这个接口的命名空间下,还有各种各样的类,对Visual Studio Package开发有兴趣的同学可以去看看。传送门
MSBuild的使用
Microsoft Build Engine 是MSBuild的全称,是一个独立的存在生成平台,不需要依赖vs,但是vs的生成、发布等等功能都是基于MSBuild去构建的,它能读取.sln、.csproj、.pubxml等xml文件里的参数进行生成解决和项目。这里就不做过多的介绍和深入,有需要可以点击这里进行查看文档
MSBuild.exe在C:\Windows\Microsoft.NET\Framework\v4.0.30319 这个路径下,值得注意的是Framework 的位数和版本,这个影响选择MSBuild.exe的路径。
尝试一下,打开cmd,输入-> C:\Windows\Microsoft.NET\Framework\v4.0.30319 "您的项目文件路径" /t:Rebuild /p:Configuration=Release /p:VisualStudioVersion=12.0
这句话指,用msbuild重新生成Release版本,注意项目路径是有双引号的。
然而,我们需要在.net程序里使用这段dos指令,因此我们写编写一个dos指令帮助类
1 #region Dos指令帮助类
2 /// <summary>
3 /// Dos指令帮助类
4 /// </summary>
5 public class DosCommanHelper
6 {
7 #region 执行指令
8 /// <summary>
9 /// 执行指令
10 /// </summary>
11 /// <param name="command">指令</param>
12 /// <param name="seconds">最长等待时间(秒)</param>
13 /// <returns></returns>
14 public static string ExeCommand(string command, int seconds = 3)
15 {
16 var output = "";
17 if (string.IsNullOrWhiteSpace(command))
18 return output;
19
20 var process = new Process(); //创建进程对象
21 var startInfo = new ProcessStartInfo
22 {
23 FileName = "cmd.exe", //设定需要执行的命令
24 Arguments = "/C " + command, //“/C”表示执行完命令后马上退出
25 UseShellExecute = false, //不使用系统外壳程序启动
26 RedirectStandardInput = false, //不重定向输入
27 RedirectStandardOutput = true, //重定向输出
28 CreateNoWindow = true //不创建窗口
29 };
30
31 process.StartInfo = startInfo;
32 try
33 {
34 if (process.Start())
35 {
36 if (seconds == 0)
37 {
38 process.WaitForExit();
39 }
40 else
41 {
42 process.WaitForExit(seconds * 1000);
43 }
44 output = process.StandardOutput.ReadToEnd();
45 }
46 }
47 catch (Exception e)
48 {
49 Console.WriteLine(e);
50 }
51 finally
52 {
53 process.Close();
54 }
55 return output;
56 }
57 #endregion
58 }
59 #endregion
拷贝生成文件
从上面我们已经读取到了解决方案对应的项目信息,包括路径,新建的项目默认生成到.csproj文件目录下的bin/Release里。
我们利用Path.GetDirectoryName和Path.Combine方法,获取对应路径,再自己编写文件操作帮助类,对应Release里的文件复制到指定位置。
1 #region 文件操作帮助类
2 /// <summary>
3 /// 文件操作帮助类
4 /// </summary>
5 public static class FilesHelper
6 {
7 #region 复制文件
8 /// <summary>
9 /// 复制文件
10 /// </summary>
11 /// <param name="fromPath">原路径</param>
12 /// <param name="toPath">新路径</param>
13 /// <returns></returns>
14 public static bool CopyFiles(string fromPath, string toPath)
15 {
16 try
17 {
18 if (!Directory.Exists(fromPath))
19 throw new Exception("no fromPath");
20
21 if (Directory.Exists(toPath))
22 Directory.Delete(toPath, true);
23
24 Directory.CreateDirectory(toPath);
25
26 var fromfiles = Directory.GetFiles(fromPath).ToList();
27 fromfiles.ForEach(file =>
28 {
29 var newFile = Path.Combine(new[] { toPath, Path.GetFileName(file) });
30 File.Copy(file, newFile, true);
31 });
32
33 var fromFolders = Directory.GetDirectories(fromPath).ToList();
34 fromFolders.ForEach(folder =>
35 {
36 var destDir = Path.Combine(new[] { toPath, Path.GetFileName(folder) });
37 CopyFiles(folder, destDir);
38 });
39
40 return true;
41 }
42 catch
43 {
44 return false;
45 }
46 }
47 #endregion
48 }
49 #endregion
最后我们只需要完善发布按钮事件,获取列表选择项->获取打包到的指定路径->遍历列表项数据->执行MSBuild指令->复制文件到指定路径->完毕
1 private void Button_Click_1(object sender, RoutedEventArgs e)
2 {
3 var list = MyListView.SelectedItems.Cast<ProjectList>().ToList();
4
5 var fromPath = PathLabel.Content;
6
7 list.ForEach(item =>
8 {
9 DosCommanHelper.ExeCommand(string.Format(@"C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe {0} /t:Rebuild /p:Configuration=Release /p:VisualStudioVersion=12.0", item.Path));
10
11 var theFileOfDirectoryName = Path.GetDirectoryName(item.Path);
12 var toPath = Path.Combine(theFileOfDirectoryName, @"bin\Release");
13 FilesHelper.CopyFiles(fromPath.ToString(), Path.Combine(toPath, item.Name));
14 });
15 }
完毕
源码我这里没有提供,还是希望读了这篇文章感兴趣的小伙伴动手折腾下,Visual Studio Package还可以做模版开发等等,我也没太多的去深入了解,感兴趣的可以去google一下关键字Visual Studio Package、vssdk、vsix、插件开发。
以上纯属自己初步折腾的结果,为了写文章弄出来的简单demo,还有很多可优化的地方,例如各种验证判断,插件按钮的动态显示、读取项目的类型过滤、web项目的发布,文件过滤复制等等。。。。
本篇文章有什么写错的或者更好的建议麻烦大家在评论写给我,我会一一补充修改。如果对大家有帮助,还希望推荐一下,谢谢。
作 者: 陈珙
出 处:
http://www.cnblogs.com/skychen1218/
相关推荐
- git的撤销、删除和版本回退_git撤销删除的文件
-
备注:本文参考于廖雪峰的博客Git教程。依照其博客进行学习和记录,感谢其无私分享,也欢迎各位查看原文。知识点:1、gitstatus,查看git仓库的状态2、gitdiff查看git修改了的内容...
- 程序员开发必会之git常用命令,git配置、拉取、提交、分支管理
-
整理日常开发过程中经常使用的git命令!git配置SSH刚进入项目开发中,我们首先需要配置git的config、配置SSH方式拉取代码,以后就免输入账号密码了!#按顺序执行gitconfig-...
- Git使用指南 | 教你轻松学会Git_git用法详解
-
4000字,教大家学会Git使用。一、Git基础1、Git介绍Git是目前世界上最先进的分布式版本控制系统。版本控制系统:设计师在设计的时候做了很多版本经过了数天去问设计师每个版本都改了些啥,设计师此...
- 深入浅出 Git_深入浅出 gRPC
-
git初体验使用git前需设置用户名和Email,这些信息会出现在提交记录中以标识作者。gitconfig--globaluser.name"YeHanlin"gitc...
- Git不提交指定文件的方法_git不提交指定文件的方法有哪些
-
大家在开发项目的时候都很喜欢使用git作为代码管理工具,但是在开发项目的时候我们的本地配置文件不应该覆盖服务器中的配置文件,我们使用命令gitstatus查看待提交文件的时候需要注意不要把本地的配...
- 相见恨晚的 Git 命令动画演示,一看就懂
-
虽然Git是一个强大的工具,但是我觉得大部分人都会同意我说的:它也可以是一个……噩梦!我一直觉得,使用Git的时候把操作过程在脑海里视觉化会非常有用:当我执行某个命令的时候,分支之间是如何交互...
- GitCode的一些命令_git命令大全
-
GitCode的一些命令配置工具对所有本地仓库的用户信息进行配置$gitconfig--globaluser.name"[name]"对你的commit操作设置关联的用户名$...
- 【git】 如何删除所有 tag(本地和远程)
-
要删除所有本地和远程的Git标签,可以按照以下步骤进行:删除本地标签首先,删除本地标签。你可以使用以下命令删除本地的所有标签:gittag-d$(gittag-l)这将列出并删除所有本地...
- 互联网大漏洞:每600个网站就有1个暴露了.git文件夹
-
对于Web开发人员来说,向外界暴露你的.git文件夹绝对是一个菜鸟级错误。因为这样会允许任何人下载你的整个源代码存储库,包括数据库密码、加密盐、Hash和第三方接口密钥API,还有你的用户名和密码。多...
- git常用命令整理_git 常用
-
一、Git仓库完整迁移完整迁移,就是指,不仅将所有代码移植到新的仓库,而且要保留所有的commit记录1.随便找个文件夹,从原地址克隆一份裸版本库gitclone--bare旧的git地址...
- 项目常用GIT操作命令_git常用操作命令 简书
-
Git仓库更新依赖的命令:gradle--refresh-dependenciesgradleaR完全编译;./gradlewecomm:packages:telephony:larges...
- 【超详细】Git 所有常用命令 + 提交规范全指南(建议收藏!)
-
Git命令大全初始化类命令作用gitinit初始化一个本地Git仓库(当前目录会出现.git文件夹)gitclone<仓库地址>克隆远程仓库到本地,一般用来拉项目提交代...
- Git 常用的alias命令大全_git -a
-
Git的alias(别名)功能可以将常用的复杂命令简化,大幅提升操作效率。以下是一些实用的Gitalias配置和常用示例:一、配置alias的方法通过gitconfig命令设置,分...
- Git使用教程:最详细、最傻瓜、最浅显、真正手把手教
-
导读:因为教程详细,所以行文有些长,新手边看边操作效果出乎你的预料。GitHub虽然有些许改版,但并无大碍。一、Git是什么?Git是目前世界上最先进的分布式版本控制系统。工作原理/流程:Work...
- 实用干货分享(3)- Git常用操作干货分享
-
官方学习地址https://git-scm.com/book/zh/v2简单的代码提交流程1.gitstatus查看工作区代码相对于暂存区的差别;2.gitadd.将当前目录下修改的所有...
- 一周热门
-
-
【验证码逆向专栏】vaptcha 手势验证码逆向分析
-
Python实现人事自动打卡,再也不会被批评
-
Psutil + Flask + Pyecharts + Bootstrap 开发动态可视化系统监控
-
一个解决支持HTML/CSS/JS网页转PDF(高质量)的终极解决方案
-
再见Swagger UI 国人开源了一款超好用的 API 文档生成框架,真香
-
网页转成pdf文件的经验分享 网页转成pdf文件的经验分享怎么弄
-
C++ std::vector 简介
-
飞牛OS入门安装遇到问题,如何解决?
-
系统C盘清理:微信PC端文件清理,扩大C盘可用空间步骤
-
10款高性能NAS丨双十一必看,轻松搞定虚拟机、Docker、软路由
-
- 最近发表
- 标签列表
-
- python判断字典是否为空 (50)
- crontab每周一执行 (48)
- aes和des区别 (43)
- bash脚本和shell脚本的区别 (35)
- canvas库 (33)
- dataframe筛选满足条件的行 (35)
- gitlab日志 (33)
- lua xpcall (36)
- blob转json (33)
- python判断是否在列表中 (34)
- python html转pdf (36)
- 安装指定版本npm (37)
- idea搜索jar包内容 (33)
- css鼠标悬停出现隐藏的文字 (34)
- linux nacos启动命令 (33)
- gitlab 日志 (36)
- adb pull (37)
- python判断元素在不在列表里 (34)
- python 字典删除元素 (34)
- vscode切换git分支 (35)
- python bytes转16进制 (35)
- grep前后几行 (34)
- hashmap转list (35)
- c++ 字符串查找 (35)
- mysql刷新权限 (34)