You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# Selenium如何读写本机已打开的Excel文件数据

结论

完全可以直接连接用户设备上已经打开的Excel文件完成读写,不需要提前知道文件存储路径,也不需要强制关闭或重启Excel进程重新打开目标文件,该逻辑可以直接集成在C# Selenium自动化项目中使用。

实现原理

所有被Excel程序打开的工作簿对应的COM实例都会注册到系统运行对象表(ROT)中,我们不需要启动新的Excel进程,只需要遍历ROT中所有运行的Excel实例,匹配已知的目标文件名即可定位到对应工作簿对象,后续读写逻辑和常规Excel Interop操作完全一致。

注意:网上常见的Marshal.GetActiveObject("Excel.Application")方法仅能获取系统中第一个注册的Excel实例,当用户打开多个Excel窗口/多个工作簿时大概率出现匹配错误,必须通过全量遍历ROT的方式实现精准匹配。

前置准备
  • 在项目依赖中添加COM引用,选择和本机安装Excel版本匹配的Microsoft Excel XX.X Object Library,将该引用的「嵌入互操作类型」属性设置为True即可,无需额外引入第三方NuGet包。
完整实现代码

首先引入所需命名空间:

using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using Excel = Microsoft.Office.Interop.Excel;

核心方法:遍历ROT匹配目标工作簿

[DllImport("ole32.dll")]
private static extern int GetRunningObjectTable(int reserved, out IRunningObjectTable prot);
[DllImport("ole32.dll")]
private static extern int CreateBindCtx(int reserved, out IBindCtx ppbc);

/// <summary>
/// 根据文件名获取已打开的Excel工作簿对象
/// </summary>
/// <param name="targetFileName">目标文件名,例如"业务统计.xlsx"</param>
/// <returns>匹配到的工作簿,未找到返回null</returns>
public static Excel.Workbook GetOpenedWorkbook(string targetFileName)
{
    IRunningObjectTable rot = null;
    IEnumMoniker monikerEnumerator = null;
    try
    {
        GetRunningObjectTable(0, out rot);
        rot.EnumRunning(out monikerEnumerator);
        IMoniker[] monikers = new IMoniker[1];
        IntPtr fetched = IntPtr.Zero;

        while (monikerEnumerator.Next(1, monikers, fetched) == 0)
        {
            IBindCtx bindCtx = null;
            CreateBindCtx(0, out bindCtx);
            monikers[0].GetDisplayName(bindCtx, null, out string objectName);

            if (objectName.StartsWith("!Microsoft Excel"))
            {
                rot.GetObject(monikers[0], out object comObj);
                if (comObj is Excel.Application excelApp)
                {
                    foreach (Excel.Workbook wb in excelApp.Workbooks)
                    {
                        if (wb.Name.Equals(targetFileName, StringComparison.OrdinalIgnoreCase))
                        {
                            return wb;
                        }
                    }
                    Marshal.ReleaseComObject(excelApp);
                }
            }
            Marshal.ReleaseComObject(monikers[0]);
            Marshal.ReleaseComObject(bindCtx);
        }
        return null;
    }
    finally
    {
        if (monikerEnumerator != null) Marshal.ReleaseComObject(monikerEnumerator);
        if (rot != null) Marshal.ReleaseComObject(rot);
    }
}

读写操作调用示例:

// 匹配名为"测试数据.xlsx"的已打开文件
Excel.Workbook targetWb = GetOpenedWorkbook("测试数据.xlsx");
if (targetWb == null)
{
    throw new Exception("未检测到处于打开状态的目标Excel文件,请确认文件已正常打开");
}

// 读取操作:获取第一个工作表A1单元格的值
Excel.Worksheet activeWs = targetWb.Worksheets[1];
var cellValue = activeWs.Range["A1"].Value2;

// 写入操作:向B2单元格写入指定内容
activeWs.Range["B2"].Value2 = "Selenium自动化流程写入内容";

// 操作完成后按创建逆序释放COM对象,避免进程残留
Marshal.ReleaseComObject(activeWs);
Marshal.ReleaseComObject(targetWb);
注意事项
  • 匹配逻辑仅校验文件名,不需要提供文件的完整存储路径,文件名匹配大小写不敏感。
  • 所有COM对象必须按创建顺序的逆序手动释放,禁止依赖GC回收,否则会导致后台残留Excel进程,即使用户手动关闭Excel窗口,进程也会持续驻留占用文件。
  • 如果目标Excel是以管理员权限启动的,自动化程序也需要以管理员权限运行,否则无法枚举到ROT中的对应实例,会出现找不到目标文件的问题。
  • 如果文件处于受保护视图状态,需要先启用编辑才能执行写入操作,否则会抛出权限异常。
  • 连接已打开文件执行读写不会中断用户当前的Excel操作,写入完成后用户可以直接看到修改内容,不需要重新加载文件。

内容的提问来源于stack exchange,提问作者SenatorUppercut

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 10:33:28