将 Excel 图表从 Excel 导入 PowerPoint 会导致某些机器上出现“RPC_E_SERVERFAULT”

Importing Excel Charts from Excel to PowerPoint causes `RPC_E_SERVERFAULT` on some machines

这是一个恼人的问题。我创建了一种将工作簿中的所有 Excel 个图表复制到 PowerPoint 幻灯片的方法。

public int ImportExcelChartsFromWorkbookToSlides(int startingSlideIndex, string workbookPath, string[] slideTitles, int chartPosTop, int chartPosLeft = 10, int titleWidth = 680, int titleHeight = 20, int titlePosTop = 90, int titlePosLeft = 20, int titleFontSize = 18)
{
    int slideIndex = startingSlideIndex;
    int titleIndex = 0;
    EXCL.Application objExclApp = new EXCL.Application();
    EXCL.Workbook objWorkbook = objExclApp.Workbooks.Open(workbookPath, Editable: false);
    foreach (EXCL.Worksheet objSheet in objWorkbook.Worksheets)
    {
        foreach (EXCL.ChartObject objChart in objSheet.ChartObjects())
        {
            AddBlankSlide(slideIndex);
            AddTextBox(titleWidth.ToString(), titleHeight.ToString(), titlePosTop.ToString(), titlePosLeft.ToString());
            AddTextBoxParagraph(slideTitles[titleIndex], fontSize: titleFontSize.ToString(), useThemeFont: true);

            // Copy Chart from Sheet to Slide
            objChart.CopyPicture();

            PPT.ShapeRange objShapeRange = objSlide.Shapes.Paste();

            objShapeRange.Left = chartPosLeft;
            objShapeRange.Top = chartPosTop;

            slideIndex++;
            titleIndex++;

            Marshal.ReleaseComObject(objChart);
            Marshal.ReleaseComObject(objShapeRange);
        }
        Marshal.ReleaseComObject(objSheet);
    }
    objWorkbook.Close();
    objExclApp.Quit();
    Marshal.ReleaseComObject(objWorkbook);
    Marshal.ReleaseComObject(objExclApp);
    objWorkbook = null;
    objExclApp = null;
    return slideIndex;
}

通常情况下,这在我的机器上运行完美,但一些用户报告说 RPC_E_SERVERFAULT 使用此方法。 (HRESULT: 0x80010105)

此方法中的某处导致了问题。或者是不同的 office 安装问题、内存问题或导致问题的加载项。我已经在其他几台机器上试过了,但它们仍然有效。

RPC_E_SERVERFAULT 令人讨厌且难以诊断。 Excel 崩溃时出现此错误。没有任何细节,这种崩溃应该是由应用程序本身报告的。这并没有发生,更糟糕的是 Excel 保持 运行 即使发生了相当糟糕的事情。在您接触到出现此问题的机器之前,您无法在此类事故中取得任何真正的进展。

然而,要找到其他受害者并不难,只是 Google "chartobject rpc_e_serverfault"。它们看起来都和你的一样。减去一个好的解决方案。

我对潜在问题有一个相当好的理论。问题在于,Microsoft 已经设法使 Office 互操作界面兼容 19 年了。这是一项令人惊叹的成就,也是每个人都认为理所当然的事情,尽管它没有什么微不足道的,但它已经 运行 没油了。图表作为常见的麻烦制造者值得注意。

看看IChartObject interface的定义。在 Office 2013 和 2003 定义之间来回切换。并注意神秘的 _Copy() 方法添加。似乎完全没有必要,因为已经有一个 Copy() 方法。并且没有记录。

这是个问题。如果您在 VS 中使用 GoTo Definition 查看接口定义,请注意它是接口 table 中的 second 方法。这是一个很大很大的问题。它破坏了接口的二进制兼容性。

后果很严重,如果您使用 Office 2013 的互操作库来构建您的程序,并且用户在他的机器上安装了 Office 2003(或 2007,不知道),那么您程序中的 CopyPicture() 调用会调用完全错误的实现方法。大概是 Cut(),一种不带参数的方法。这非常糟糕,如果方法本身没有崩溃,那么堆栈不平衡会导致各种破坏。 RPC_E_SERVERFAULT 是预期结果。

因此,一个可行的理论是,这会在具有旧 Office 版本的计算机上爆炸。除了构建使用 2003 互操作库的程序的另一个版本并指示 IT 人员在分发它时要小心外,您对此无能为力。升级机器是迄今为止最简单的解决方法。

我在使用 ChartObject.Copy() 方法时遇到了类似的问题。当我尝试使应用程序可见以查看是否显示任何对话框时,它实际上最终修复了 RPC 错误。作为解决方法,我执行了以下操作以打开 excel 应用程序并使其短暂可见但在 运行 ChartObject.Copy() 和其他操作之前最小化。

var excel = new Microsoft.Office.Interop.Excel.Application();
excel.WindowState = Microsoft.Office.Interop.Excel.XlWindowState.xlMinimized;
excel.Visible = true;
var workbooks = excel.Workbooks;
var workbook = workbooks.Open(excelFilePath, ReadOnly: false);
excel.Visible = false;

我在 (HRESULT 异常:0x80010105(RPC_E_SERVERFAULT)) 尝试向 Excel 添加图表时也遇到了这个问题。我发现这是由我的文件的访问模式设置引起的,这些设置是通过 Excel 在文件中和在我自己的代码中设置的。

我在另一个主题上发布了我的解决方案,对我来说效果很好,您可以查看 here。我希望这会帮助那里的人!