首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >检查Excel工作簿是否已打开

检查Excel工作簿是否已打开
EN

Stack Overflow用户
提问于 2010-07-01 17:52:00
回答 8查看 40.8K关注 0票数 15

有没有办法查看Excel Workbook,比如DataSheet.xls,是否打开(正在使用)?如果该工作簿已打开,我希望将其关闭。

EN

回答 8

Stack Overflow用户

回答已采纳

发布于 2010-07-07 05:16:11

正确的方法是检查Application.Workbooks对象。在VBA中,您可以这样写:

代码语言:javascript
运行
复制
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#中,以下代码可以正常工作:

代码语言:javascript
运行
复制
    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。

票数 14
EN

Stack Overflow用户

发布于 2010-07-01 18:26:42

试试这个:

代码语言:javascript
运行
复制
try
{
   Stream s = File.Open(FileName, FileMode.Open, FileAccess.Read, FileShare.None);

   s.Close();

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

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

票数 11
EN

Stack Overflow用户

发布于 2016-07-22 03:20:36

对于任何对避免使用try-catch的one liner感兴趣的人...

代码语言:javascript
运行
复制
bool wbOpened = ((Application)Marshal.GetActiveObject("Excel.Application")).Workbooks.Cast<Workbook>().FirstOrDefault(x => x.Name == "Some Workbook.xlsx") != null;

或者使用完全限定的名称...

代码语言:javascript
运行
复制
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内。

代码语言:javascript
运行
复制
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实例,它还可以避免引发错误。

用法是这样的……

代码语言:javascript
运行
复制
If (IsOpenedWB_ByName("MyWB.xlsx"))
{
   ....
}

代码语言:javascript
运行
复制
Workbook wb = GetOpenedWB_ByPath("C:\MyWB.xlsx")
if (wb.obj == null) //If null then Workbook is not already opened
{
  ...
}

代码语言:javascript
运行
复制
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);
}

我在上面的代码中采用了来自hereGetRunningObjects()方法。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3156676

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档