You can get VS instances from the IRunningObjectTable
This test works for me with VS2022 on Windows 10 21H1 =>
// Add reference to : "C:\Program Files (x86)\Common Files\microsoft shared\MSEnv\PublicAssemblies\envdte.dll"
using EnvDTE;
Main loop :
System.Runtime.InteropServices.ComTypes.IRunningObjectTable prot = null;
HRESULT hr = GetRunningObjectTable(0, out prot);
if (hr == HRESULT.S_OK)
{
System.Runtime.InteropServices.ComTypes.IBindCtx pbc = null;
hr = CreateBindCtx(0, out pbc);
System.Runtime.InteropServices.ComTypes.IEnumMoniker penumMk = null;
prot.EnumRunning(out penumMk);
System.Runtime.InteropServices.ComTypes.IMoniker[] pmk = new System.Runtime.InteropServices.ComTypes.IMoniker[1];
IntPtr celt = IntPtr.Zero;
while (penumMk.Next(1, pmk, celt) == (int)HRESULT.S_OK)
{
string sDisplayName;
pmk[0].GetDisplayName(pbc, null, out sDisplayName);
if (sDisplayName.StartsWith("!VisualStudio"))
{
Console.WriteLine("Name : {0}", sDisplayName);
object pUnk = null;
hr = (HRESULT)prot.GetObject(pmk[0], out pUnk);
if (hr == HRESULT.S_OK)
{
_DTE pDTE = (_DTE)pUnk;
var mw = pDTE.MainWindow;
string sCaption = mw.Caption;
Console.WriteLine("Caption : {0}", sCaption);
}
}
}
}
Declarations :
public enum HRESULT : int
{
S_OK = 0,
S_FALSE = 1,
E_NOINTERFACE = unchecked((int)0x80004002),
E_NOTIMPL = unchecked((int)0x80004001),
E_FAIL = unchecked((int)0x80004005)
}
[DllImport("Ole32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern HRESULT GetRunningObjectTable(uint reserved, out System.Runtime.InteropServices.ComTypes.IRunningObjectTable pprot);
[DllImport("Ole32.dll", SetLastError = true, CharSet = CharSet.Auto)]
public static extern HRESULT CreateBindCtx(uint reserved, out System.Runtime.InteropServices.ComTypes.IBindCtx ppbc);