检查Excel工作簿是否已打开

时间:2010-07-01 09:52:00

标签: c# visual-studio-2005 excel-2007

有没有办法查看Excel工作簿,比如说DataSheet.xls是否已打开(正在使用中)?如果它被打开,我想关闭该工作簿。

7 个答案:

答案 0 :(得分:12)

正确的方法是检查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

换句话说,Workbooks是所有打开的工作簿的数组(或VBA术语,Collection)。

在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。

答案 1 :(得分:9)

试试这个:

try
{
   Stream s = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None);

   s.Close();

   return true;
}
catch (Exception)
{
   return false;
}

这将尝试独占打开文件。如果文件已经打开,它将抛出异常,然后您可以(尝试)关闭它并继续。

答案 2 :(得分:1)

对于任何对单线运输感兴趣的人,避免使用试用......

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实例,则会抛出错误。因此,除非另有保证或处理,否则应始终在试图捕获。

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);
}

我在here中修改了上述代码中的GetRunningObjects()方法。

答案 3 :(得分:0)

这不是特别好 - 我们将尝试打开文件并检查异常是否失败。我不确定你在C#中还有其他选择。

但是,只处理正确的异常很重要:基本上我们尝试打开文件,不允许共享。如果失败,我们得到正确的异常类型并且我们在异常中得到正确的消息,然后我们知道它是开放的。

// open the file with no sharing semantics (FileShare.None)
using (FileStream stream = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.None))
{
    try
    {
        stream.ReadByte();
        return false;
    }
    catch (IOException ex)
    {
        // catch ONLY the exception we are interested in, and check the message too
        if (ex.Message != null 
            && ex.Message.Contains("The process cannot access the file"));
        {
            return true;
        }

        // if the message was incorrect, this was not the IOException we were looking for. Rethrow it.
        throw;
    }
}

显然,对于在.Net的未来版本中更改的异常消息,这种方法很脆弱。您可能希望通过有意锁定文件的测试来补充此类功能,然后调用此方法以检查它是否正确检测到该消息。

答案 4 :(得分:0)

如果您有工作表和工作簿对象,则可以进行父检查

if(sheet.Parent == workbook)

答案 5 :(得分:0)

如果Excel Application当前未运行,则马丁的答案无效。 您可能希望修改代码如下:

static bool IsOpened(string wbook)
{
    bool isOpened = true;
    Excel.Application exApp;

    try
    {
        // place the following line here :
        exApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
        // because it throws an exception if Excel is not running.
        exApp.Workbooks.get_Item(wbook);
    }
    catch (Exception)
    {
        isOpened = false;
    }
    return isOpened;
}

感谢您的关注。此致

答案 6 :(得分:0)

  

下面的此函数将返回您是打开excel文件还是打开excel文件   不是。

     

第二个功能将为您提供Excel应用程序,工作簿和表格   用于您的代码。

using System.Collections.Generic;
using System.IO;
using System.Linq;
using wf = System.Windows.Forms;
using xl = Microsoft.Office.Interop.Excel;

public static class ExcelTest
{   
    public xl.Application xlApp = null;
    public xl.Workbook xlWb = null;
    public xl.Worksheet xlWs = null;

    public static bool IsXlFileOpen(string xlFileName)
    {       
        try
        {       
            if (!File.Exists(xlFileName))
            {
                wf.MessageBox.Show("Excel File does not exists!");
                return false;
            }

            try
            {
                xlApp = (xl.Application)Marshal.GetActiveObject("Excel.Application");
            }
            catch (Exception ex)
            {
                return false;
            }

            foreach (xl.Workbook wb in xlApp.Workbooks)
            {
                if (wb.FullName == xlFileName)
                {
                    xlWb = wb;
                    return true;
                }
            }

            return false;
        }
        catch (Exception ex)
        {
            return false;
        }
    }

    public static void GetXlSheet(string xlFileName,
                                    string xlSheetName)
    {
        try
        {
            if (!File.Exists(xlFileName))
            {
                wf.MessageBox.Show("Excel File does not exists!");
                return false;
            }

            xlApp = (xl.Application)Marshal.GetActiveObject("Excel.Application");
            foreach (xl.Workbook wb in xlApp.Workbooks)
            {
                if (wb.FullName == xlFileName)
                {
                    if (!xlWb
                        .Sheets
                        .Cast<xl.Worksheet>()
                        .Select(s => s.Name)
                        .Contains(xlSheetName))
                    {
                        wf.MessageBox.Show("Sheet name does not exist in the Excel workbook!");
                        return;
                    }
                    xlWs = xlWb.Sheets[xlSheetName];
                }
            }
        }
        catch (Exception ex)
        {
            // catch errors
        }
    }   
}