最近工作中想做一个小工具,希望能在Vistual Studio外部运行指定的解决方案。经过调试完成了以下Demo。
打开解决方案
打开解决方案其实本事只是打开一个文件,所以需要启动一个进程,使用默认程序打开文件。
- Process 类:
System.Diagnostics.Process
类提供了启动和停止系统进程的方法。它可以用来启动外部应用程序或文件。 - ProcessStartInfo 类:
ProcessStartInfo
类用于指定启动进程时的参数。通过设置FileName
属性,可以指定要启动的文件或应用程序的路径。UseShellExecute 属性:布尔类型的属性,用于决定启动进程的方式。
使用操作系统的外壳程序:
如果
UseShellExecute
设置为true
,启动进程时会使用操作系统的外壳程序(例如 Windows Explorer)。外壳程序会根据文件类型选择合适的应用程序来打开文件。通常用于启动非可执行文件(如文档、URL 等)。直接启动进程
如果
UseShellExecute
设置为false
,则直接启动指定的可执行文件,而不使用外壳程序,通常用于启动可执行文件(如 .exe 文件)。
- 启动外部程序:通过调用
Process.Start
方法并传入ProcessStartInfo
对象,可以启动指定的外部程序或打开指定的文件。
// 创建一个 ProcessStartInfo 对象,用于启动一个新进程
Process.Start(new ProcessStartInfo
{
// 设置要启动的文件路径
FileName = FilePath,
// 指定是否使用操作系统的外壳程序来启动进程
UseShellExecute = true
});
运行解决方案
想要对Visual Studio 进行自动化操作,不可避免需要了解一下DTE2,
DTE2 是指 Development Tools Environment 2。
它允许开发者通过编程方式控制和扩展 Visual Studio 的功能。例如:
- 项目管理:创建、打开、关闭和保存项目。
- 代码操作:编辑、格式化和重构代码。
- 调试支持:启动和控制调试会话,设置断点,监视变量等。
常用对象和方法
- DTE2.Solution:管理解决方案。
- DTE2.SolutionBuild:解决方案级别构建自动化模型
具体步骤
- 安装EnvDTE80
EnvDTE80 是 Visual Studio 的自动化对象模型的一部分,允许开发者通过编程方式控制和扩展 Visual Studio 的功能。
- 获取 DTE 对象
思路: 通过指定的名称在运行对象表(ROT)中查找并返回一个 DTE2
对象。
其中涉及主要内容,GetRunningObjectTable
方法: 运行对象表(ROT) 是一个系统级的表格,包含了当前正在运行的所有 COM 对象。通过 ROT,可以枚举和访问这些对象。
public static DTE2 GetDteByName(string name)
{
// 分配内存用于存储获取的对象数量
uint numFetchedUInt = (uint)Marshal.SizeOf(numFetched);
// 声明运行对象表和枚举器,以及用于存储枚举到的单个对象的数组。
IRunningObjectTable runningObjectTable;
IEnumMoniker monikerEnumerator;
IMoniker[] monikers = new IMoniker[1];
// 创建绑定上下文
IBindCtx bindCtx;
Marshal.ThrowExceptionForHR(CreateBindCtx(reserved: 0, ppbc: out bindCtx));
// 获取运行对象表 通过绑定上下文获取当前的运行对象表。
bindCtx.GetRunningObjectTable(out runningObjectTable);
// 枚举运行对象
runningObjectTable.EnumRunning(out monikerEnumerator);
monikerEnumerator.Reset();
// 遍历所有运行对象
while (monikerEnumerator.Next(1, monikers, out numFetchedUInt) == 0)
{
// 为每个对象创建新的绑定上下文
IBindCtx ctx;
CreateBindCtx(0, out ctx);
// 获取运行对象的显示名称
string runningObjectName;
monikers[0].GetDisplayName(ctx, null, out runningObjectName);
// 检查显示名称是否包含指定的名称
if (runningObjectName.Contains(name))
{
// 获取运行对象
object runningObjectVal;
runningObjectTable.GetObject(monikers[0], out runningObjectVal);
// 将运行对象转换为DTE2类型并返回
DTE2 dte = (DTE2)runningObjectVal;
return (dte);
}
}
// 如果没有找到匹配的对象,返回null
return null;
}
- 使用
dte.Solution.SolutionBuild
调试运行
// 获取所有名为 "VisualStudio.DTE" 的 DTE 对象
var dtes = CsFile.GetDtesByName("VisualStudio.DTE");
// 初始化一个标志变量,表示是否找到并打开了解决方案
bool isOpened = false;
// 遍历所有 DTE 对象
foreach (DTE2 dte in dtes)
{
// 如果当前 DTE 对象的解决方案文件名与指定的文件路径匹配
if (dte.Solution.FileName == FilePath)
{
// 启动调试
dte.Solution.SolutionBuild.Debug();
// 设置标志变量为 true,表示已找到并打开了解决方案
isOpened = true;
// 退出循环
break;
}
}
// 如果没有找到并打开任何匹配的解决方案
if (!isOpened)
{
// 显示消息框,提示用户先打开指定的解决方案
MessageBox.Show($"未找到打开的{FilePath}解决方案,请先打开该解决方案!");
}
- 停止
public static void CloseSolution(string solutionPath)
{
var dtes = CsFile.GetDtesByName("VisualStudio.DTE");
foreach (DTE2 dte in dtes)
{
if (dte.Solution.FileName == solutionPath)
{
dte.Debugger.Stop();
break;
}
}
}