簡體   English   中英

如何從外部 DTE 檢索 IVsDebugger 以在 Visual Studio 2019 中實現自動化

[英]How to retrieve IVsDebugger from external DTE for automation in Visual Studio 2019

我正在嘗試為 Visual Studio 2019 編寫一個 VSIX,用於控制 Visual Studio IDE 的多個實例。 我們正在開展一個網絡項目,該項目需要一些自動化來執行多個用戶的測試。 過去我會在外部工具中使用 DTE,但我的理解是,從 VS2017 開始,COM guid 不再全局注冊,因此在 IDE 中進行這是唯一的方法。

無論如何,我正在嘗試獲取 IVsDebugger,以便我可以在調試器中跟蹤事件。 但是,我沒有運氣。 我可以得到 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;
}

讓我困惑的是我通過調用獲得了本地 IVsDebugger

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

我看到的是使用 GlobalService。 我認為我檢索的 DTE 中沒有等效項。

任何見解?

我也遇到了這個問題(但是在我的情況下,我實際上是在嘗試檢索proc 中IVsDebugger而不是聽起來像是out of proc ); 在調試到vsdebug!CDebugger::QueryInterface如何工作后,我確定實際問題似乎是您的應用程序的調用線程需要是 STA

  • 當應用程序中的調用線程是 MTA 時,而vsdebug!CDebugger::QueryInterface返回HRESULT 0
  • 由於CStdWrapper::GetPSFactory未能找到這種類型的代理 DLL,這很快就會被 OLE 變成0x80040155 ( REGDB_E_IIDNOTREG )
  • 這個錯誤反過來被CRemoteUnknown::RemQueryInterface轉換為0x80004002 ( E_NOINTERFACE )
  • 如果您嘗試使用 C# 中的Marshal.QueryInterface直接查看發生了什么,那么這就是返回給您的信息。

如果您的程序包含位於遠程 Visual Studio 進程中的進程內組件(就像我的一樣),您可以在 UI 線程上針對IVsDebugger檢索和執行您的操作。 否則,您可能會創建一個新Thread並在啟動它之前對其調用thread.SetApartmentState(ApartmentState.STA)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM