Viele bekannte Anwendungen (z.B. Excel, Word, Access, Outlook oder Visual Studio) bieten Automatisierungsmöglichkeiten über COM-Schnittstellen. Manchmal möchte man eine bereits geöffnete Instanz einer solchen Anwendung fernsteuern. Wenn nun z.B. aber gleich mehrere Excel-Sheets gleichzeitig geöffnet sind? Wie findet man die richtige Instanz?
Das geht über die "Running Object Table". Dort werden laufende Objekte registiert, die als COM-Server fungieren. Jedes laufende Objekt bekommt einen Namen. Oft ist es der Dateiname des Dokuments oder eine GUID (Das hängt von der Anwendung ab).
Das folgende Snippet gibt alle laufenden COM-Objekte aus der Running Object Table zurück und kann direkt auf die einzelnen Objekte über ihren Namen zugreifen.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
namespace Rainbird.Tools.COMInterop
{
/// <summary>
/// Ermöglicht .NET-Anwendungen direkten Zugriff auf die Running Object Table (Tabelle mit allen momentan laufenden COM-Objekte)
/// </summary>
public class RunningObjectTable
{
/// <summary>
/// Privater Standardkonstruktor.
/// </summary>
private RunningObjectTable() { }
// Win32-API-Aufruf zum lesen der ROT
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);
// Win32-API-Aufruf zum erstellen von Bindungen
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx pctx);
/// <summary>
/// Gibt einen Verweis auf eine laufendes COM-Objekt anhand ihres Anzeigenamens zurück.
/// </summary>
/// <param name="objectDisplayName">Anzeigename einer COM-Instanz</param>
/// <returns>Verweis auf COM-Objekt, oder null, wenn kein COM-Objekt mit dem angegbenen Namen läuft</returns>
public static object GetRunningCOMObjectByName(string objectDisplayName)
{
// ROT-Schnittstelle
IRunningObjectTable runningObjectTable = null;
// Moniker-Auflistung
IEnumMoniker monikerList = null;
try
{
// Running Object Table abfragen und nichts zurückgeben, wenn keine COM-Objekte laufen
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null) return null;
// Moniker abfragen
runningObjectTable.EnumRunning(out monikerList);
// An den Anfang der Auflistung springen
monikerList.Reset();
// Array für Moniker-Abfrage erzeugen
IMoniker[] monikerContainer = new IMoniker[1];
// Zeiger auf die Anzahl der tatsächlich abgefragten Moniker erzeugen
IntPtr pointerFetchedMonikers = IntPtr.Zero;
// Alle Moniker durchlaufen
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
// Objekt für Bindungsinformationen
IBindCtx bindInfo;
// Variable für den Anzeigenamen des aktuellen COM-Objekts
string displayName;
// Bindungsobjekt erzeugen
CreateBindCtx(0, out bindInfo);
// Anzeigename des COM-Objekts über den Moniker abfragen
monikerContainer[0].GetDisplayName(bindInfo, null, out displayName);
// Bindungsobjekt entsorgen
Marshal.ReleaseComObject(bindInfo);
// Wenn der Anzeigename mit dem gesuchten übereinstimmt ...
if (displayName.IndexOf(objectDisplayName) != -1)
{
// Variable für COM-Objekt
object comInstance;
// COM-Objekt über den Anzeigenamen abrfragen
runningObjectTable.GetObject(monikerContainer[0], out comInstance);
// COM-Objekt zurückgeben
return comInstance;
}
}
}
catch
{
// Nichts zurückgeben
return null;
}
finally
{
// Ggf. COM-Verweise entsorgen
if (runningObjectTable != null) Marshal.ReleaseComObject(runningObjectTable);
if (monikerList != null) Marshal.ReleaseComObject(monikerList);
}
// Nichts zurückgeben
return null;
}
/// <summary>
/// Gibt eine Liste mit Anzeigenamen aller momentan laufenden COM-Objekte zurück.
/// </summary>
/// <returns>Liste mit Anzeigenamen</returns>
public static IList<string> GetRunningCOMObjectNames()
{
// Auflistung der Anzeigenamen erzeugen
IList<string> result = new List<string>();
// Informationsobjekt der laufenden COM-Instanzen
IRunningObjectTable runningObjectTable = null;
// Moniker-Auflistung
IEnumMoniker monikerList = null;
try
{
// Running Object Table abfragen und nichts zurückgeben, wenn keine COM-Objekte laufen
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null) return null;
// Moniker abfragen
runningObjectTable.EnumRunning(out monikerList);
// An den Anfang der Auflistung springen
monikerList.Reset();
// Array für Moniker-Abfrage erzeugen
IMoniker[] monikerContainer = new IMoniker[1];
// Zeiger auf die Anzahl der tatsächlich abgefragten Moniker erzeugen
IntPtr pointerFetchedMonikers = IntPtr.Zero;
// Alle Moniker durchlaufen
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
// Objekt für Bindungsinformationen
IBindCtx bindInfo;
// Variable für den Anzeigenamen des aktuellen COM-Objekts
string displayName;
// Bindungsobjekt erzeugen
CreateBindCtx(0, out bindInfo);
// Anzeigename des COM-Objekts über den Moniker abfragen
monikerContainer[0].GetDisplayName(bindInfo, null, out displayName);
// Bindungsobjekt entsorgen
Marshal.ReleaseComObject(bindInfo);
// Anzeigenamen der Auflistung zufügen
result.Add(displayName);
}
// Auflistung zurückgeben
return result;
}
catch
{
// Nichts zurückgeben
return null;
}
finally
{
// Ggf. COM-Verweise entsorgen
if (runningObjectTable != null) Marshal.ReleaseComObject(runningObjectTable);
if (monikerList != null) Marshal.ReleaseComObject(monikerList);
}
}
}
}
Abgelegt unter
ROT,
Running Object Table,
Office,
Excel,
COM,
COM-Interop,
Access,
Word,
Visio,
PowerPoint,
Outlook,
GetObject,
COM-Server,
OLE.
Kommentare zum Snippet