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

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

问题描述

我试图让所有当前打开的Excel工作簿的列表,以便用户可以选择其中之一,从得到一些数据。



我尝试这样:

 列表<串GT; excelList =新的List<串GT;(); 
过程[] = PROCESSLIST Process.GetProcessesByName(创先争优);
的foreach(在PROCESSLIST进程p)
{
excelList.Add(p.MainWindowTitle);
Console.WriteLine(p.MainWindowTitle);
}



不过,只有得到Excel的第一个打开的实例和最近打开的情况下,所以这两个之间被打开,任何工作簿是不在列表中



我也开始探索在的博客链接在回答的的http://计算器.COM /问题/ 393167 /的净互操作 - 查找 - 所有实例的一运行-COM-对象与-C-尖>这太问题,并试图以访问与代码的运行对象表在博客中建议:

  IBindCtx BC; 
IRunningObjectTable腐烂;
CreateBindCtx(0,出BC);
bc.GetRunningObjectTable(出腐烂);



这里的问题是, CreateBindCtx 实际上接受 UCOMIBindCTX 而不是 IBindCTX ,但 UCOMIBindCTX 每<过时A HREF =http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.ucomibindctx.aspx相对=nofollow> MSDN 。



有没有更简单的方式做我想要做的事:让工作簿对应于所有打开的Excel的书籍对象的列表<? / p>

解决方案

好吧,我发现了一个办法做到这一点。描述的解决方案的博客似乎不再是可用的,但有一个谷歌缓存版本



我稍微适应代码,以便在构造函数接受一个MainWindowHandle,因为我遍历通过手柄的所有进程。



类如下: 。我留下了一些安德鲁白教堂的评论中解释发生的事情,因为这个代码是超出了我目前的Windows操作系统管理方面的知识:



 使用系统; 
使用System.Collections.Generic;
使用System.Linq的;
使用System.Text;使用System.Threading.Tasks
;使用System.Runtime.InteropServices
;使用Excel =的Microsoft.Office.Interop.Excel
;

命名空间DTEExcel
{
类ExcelApplicationRetriever
{
函数[DllImport(Oleacc.dll)]
公共静态外部INT AccessibleObjectFromWindow(
INT HWND,UINT dwObjectID,字节[] RIID,
参考Microsoft.Office.Interop.Excel.Window PTR);

函数[DllImport(User32.dll中)]
公共静态外部INT GetClassName(
INT的hWnd,StringBuilder的lpClassName,诠释nMaxCount);

函数[DllImport(User32.dll中)]
公共静态的extern BOOL EnumChildWindows(
INT hWndParent,EnumChildCallback lpEnumFunc,
REF INT lParam的);

公共委托布尔EnumChildCallback(HWND INT,楼盘INT lParam的);
私人EnumChildCallback CB;
公共Excel.Application XL;

公共ExcelApplicationRetriever(INT窗口句柄)
{
//我们需要枚举子窗口,找到一个
//支持易用性。要做到这一点,实例化
//委托,并在其包装回调方法,然后调用
// EnumChildWindows,传递委托作为第二ARG。
如果(!窗口句柄= 0)
{
INT hwndChild = 0;
CB =新EnumChildCallback(EnumChildProc);
EnumChildWindows(窗口句柄,CB,楼盘hwndChild);

//如果我们发现一个可访问的子窗口,调用
// AccessibleObjectFromWindow,传递常量
// OBJID_NATIVEOM(WINUSER.H中的定义)和
/ / IID_IDispatch - 我们希望有一个IDispatch指针
//到原有的对象模型。
如果(hwndChild!= 0)
{
常量UINT OBJID_NATIVEOM = 0xFFFFFFF0;
的Guid = IID_IDispatch新的GUID(
{00020400-0000-0000-C000-000000000046});
Excel.Window PTR = NULL;

INT HR = AccessibleObjectFromWindow(
hwndChild,OBJID_NATIVEOM,
IID_IDispatch.ToByteArray(),REF PTR);
如果(HR> = 0)
{
//如果我们成功地得到了一个原生OM
// IDispatch指针,我们可以补气此为
// Excel应用程序(使用PIA提供的隐含
//转换运算符)。
XL = ptr.Application;
}
}
}
}

公共BOOL EnumChildProc(INT hwndChild,楼盘INT lParam的)
{
StringBuilder的BUF =新的StringBuilder(128);
GetClassName(hwndChild,BUF,128);
如果(buf.ToString()==EXCEL7)
{
lParam的= hwndChild;
返回FALSE;
}
返回真;
}

}
}


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.

I tried this:

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

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.

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);

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

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?

解决方案

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.

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

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天全站免登陆