在C#中运行对象表中访问其他Excel实例的Excel.Application对象

我一直在尝试访问在Visual C#Express 2010 ROT中注册的Excel 2010的所有实例的COM对象。我在http://adndevblog.typepad.com/autocad/2013/12/accessing-com-运行object-table.html的应用程序 ,我稍微修改了一下,以便返回Running Object Table中注册的所有可能的Excel.Application对象。 代码 :-

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices.ComTypes; using System.Runtime.InteropServices; using Excel = Microsoft.Office.Interop.Excel; namespace APPROT { [ComVisible(true)] class COMApp { [DllImport("Ole32.dll")] public static extern int CreateBindCtx( uint reserved, out IBindCtx ppbc); [DllImport("Ole32.dll")] public static extern int GetRunningObjectTable( int reserved, out IRunningObjectTable prot); [STAThread] public static List<Excel.Application> GetRunningInstances() { string[] progIds = new string[] { "Excel.Application"}; List<string> clsIds = new List<string>(); // get the app clsid foreach (string progId in progIds) { Type type = Type.GetTypeFromProgID(progId); if (type != null) clsIds.Add(type.GUID.ToString().ToUpper()); } // get Running Object Table ... IRunningObjectTable Rot = null; GetRunningObjectTable(0, out Rot); if (Rot == null) return null; // get enumerator for ROT entries IEnumMoniker monikerEnumerator = null; Rot.EnumRunning(out monikerEnumerator); if (monikerEnumerator == null) return null; monikerEnumerator.Reset(); List<Excel.Application> instances = new List<Excel.Application>(); IntPtr pNumFetched = new IntPtr(); IMoniker[] monikers = new IMoniker[1]; // go through all entries and identifies app instances while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0) { object ComObject; Rot.GetObject(monikers[0], out ComObject); if (ComObject == null) continue; try { instances.Add((Excel.Application)ComObject); } catch {} } return instances; } } } 

但是这只返回Excel的第一个实例的Excel.Application对象。 我也试着用http://dotnet-snippets.de/snippet/laufende-com-objekte-abfragen/526 (德语网站)上提到的代码,即使用GetRunningCOMObjectByName(string objectDisplayname)来访问对象,但是获取COM对象后,当我尝试将其转换为Excel.Application ,我得到以下错误: –

无法将“System .__ ComObject”types的COM对象转换为接口types“Microsoft.Office.Interop.Excel.Application”。 此操作失败,因为IID为“{000208D5-0000-0000-C000-000000000046}”的接口的COM组件上的QueryInterface调用失败,原因是出现以下错误:Cette接口不受支持(exception来自HRESULT: 0x80004002(E_NOINTERFACE))。

我已经尝试检查有问题的DLL,检查registry,如果CLSID由于在HKEY_CLASSES_ROOT下的TypeLib存在不同的“版本”冲突,试图修复MS Office 2010,卸载旧版本的Office(2003)等以解决此问题错误。 但没有任何工作。 我也尝试使用Microsoft.VisualBasic引用,然后使用Interaction.GetObject ,但是这也给出了相同的错误。

有任何想法吗?

我也尝试了https://stackoverflow.com/a/779710/2960814上提到的后期绑定方法。 但是这也可以访问ROT中的第一个Excel实例。

我认为我们面临同样的问题。 我正在使用windows7和office2010,使用与您所提到的相同的方式来获取ROT表来处理所有打开的excel。

你有GetRunningCOMObjectByName(stringobjectDisplayname)来获取COM对象,并尝试转换为Excel.Application,但它不是那种types。 我试过了,如果你通过fullName得到对象,你得到的对象是Excel.Workbook的types ,所以它可以转换成Workbook 。它对我很有用。

因此,您可以从ROT中看到,在Excel中打开的每个文档都有一个与其相关的完整名称。而您通过名称获得的comObj是“ 工作簿”types。

但是我仍然有一些关于ROT的问题。 如果我们查看ROT表,它有两个名称分别为:{00024505-0014-0000-C000-000000000046}和!{00024500-0000-0000-C000-000000000046}的项目,与Excel.Application相似的classId。 如果您获得这两个项目的comObj,则可以转换为Excel.Application 。 就像Marshal.GetActiveObject(“Excel.Application”)一样。 和2项是参考相等

但是当有多个EXCEL.EXE进程运行时,我想我可以在ROT中获得更多的应用程序项目,但事实是

  1. 在ROT里面还有两个项目,这意味着在ROT里只有一个应用程序(你可以打开2个Excel工作簿来查看它,工作簿1和工作簿2)
  2. 但是Workbook运行良好,您可以打开alll Workbook(workbook1和workbook2)。
  3. 应用程序引用等于ROT中的应用程序,但不包含workbook2.Application。

因此,如果在ROT中只有一个应用程序,并且等于workbook1.Applicaton,那么workbook2.Application在哪里? 为什么workbook2.Application未在ROT表中注册?

请尝试以下C#4.0+的代码片段:

 using System; using System.Collections.Generic; using System.Runtime.InteropServices; using System.Runtime.InteropServices.ComTypes; namespace ROT.TestConsole { /// <summary> /// Gets MS Excel running workbook instances via ROT /// </summary> public class MSExcelWorkbookRunningInstances { [DllImport("ole32.dll")] static extern int CreateBindCtx(uint reserved, out IBindCtx ppbc); [DllImport("ole32.dll")] public static extern void GetRunningObjectTable(int reserved, out IRunningObjectTable prot); public static IEnumerable<dynamic> Enum() { // get Running Object Table ... IRunningObjectTable Rot; GetRunningObjectTable(0, out Rot); // get enumerator for ROT entries IEnumMoniker monikerEnumerator = null; Rot.EnumRunning(out monikerEnumerator); IntPtr pNumFetched = new IntPtr(); IMoniker[] monikers = new IMoniker[1]; IBindCtx bindCtx; CreateBindCtx(0, out bindCtx); while (monikerEnumerator.Next(1, monikers, pNumFetched) == 0) { string applicationName = ""; dynamic workBook = null; try { Guid IUnknown = new Guid("{00000000-0000-0000-C000-000000000046}"); monikers[0].BindToObject(bindCtx, null, ref IUnknown, out workBook); applicationName = workBook.Application.Name; } catch { } if (applicationName == "Microsoft Excel") yield return workBook; } } } } 

testing它:

 using System; namespace ROT.TestConsole { class Program { static void Main(string[] args) { try { int index = 1; foreach (dynamic worbook in MSExcelWorkbookRunningInstances.Enum()) System.Console.WriteLine("{0}. '{1}' '{2}'", index++, worbook.Application.Name, worbook.FullName); } catch (Exception ex) { System.Console.WriteLine("Error = '{0}'", ex.Message); } } } }