如何在C#中迭代Excel实例

3

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

我希望能够迭代所有实例,并能够选择要链接的实例。

请问有人能帮忙吗?

1个回答

5

试试这个。

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

编辑: 这篇文章完全实现了这个功能,链接在这里。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参数? - ManInMoon
你应该能够从列表中获取进程ID。然后执行Marshal.GetActiveObject(procID)。 - Jesse Seger
嗯...尝试获取进程的MainWindowHandle。Marshall.GetActiveObject(process.MainWindowHandle); - Jesse Seger
它期望一个字符串 - 所以我尝试了MainWindowHandle.ToString(),但是得到了相同的错误:"无效的类字符串 (来自 HRESULT: 0x800401F3 (CO_E_CLASSSTRING))"。 - ManInMoon
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/3997/discussion-between-jesse-seger-and-maninmoon - Jesse Seger
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接