Для тех, кто интересуется одним вкладышем, который избегает использования try-catch ...
bool wbOpened = ((Application)Marshal.GetActiveObject("Excel.Application")).Workbooks.Cast<Workbook>().FirstOrDefault(x => x.Name == "Some Workbook.xlsx") != null;
Или с полностью определенными именами ...
bool wbOpened = ((Microsoft.Office.Interop.Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application")).Workbooks.Cast<Microsoft.Office.Interop.Excel.Workbook>().FirstOrDefault(x => x.Name == "Some Workbook.xlsx") != null;
Конечно, вывозможно, захотите немного разделить это.Главное - использовать LINQ вместо try-catch для проверки существования книги.
Примечание 1: Marshal.GetActiveObject("Excel.Application")
выдаст ошибку, если ни один экземпляр Excel не открыт.Поэтому, если иное не гарантировано или не обработано, это всегда должно быть в пределах try-catch.
bool wbOpened = false;
try
{
wbOpened = ((Application)Marshal.GetActiveObject("Excel.Application")).Workbooks.Cast<Workbook>().FirstOrDefault(x => x.Name == "Some Workbook.xlsx") != null;
}
catch
{
...
}
Примечание 2: Marshal.GetActiveObject("Excel.Application")
вернет только один экземпляр Excel.Если вам нужно выполнить поиск любого возможного экземпляра Excel, то приведенный ниже код может быть лучшей альтернативой.
Лучшая альтернатива
Если вы не против добавитьвспомогательный класс с кодом ниже может быть лучшей альтернативой.Помимо возможности поиска любого открытого экземпляра Excel, он также позволяет проверить полный путь и вернуть фактический объект рабочей книги, если он найден.Это также позволяет избежать выдачи ошибки, если не открыт ни один экземпляр Excel.
использование будет таким: ...
If (IsOpenedWB_ByName("MyWB.xlsx"))
{
....
}
или
Workbook wb = GetOpenedWB_ByPath("C:\MyWB.xlsx")
if (wb.obj == null) //If null then Workbook is not already opened
{
...
}
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Office.Interop.Excel;
using System.Runtime.InteropServices.ComTypes;
public class WBHelper
{
public static bool IsOpenedWB_ByName(string wbName)
{
return (GetOpenedWB_ByName(wbName) != null);
}
public static bool IsOpenedWB_ByPath(string wbPath)
{
return (GetOpenedWB_ByPath(wbPath) != null);
}
public static Workbook GetOpenedWB_ByName(string wbName)
{
return (Workbook)GetRunningObjects().FirstOrDefault(x => (System.IO.Path.GetFileName(x.Path) == wbName) && (x.Obj is Workbook)).Obj;
}
public static Workbook GetOpenedWB_ByPath(string wbPath)
{
return (Workbook)GetRunningObjects().FirstOrDefault(x => (x.Path == wbPath) && (x.Obj is Workbook)).Obj;
}
public static List<RunningObject> GetRunningObjects()
{
// Get the table.
List<RunningObject> roList = new List<RunningObject>();
IBindCtx bc;
CreateBindCtx(0, out bc);
IRunningObjectTable runningObjectTable;
bc.GetRunningObjectTable(out runningObjectTable);
IEnumMoniker monikerEnumerator;
runningObjectTable.EnumRunning(out monikerEnumerator);
monikerEnumerator.Reset();
// Enumerate and fill list
IMoniker[] monikers = new IMoniker[1];
IntPtr numFetched = IntPtr.Zero;
List<object> names = new List<object>();
List<object> books = new List<object>();
while (monikerEnumerator.Next(1, monikers, numFetched) == 0)
{
RunningObject running;
monikers[0].GetDisplayName(bc, null, out running.Path);
runningObjectTable.GetObject(monikers[0], out running.Obj);
roList.Add(running);
}
return roList;
}
public struct RunningObject
{
public string Path;
public object Obj;
}
[System.Runtime.InteropServices.DllImport("ole32.dll")]
static extern void CreateBindCtx(int a, out IBindCtx b);
}
Я адаптировал метод GetRunningObjects()
в приведенном выше коде с здесь .