找到所有打开的Excel工作簿 [英] find all open Excel workbooks

查看:110
本文介绍了找到所有打开的Excel工作簿的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试获取所有当前打开的Excel工作簿的列表,以便用户可以选择其中一个来获取一些数据。

I'm trying to get a list of all currently open Excel workbooks, so that the user can select which one of them to get some data from.

我尝试这样:

List<string> excelList = new List<string>();
Process[] processList = Process.GetProcessesByName("excel");
foreach (Process p in processList)
{
 excelList.Add(p.MainWindowTitle);
 Console.WriteLine(p.MainWindowTitle);
}

但是,只有第一个打开的Excel实例和最近打开的实例,所以在这两个之间打开的任何工作簿都不在列表中。

But that only gets the first open instance of Excel and the most recently opened instance, so any workbooks that were opened between those two aren't in the list.

我还开始探索在博客链接 stackoverflow.com/questions/393167/net-interop-find-all-instances-of-of-a-run-com-object-with-c-sharp\">这个SO问题,并尝试获取访问权限到运行对象表与博客条目中建议的代码:

I also started exploring the solution described in the blog link in the answer to this SO question, and tried to get access to the Running Object Table with the code suggested in the blog entry:

IBindCtx bc;
IRunningObjectTable rot;
CreateBindCtx(0, out bc);
bc.GetRunningObjectTable(out rot);

这里的问题是 CreateBindCtx 实际上接受 UCOMIBindCTX 而不是 IBindCTX ,但 UCOMIBindCTX a href =http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.ucomibindctx.aspx =nofollow noreferrer> MSDN 。

Problem here is that CreateBindCtx actually accepts a UCOMIBindCTX instead of IBindCTX, but UCOMIBindCTX is obsolete per MSDN.

有没有更简单的方法来做我想做的事情:获取与所有打开的Excel书对应的 Workbook 对象的列表?

Is there a simpler way to do what I'm trying to do: get a list of Workbook objects corresponding to all the open Excel books?

推荐答案

好的,我找到了一个办法。描述该解决方案的博客似乎不再可用,但是有一个 Google缓存版本

Ok, I found a way to do this. The blog that describes the solution appears to no longer be available, but there is a Google cached version.

我稍微调整了代码,以便构造函数接受MainWindowHandle,因为我正在遍历所有进程的句柄。

I slightly adapted the code so that the constructor accepts a MainWindowHandle, since I'm iterating through the handles for all processes.

该类如下。我已经离开了Andrew Whitechapel的一些评论来解释发生了什么,因为这段代码超出了我目前对Windows操作系统管理的认识:

The class is as follows. I've left some of Andrew Whitechapel's comments in to explain what's happening, since this code is beyond my present knowledge of Windows OS management:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Runtime.InteropServices;
using Excel = Microsoft.Office.Interop.Excel;

namespace DTEExcel
{
    class ExcelApplicationRetriever
    {
        [DllImport("Oleacc.dll")]
        public static extern int AccessibleObjectFromWindow(
              int hwnd, uint dwObjectID, byte[] riid,
              ref Microsoft.Office.Interop.Excel.Window ptr);

        [DllImport("User32.dll")]
        public static extern int GetClassName(
              int hWnd, StringBuilder lpClassName, int nMaxCount);

        [DllImport("User32.dll")]
        public static extern bool EnumChildWindows(
              int hWndParent, EnumChildCallback lpEnumFunc,
              ref int lParam);

        public delegate bool EnumChildCallback(int hwnd, ref int lParam);
        private EnumChildCallback cb;
        public Excel.Application xl;

        public ExcelApplicationRetriever(int winHandle)
        {
            // We need to enumerate the child windows to find one that
            // supports accessibility. To do this, instantiate the
            // delegate and wrap the callback method in it, then call
            // EnumChildWindows, passing the delegate as the 2nd arg.
            if (winHandle != 0)
            {
                int hwndChild = 0;
                cb = new EnumChildCallback(EnumChildProc);
                EnumChildWindows(winHandle, cb, ref hwndChild);

                // If we found an accessible child window, call
                // AccessibleObjectFromWindow, passing the constant
                // OBJID_NATIVEOM (defined in winuser.h) and
                // IID_IDispatch - we want an IDispatch pointer
                // into the native object model.
                if (hwndChild != 0)
                {
                    const uint OBJID_NATIVEOM = 0xFFFFFFF0;
                    Guid IID_IDispatch = new Guid(
                         "{00020400-0000-0000-C000-000000000046}");
                    Excel.Window ptr = null;

                    int hr = AccessibleObjectFromWindow(
                          hwndChild, OBJID_NATIVEOM,
                         IID_IDispatch.ToByteArray(), ref ptr);
                    if (hr >= 0)
                    {
                        // If we successfully got a native OM
                        // IDispatch pointer, we can QI this for
                        // an Excel Application (using the implicit
                        // cast operator supplied in the PIA).
                        xl = ptr.Application;
                    }
                }
            }
        }

        public 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;
        }

    }
}

这篇关于找到所有打开的Excel工作簿的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆