【发布时间】: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 之外,我还没有发现太多。一个 StackOverflow 答案表明多线程是问题所在,但这在我的代码中似乎并不明显;虽然我 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, @"\p{IsArabic}|\p{IsHebrew}");
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 副本是可取的。
标签: c# com ms-word interop rpc