如何在 C# 中访问已打开的 Excel 文件?

发布于 2024-11-24 05:14:24 字数 2610 浏览 1 评论 0原文

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

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

xlBooks.Count equals 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 { }
    }
}

I have an excel workbook opened via double-clicking it in windows explorer but cannot access it in code

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

xlBooks.Count equals 0, why isn't it referencing my opened workbook?

EDIT

Here are the various scenarios and what is happening:

Scenario 1: If the file is not already open

  • Code opens workbook, I am happy.

Scenario 2: If the file is initially opened from code and I close and reopen the app

  • Code references file just fine xlBooks.Count equals 1, I am happy.

Scenario 3: If the file is initially opened not from code, and via double-clicking it in explorer

  • Code opens another instance of the file xlBooks.Count equals 0, I am in a rage!

Here is the entire code as it stands right now

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 { }
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

叫思念不要吵 2024-12-01 05:14:24

我知道这个线程有点旧,但我找到了另一种方法来做到这一点。当您创建新的 Excel.Application 对象时,您必须创建 WorkBooks 对象。当您访问已打开的 Excel 文件时,WorkBooks 对象已创建,因此您只需向现有 WorkBook 添加一个新的 WorkBook 即可。如果您有权访问 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

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

I know this thread is a little old, but I found another way of doing this. When you create a new Excel.Applicationobject you have to create the WorkBooks object. When you access an already opened Excel file, the WorkBooks object is already created, so you just need to add a new WorkBook to the existing one. @Tipx 's solution works great if you have access to the WorkBook name, but in my case the current WorkBook name is always random. Here's the solution I came up with to get around this:

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

Might not be the best solution but it worked for my needs. Hope this helps someone. :)

空‖城人不在 2024-12-01 05:14:24

如果您的所有工作簿都在同一个 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!"

If all your workbooks are opened in the same Excel instance (you can check this by checking if you can switch from one to the other using Alt-tab). You can simply refer to the other using Workbooks("[FileName]"). So, for example :

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!"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文