使用 C# 自动化 Visual Studio .NET 的特定实例






4.91/5 (20投票s)
2004 年 8 月 15 日
2分钟阅读

83682

2216
获取正在运行的 Visual Studio 实例列表,以及对自动化服务器的引用。
引言
本文向您展示如何获取当前正在运行的 Visual Studio IDE 实例的列表。对于每个实例,您可以获取对 DTE 对象的引用 - Visual Studio 自动化对象模型中的顶级对象。一旦您获得了对该对象的引用,您就可以查询有关解决方案、解决方案中的项目、启动构建等信息。
MsdevManager 是一个非常简单的测试应用程序,它使用了所提供的功能:它显示正在运行的实例,并允许您双击以将选定的 IDE 调到前台。它通过从 DTE 对象中获取 IDE 的 MainWindow 的 HWnd
,并使用它将 IDE 调到前台来实现这一点。虽然显然还有其他方法可以实现此特定功能,但重点是使用 DTE 对象演示它。有关更详细的自动化示例,您可以查看 MSDN 文档,但本文应该可以帮助您开始使用对对象模型的引用。
运行对象表
许多应用程序,例如 Visual Studio 和 Microsoft Office,在启动时在运行对象表 (ROT) 中注册一个 COM 自动化服务器。 MsdevManager 等自动化客户端然后可以获取指向此对象的指针以操作服务器。 Visual Studio .NET 2003 将自身注册到 ROT 中,注册为 "!VisualStudio.DTE.7.1:pid",其中 "pid" 将被相应的 devenv.exe 进程的进程 ID 替换。 Visual Studio .NET 2002 将自身注册为 "!VisualStudio.DTE.7:pid"。
DTE 对象
DTE 代表“开发工具扩展性”,是对象的 coclass。它实现了接口 "_DTE
"。您可以在 Visual Studio 文档的“DTE 对象”下以及文档“引用 DTE 对象”中找到有关 DTE 对象的更多信息。 O'Reilly 著作“精通 Visual Studio .NET”也有一章包含一些有用的信息。
使用代码
文件 MsdevManager.cs 包含一个名为 Msdev
的类,该类定义了几个相关的方法。我们需要做的第一件事是能够访问系统的运行对象表。为此,我们需要访问 ole32.dll 中的几个函数
public class Msdev
{
[DllImport("ole32.dll")]
public static extern int GetRunningObjectTable(int reserved,
out UCOMIRunningObjectTable prot);
[DllImport("ole32.dll")]
public static extern int CreateBindCtx(int reserved,
out UCOMIBindCtx ppbc);
现在我们可以访问这两个函数了,让我们编写一个方法来枚举 ROT 中的对象,从而获得其内容的快照
/// <summary>
/// Get a snapshot of the running object table (ROT).
/// </summary>
/// <returns>A hashtable mapping the name of the object
// in the ROT to the corresponding object</returns>
public static Hashtable GetRunningObjectTable()
{
Hashtable result = new Hashtable();
int numFetched;
UCOMIRunningObjectTable runningObjectTable;
UCOMIEnumMoniker monikerEnumerator;
UCOMIMoniker[] monikers = new UCOMIMoniker[1];
GetRunningObjectTable(0, out runningObjectTable);
runningObjectTable.EnumRunning(out monikerEnumerator);
monikerEnumerator.Reset();
while (monikerEnumerator.Next(1, monikers, out numFetched) == 0)
{
UCOMIBindCtx ctx;
CreateBindCtx(0, out ctx);
string runningObjectName;
monikers[0].GetDisplayName(ctx, null, out runningObjectName);
object runningObjectVal;
runningObjectTable.GetObject( monikers[0], out runningObjectVal);
result[ runningObjectName ] = runningObjectVal;
}
return result;
}
从这里,很容易编写另一个方法,该方法只为我们提供 Visual Studio IDE 实例的列表。我们还将包含一个参数,允许我们指定我们只想包含具有打开的解决方案的 IDE 实例
/// <summary> /// Get a table of the currently running instances of the Visual Studio .NET IDE. /// </summary> /// <param name="openSolutionsOnly">Only return instances /// that have opened a solution</param> /// <returns>A hashtable mapping the name of the IDE /// in the running object table to the corresponding /// DTE object</returns> public static Hashtable GetIDEInstances( bool openSolutionsOnly ) { Hashtable runningIDEInstances = new Hashtable(); Hashtable runningObjects = GetRunningObjectTable(); IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator(); while ( rotEnumerator.MoveNext() ) { string candidateName = (string) rotEnumerator.Key; if (!candidateName.StartsWith("!VisualStudio.DTE")) continue; _DTE ide = rotEnumerator.Value as _DTE; if (ide == null) continue; if (openSolutionsOnly) { try { string solutionFile = ide.Solution.FullName; if (solutionFile != String.Empty) { runningIDEInstances[ candidateName ] = ide; } } catch {} } else { runningIDEInstances[ candidateName ] = ide; } } return runningIDEInstances; }
最后,一旦我们获得了对要自动化的 IDE 的 DTE 的引用,我们就可以做一些有用的事情
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
private const int SW_RESTORE = 9;
[DllImport("user32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd,int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
/// <summary>
/// Raises an instance of the Visual Studio IDE to the foreground.
/// </summary>
/// <param name="ide">The DTE object for the IDE you
/// would like to raise to the foreground</param>
public static void ShowIDE( EnvDTE.DTE ide )
{
// To show an existing IDE, we get the HWND for the MainWindow
// and do a little interop to bring the desired IDE to the
// foreground. I tried some of the following other potentially
// promising approaches but could only succeed in getting the
// IDE's taskbar button to flash (this is as designed). Ex:
//
// ide.MainWindow.Activate();
// ide.MainWindow.SetFocus();
// ide.MainWindow.Visible = true;
// ide.MainWindow.WindowState = EnvDTE.vsWindowState.vsWindowStateMinimize;
// ide.MainWindow.WindowState = EnvDTE.vsWindowState.vsWindowStateMaximize;
System.IntPtr hWnd = (System.IntPtr) ide.MainWindow.HWnd;
if (IsIconic(hWnd))
{
ShowWindowAsync(hWnd,SW_RESTORE);
}
SetForegroundWindow(hWnd);
ide.MainWindow.Visible = true;
}
历史
- 04 年 8 月 14 日 - 初始版本。