关闭 Word 文档时出现 RPC_E_SERVERFAULT

Posted

技术标签:

【中文标题】关闭 Word 文档时出现 RPC_E_SERVERFAULT【英文标题】:RPC_E_SERVERFAULT when closing Word document 【发布时间】:2013-10-18 15:59:28 【问题描述】:

我正在尝试循环读取一组 Word 文件。在循环的第一次迭代中,从来没有问题。在第 2、3、.. n 次迭代中,我在尝试关闭文档时收到以下错误:

The server threw an exception. (exception from hresult: 0x80010105 (rpc_e_serverfault))

我的电话如下:

(doc as Word._Document).Close(Word.WdSaveOptions.wdDoNotSaveChanges, x, x);(其中 x 是 Type.Missing)

此外,当仅处理一个文件(即循环中的一个文件)时,在单独运行该循环 2、3 等时永远不会引发错误。第一次迭代后出现了一些问题,在后续迭代中没有得到修复。然而,我似乎正确地重新初始化了所有变量,并且正在重用 ApplicationClass 对象。

我对这个错误做了一些不错的研究。除了了解到我们真的不应该使用 COM Interop 之外,我还没有发现太多。一个 *** 答案表明多线程是问题所在,但这在我的代码中似乎并不明显;虽然我 90% 确定这是一个错误。就是没找到。

我的代码如下: 我有一个类级变量,用于为循环的每次迭代重新使用应用程序类: Word.ApplicationClass _WordApp;

循环在退出 Word 应用程序之前运行以下代码 n 次(要读取的文件数不限):

内循环:

        byte[] wordDocBytes = GetWordDocumentData(att.Data, att.FileName);
        pagesToCombine.Add(wordDocBytes);
        if (counter == wordFileCount)  QuitWordApplication(); 
        else  counter += 1; 

GetWordDocumentData 方法:

    private byte[] GetWordDocumentData(byte[] wordBytes, string path)
    
        // Save bytes to word file in temp dir, open, copy info. Then delete the temp file after.

        object x = Type.Missing;
        string ext = Path.GetExtension(path).ToLower();
        string tmpPath = Path.ChangeExtension(Path.GetTempFileName(), ext);
        File.WriteAllBytes(tmpPath, wordBytes);

        // Open temp file with Excel Interop:
        Word.Documents docs = null;
        if (_WordApp == null)
        
            _WordApp = new Word.ApplicationClass();
        

        try
        
            docs = _WordApp.Documents;
        
        catch (COMException cx)
        
            _WordApp = new Word.ApplicationClass();
            docs = _WordApp.Documents;
        
        Word.Document doc = docs.Open(tmpPath, x, x, x, x, x, x, x, x, x, x, x, x, x, x);

        doc.ActiveWindow.Selection.WholeStory();
        doc.ActiveWindow.Selection.Copy();
        IDataObject data = Clipboard.GetDataObject();
        string documentText = data.GetData(DataFormats.Text).ToString();

        // Add text to pages.
        byte[] wordDoc = null;
        using (MemoryStream myMemoryStream = new MemoryStream())
        
            Document myDocument = new Document();
            PdfWriter myPDFWriter = PdfWriter.GetInstance(myDocument, myMemoryStream); // REQUIRED.
            PdfPTable table = new PdfPTable(1);
            myDocument.Open();

            // Create a font that will accept unicode characters.
            BaseFont bfArial = BaseFont.CreateFont(@"C:\Windows\Fonts\Arial.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            Font arial = new Font(bfArial, 12);

            // If Hebrew character found, change page direction of documentText.
            PdfPCell page = new PdfPCell(new Paragraph(documentText, arial))  Colspan = 1 ;
            Match rgx = Regex.Match(documentText, @"\pIsArabic|\pIsHebrew");
            if (rgx.Success) page.RunDirection = PdfWriter.RUN_DIRECTION_RTL;

            table.AddCell(page);

            // Add image to document (Not in order with text...)
            foreach (Word.InlineShape ils in doc.InlineShapes)
            
                if (ils != null && ils.Type == Word.WdInlineShapeType.wdInlineShapePicture)
                
                    PdfPCell imageCell = new PdfPCell();
                    ils.Select();
                    doc.ActiveWindow.Selection.Copy();
                    System.Drawing.Image img = Clipboard.GetImage();
                    byte[] imgb = null;
                    using (MemoryStream ms = new MemoryStream())
                    
                        img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg); // Null reference exception - SOMETIMES.
                        imgb = ms.ToArray();
                    

                    Image wordPic = Image.GetInstance(imgb);
                    imageCell.AddElement(wordPic);
                    table.AddCell(imageCell);
                
            

            myDocument.Add(table);
            myDocument.Close();
            myPDFWriter.Close();
            wordDoc = myMemoryStream.ToArray();
        

        // Cleanup:
        Clipboard.Clear();
        (doc as Word._Document).Close(Word.WdSaveOptions.wdDoNotSaveChanges, x, x); // "The server generated an exception." - SOMETIMES.
        try  File.Delete(tmpPath); 
        catch  

        return wordDoc;
    

QutiWord应用方法:

    private void QuitWordApplication()
    
        try
        
            (_WordApp as Word._Application).Quit(Type.Missing, Type.Missing, Type.Missing);
            GC.Collect();
            GC.WaitForPendingFinalizers();
        
        catch (Exception ex)
        
            MessageBox.Show(ex.Message + ex.StackTrace);
        
    

有什么方法可以修复或防止此错误?如何改进管理此文档对象的方式?

【问题讨论】:

Word 崩溃了。它不会告诉你为什么它崩溃了,那种信息不能通过互操作管挤压。您需要关注 Word 本身才能找出原因。不知道这需要什么,但我会首先在 Windows 应用程序事件日志中查找面包屑。接下来,我将调试器附加到 winword.exe 并使用 Debug + Exceptions, Throw 复选框来了解更多信息。接下来,我将禁用加载项。接下来,我会怀疑 PDF 编写器有 cooties,看看如果我禁用它或修改选项会发生什么。 您是否尝试过为每次迭代创建应用程序对象?会崩溃吗? @HansPassant:关于应用程序日志,周五我收到一个“经典”应用程序错误,指出错误的应用程序名称是 WINWORD.EXE,错误的模块名称是 VBE6.DLL。并没有真正说明发生了什么。那就是运行上面的代码。当我删除 Itextsharp 代码时,故障模块现在是 ntdll.dll。如您所述,您如何附加调试器?我用谷歌搜索了它,但没有找到如何做到这一点。 Claptrap:我尝试在每次迭代中重新创建 ApplicationClass,但无济于事。它在第一次或第二次迭代时崩溃。 VBE6.DLL 是执行 Visual Basic for Applications (VBA) 代码的模块。可以是任何东西。获得一个没有安装扩展、没有宏和加载空 .doc 的干净 Word 副本是可取的。 【参考方案1】:

看来关键是 Document.Activate():

doc.Activate();

应该在 docs.Open(...) 之后运行:

Word.Document doc = docs.Open(ref fpath, ref x, ref readOnly, ref x, ref x, ref x, ref x, ref x, ref x, ref x, ref x, ref visible, ref x, ref x, ref x, ref x);

我认为在 Open() 命令中使用 ref x 等也有帮助。我最终退出了每次迭代的应用程序。现在没有崩溃,WINWORD.exe 进程也不会成倍增加。谢天谢地……

最终代码:

    private byte[] GetWordDocumentData(byte[] wordBytes, string path) //
    
        // Save bytes to word file in temp dir, open, copy info. Then delete the temp file after.

        object x = System.Reflection.Missing.Value;
        string ext = Path.GetExtension(path).ToLower();
        string tmpPath = Path.ChangeExtension(Path.GetTempFileName(), ext);
        File.WriteAllBytes(tmpPath, wordBytes);

        // Open temp file with Excel Interop:
        Word.Documents docs = null;
        Word.ApplicationClass app = new Word.ApplicationClass();

        try
        
            docs = app.Documents;
        
        catch
        
            app = new Word.ApplicationClass();
            docs = app.Documents;
        

        object fpath = tmpPath;
        object visible = false;
        object readOnly = false;
        Word.Document doc = docs.Open(ref fpath, ref x, ref readOnly, ref x, ref x, ref x, ref x, ref x, ref x, ref x, ref x, ref visible, ref x, ref x, ref x, ref x);
        doc.Activate(); //New
        doc.ActiveWindow.Selection.WholeStory();
        doc.ActiveWindow.Selection.Copy();
        IDataObject data = Clipboard.GetDataObject();
        string documentText = data.GetData(DataFormats.Text).ToString();

        // Add text to pages.
        byte[] wordDoc = null;
        using (MemoryStream myMemoryStream = new MemoryStream())
        
            Document myDocument = new Document();
            PdfWriter myPDFWriter = PdfWriter.GetInstance(myDocument, myMemoryStream); // REQUIRED.
            PdfPTable table = new PdfPTable(1);
            myDocument.Open();

            // Create a font that will accept unicode characters.
            BaseFont bfArial = BaseFont.CreateFont(@"C:\Windows\Fonts\Arial.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED);
            Font arial = new Font(bfArial, 12);

            // If Hebrew character found, change page direction of documentText.
            PdfPCell page = new PdfPCell(new Paragraph(documentText, arial))  Colspan = 1 ;
            Match rgx = Regex.Match(documentText, @"\pIsArabic|\pIsHebrew");
            if (rgx.Success) page.RunDirection = PdfWriter.RUN_DIRECTION_RTL;

            table.AddCell(page);

            // Add image to document (Not in order with text...)
            foreach (Word.InlineShape ils in doc.InlineShapes)
            
                if (ils != null && ils.Type == Word.WdInlineShapeType.wdInlineShapePicture)
                
                    PdfPCell imageCell = new PdfPCell();
                    ils.Select();
                    doc.ActiveWindow.Selection.Copy();
                    System.Drawing.Image img = Clipboard.GetImage();
                    byte[] imgb = null;
                    using (MemoryStream ms = new MemoryStream())
                    
                        img.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
                        imgb = ms.ToArray();
                    

                    Image wordPic = Image.GetInstance(imgb);
                    imageCell.AddElement(wordPic);
                    table.AddCell(imageCell);
                
            

            myDocument.Add(table);
            myDocument.Close();
            myPDFWriter.Close();
            wordDoc = myMemoryStream.ToArray();
        

        Cleanup(x, tmpPath, app, doc);

        return wordDoc;
    

我认为将清理工作与工作分开很重要:

    private static void Cleanup(object x, string tmpPath, Word.ApplicationClass app, Word.Document doc)
    
        Clipboard.Clear();
        object Save = false;
        (doc as Word._Document).Close(ref Save, ref x, ref x);
        doc = null;
        (app as Word._Application).Quit();
        app = null;
        try  File.Delete(tmpPath); 
        catch  
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    

【讨论】:

以上是关于关闭 Word 文档时出现 RPC_E_SERVERFAULT的主要内容,如果未能解决你的问题,请参考以下文章

当另一个文档已经打开时,打开Word文档时出现错误4605

怎么解决Word转pdf时出现“PDF Maker文件遗失”的情况

Microsoft Word 2007 向程序发送命令时出现问题解决方法

Aspose生成word添加一个具有横向页面的文档时出现换页

如何解决利用aspose把word文档转换为pdf文档时出现乱码 C#

怎样在word打开时,鼠标停在上次关闭的时候编辑的位置?