Microsoft Interop Word Automation的DCOM配置设置

时间:2014-05-17 04:09:15

标签: c# .net office-interop com-interop dcom

我使用Microsoft Office Interop Word使用C#生成文档。为了使文档生成起作用,"Microsoft Office Word 97 - 2003 Document"下的Dcom Config Settings应该有一个条目,如下所示:

enter image description here

首次安装Microsoft Office时,Local Path下的General Tab具有正确的路径。如果我然后将计算机加入域,然后使用域用户重新启动系统,Local Path将变为空白,应用程序不会生成文档并出错。

即使我先将计算机加入域,然后使用域用户登录,然后安装Microsoft Office,Local Path首先显示正确,然后重新启动后再次变为空白。同时,如果我使用Local User登录,Path仍然存在。

是什么导致Local Path的值变为空白?

所有设置都在虚拟机上,自动化一词在域帐户上工作,因为我看到它在加入域的物理机器上工作。

UPDATE: What my application is doing:

我的应用程序中有4-5个组件。

第一个是VSTO Word AddIn,它与Microsoft Word集成,我们在其中创建包含一些也保存在数据库中的表达式的新文档。表达式上也有条件,它们也可以嵌套。表达式包含XSD文件中的架构元素,这些元素保存在数据库中。创建此类文档后,其WordML将保存在数据库中。这一切都在VSTO AddIn中完成。

第二个是Web服务,它从另一个组件接收输入xml,该组件确认上面的XSD,架构元素嵌入到通过VSTO addIn创建的文档中的表达式中。此Web服务检查验证和其他几项任务。然后,它从数据库中获取相应word文档的WordML,并将其传递给使用其API的Word Interop,递归地迭代它以使用输入xml中的实际值替换模式元素。然后,将WordML作为word文档保存到文件中。

这也会在保存文档之前将模板附加到文档中。它使用Word Interop的SaveAs功能将文件另存为PDF。

  

更新:   我再次通过我的完整应用程序,并通过解析Office Open XML(例如,用于将输入提供给word文档)来了解我们正在做所有事情,但我们使用Word Automation进行的唯一事情如下:

  1. 使用Word Interop将生成的WordML保存为Word格式文件之一。
  2. 将生成的WordML导出为PDF文件。
  3. 将多个WordML合并到一个word文档文件中。
  4. 为它获取XML。
  5. 所有这四个代码如下所示,仅包含相关的代码部分:

    Microsoft.Office.Interop.Word.Document wordDocument = null;
    object templateName = "templateFile.dotm";
    wordDocument = this.WordApplication.Documents.Add(ref missing, ref missing, ref missing, ref missing);
    wordDocument.Range(ref missing, ref missing).Text = "";
    wordDocument.set_AttachedTemplate(ref templateName);
    
    wordDocument = this.WordApplication.Documents.Open(
                       ref objSourceFilePath, ref oFalse, ref oTrue,
                       ref oMissing, ref oMissing, ref oMissing,
                       ref oMissing, ref oMissing, ref oMissing,
                       ref oMissing, ref oMissing, ref oMissing,
                       ref oMissing, ref oMissing, ref oMissing,
                       ref oMissing);
    wordDocument.ExportAsFixedFormat(
            strTargetPath,
            targetFormat,
            paramOpenAfterExport,
            paramExportOptimizeFor,
            paramExportRange,
            paramStartPage,
            paramEndPage,
            paramExportItem,
            paramIncludeDocProps,
            paramKeepIRM,
            paramCreateBookmarks,
            paramDocStructureTags,
            paramBitmapMissingFonts,
            paramUseISO19005_1,
            ref oMissing);
    
    object SaveToFormat = SaveToFormat = Microsoft.Office.Interop.Word.WdSaveFormat.wdFormatDocument97;
    wordDocument.SaveAs(ref objTargetFilePath, ref SaveToFormat, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing);
    

    合并多个文件:

    Microsoft.Office.Interop.Word.Document doc = null;
    Microsoft.Office.Interop.Word.Section section = null;
    object sectionBreakNextPage = (object)WdBreakType.wdSectionBreakNextPage;
    
    WordApp.Visible = false;
    doc = this.WordApplication.Documents.Add(ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing);
    
    if (doc != null)
    {
        doc.Activate();
        int fileCount = sourceFiles.Length;
        String fileName = string.Empty;
    
        for (int fileIndex = 0; fileIndex < fileCount; fileIndex++)
        {
            fileName = sourceFiles[fileIndex];
            if (System.IO.File.Exists(fileName))
            {
                section = doc.Sections.Last;
                //delink the current section's header & footer from previous section's header & footer
                section.Headers[WdHeaderFooterIndex.wdHeaderFooterFirstPage].LinkToPrevious = false;
                section.Footers[WdHeaderFooterIndex.wdHeaderFooterFirstPage].LinkToPrevious = false;
                section.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary].LinkToPrevious = false;
                section.Footers[WdHeaderFooterIndex.wdHeaderFooterPrimary].LinkToPrevious = false;
                section.Headers[WdHeaderFooterIndex.wdHeaderFooterEvenPages].LinkToPrevious = false;
                section.Footers[WdHeaderFooterIndex.wdHeaderFooterEvenPages].LinkToPrevious = false;
    
                section.Range.InsertFile(fileName, ref paramMissing, ref paramMissing, ref paramMissing, ref paramMissing);
                //if it is last iteration, do'nt insert break
                if (fileIndex < fileCount - 1)
                {
                    object rangeStart = (object)(section.Range.End - 1);
                    doc.Range(ref rangeStart, ref paramMissing).InsertBreak(ref sectionBreakNextPage);
                }
            }
        }
        doc.SaveAs(ref targetFile, ref wordFormat, ref paramMissing,
            ref paramMissing, ref paramMissing, ref paramMissing,
            ref paramMissing, ref paramMissing, ref paramMissing,
            ref paramMissing, ref paramMissing, ref paramMissing,
            ref paramMissing, ref paramMissing, ref paramMissing,
            ref paramMissing);
        return true;
    }
    

    现在,我收到以下错误:

    The message filter indicated that the application is busy. (Exception from HRESULT: 0x8001010A (RPC_E_SERVERCALL_RETRYLATER))

    这一切都可以在不使用Word Automation的情况下完成吗?

1 个答案:

答案 0 :(得分:5)

我认为你应该阅读this,然后尝试另一种解决问题的方法,而不是尝试修复和处理该错误:

(...) Microsoft目前不建议也不支持从任何无人参与的非交互式客户端应用程序或组件(包括ASP,DCOM和NT)自动化Microsoft Office应用程序服务),因为Office在此环境中运行时可能会出现不稳定的行为和/或死锁。的(...)

该KB推荐的一些替代方案是:

(...) Microsoft强烈建议使用许多替代方案,这些方案不需要在服务器端安装Office,并且可以比自动化更高效,更快速地执行大多数常见任务。在将Office作为项目中的服务器端组件介入之前,请考虑替代方案。

大多数服务器端自动化任务涉及文档创建或编辑。 Office 2007支持新的Open XML文件格式,允许开发人员在服务器端创建,编辑,读取和转换文件内容。这些文件格式使用Microsoft .NET 3.x Framework中的System.IO.Package.IO命名空间来编辑Office文件,而无需使用Office客户端应用程序本身。这是处理从服务更改Office文件的推荐和支持的方法。的(...)

并且

(...) Microsoft提供了一个SDK,用于从.NET 3.x Framework中操作Open XML文件格式。有关SDK以及如何使用SDK创建或编辑Open XML文件的更多信息,请访问下面的Microsoft Developer Network(MSDN)网站:

请注意,即使您解决了问题,您的解决方案也很难稳定......实际上,似乎正在发生的事情是您搞砸了您的注册表,而且您的Word重新安装似乎没有修复您的注册表,这是有问题的。

基于此,我建议您阅读上述文档,并尝试使用上述替代方案组合一个更稳定的解决方案,作为来自任何无人参与的非交互式客户端应用程序或组件的Microsoft Office应用程序的自动化,这是您的案件,可能表现出不稳定的行为。

更新1

你有一个Hello World示例here。 使用Open XML创建文档就像这样简单:

public void HelloWorld(string docName) 
{
  // Create a Wordprocessing document. 
  using (WordprocessingDocument package = WordprocessingDocument.Create(docName, WordprocessingDocumentType.Document)) 
  {
    // Add a new main document part. 
    package.AddMainDocumentPart(); 

    // Create the Document DOM. 
    package.MainDocumentPart.Document = 
      new Document( 
        new Body( 
          new Paragraph( 
            new Run( 
              new Text("Hello World!"))))); 

    // Save changes to the main document part. 
    package.MainDocumentPart.Document.Save(); 
  } 
}

注意

我可以在这里花几个小时,尝试解决您的注册表问题,但正如您在我的博客中this article所看到的那样,这些问题非常令人头疼,在您的情况下,即使您找到了解决问题的方法在我看来,它不会是可维护的或可扩展的解决方案。

更新2

根据this,本地路径等配置是从注册表中提取的,不可修改:

(...)“常规”选项卡提供有关应用程序的一般信息。此选项卡显示应用程序名称,类型(本地服务器或远程服务器)和位置(本地路径或远程计算机)。这些设置无法通过DCOM Config界面进行修改。

“常规”选项卡从以下注册表项的子项中检索其所有信息: HKEY_CLASSES_ROOT \ CLSID {... CLSID ...} 其中{... CLSID ...}是当前正在查看的对象服务器的唯一CLSID。的(...)

原来如此!运行&gt; regedit&gt;转到HKEY_CLASSES_ROOT \ CLSID,然后转到“编辑”菜单并单击“查找”,按键过滤并将ApplicationID放在那里。你应该这样找到它。

现在找到DCOM的注册表项后,展开它,您应该看到一个LocalServer32,该属性(默认)保存您的本地路径值,尝试将其更改为与新的Oracle Virtual Box中相同的路径。

如果这样做,请测试重新启动后是否保留该值并使用您的域用户帐户登录(如果有),如果没有,请运行批处理以在每次登录时运行.reg文件以执行此修改。 / p>

警告:然而,这是不好的事情,我强烈强烈建议您反过来,这不是实现目标的方法。

更新3

关于&#34; MS-WORD AUTOMATION ERROR:&#34;消息过滤器指示应用程序正在忙碌&#34;,您对该问题here的回复非常好。我将引用上述链接,以进一步了解错误发生的原因:

(...)该问题是您调用的Word对象不支持多线程。由于它们通过COM暴露给任意客户端,因此存在多个线程可能尝试同时执行对象内的代码的可能性。为了防止这种情况发生,将通过对它们进行排队来序列化所有传入呼叫,并且一次只允许一个呼叫执行。这是通过打包每个调用的详细信息并将消息发布到Word来完成的。当Word处理消息时,调用将在Word自己的主线程上执行。这种方法的问题在于,如果Word在呼叫进入时忙于做其他事情,则呼叫者将不得不等待。的(...)

关于合并,这个tool声称能够合并OpenXML文档,我从未使用它,但我会尝试一下(如果我是你)。

(...) Open XML的PowerTools包含使用Open XML SDK完成各种常见任务的源代码和指南,例如: - 使用高保真转换DOCX到HTML / CSS HtmlConverter.cs; - 使用DocumentBuilder.cs合并和拆分DOCX文档; - 使用PresentationBuilder.cs合并和拆分PPTX演示文稿; - 使用RevisionAccepter.cs接受DOCX文档中的跟踪修订; - 使用TextReplacer.cs搜索和替换DOCX文档中的文本(...)

最后,要生成PDF,请从word文档中使用此工具here

所以你可以看到,再一次,你可以继续处理Word Automation(黑暗面),或者你可以加入力量的光明面:)。