C#调用Workbooks.Open加载Excel插件(.xla/.xlam)失败,报错RPC_E_SERVERFAULT
解决C#操作Excel循环时出现RPC_E_SERVERFAULT(0x80010105)的问题
这个RPC_E_SERVERFAULT错误本质是Excel COM服务端内部触发了未处理异常,你的代码里存在几个明显的问题,导致操作不稳定,以下是具体修复方案:
核心问题分析
- 重复加载AddIn且操作冗余:代码里两次重复打开并重置
REFPROP.XLA和REFPROP_Ribbon.xlam的Installed状态,这会导致Excel内部加载状态混乱,触发服务端异常。 - 不可靠的等待方式:
Thread.Sleep(3000)是强制阻塞线程,但无法保证Excel已经完成加载/初始化操作,经常会出现代码继续执行但Excel还没就绪的情况。 - COM对象未正确释放:没有显式释放Excel相关的COM对象,容易导致内存泄漏和残留Excel进程,干扰后续循环操作。
- Office COM线程安全问题:如果你的循环是在多线程环境下执行,Office COM组件不支持跨线程调用,必然会出现随机异常。
具体修复步骤
1. 优化AddIn加载逻辑,避免重复操作
只需要加载一次AddIn,并且先检查是否已加载,再执行安装/重置操作:
// 封装AddIn加载方法,避免重复代码 private void LoadRefPropAddIns(Excel.Application excelApp) { string[] addInPaths = { @"C:\Program Files (x86)\REFPROP\REFPROP.XLA", @"C:\Program Files (x86)\REFPROP\REFPROP_Ribbon.xlam" }; foreach (string path in addInPaths) { string addInName = System.IO.Path.GetFileName(path); Excel.AddIn addIn = null; try { addIn = excelApp.AddIns.Item(addInName); } catch { // AddIn不在列表中,尝试打开加载 excelApp.Workbooks.Open(path); addIn = excelApp.AddIns.Item(addInName); } if (addIn != null && !addIn.Installed) { addIn.Installed = true; } } }
2. 替换Thread.Sleep为Excel原生等待方法
使用Excel的Wait方法,等待Excel内部操作完成,而不是固定睡眠:
// 等待3秒,直到Excel就绪 excelApp.Wait(DateTime.Now.AddSeconds(3));
3. 严格管理COM对象释放
每次操作完成后,必须显式释放所有Excel相关的COM对象,避免泄漏:
// 使用完Workbook后释放 if (ExcelBook != null) { ExcelBook.Close(false); Marshal.ReleaseComObject(ExcelBook); ExcelBook = null; } // 最后退出Excel并释放Application对象 if (ExcelApp != null) { ExcelApp.Quit(); Marshal.ReleaseComObject(ExcelApp); } GC.Collect(); GC.WaitForPendingFinalizers();
4. 确保单线程执行所有Excel操作
Office COM组件仅支持STA线程,所有操作必须在创建Excel.Application的同一个线程中执行,禁止跨线程调用。如果是循环执行,确保每次循环都在同一个STA线程内,或者每次循环创建新的Excel实例并正确释放。
5. 清理残留Excel进程
在循环开始前,检查并杀掉所有残留的Excel进程,避免干扰:
foreach (Process proc in Process.GetProcessesByName("EXCEL")) { proc.Kill(); }
修改后的完整Open方法示例
using System; using System.Runtime.InteropServices; using System.Diagnostics; using Excel = Microsoft.Office.Interop.Excel; public bool Opened = false; public string ExcelPath = "你的目标Excel路径"; public void Open() { Excel.Application ExcelApp = null; Excel.Workbook ExcelBook = null; try { // 清理残留Excel进程 foreach (Process proc in Process.GetProcessesByName("EXCEL")) { proc.Kill(); } ExcelApp = new Excel.Application(); // 加载AddIn,仅执行一次 LoadRefPropAddIns(ExcelApp); // 等待Excel就绪 ExcelApp.Wait(DateTime.Now.AddSeconds(3)); // 打开目标工作簿 ExcelBook = ExcelApp.Workbooks.Open(ExcelPath); Opened = true; // 等待工作簿加载完成 ExcelApp.Wait(DateTime.Now.AddSeconds(3)); // 这里添加运行宏的代码 // ExcelApp.Run("你的宏名称"); } catch (Exception e) { // 可添加日志记录逻辑 throw; } finally { // 释放所有COM对象 if (ExcelBook != null) { ExcelBook.Close(false); Marshal.ReleaseComObject(ExcelBook); } if (ExcelApp != null) { ExcelApp.Quit(); Marshal.ReleaseComObject(ExcelApp); } GC.Collect(); GC.WaitForPendingFinalizers(); } } private void LoadRefPropAddIns(Excel.Application excelApp) { string[] addInPaths = { @"C:\Program Files (x86)\REFPROP\REFPROP.XLA", @"C:\Program Files (x86)\REFPROP\REFPROP_Ribbon.xlam" }; foreach (string path in addInPaths) { string addInName = System.IO.Path.GetFileName(path); Excel.AddIn addIn = null; try { addIn = excelApp.AddIns.Item(addInName); } catch { // AddIn不在列表中,尝试打开加载 excelApp.Workbooks.Open(path); addIn = excelApp.AddIns.Item(addInName); } if (addIn != null && !addIn.Installed) { addIn.Installed = true; } } }
内容的提问来源于stack exchange,提问作者Reut Yfrach
相关产品推荐
相关产品推荐

