|
| » myCSharp.de Diskussionsforum |
|
|
|
|
Autor
 |
|
Rainbird
myCSharp.de-Poweruser/ Experte
Dabei seit: 28.05.2005
Beiträge: 3.716
Entwicklungsumgebung: Visual Studio 2010 Herkunft: Mauer
|
|
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
{
public class RunningObjectTable
{
private RunningObjectTable() { }
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx pctx);
public static object GetRunningCOMObjectByName(string objectDisplayName)
{
IRunningObjectTable runningObjectTable = null;
IEnumMoniker monikerList = null;
try
{
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null) return null;
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
IBindCtx bindInfo;
string displayName;
CreateBindCtx(0, out bindInfo);
monikerContainer[0].GetDisplayName(bindInfo, null, out displayName);
Marshal.ReleaseComObject(bindInfo);
if (displayName.IndexOf(objectDisplayName) != -1)
{
object comInstance;
runningObjectTable.GetObject(monikerContainer[0], out comInstance);
return comInstance;
}
}
}
catch
{
return null;
}
finally
{
if (runningObjectTable != null) Marshal.ReleaseComObject(runningObjectTable);
if (monikerList != null) Marshal.ReleaseComObject(monikerList);
}
return null;
}
public static IList<string> GetRunningCOMObjectNames()
{
IList<string> result = new List<string>();
IRunningObjectTable runningObjectTable = null;
IEnumMoniker monikerList = null;
try
{
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null) return null;
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
IBindCtx bindInfo;
string displayName;
CreateBindCtx(0, out bindInfo);
monikerContainer[0].GetDisplayName(bindInfo, null, out displayName);
Marshal.ReleaseComObject(bindInfo);
result.Add(displayName);
}
return result;
}
catch
{
return null;
}
finally
{
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
|
|
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
myCSharp.de-Poweruser/ Experte
Dabei seit: 22.06.2007
Beiträge: 915
Entwicklungsumgebung: Visual Studio 2008, 2010 Herkunft: Berlin
|
|
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
{
[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(uint reserved, out IRunningObjectTable pprot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(uint reserved, out IBindCtx pctx);
private static object GetApplicationInstanceFromROT(string componentName, string className)
{
IEnumMoniker monikerList = null;
IRunningObjectTable runningObjectTable = null;
try
{
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null)
return null;
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
IBindCtx bindInfo;
CreateBindCtx(0, out bindInfo);
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))
{
Marshal.ReleaseComObject(bindInfo);
return comInstance;
}
else
Marshal.ReleaseComObject(comInstance);
Marshal.ReleaseComObject(bindInfo);
}
return null;
}
finally
{
if (runningObjectTable != null)
Marshal.ReleaseComObject(runningObjectTable);
if (monikerList != null)
Marshal.ReleaseComObject(monikerList);
}
}
private static List<object> GetApplicationInstancesFromROT(string componentName, string className)
{
IEnumMoniker monikerList = null;
IRunningObjectTable runningObjectTable = null;
List<object> resultList = new List<object>();
try
{
if (GetRunningObjectTable(0, out runningObjectTable) != 0 || runningObjectTable == null)
return null;
runningObjectTable.EnumRunning(out monikerList);
monikerList.Reset();
IMoniker[] monikerContainer = new IMoniker[1];
IntPtr pointerFetchedMonikers = IntPtr.Zero;
while (monikerList.Next(1, monikerContainer, pointerFetchedMonikers) == 0)
{
IBindCtx bindInfo;
CreateBindCtx(0, out bindInfo);
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))
{
Marshal.ReleaseComObject(bindInfo);
resultList.Add(comInstance);
}
else
Marshal.ReleaseComObject(comInstance);
Marshal.ReleaseComObject(bindInfo);
}
return resultList;
}
finally
{
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;
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
|
|
|
|