有没有办法查看Excel Workbook,比如DataSheet.xls,是否打开(正在使用)?如果该工作簿已打开,我希望将其关闭。
发布于 2010-07-07 05:16:11
正确的方法是检查Application.Workbooks对象。在VBA中,您可以这样写:
Dim wb as Workbook
On Error Resume Next                       '//this is VBA way of saying "try"'
Set wb = Application.Workbooks(wbookName)
If err.Number = 9 then                     '//this is VBA way of saying "catch"'
    'the file is not opened...'
End If换句话说,工作簿是所有打开的工作簿的数组(或者在VBA术语中是集合)。
在C#中,以下代码可以正常工作:
    static bool IsOpened(string wbook)
    {
        bool isOpened = true;
        Excel.Application exApp;
        exApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
        try
        {
            exApp.Workbooks.get_Item(wbook);
        }
        catch (Exception)
        {
            isOpened = false;
        }
        return isOpened;
    }您可能希望自己将引用传递给Excel.Application。
发布于 2010-07-01 18:26:42
试试这个:
try
{
   Stream s = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None);
   s.Close();
   return true;
}
catch (Exception)
{
   return false;
}这将尝试以独占方式打开该文件。如果文件已经打开,它将抛出一个异常,然后您可以(尝试)关闭它并继续。
发布于 2016-07-22 03:20:36
对于任何对避免使用try-catch的one liner感兴趣的人...
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:如果没有打开任何Excel实例, Marshal.GetActiveObject("Excel.Application")将抛出错误。因此,除非另有保证或处理,否则这应该始终在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实例,它还可以避免引发错误。
用法是这样的……
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);
}我在上面的代码中采用了来自here的GetRunningObjects()方法。
https://stackoverflow.com/questions/3156676
复制相似问题