【问题标题】:How to access an already opened Excel file in C#?如何在 C# 中访问已打开的 Excel 文件?
【发布时间】:2011-07-13 23:28:11
【问题描述】:

我有一个通过在 Windows 资源管理器中双击打开的 Excel 工作簿,但无法在代码中访问它

Excel.Application xlApp = (Application)Marshal.GetActiveObject("Excel.Application");
Excel.Workbooks xlBooks = xlApp.Workbooks;

xlBooks.Count 等于 0,为什么不引用我打开的工作簿?

编辑

以下是各种场景和正在发生的事情:

场景 1:如果文件尚未打开

  • 代码打开工作簿,我很高兴。

场景 2:如果文件最初是通过代码打开的,我关闭并重新打开应用程序

  • 代码引用文件就好了xlBooks.Count等于1,我很高兴。

场景 3:如果文件最初不是通过代码打开的,而是通过在资源管理器中双击来打开的

  • 代码打开文件的另一个实例xlBooks.Count等于0,我很生气!

这是现在的整个代码

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.Office.Interop.Excel;

public class ExcelService : IExcelService
{
    const string _filePath = @"C:\Somewhere";
    const string _fileName = @"TestFile.xlsb";
    string _fileNameAndPath = Path.Combine(_filePath, _fileName);

    Application xlApp;
    Workbooks xlBooks;
    Workbook xlBook;
    Worksheet xlSheet;

    public ExcelService()
    {
        try
        {
            xlApp = (Application)Marshal.GetActiveObject("Excel.Application");
            xlBooks = xlApp.Workbooks;

            var numBooks = xlBooks.Count;
            Log.Info("Number of workbooks: {0}".FormatWith(numBooks));
            if (numBooks > 0)
            {
                xlBook = xlBooks[1];
                Log.Info("Using already opened workbook");
            }
            else
            {
                xlBook = xlBooks.Open(_fileNameAndPath);
                Log.Info("Opening workbook: {0}".FormatWith(_fileNameAndPath));
            }

            xlSheet = (Worksheet)xlBook.Worksheets[1];

            // test reading a named range
            string value = xlSheet.Range["TEST"].Value.ToString();
            Log.Info(@"TEST: {0}".FormatWith(value));

            xlApp.Visible = true;
        }
        catch (Exception e)
        {
            Log.Error(e.Message);
        }
    }

    ~ExcelService()
    {
        GC.Collect();
        GC.WaitForPendingFinalizers();

        try
        {
            Marshal.FinalReleaseComObject(xlSheet);
        }
        catch { }

        try
        {
            Marshal.FinalReleaseComObject(xlBook);
        }
        catch { }

        try
        {
            Marshal.FinalReleaseComObject(xlBooks);
        }
        catch { }

        try
        {
            Marshal.FinalReleaseComObject(xlApp);
        }
        catch { }
    }
}

【问题讨论】:

  • 您确定您的 Excel 实例不超过一个?
  • 向我们展示您尝试打开“已打开”电子表格的代码行。
  • 骗了他自己的问题...哇...
  • 是的,我很确定,我正在查看多个实例的任务管理器,并且只有一个我目前打开的实例。我也在析构函数中执行Marshal.FinalReleaseComObject(xlApp);跨度>

标签: c# excel ms-office office-interop excel-interop


【解决方案1】:

我知道这个帖子有点老了,但我找到了另一种方法。当您创建一个新的Excel.Applicationobject 时,您必须创建 WorkBooks 对象。当您访问已打开的 Excel 文件时,WorkBooks 对象已创建,因此您只需在现有的工作簿中添加一个新工作簿。如果您可以访问 WorkBook 名称,@Tipx 的解决方案效果很好,但在我的情况下,当前的 WorkBook 名称始终是随机的。这是我想出的解决方案:

Excel.Application excelApp = null;
Excel.Workbooks wkbks = null;
Excel.Workbook wkbk = null;

bool wasFoundRunning = false;

Excel.Application tApp = null;
//Checks to see if excel is opened
try
{
    tApp = (Excel.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Excel.Application");
    wasFoundRunning = true;
}
catch (Exception)//Excel not open
{
    wasFoundRunning = false;
}
finally
{
    if (true == wasFoundRunning)
    {
        excelApp = tApp;
        wkbk = excelApp.Workbooks.Add(Type.Missing);                    
    }
    else
    {
        excelApp = new Excel.Application();
        wkbks = excelApp.Workbooks;
        wkbk = wkbks.Add(Type.Missing);
    }
    //Release the temp if in use
    if (null != tApp) { Marshal.FinalReleaseComObject(tApp); }
    tApp = null;
}
//Initialize the sheets in the new workbook

可能不是最好的解决方案,但它可以满足我的需求。希望这可以帮助某人。 :)

【讨论】:

  • 这正是我想要的。谢谢。
  • @Nathan 知道如何使用 Apache POI(Java 中)来完成。
  • @Devendra 对不起,我不知道;我什至不知道它存在,有时间我将不得不研究它。
【解决方案2】:

如果您的所有工作簿都在同一个 Excel 实例中打开(您可以通过检查是否可以使用 Alt-tab 从一个工作簿切换到另一个来检查这一点)。您可以使用Workbooks("[FileName]") 简单地引用另一个。所以,例如:

Dim wb as Workbook //for C#, type Excel.Workbook wb = null;
Set wb = Workbooks("MyDuperWorkbook.xlsx") //for C#, type wb = Excel.Workbooks["MyDuperWorkbook.xlsx"];
wb.Sheets(1).Cells(1,1).Value = "Wahou!"

【讨论】:

  • 这适用于 Office 2013 及更高版本吗?我使用的是 Office 2010,而 Excel.Workbooks 不接受“字符串”输入参数。
  • 答案是近 5 年前给出的,所以最有可能是 Excel 2010,但我不记得了。
  • @Tipx 知道如何使用 Apache POI(Java 中)来完成。
  • @Devendra 很遗憾,我没有任何想法,抱歉。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-30
  • 1970-01-01
相关资源
最近更新 更多