C# 在C中运行对象表访问其他Excel实例的应用程序对象#

C# 在C中运行对象表访问其他Excel实例的应用程序对象#,c#,.net,excel,C#,.net,Excel,我一直在尝试访问在Visual C#Express 2010中ROT中注册的所有Excel 2010实例的COM对象。我在上找到了一个代码,我对其进行了一些修改,以便返回在运行对象表中注册的所有可能的Excel.Application对象。守则如下: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.InteropServices.C

我一直在尝试访问在Visual C#Express 2010中ROT中注册的所有Excel 2010实例的COM对象。我在上找到了一个代码,我对其进行了一些修改,以便返回在运行对象表中注册的所有可能的
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;
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用系统文本;
使用System.Runtime.InteropServices.ComTypes;
使用System.Runtime.InteropServices;
使用Excel=Microsoft.Office.Interop.Excel;
名称空间批准
{
[ComVisible(true)]
类COMApp
{
[DllImport(“Ole32.dll”)]
公共静态外部int CreateBindCtx(
尤因保留,
out IBindCtx ppbc);
[DllImport(“Ole32.dll”)]
公共静态外部int GetRunningObjectTable(
保留整数,
out IrunningObject表保护);
[状态线程]
公共静态列表GetRunningInstances()
{
字符串[]progIds=新字符串[]{“Excel.Application”};
List clsIds=新列表();
//获取应用程序clsid
foreach(progIds中的字符串progId)
{
Type Type=Type.GetTypeFromProgID(progId);
if(type!=null)
添加(type.GUID.ToString().ToUpper());
}
//获取正在运行的对象表。。。
IRunningObjectTable Rot=null;
GetRunningObjectTable(0,out Rot);
if(Rot==null)
返回null;
//获取ROT项的枚举数
IEnumMoniker名字枚举器=null;
Rot.EnumRunning(超出监视器枚举器);
if(monikerEnumerator==null)
返回null;
monikerEnumerator.Reset();
列表实例=新列表();
IntPtr pNumFetched=新的IntPtr();
IMoniker[]名字=新IMoniker[1];
//检查所有条目并识别应用程序实例
while(monikerEnumerator.Next(1,名字对象,pNumFetched)==0)
{
对象与对象;
Rot.GetObject(名字对象[0],out-ComObject);
if(ComObject==null)
继续;
尝试
{
添加((Excel.Application)ComObject);
}
捕获{}
}
返回实例;
}
}
}
但这只返回Excel第一个实例的
Excel.Application
对象。 我还尝试使用文件名和(德语站点)中提到的代码访问对象,即使用
GetRunningCOMObjectByName(string objectDisplayname)
,但在使用该文件名获取COM对象后,当我尝试将其转换为
Excel.Application
,我得到以下错误:-

无法将“System.\u ComObject”类型的COM对象强制转换为接口类型“Microsoft.Office.Interop.Excel.Application”。此操作失败,因为对IID为“{000208D5-0000-0000-C000-0000000000 46}”的接口的COM组件的QueryInterface调用由于以下错误而失败:Cette接口不收费(HRESULT的例外:0x80004002(E_NOINTERFACE))

我曾尝试检查有故障的DLL,检查注册表中的CLSID是否因
HKEY_CLASSES_ROOT
下的
TypeLib
中存在不同的“版本”而发生冲突,尝试修复Ms Office 2010,卸载Office(2003)的旧版本等以避免此错误。但什么都不管用。我也尝试过使用
Microsoft.VisualBasic
引用,然后使用
Interaction.GetObject
,但这也会产生同样的错误

有什么想法吗

我还尝试了上面提到的后期绑定方法。
但这也让我们可以访问ROT中的第一个Excel实例。

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

您有GetRunningCOMObjectByName(string objectDisplayname)来获取com对象,并尝试转换为Excel.Application,但它不是那种类型。我已经尝试过了,如果您按全名获取对象,则得到的对象是Excel.Workbook的类型,因此可以将其转换为Workbook。它适合我

因此,您可以从ROT中看到,您在Excel中打开的每个文档都有一个与之相关的全名。您通过名称获得的comObj类型为工作簿

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

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

  • ROT中仍然有我上面提到的两项,这意味着ROT中只有一个应用程序(您可以打开两个excel工作簿来检查它,workbook1和workbook2)
  • 但工作簿运行良好,您可以打开所有工作簿(workbook1和workbook2)
  • workbook1.Application引用等于ROT中的应用程序,但workbook2.Application不等于
    那么,如果ROT中只有一个应用程序,并且等于workbook1.Applicaton,那么workbook2.Application在哪里?为什么workbook2.Application未在ROT表中注册?

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


    Excel是一个单实例应用程序。如果你重新开始,它只会问第一个问题
    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;
                }
            }
    
        }
    }
    
    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);   
                }
            }
        }
    }