Attaching to an existing Visual Studio instance

The following code snippets demonstrate how to attach to an existing (already running) instance of Visual Studio. The snippets have been written in C#.

The sample consists of three different methods that depend on each other. Of course, you may change this accordingly so that it better fits your application environment.The following table explains each method in more detail.

Method

Description

getRunningObjectTable()

Queries the Running Object Table (ROT) for a snapshot of all running processes in the table. Returns all found processes in a Hashtable, which are then used by getIdeInstances() for further filtering for DTE instances.

getIdeInstances()

Searches for DTE instances in the ROT snapshot and returns a Hashtable with all found instances. This Hashtable may then be used by the method attachToExistingDte() to select single DTE instances.
You may change the query for candidateName according to a more specific Visual Studio progId , e.g. "VisualStudio.DTE.11.0" to query for Visual Studio 2012 instances.

attachToExistingDte()

Uses the getIdeInstances() method to select a DTE instance based on its solution path and, when found, attaches a new DTE object to this instance.

getRunningObjectTable()

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;
}

Please note that you need to explicitely reference the CreateBindCtx() method as a DllImport from the ole32.dll, e.g.:

[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc);

getIdeInstances()

public static Hashtable GetIDEInstances(bool openSolutionsOnly, string progId)
{
  Hashtable runningIDEInstances = new Hashtable();
  Hashtable runningObjects = GetRunningObjectTable();
  IDictionaryEnumerator rotEnumerator = runningObjects.GetEnumerator();
  while (rotEnumerator.MoveNext())
  {
    string candidateName = (string)rotEnumerator.Key;
    if (!candidateName.StartsWith("!" + progId))
      continue;
    EnvDTE.DTE ide = rotEnumerator.Value as EnvDTE.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;
}

attachToExistingDte()

public EnvDTE.DTE attachToExistingDte(string solutionPath) 
{
EnvDTE.DTE dte = null;
Hashtable dteInstances = GetIDEInstances(false, progId);
IDictionaryEnumerator hashtableEnumerator = dteInstances.GetEnumerator();

while (hashtableEnumerator.MoveNext())
{
EnvDTE.DTE dteTemp = hashtableEnumerator.Value as EnvDTE.DTE;
if (dteTemp.Solution.FullName == solutionPath)
{
Console.WriteLine("Found solution in list of all open DTE objects. " + dteTemp.Name); dte = dteTemp;
}
}
return dte;
}