![](/img/trans.png)
[英]Package Manager Console Automation using DTE in Visual Studio
[英]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 。
vsdebug!CDebugger::QueryInterface
返回HRESULT
0
CStdWrapper::GetPSFactory
未能找到這種類型的代理 DLL,這很快就會被 OLE 變成0x80040155
( REGDB_E_IIDNOTREG
)CRemoteUnknown::RemQueryInterface
轉換為0x80004002
( E_NOINTERFACE
)Marshal.QueryInterface
直接查看發生了什么,那么這就是返回給您的信息。 如果您的程序包含位於遠程 Visual Studio 進程中的進程內組件(就像我的一樣),您可以在 UI 線程上針對IVsDebugger
檢索和執行您的操作。 否則,您可能會創建一個新Thread
並在啟動它之前對其調用thread.SetApartmentState(ApartmentState.STA)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.