I'm trying to find the first visible instance of Word. I have found some helpful code here and modified it sligthly.
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Office.Interop.Word;
namespace TestConsole
{
internal class Program
{
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);
private static void Main(string[] args)
{
Application word1 = new Application();
word1.Visible = false;
Application word2 = new Application();
word2.Visible = true;
Application word3 = new Application();
word3.Visible = false;
int index = 0;
while (true)
{
Application application = Program.GetRunningCOMObjectOfType<Application>(++index);
if (application != null)
{
Console.WriteLine($"{index}) IsVisible: {application.Visible}");
Debug.WriteLine($"{index}) IsVisible: {application.Visible}");
}
else
{
break;
}
}
Console.WriteLine("############# End of program #############");
Console.ReadLine();
}
public static T GetRunningCOMObjectOfType<T>(int index)
{
IRunningObjectTable runningObjectTable = null;
IEnumMoniker monikerList = null;
try
{
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null)
{
return default(T);
}
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
int counter = 0;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
runningObjectTable.GetObject(monikerContainer[0], out object comInstance);
if (comInstance is T castedInstance)
{
if (index == ++counter)
{
return castedInstance;
}
}
}
}
finally
{
if (runningObjectTable != null)
{
Marshal.ReleaseComObject(runningObjectTable);
}
if (monikerList != null)
{
Marshal.ReleaseComObject(monikerList);
}
}
return default(T);
}
}
}
The result of this code looks like this:
1) IsVisible: False
2) IsVisible: False
3) IsVisible: False
I expect that for one instance Visible should return true. It seems that always the first instance is returned. If word1 is made visible true is returned for all instances.
After trying hard to get this working it turned out that this is not possible with that generic approach because some components register different instances with identical keys on the Running Object Table (ROT).
IRunningObjectTable.GetObjectreturns the first registered instance in this case. E.g. Word do it that way with the instances of itsApplicationClass.Solution:
There seams to be no clean and generic solution but something that worked for me. Word also registers the instances of the
Documentin the ROT. So we can easily get this documents and from there we get the application.This code produces the following result:
OK, this is a little fishy. A nasty problem with this approach is that instances that do not have a document can not be found.