c# – 找到所有打开的Excel工作簿
作者:互联网
我正在尝试获取所有当前打开的Excel工作簿的列表,以便用户可以选择从哪一个获取一些数据.
我试过这个:
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的第一个打开实例和最近打开的实例,因此在这两个之间打开的任何工作簿都不在列表中.
我也开始在this SO question的答案中探索blog link中描述的解决方案,并尝试使用博客条目中建议的代码访问运行对象表:
IBindCtx bc;
IRunningObjectTable rot;
CreateBindCtx(0, out bc);
bc.GetRunningObjectTable(out rot);
这里的问题是CreateBindCtx实际上接受UCOMIBindCTX而不是IBindCTX,但UCOMIBindCTX已经过时了MSDN.
有没有更简单的方法来做我正在尝试做的事情:获取与所有打开的Excel书籍相对应的工作簿对象列表?
解决方法:
好的,我找到了一种方法来做到这一点.描述解决方案的博客似乎不再可用,但有一个Google cached version.
我略微调整了代码,以便构造函数接受MainWindowHandle,因为我正在迭代所有进程的句柄.
课程如下.我已经留下了一些Andrew Whitechapel的评论来解释发生了什么,因为这段代码超出了我目前对Windows操作系统管理的了解:
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;
}
}
}
标签:c,excel,office-interop 来源: https://codeday.me/bug/20190629/1330081.html