使用标准打开方法,您将无法控制将使用哪个正在运行的实例。在后台它使用 DDE,它是 undetermined 哪个实例将处理 DDE 请求。
使用Activator.GetObject 时也是如此。
幸运的是,在 ole32.dll 中,我们可以调用 GetRunningObjectTable 并从那里枚举所有实例以查找所有已注册的 OLE 服务器,对于每个实例,包括所有 Visual Studio 进程。
一旦我们找到了一个实例,您就可以获得其 OLE 自动化接口 EnvDTE 的实例,并使用它来深入检查这是否是与之交互的正确实例,如果是,则执行我们感兴趣的任何命令例如加载一个文件。
private void OpenFileExecute(string file)
{
IRunningObjectTable ir;
// get all OLE/COM Automation servers
GetRunningObjectTable(0, out ir);
if (ir != null)
{
IEnumMoniker moniker;
// Get an enumerator to iterate over them
ir.EnumRunning(out moniker);
if (moniker != null)
{
moniker.Reset();
IMoniker[] results = new IMoniker[1];
// iterate
while (moniker.Next(1, results, IntPtr.Zero) == 0)
{
// we need a Bind Context
IBindCtx bindCtx;
CreateBindCtx(0, out bindCtx);
// what is the name of the OLE/COM Server
string objName;
results[0].GetDisplayName(bindCtx, null, out objName);
// what have we got ...
Trace.WriteLine(objName);
// I test with VS2010 instances,
// but feel free to get rid of the .10
if (objName.StartsWith("!VisualStudio.DTE.10"))
{
object dteObj; //
ir.GetObject(results[0], out dteObj);
// now we have an OLE automation interface
// to the correct instance
DTE dteTry = (DTE)dteObj;
// determine if this is indeed
// the one you need
// my naive approach is to check if
// there is a Document loaded
if (dteTry.Documents.Count == 1)
{
dteTry.ExecuteCommand(
"File.OpenFile",
String.Format("\"{0}\"", file));
}
}
bindCtx.ReleaseBoundObjects();
}
}
}
}
[DllImport("ole32.dll")]
public static extern int GetRunningObjectTable(int reserved,
out IRunningObjectTable prot);
[DllImport("ole32.dll")]
public static extern int CreateBindCtx(int reserved,
out IBindCtx ppbc);
背景阅读:How to use Marshal.getActiveObject() to get 2 instance of of a running process that has two processes open