我正在尝试获取所有当前打开的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实例和最近打开的实例,因此在这两个实例之间打开的所有工作簿均不在列表中。
我还开始探索blog link的答案中this SO question中描述的解决方案,并尝试使用博客条目中建议的代码访问“运行对象表”:
IBindCtx bc;
IRunningObjectTable rot;
CreateBindCtx(0, out bc);
bc.GetRunningObjectTable(out rot);
这里的问题是
CreateBindCtx
实际上接受UCOMIBindCTX
而不是IBindCTX
,但是UCOMIBindCTX
对于MSDN已过时。有没有一种更简单的方法可以执行我想做的事情:获取与所有打开的Excel图书相对应的
Workbook
对象列表? 最佳答案
好的,我找到了一种方法。描述该解决方案的博客似乎不再可用,但是有一个Google cached version。
我略微修改了代码,以便构造函数接受MainWindowHandle,因为我正在遍历所有进程的句柄。
该类如下。我留下了Andrew Whitechapel的一些评论来解释发生了什么,因为这段代码超出了我目前对Windows OS管理的了解:
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工作簿,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/13807102/