这与此问题的选定答案有关:
How to iterate through instance of Excel c#
此代码非常适合获取Excel的所有实例,除非其中一个实例打开了VBA编辑器。代码在尝试查找EXCEL7
的类时会中断。这是工作簿子窗口的类。在调试时我确定在枚举子窗口时,无法找到EXCEL7子窗口。像VbaWindow
这样的类会显示出来。我甚至试图用这个vba窗口类的窗口句柄获取Excel.Window,但它失败了。我怎样才能让方法AccessibleObjectFromWindow
引用Excel.Window,然后我可以使用它来引用应用程序。这是我修改过的方法(我已经有了Excel Process 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;
}
答案 0 :(得分:1)
我有完全相同的问题。我解决了它:
以下是一些示例代码:
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;
}
}