【问题标题】:How to iterate through instance of Excel c#如何遍历Excel c#的实例
【发布时间】:2011-10-04 21:12:14
【问题描述】:

我可以使用 Marshal.GetActiveObject 访问内存中的 Excel 实例。但这总是返回最旧的现有实例。

我想遍历所有实例并能够选择要链接到的实例。

谁能帮忙解决这个问题。

【问题讨论】:

    标签: c# interop marshalling


    【解决方案1】:

    试试这个。

            List<Process> procs = new List<Process>();
            procs.AddRange(Process.GetProcessesByName("excel"));
    

    编辑: 在http://blogs.officezealot.com/whitechapel/archive/2005/04/10/4514.aspx 有一篇文章完全实现了这一点。 GetActiveObject 将始终返回表中的第一个对象。这是因为 Office 不注册新对象。您必须从子窗口中获取应用程序。

    编辑: 这是对我有用的代码。

    using Excel = Microsoft.Office.Interop.Excel;
    using System.Runtime.InteropServices;
    
    namespace ConsoleApplication1
    {        
    
    class Program
    {
        [DllImport("Oleacc.dll")]
        public static extern int AccessibleObjectFromWindow(
              int hwnd, uint dwObjectID, byte[] riid,
              ref Microsoft.Office.Interop.Excel.Window ptr);
    
        public delegate bool EnumChildCallback(int hwnd, ref int lParam);
    
        [DllImport("User32.dll")]
        public static extern bool EnumChildWindows(
              int hWndParent, EnumChildCallback lpEnumFunc,
              ref int lParam);
    
    
        [DllImport("User32.dll")]
        public static extern int GetClassName(
              int hWnd, StringBuilder lpClassName, int nMaxCount);
    
        public static bool EnumChildProc(int hwndChild, ref int lParam)
        {
            StringBuilder buf = new StringBuilder(128);
            GetClassName(hwndChild, buf, 128);
            if (buf.ToString() == "EXCEL7")
            {
                lParam = hwndChild;
                return false;
            }
            return true;
        }
    
        static void Main(string[] args)
        {
            Excel.Application app = new Excel.Application();
            EnumChildCallback cb;
            List<Process> procs = new List<Process>();
            procs.AddRange(Process.GetProcessesByName("excel"));
    
            foreach (Process p in procs)
            {
                if ((int)p.MainWindowHandle > 0)
                {
                    int childWindow = 0;
                    cb = new EnumChildCallback(EnumChildProc);
                    EnumChildWindows((int)p.MainWindowHandle, cb, ref childWindow);
    
                    if (childWindow > 0)
                    {
                        const uint OBJID_NATIVEOM = 0xFFFFFFF0;
                        Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}");
                        Excel.Window window = null;
                        int res = AccessibleObjectFromWindow(childWindow, OBJID_NATIVEOM, IID_IDispatch.ToByteArray(), ref window);
                        if (res >= 0)
                        {
                            app = window.Application;
                            Console.WriteLine(app.Name);
                        }
                    }
                }
            }
    
        }
    }
    

    【讨论】:

    • 杰西:是的,就是这样。
    • 杰西:是的,就是这样。但是我应该给 Marshal.GetActiveObject() 的 procs 什么参数?
    • 您应该能够从列表中获取进程 ID。然后执行 Marshal.GetActiveObject(procID).
    • 我试过了——不喜欢。我也将 ProcID 转换为字符串 - 也不喜欢。
    • 嗯...尝试获取进程的 MainWindowHandle。 Marshall.GetActiveObject(process.MainWindowHandle);
    猜你喜欢
    • 2010-12-19
    • 2018-08-17
    • 1970-01-01
    • 2014-04-03
    • 2012-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-28
    相关资源
    最近更新 更多