有没有办法查看Excel工作簿,比如说DataSheet.xls是否已打开(正在使用中)?如果它被打开,我想关闭该工作簿。
答案 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)
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
}
}
}