即使VBA由Excel实例打开,也附加到现有的Excel实例

这是关于这个问题的select答案:
如何遍历Excel的实例c#

此代码非常适合于获取Excel的所有实例,除非这些实例中的一个已打开VBA编辑器。 当它试图findEXCEL7的类时代码会中断。 这是工作簿子窗口的类。 在debugging时,我确定在枚举子窗口时,EXCEL7子窗口不能被定位。 像VbaWindow类而不是显示。 我甚至试图得到这个窗口句柄的Excel.Window这个VBA窗口类,但它失败了。 我怎么能仍然得到的方法AccessibleObjectFromWindow引用Excel.Window,然后我可以用来引用应用程序。 这里是我修改的方法(我已经有Excel进程ID …所有其他声明被省略为了可读性):

 internal static Excel.Application GetExcelInstance(int procID) { EnumChildCallback cb; Process p = Process.GetProcessById(procID); if (p != null) { 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; // GUIDs used by the OLE Automation Protocol: // https://msdn.microsoft.com/en-us/library/cc237842.aspx 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) { return window.Application; } } } } return null; } // If VBA is open this method will fail when enumerating // all child windows of the excel process // EXCEL7 will not be found in child windows but other windows // will be found like the window for class "VbaWindow" private static bool EnumChildProc(int hwndChild, ref int lParam) { StringBuilder buf = new StringBuilder(128); GetClassName(hwndChild, buf, 128); // More info on excel classes: // http://www.mrexcel.com/forum/excel-questions/54007-worksheet-class-findwindow-api.html if (buf.ToString() == "EXCEL7") { lParam = hwndChild; return false; } return true; } 

我有完全一样的问题。 我解决了它:

  1. 获取所有Excel进程ID的列表
  2. 循环遍历所有顶级窗口并检查其进程ID是否在Excel ID列表中。 如果是这样,然后将其添加到另一个列表。 (使用EnumWindows和GetWindowThreadProcessID)
  3. 然后遍历这个Excel列表,基本上做你以前正在做的,即通过他们的子窗口searchfind一个类的名称是EXCEL7

以下是一些示例代码:

 public class ExcelInstances { HashSet<int> _ExcelProcessIDs; List<int> _ExcelTopLevelWindowHwnds; List<Excel.Application> _XLInstances; public Excel.Application[] GetExcelInstances() { _XLInstances = new List<Excel.Application>(); _ExcelProcessIDs = new HashSet<int>(); _ExcelTopLevelWindowHwnds = new List<int>(); foreach (Process p in Process.GetProcessesByName("EXCEL")) _ExcelProcessIDs.Add(p.Id); //find all process ids related to Excel int hwnd = 0; var cb = new WinAPI.WindowEnumProc(GetAllExcelTopLevelWindowHwnds); WinAPI.EnumWindows(cb, ref hwnd); foreach (var hwnd2 in _ExcelTopLevelWindowHwnds) { var excelHwnd = 0; var cb2 = new WinAPI.WindowEnumProc(GetExcelWorkbooksFromExcelWindowHandles); WinAPI.EnumChildWindows(hwnd2, cb2, ref excelHwnd); } return _XLInstances.ToArray(); } private bool GetAllExcelTopLevelWindowHwnds(int hwnd, ref int lParam) { int id = 0; WinAPI.GetWindowThreadProcessId(hwnd, ref id); if (_ExcelProcessIDs.Contains(id)) { if (hwnd > 0) { _ExcelTopLevelWindowHwnds.Add(hwnd); } } return true; } private bool GetExcelWorkbooksFromExcelWindowHandles(int hwndChild, ref int lParam) { int id = 0; WinAPI.GetWindowThreadProcessId(hwndChild, ref id); StringBuilder buf = new StringBuilder(128); WinAPI.GetClassName(hwndChild, buf, 128); string clsName = buf.ToString(); if (clsName == "EXCEL7") { lParam = hwndChild; var wb = UsefulStaticMethods.GetActiveWorkbookFromExcelHandle(hwndChild); if (wb != null) _XLInstances.Add(wb.Parent); } return true; } }