我正在尝试在循环中读取一组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;
}
QutiWordApplication方法:
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);
}
}
我有什么方法可以修复或阻止此错误吗?如何改进管理此文档对象的方式?
答案 0 :(得分:0)
似乎关键是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, @"\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);
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();
}