myCSharp.de - DIE C# und .NET Community
Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

» Hauptmenü
myCSharp.de
» Startseite
» Forum
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Suche
   » Plugin für Firefox
   » Plugin für IE7
   » Gadget für Vista
» Regeln
» Wie poste ich richtig?
» Datenschutzerklärung
» wbb-FAQ

Mitglieder
» Liste / Suche
» Stadt / Anleitung dazu
» Wer ist wo online?

Angebote
» ASP.NET Webspace
» Bücher
» Zeitschriften
   » dot.net magazin
» Accessoires

Ressourcen
» .NET-Glossar
» guide to C#
» openbook: Visual C#
» openbook: OO
» .NET BlogBook
» MSDN Webcasts
» dotnetjob.de
» Search.Net

Team
» Kontakt
» Übersicht
» Wir über uns
» Bankverbindung
» Impressum

» Unsere MiniCity
MiniCity
» myCSharp.de Diskussionsforum
Du befindest Dich hier: Community-Index » Diskussionsforum » Gemeinschaft » .NET-Komponenten und C#-Snippets » Laufende COM-Objekte abfragen
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | An Freund senden | Thema zu Favoriten hinzufügen

Antwort erstellen
Zum Ende der Seite springen  

Laufende COM-Objekte abfragen

 
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
Rainbird Rainbird ist männlich
myCSharp.de-Poweruser/ Experte

images/avatars/avatar-2834.jpg


Dabei seit: 28.05.2005
Beiträge: 3.716
Entwicklungsumgebung: Visual Studio 2010
Herkunft: Mauer


Rainbird ist offline MSN-Passport-Profil von Rainbird anzeigen

Laufende COM-Objekte abfragen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Beschreibung:

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.

C#-Code:
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);
            }
        }
    }
}

Schlagwörter: ROT,Running Object Table,Office,Excel,COM,COM-Interop,Access,Word,Visio,PowerPoint,Outlook,GetObject,COM-Server,OLE

Quelle: .NET-Snippets
03.05.2007 23:26 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 5 Jahre.
tecla
myCSharp.de-Mitglied

Dabei seit: 17.10.2007
Beiträge: 15
Entwicklungsumgebung: Visual Studio


tecla ist offline

Laufende COM-Objekte abfragen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo Rainbird,

Vielen Dank für deine Klasse RunningObjectTable!
habe soeben eine Excel-Datei mit deiner Funktion GetRunningCOMObjectByName als object zurückerhalten. Nun schaff ichs einfach nicht dieses Object in ein Excel.Application-Objekt zu verwandeln, damit ich ich dann die Datei auch schliessen oder anderes damit anstellen kann.

Herzliche Grüsse
Tecla
16.05.2012 15:05 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Zwischen diesen beiden Beiträgen liegen mehr als 2 Monate.
Sebastian.Lange Sebastian.Lange ist männlich
myCSharp.de-Poweruser/ Experte

Dabei seit: 22.06.2007
Beiträge: 915
Entwicklungsumgebung: Visual Studio 2008, 2010
Herkunft: Berlin


Sebastian.Lange ist offline MSN-Passport-Profil von Sebastian.Lange anzeigen

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Aufgrund einer Frage im Office Forum habe ich eine modifizierte Variante erstellt.
Diese arbeitet nicht nach Display-Name in der ROT sondern vielmehr nach ClassID bzw. Komponentenname und Klassenname(die ClassID setzt sich üblicherweise daraus zusammen) Damit ist eine ähnliche Verwendung wie Marshal.GetActiveObject und Co. möglich.

C#-Code:
public class RunningObjectTable
{
// Win32-API-call for reading ROT
        [DllImport("ole32.dll")]
        private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);

        // Win32-API-call to create binding
        [DllImport("ole32.dll")]
        private static extern int CreateBindCtx(uint reserved, out IBindCtx pctx);

        /// <summary>
        /// Gibt eine laufene Instanz aus der Running Object Table zurück
        /// </summary>
        /// <param name="componentName">Einfache Komponentenangabe z.B. "Excel" oder "Outlook"</param>
        /// <param name="className">Name der Klasse z.B. "Application" oder "Workbook"</param>
        /// <returns>Den ersten COM Proxy in der RunngingObject Table der den Eingangsparametern entspricht oder null</returns>
        private static object GetApplicationInstanceFromROT(string componentName, string className)
        {
            IEnumMoniker monikerList = null;
            IRunningObjectTable runningObjectTable = null;
            try
            {
                // query table and returns null if no objects runnings
                if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null)
                    return null;

                // query moniker & reset
                runningObjectTable.EnumRunning(out monikerList);
                monikerList.Reset();

                IMoniker[] monikerContainer = new IMoniker[1];
                IntPtr pointerFetchedMonikers = IntPtr.Zero;

                // fetch all moniker
                while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
                {
                    // create binding object
                    IBindCtx bindInfo;
                    CreateBindCtx(0, out bindInfo);

                    // query com proxy info      
                    object comInstance = null;
                    runningObjectTable.GetObject(monikerContainer[0], out comInstance);

                    string name = TypeDescriptor.GetClassName(comInstance);
                    string component = TypeDescriptor.GetComponentName(comInstance, false);

                    if ((component == componentName) && (name == className))
                    {
                        Marshal.ReleaseComObject(bindInfo);
                        return comInstance;
                    }
                    else if ((component == "Micrcosoft " + componentName) && (name == className))
                    {
                        // nur manche office anwendungen führen je nach version "Microsoft" im Komponentennamen
                        Marshal.ReleaseComObject(bindInfo);
                        return comInstance;
                    }
                    else
                        Marshal.ReleaseComObject(comInstance);

                    Marshal.ReleaseComObject(bindInfo);
                }

                // not running
                return null;
            }
            finally
            {
                // release proxies
                if (runningObjectTable != null)
                    Marshal.ReleaseComObject(runningObjectTable);
                if (monikerList != null)
                    Marshal.ReleaseComObject(monikerList);
            }
        }

        /// <summary>
        /// Gibt eine oder mehrere laufende Instanzen aus der Running Object Table zurück
        /// </summary>
        /// <param name="componentName">infache Komponentenangabe z.B. "Excel" oder "Outlook"</param>
        /// <param name="className">Name der Klasse z.B. "Application" oder "Workbook"</param>
        /// <returns>Alle COM Proxies in der RunngingObject Table die den Eingangsparametern entsprechen</returns>
        private static List<object> GetApplicationInstancesFromROT(string componentName, string className)
        {
            IEnumMoniker monikerList = null;
            IRunningObjectTable runningObjectTable = null;
            List<object> resultList = new List<object>();
            try
            {
                // query table and returns null if no objects runnings
                if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null)
                    return null;

                // query moniker & reset
                runningObjectTable.EnumRunning(out monikerList);
                monikerList.Reset();

                IMoniker[] monikerContainer = new IMoniker[1];
                IntPtr pointerFetchedMonikers = IntPtr.Zero;

                // fetch all moniker
                while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
                {
                    // create binding object
                    IBindCtx bindInfo;
                    CreateBindCtx(0, out bindInfo);

                    // query com proxy info      
                    object comInstance = null;
                    runningObjectTable.GetObject(monikerContainer[0], out comInstance);

                    string name = TypeDescriptor.GetClassName(comInstance);
                    string component = TypeDescriptor.GetComponentName(comInstance, false);

                    if ((component == componentName) && (name == className))
                    {
                        Marshal.ReleaseComObject(bindInfo);
                        resultList.Add(comInstance);
                    }
                    else if ((component == "Micrcosoft " + componentName) && (name == className))
                    {
                        // nur manche office anwendungen führen je nach version "Microsoft" im Komponentennamen
                        Marshal.ReleaseComObject(bindInfo);
                        resultList.Add(comInstance);
                    }
                    else
                        Marshal.ReleaseComObject(comInstance);

                    Marshal.ReleaseComObject(bindInfo);
                }

                // not running
                return resultList;
            }
            finally
            {
                // release proxies
                if (runningObjectTable != null)
                    Marshal.ReleaseComObject(runningObjectTable);
                if (monikerList != null)
                    Marshal.ReleaseComObject(monikerList);
            }
        }
}

Der Aufruf ist vergleichsweise simpel:

C#-Code:
foreach(object proxy in RunningObjectTable.GetApplicationInstancesFromROT("Excel", "Application"))
{
   Excel.Application app = proxy as Excel.Application; // Interop Beispiel

   Marshal.ReleaseComObject(proxy);
}

Dieser Beitrag wurde 4 mal editiert, zum letzten Mal von Sebastian.Lange am 18.07.2012 17:53.

18.07.2012 17:48 Beiträge des Benutzers | zu Buddylist hinzufügen
NeueWelt NeueWelt ist männlich
myCSharp.de-Mitglied

Dabei seit: 07.10.2011
Beiträge: 48
Entwicklungsumgebung: Visual Studio C#
Herkunft: Bayern


NeueWelt ist offline

Beitrag: beantworten | zitieren | editieren | melden/löschen       | Top

Hallo,

Vielen Dank an Rainbird und Sebastian, habt mir sehr geholfen.

gruß
19.07.2012 11:46 E-Mail | Beiträge des Benutzers | zu Buddylist hinzufügen
Baumstruktur | Brettstruktur       | Top 
myCSharp.de | Forum Der Startbeitrag ist älter als 6 Jahre.
Der letzte Beitrag ist älter als 10 Monate.
Antwort erstellen


© Copyright 2003-2013 myCSharp.de-Team. Alle Rechte vorbehalten. 24.05.2013 01:39