如何在Visual Studio 2019中从外部DTE检索IVsDebugger以进行自动化



我正在尝试为Visual Studio 2019编写一个VSIX,用于控制Visual Studio IDE的多个实例。我们正在开发一个网络项目,该项目需要一些自动化来执行多个用户的测试。过去,我会在外部工具中使用 DTE,但我的理解是,从 VS2017 开始,COM GUID 不再全局注册,因此在 IDE 中执行此操作是唯一的方法。

无论如何,我正在尝试获取 IVs调试器,以便我可以跟踪调试器中的事件。但是,我没有运气。我可以得到IVsDebugger2,3,4,5,但不能得到IVSDebugger。以下是我正在做的事情的一般流程:

void CaptureDebugger()
{
DTE dte = GetDTE(GetRemoteProcessID());
ServiceProvider sp = new     ServiceProvider((Microsoft.VisualStudio.OLE.Interop.IServiceProvider)dte);
IVsDebugger vsDebugger = sp.GetService(typeof(SVsShellDebugger)) as IVsDebugger;
// vsDebugger is null!
IVsDebugger2 vsDebugger2 = sp.GetService(typeof(SVsShellDebugger)) as IVsDebugger2;
// vsDebugger2 is not null!

}
/// <summary>
/// Gets the DTE object from any devenv process.
/// </summary>
private static EnvDTE.DTE GetDTE(int processId)
{
object runningObject = null;
IBindCtx bindCtx = null;
IRunningObjectTable rot = null;
IEnumMoniker enumMonikers = null;
try
{
Marshal.ThrowExceptionForHR(CreateBindCtx(reserved: 0, ppbc: out bindCtx));
bindCtx.GetRunningObjectTable(out rot);
rot.EnumRunning(out enumMonikers);
IMoniker[] moniker = new IMoniker[1];
IntPtr numberFetched = IntPtr.Zero;
while (enumMonikers.Next(1, moniker, numberFetched) == 0)
{
IMoniker runningObjectMoniker = moniker[0];
string name = null;
try
{
if (runningObjectMoniker != null)
{
runningObjectMoniker.GetDisplayName(bindCtx, null, out name);
}
}
catch (UnauthorizedAccessException)
{
// Do nothing, there is something in the ROT that we do not have access to.
}
Regex monikerRegex = new Regex(@"!VisualStudio.DTE.d+.d+:" + processId, RegexOptions.IgnoreCase);
if (!string.IsNullOrEmpty(name) && monikerRegex.IsMatch(name))
{
Marshal.ThrowExceptionForHR(rot.GetObject(runningObjectMoniker, out runningObject));
}
}
}
finally
{
if (enumMonikers != null)
Marshal.ReleaseComObject(enumMonikers);
if (rot != null)
Marshal.ReleaseComObject(rot);
if (bindCtx != null)
Marshal.ReleaseComObject(bindCtx);
}
return runningObject as EnvDTE.DTE;
}

让我感到困惑的是我通过调用获取本地IVs调试器

var MYDEBUGGER = Package.GetGlobalService(typeof(SVsShellDebugger)) as IVsDebugger;

我看到的是使用全球服务。我认为我检索的 DTE 中没有等效项。

有什么见解吗?

我也遇到了这个问题(但是就我而言,我实际上是在尝试在proc中检索IVsDebugger,而不是听起来像proc之外的内容); 在调试vsdebug!CDebugger::QueryInterface的工作方式后,我确定实际问题似乎是应用程序中的调用线程需要是 STA。

  • 当应用程序中的调用线程是 MTA 时,而vsdebug!CDebugger::QueryInterface返回时HRESULT0
  • 这很快就会被 OLE 变成0x80040155(REGDB_E_IIDNOTREGCStdWrapper::GetPSFactory因为找不到这种类型的代理 DLL
  • 此错误依次被CRemoteUnknown::RemQueryInterface转换为0x80004002(E_NOINTERFACE)
  • 如果您尝试在 C# 中Marshal.QueryInterface直接查看正在发生的事情,则会向您报告的内容。

如果您的程序包含位于远程 Visual Studio 进程中的进程内组件(就像我一样),则可以针对 UI 线程上的IVsDebugger检索和执行操作。否则,您可能会创建一个新Thread并在启动之前调用thread.SetApartmentState(ApartmentState.STA)

最新更新