C# 在Visual Studio IDE外部获取EnvDTE.DTE实例

C# 在Visual Studio IDE外部获取EnvDTE.DTE实例,c#,visual-studio-2013,envdte,C#,Visual Studio 2013,Envdte,我正在Visual Studio 2013中创建一个项目自动化工具,其中我有自己的项目模板,并试图通过编程方式将其添加到现有解决方案中 EnvDTE.DTE dte = (EnvDTE.DTE)Marshal.GetActiveObject("VisualStudio.DTE.12.0"); string solDir = dte.Solution.FullName; solDir=solDir.Substring(0, solDir.LastIndexOf("\\")); dte.Soluti

我正在Visual Studio 2013中创建一个项目自动化工具,其中我有自己的项目模板,并试图通过编程方式将其添加到现有解决方案中

EnvDTE.DTE dte = (EnvDTE.DTE)Marshal.GetActiveObject("VisualStudio.DTE.12.0");
string solDir = dte.Solution.FullName;
solDir=solDir.Substring(0, solDir.LastIndexOf("\\"));
dte.Solution.AddFromTemplate(path, solDir+"\\TestProj", "TestProj", false);
当我从VisualStudioIDE运行应用程序时,它正在工作。但是,当我试图从命令提示符下运行exe时,出现了以下异常

Unhandled Exception: System.Runtime.InteropServices.COMException: Operation unav
ailable (Exception from HRESULT: 0x800401E3 (MK_E_UNAVAILABLE))
at System.Runtime.InteropServices.Marshal.GetActiveObject(Guid& rclsid, IntPtr reserved, Object&   ppunk)
at System.Runtime.InteropServices.Marshal.GetActiveObject(String progID)
at ProjectAutomation.Console.Program.Main(String[] args) 

我想知道是否有任何方法可以在Visual Studio IDE外部获取活动的EnvDTE.DTE实例。

将现有Visual Studio实例从外部工具自动化以修改加载的解决方案是一个坏主意。如果使用GetActiveObject(…),并且启动了两个Visual Studio实例,您如何知道返回了正确的实例?当用户启动外部工具时,如果用户或VisualStudio正在对解决方案执行某些操作,该怎么办?有两种更好的方法:

1) 使用外部工具自动化新的Visual Studio实例,加载所需的解决方案并对其进行修改。即使VS实例不可见,也可以这样做。要创建新实例,正确的代码为:

System.Type type = Type.GetTypeFromProgID("VisualStudio.DTE.12.0");
EnvDTE.DTE dte = (EnvDTE.DTE) System.Activator.CreateInstance(type);
dte.MainWindow.Visible = true;
...

2) 使用Visual Studio扩展,例如宏(VS 2010或更低版本)、外接程序(VS 2013或更低版本)或包(任何VS版本)提供菜单项或按钮工具栏,单击该菜单项或按钮工具栏可修改当前加载的解决方案。这可以防止出现“忙”情况,因为如果VS忙,则无法单击菜单项或工具栏按钮(除非“忙”操作是异步的)。

我找到了GetActiveObject的替代方案,其中Kiril解释了如何枚举ROT。MSDN上还有其他示例

由于一些SO用户不喜欢链接,以下是详细信息:

  • 枚举所有名为devenv.exe的进程
  • 显示主窗口标题的列表。(我把“Microsoft Visual Studio”从末尾去掉)
  • 询问用户要使用哪一个
  • 使用process.Id在ROT中查找对象,我相信这是OP的问题。这是通过使用IEnumMoniker.Next()枚举ROT来完成的,该函数返回名字对象和进程id(对于VS)

  • 找到了绰号。将正在运行的对象投射到DTE,然后离开

COM、ROT和monike对我来说太复杂了,所以我很高兴看到上面的链接已经完成了繁重的工作

我让这个例子在几分钟内完成。我第一次使用调试器时它就工作了。但在全速运行时,我需要添加一些睡眠或重试,因为很容易从HRESULT中获取异常:0x8001010A(RPC_E_SERVERCALL_RETRYLATER))

另外,我用一个可以容忍其他版本VS的正则表达式替换了精确匹配:

Regex monikerRegex = new Regex(@"!VisualStudio.DTE\.\d+\.\d+\:" + processId, RegexOptions.IgnoreCase);

VS可能很忙、有打开的对话框或编译许多项目的问题在许多应用程序中都很常见,您可能会尝试强制输入按键或COM请求。如果出现错误,请重试几秒钟。最后,如果需要的话,弹出一个消息框。

Marshal.GetActiveObject(“VisualStudio.DTE.12.0”)适合我。将exception.ToString()结果添加到问题中。我在一个普通控制台应用程序中使用了上述代码。我是否应该使用Visual Studio中的任何可扩展项目模板。?我的水晶球显示VS正在提升运行,但您的控制台应用程序没有。仅供参考,如果有多个实例正在运行,您的代码将无法按预期工作。如果我们通过dte.solution.Open()加载解决方案并将另一个项目添加到解决方案中,是否正确?是,您可以创建DTE的新实例,卸载现有解决方案(如果有的话)(以防VS设置为加载上次使用的解决方案),加载所需的解决方案并添加项目。感谢
MainWindow.Visible
!!!这是我见过的唯一一篇使用它的帖子。我绝望地试图通过
suppressuui
做同样的事情。(我了解你的网站/博客,我真的认为你是VS可扩展性方面的全球专家。)