在Visual C#2010中获取DTE2对象的引用
我想在VisualStudio2010中使用带有C#的DTE2对象来获取对当前解决方案的引用 我首先尝试了以下代码:在Visual C#2010中获取DTE2对象的引用,c#,visual-studio-2010,add-in,envdte,C#,Visual Studio 2010,Add In,Envdte,我想在VisualStudio2010中使用带有C#的DTE2对象来获取对当前解决方案的引用 我首先尝试了以下代码: var dte = Marshal.GetActiveObject("VisualStudio.DTE.10.0") as EnvDTE80.DTE2; 但是当我打开两个解决方案时,这段代码在第一个解决方案中,我得到的不是对当前解决方案的引用,而是对我加载的最后一个解决方案的引用。我需要当前的解决方案 在internet上搜索时,我在中找到了以下解决方案: 但是当我使用它时,我
var dte = Marshal.GetActiveObject("VisualStudio.DTE.10.0") as EnvDTE80.DTE2;
但是当我打开两个解决方案时,这段代码在第一个解决方案中,我得到的不是对当前解决方案的引用,而是对我加载的最后一个解决方案的引用。我需要当前的解决方案
在internet上搜索时,我在中找到了以下解决方案:
但是当我使用它时,我的dte对象总是空的
那么,我如何使用.net framework 4.0上的C#访问VS2010中当前的解决方案对象呢?经过广泛的搜索和尝试,我最终使用添加到MSDN页面的注释得到了答案: 我在我的c#项目中添加了一个静态类: 在我想要访问当前IDE的时候:
var dte = CurrentIde.GetCurrent();
var sol = dte.Solution;
但请记住。。。。此代码在调试期间不起作用!!!以字符串Roentry开头的代码行。。。调用Process.GetCurrentProcess以获取当前进程的ID
在调试我的加载项中的某些功能时(使用MME),我调用了一个需要当前IDE的方法。我用一个调用addin方法的ConsoleApp来测试这一点。在获取当前IDE时,currentprocess不是IDE,而是ConsoleApp.vshost.exe。因此,我的代码在调试过程中不起作用,但在构建加载项并安装此加载项后确实起作用。我觉得以下几点令人不安,因此我解决了这些问题并找到了适合我的解决方案:
仅适用于第一个打开的(我想)VisualStudioGetActiveObject(“VisualStudio.DTE.10.0”)
- Dennis答案中的
方法需要Visual Studio进程Id。如果您从加载项(我认为)运行代码,但在单元测试中不起作用,则可以使用该Id内部静态DTE2 GetCurrent()
- 调试模式中的问题
System.Runtime.InteropServices.comeException:被调用方拒绝了调用。(来自HRESULT的异常:0x80010001(RPC调用被拒绝))
。不过,有一种补救办法叫做。为了完整起见,我在底部包含了代码
包含测试方法(用法示例)、调整后的GetCurrent
方法和用于字符串比较的助手方法的测试类:
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using EnvDTE80;
using EnvDTE;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
[TestClass]
public class ProjectSettingsTest
{
/// <summary>
/// Tests that the platform for Mixed Platforms and Any CPU configurations
/// is Any CPU for all projects of this solution
/// </summary>
[TestMethod]
public void TestReleaseBuildIsAnyCPU()
{
MessageFilter.Register();
DTE2 dte2 = GetCurrent();
Assert.IsNotNull(dte2);
foreach (SolutionConfiguration2 config in dte2.Solution.SolutionBuild.SolutionConfigurations)
{
if (config.PlatformName.Contains("Mixed Platforms") || config.PlatformName.Contains("Any CPU"))
{
foreach (SolutionContext context in config.SolutionContexts)
Assert.AreEqual("Any CPU", context.PlatformName, string.Format("{0} is configured {1} in {2}/{3}", context.ProjectName, context.PlatformName, config.PlatformName, config.Name));
}
}
MessageFilter.Revoke();
}
[DllImport("ole32.dll")]
private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
/// <summary>
/// Gets the current visual studio's solution DTE2
/// </summary>
public static DTE2 GetCurrent()
{
List<DTE2> dte2s = new List<DTE2>();
IRunningObjectTable rot;
GetRunningObjectTable(0, out rot);
IEnumMoniker enumMoniker;
rot.EnumRunning(out enumMoniker);
enumMoniker.Reset();
IntPtr fetched = IntPtr.Zero;
IMoniker[] moniker = new IMoniker[1];
while (enumMoniker.Next(1, moniker, fetched) == 0)
{
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
string displayName;
moniker[0].GetDisplayName(bindCtx, null, out displayName);
// add all VisualStudio ROT entries to list
if (displayName.StartsWith("!VisualStudio"))
{
object comObject;
rot.GetObject(moniker[0], out comObject);
dte2s.Add((DTE2)comObject);
}
}
// get path of the executing assembly (assembly that holds this code) - you may need to adapt that to your setup
string thisPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
// compare dte solution paths to find best match
KeyValuePair<DTE2, int> maxMatch = new KeyValuePair<DTE2, int>(null, 0);
foreach (DTE2 dte2 in dte2s)
{
int matching = GetMatchingCharsFromStart(thisPath, dte2.Solution.FullName);
if (matching > maxMatch.Value)
maxMatch = new KeyValuePair<DTE2, int>(dte2, matching);
}
return (DTE2)maxMatch.Key;
}
/// <summary>
/// Gets index of first non-equal char for two strings
/// Not case sensitive.
/// </summary>
private static int GetMatchingCharsFromStart(string a, string b)
{
a = (a ?? string.Empty).ToLower();
b = (b ?? string.Empty).ToLower();
int matching = 0;
for (int i = 0; i < Math.Min(a.Length, b.Length); i++)
{
if (!char.Equals(a[i], b[i]))
break;
matching++;
}
return matching;
}
}
使用系统;
使用System.Collections.Generic;
使用Microsoft.VisualStudio.TestTools.UnitTesting;
使用EnvDTE80;
使用EnvDTE;
使用System.Runtime.InteropServices;
使用System.Runtime.InteropServices.ComTypes;
[测试类]
公共类项目设置测试
{
///
///测试该平台是否支持混合平台和任何CPU配置
///此解决方案的所有项目是否都有CPU
///
[测试方法]
public void TestReleaseBuildIsAnyCPU()
{
MessageFilter.Register();
DTE2 DTE2=GetCurrent();
Assert.IsNotNull(dte2);
foreach(dte2.Solution.SolutionBuild.SolutionConfigurations中的SolutionConfiguration2配置)
{
if(config.PlatformName.Contains(“混合平台”)| | config.PlatformName.Contains(“任何CPU”))
{
foreach(config.SolutionContext中的SolutionContext上下文)
Assert.AreEqual(“任何CPU”,context.PlatformName,string.Format(“{0}在{2}/{3}中配置了{1}”,context.ProjectName,context.PlatformName,config.PlatformName,config.Name));
}
}
MessageFilter.Revoke();
}
[DllImport(“ole32.dll”)]
私有静态外部void CreateBindCtx(int保留,out IBindCtx ppbc);
[DllImport(“ole32.dll”)]
私有静态外部void GetRunningObjectTable(保留int,输出IRunningObjectTable prot);
///
///获取当前visual studio的解决方案DTE2
///
公共静态DTE2 GetCurrent()
{
列表dte2s=新列表();
IRunningObjectTable rot;
GetRunningObjectTable(0,out rot);
IEnumMoniker enumMoniker;
rot.EnumRunning(超出enumMoniker);
enumMoniker.Reset();
IntPtr fetched=IntPtr.Zero;
IMoniker[]名字=新IMoniker[1];
while(EnumMonike.Next(1,名字对象,获取)==0)
{
IBindCtx-bindCtx;
CreateBindCtx(0,out bindCtx);
字符串显示名;
名字对象[0]。GetDisplayName(bindCtx,null,out displayName);
//将所有VisualStudio ROT条目添加到列表中
if(displayName.StartsWith(“!VisualStudio”))
{
对象与对象;
rot.GetObject(名字对象[0],out-comObject);
添加((DTE2)comObject);
}
}
//获取执行程序集(保存此代码的程序集)的路径-您可能需要根据您的设置调整该路径
字符串thisPath=System.Reflection.Assembly.GetExecutionGassembly().Location;
//比较dte解决方案路径以找到最佳匹配
KeyValuePair maxMatch=新的KeyValuePair(null,0);
foreach(DTE2中的DTE2)
{
int matching=GetMatchingCharsFromStart(此路径为dte2.Solution.FullName);
如果(匹配>最大匹配值)
maxMatch=新的KeyValuePair(dte2,匹配);
}
返回(DTE2)maxMatch.Key;
}
///
///获取两个字符串的第一个不相等字符的索引
///N
var dte = CurrentIde.GetCurrent();
var sol = dte.Solution;
using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using EnvDTE80;
using EnvDTE;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
[TestClass]
public class ProjectSettingsTest
{
/// <summary>
/// Tests that the platform for Mixed Platforms and Any CPU configurations
/// is Any CPU for all projects of this solution
/// </summary>
[TestMethod]
public void TestReleaseBuildIsAnyCPU()
{
MessageFilter.Register();
DTE2 dte2 = GetCurrent();
Assert.IsNotNull(dte2);
foreach (SolutionConfiguration2 config in dte2.Solution.SolutionBuild.SolutionConfigurations)
{
if (config.PlatformName.Contains("Mixed Platforms") || config.PlatformName.Contains("Any CPU"))
{
foreach (SolutionContext context in config.SolutionContexts)
Assert.AreEqual("Any CPU", context.PlatformName, string.Format("{0} is configured {1} in {2}/{3}", context.ProjectName, context.PlatformName, config.PlatformName, config.Name));
}
}
MessageFilter.Revoke();
}
[DllImport("ole32.dll")]
private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
/// <summary>
/// Gets the current visual studio's solution DTE2
/// </summary>
public static DTE2 GetCurrent()
{
List<DTE2> dte2s = new List<DTE2>();
IRunningObjectTable rot;
GetRunningObjectTable(0, out rot);
IEnumMoniker enumMoniker;
rot.EnumRunning(out enumMoniker);
enumMoniker.Reset();
IntPtr fetched = IntPtr.Zero;
IMoniker[] moniker = new IMoniker[1];
while (enumMoniker.Next(1, moniker, fetched) == 0)
{
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
string displayName;
moniker[0].GetDisplayName(bindCtx, null, out displayName);
// add all VisualStudio ROT entries to list
if (displayName.StartsWith("!VisualStudio"))
{
object comObject;
rot.GetObject(moniker[0], out comObject);
dte2s.Add((DTE2)comObject);
}
}
// get path of the executing assembly (assembly that holds this code) - you may need to adapt that to your setup
string thisPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
// compare dte solution paths to find best match
KeyValuePair<DTE2, int> maxMatch = new KeyValuePair<DTE2, int>(null, 0);
foreach (DTE2 dte2 in dte2s)
{
int matching = GetMatchingCharsFromStart(thisPath, dte2.Solution.FullName);
if (matching > maxMatch.Value)
maxMatch = new KeyValuePair<DTE2, int>(dte2, matching);
}
return (DTE2)maxMatch.Key;
}
/// <summary>
/// Gets index of first non-equal char for two strings
/// Not case sensitive.
/// </summary>
private static int GetMatchingCharsFromStart(string a, string b)
{
a = (a ?? string.Empty).ToLower();
b = (b ?? string.Empty).ToLower();
int matching = 0;
for (int i = 0; i < Math.Min(a.Length, b.Length); i++)
{
if (!char.Equals(a[i], b[i]))
break;
matching++;
}
return matching;
}
}
/// <summary>
/// Class containing the IOleMessageFilter
/// thread error-handling functions.
/// </summary>
public class MessageFilter : IOleMessageFilter
{
// Start the filter.
public static void Register()
{
IOleMessageFilter newFilter = new MessageFilter();
IOleMessageFilter oldFilter = null;
CoRegisterMessageFilter(newFilter, out oldFilter);
}
// Done with the filter, close it.
public static void Revoke()
{
IOleMessageFilter oldFilter = null;
CoRegisterMessageFilter(null, out oldFilter);
}
//
// IOleMessageFilter functions.
// Handle incoming thread requests.
int IOleMessageFilter.HandleInComingCall(int dwCallType, System.IntPtr hTaskCaller, int dwTickCount, System.IntPtr lpInterfaceInfo)
{
return 0; //Return the flag SERVERCALL_ISHANDLED.
}
// Thread call was rejected, so try again.
int IOleMessageFilter.RetryRejectedCall(System.IntPtr hTaskCallee, int dwTickCount, int dwRejectType)
{
if (dwRejectType == 2)
// flag = SERVERCALL_RETRYLATER.
{
return 99; // Retry the thread call immediately if return >=0 & <100.
}
return -1; // Too busy; cancel call.
}
int IOleMessageFilter.MessagePending(System.IntPtr hTaskCallee, int dwTickCount, int dwPendingType)
{
//Return the flag PENDINGMSG_WAITDEFPROCESS.
return 2;
}
// Implement the IOleMessageFilter interface.
[DllImport("Ole32.dll")]
private static extern int CoRegisterMessageFilter(IOleMessageFilter newFilter, out IOleMessageFilter oldFilter);
}
[ComImport(), Guid("00000016-0000-0000-C000-000000000046"),
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIUnknown)]
interface IOleMessageFilter
{
[PreserveSig]
int HandleInComingCall(int dwCallType, IntPtr hTaskCaller, int dwTickCount, IntPtr lpInterfaceInfo);
[PreserveSig]
int RetryRejectedCall(IntPtr hTaskCallee, int dwTickCount, int dwRejectType);
[PreserveSig]
int MessagePending(IntPtr hTaskCallee, int dwTickCount, int dwPendingType);
}
string processID = Process.GetCurrentProcess().Id.ToString();
if (displayName.StartsWith("!VisualStudio.DTE.", StringComparison.OrdinalIgnoreCase) &&
displayName.EndsWith(processID))
open System;
open System.Runtime.InteropServices;
open System.Runtime.InteropServices.ComTypes;
open EnvDTE;
open System.Diagnostics;
//http://stackoverflow.com/questions/10864595/getting-the-current-envdte-or-iserviceprovider-when-not-coding-an-addin
//http://stackoverflow.com/questions/6558789/how-to-convert-out-ref-extern-parameters-to-f
//http://stackoverflow.com/questions/1689460/f-syntax-for-p-invoke-signature-using-marshalas
[<System.Runtime.InteropServices.DllImport("ole32.dll")>]
extern int CreateBindCtx(System.IntPtr inRef, IBindCtx& outParentRef);
[<System.Runtime.InteropServices.DllImport("ole32.dll")>]
extern int GetRunningObjectTable(System.IntPtr inRef, IRunningObjectTable& outParentRef);
//let dte = System.Runtime.InteropServices.Marshal.GetActiveObject("VisualStudio.DTE.12.0") :?> EnvDTE80.DTE2
let comName="VisualStudio.DTE.12.0"
let rotEntry = "!"+comName
//let mutable rot:IRunningObjectTable =null
let rot=
let mutable result:IRunningObjectTable = null
GetRunningObjectTable(nativeint 0, &result) |> ignore
result
let mutable enumMoniker:IEnumMoniker = null
rot.EnumRunning (&enumMoniker)
enumMoniker.Reset() |> ignore
let mutable fetched = IntPtr.Zero
let mutable moniker:IMoniker[] = Array.zeroCreate 1 //http://msdn.microsoft.com/en-us/library/dd233214.aspx
let matches = seq {
while enumMoniker.Next(1, moniker, fetched) = 0 do
"looping" |> Dump
let mutable bindCtx:IBindCtx = null
CreateBindCtx(nativeint 0, &bindCtx) |> ignore
let mutable displayName:string = null
moniker.[0].GetDisplayName(bindCtx,null, &displayName)
displayName |> Dump
if displayName.StartsWith(rotEntry) then
let mutable comObject = null
rot.GetObject(moniker.[0], &comObject) |> ignore
let dte = comObject:?>EnvDTE80.DTE2
yield displayName,bindCtx,comObject,dte.FullName, dte
}
matches |> Dump
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using EnvDTE80;
namespace Fortrus.Metadata
{
/// <summary>
/// This class takes care of fetching the correct DTE instance for the current process
/// The current implementation works it way down from Visual Studio version 20 to 10 so
/// it should be farely version independent
/// </summary>
public static class Processes
{
[DllImport("ole32.dll")]
private static extern void CreateBindCtx(int reserved, out IBindCtx ppbc);
[DllImport("ole32.dll")]
private static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
private const int m_MaxVersion = 20;
private const int m_MinVersion = 10;
internal static DTE2 GetDTE()
{
DTE2 dte = null;
for (int version = m_MaxVersion; version >= m_MinVersion; version--)
{
string versionString = string.Format("VisualStudio.DTE.{0}.0", version);
dte = Processes.GetCurrent(versionString);
if (dte != null)
{
return dte;
}
}
throw new Exception(string.Format("Can not get DTE object tried versions {0} through {1}", m_MaxVersion, m_MinVersion));
}
/// <summary>
/// When multiple instances of Visual Studio are running there also multiple DTE available
/// The method below takes care of selecting the right DTE for the current process
/// </summary>
/// <remarks>
/// Found this at: http://stackoverflow.com/questions/4724381/get-the-reference-of-the-dte2-object-in-visual-c-sharp-2010/27057854#27057854
/// </remarks>
private static DTE2 GetCurrent(string versionString)
{
//rot entry for visual studio running under current process.
string rotEntry = String.Format("!{0}:{1}", versionString, Process.GetCurrentProcess().Id);
IRunningObjectTable rot;
GetRunningObjectTable(0, out rot);
IEnumMoniker enumMoniker;
rot.EnumRunning(out enumMoniker);
enumMoniker.Reset();
IntPtr fetched = IntPtr.Zero;
IMoniker[] moniker = new IMoniker[1];
while (enumMoniker.Next(1, moniker, fetched) == 0)
{
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
string displayName;
moniker[0].GetDisplayName(bindCtx, null, out displayName);
if (displayName == rotEntry)
{
object comObject;
rot.GetObject(moniker[0], out comObject);
return (EnvDTE80.DTE2)comObject;
}
}
return null;
}
}
}