Feedback

C# - Laufende COM-Objekte abfragen

Veröffentlicht von am 5/3/2007
(2 Bewertungen)
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);
            }
        }
    }
}

Kommentare zum Snippet

 

Logge dich ein, um hier zu kommentieren!