【问题标题】:DCOM Config settings for Microsoft Interop Word AutomationMicrosoft Interop Word 自动化的 DCOM 配置设置
【发布时间】:2014-07-05 15:02:10
【问题描述】:

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

首次安装 Microsoft Office 时,General Tab 下的 Local Path 路径正确。如果我随后将计算机加入域,然后以域用户重新启动系统,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 确认架构元素从该 XSD 嵌入到通过 VSTO addIn 创建的文档中的表达式中。此 Web 服务检查验证和其他几项任务。然后,它从数据库中获取相应 word 文档的 WordML,并将其传递给 Word Interop,后者使用其 API,递归地遍历它,以使用输入 xml 中的实际值替换模式元素。然后将 WordML 作为 word 文档保存到文件中。

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

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

  1. 使用 Word Interop 将生成的 WordML 保存为 Word 格式文件之一。
  2. 将生成的 WordML 导出为 PDF 文件。
  3. 将多个 WordML 合并到一个 Word 文档文件中。
  4. 正在为其获取 XML。

所有这四个代码如下所示,仅包含相关部分代码:

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 的情况下完成吗?

【问题讨论】:

  • 您是否遇到任何异常?可能类似于“检索具有 CLSID {xxxx-xxxx-...} 的组件的 COM 类工厂失败,因为以下错误:80070005”
  • 我在损坏注册表之前遇到此异常,但在虚拟机上全新安装 Microsoft Office 后,如果此 LocalPath 为空白,我会收到“word 无法打开此文档模板”。
  • 您正在开发什么样的应用程序?
  • @teenup 还有什么我可以帮你的吗?我认为您已经从可靠和/或官方来源获得了答案。

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


【解决方案1】:

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

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

该知识库中推荐的一些替代方法是:

(...) Microsoft 强烈推荐一些替代方案,它们不需要在服务器端安装 Office,并且可以比自动化更高效、更快速地执行大多数常见任务。在将 Office 作为服务器端组件加入项目之前,请考虑替代方案。

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

还有

(...) Microsoft 提供了一个 SDK,用于从 .NET 3.x 框架处理 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。 (...)

所以!运行 > regedit > 转到 HKEY_CLASSES_ROOT\CLSID,然后转到编辑菜单并单击查找,按键过滤并将您的 ApplicationID 放在那里。你应该这样找到它。

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

如果可行,请在重新启动并使用您的域用户帐户登录后测试该值是否保持,如果是,很好,如果不是,则在每次登录时运行批处理以运行 .reg 文件来执行此修改。

警告:不过,这是坏事,我强烈建议你反其道而行之,这不是这样做的方法。

更新 3

关于“MS-WORD AUTOMATION ERROR :”消息过滤器显示应用程序正忙”,您对该问题的回复非常好here。我将引用上述链接的一些内容,以供进一步了解了解为什么会发生该错误:

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

关于合并,这个tool声称能够合并OpenXML文档,我没用过,但我会试一试(如果我是你的话)。

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

搜索和替换 DOCX 文档中的文本

最后要从你的word文档生成PDF,你可以使用这个工具here

如您所见,再一次,您可以继续处理文字自动化(黑暗面),或者您可以加入原力的光明面:)。

【讨论】:

  • 100% 同意。如果它是一个 weba 应用程序以及一些你是如何解决它的,那么仍然可能会出现模棱两可的行为,你会不时得到
  • 是的,我在 .NET 组件和 VB6 应用程序之间进行了 COM 集成,有时,João 会运行​​ regasm 命令来修复 damm 服务器,只是因为有人重新编译了一些东西或安装了一些导致冲突的东西......
  • 我的物理机上的注册表已损坏。但现在,我正在 Oracle Virtualbox 上安装在 VirtualMachines 上的全新操作系统上进行尝试。我知道这可能不稳定并会带来问题,但至少它应该可以在新的操作系统上运行。有东西将 LocalPath 重置为空白,这是唯一的问题。一年以来,我在我的物理机器上运行它没有问题。这里的问题是关于如何设置这个 LocalPath 以及为什么它在域用户上发生变化的知识。
  • @teenup 不,你做错了。即使在完美配置的系统上,Word WILL 在无人看管的情况下运行也会挂起。微软明确表示会发生这种情况。不要这样做。真的。现在回头。危险!危险!
猜你喜欢
  • 2012-08-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-08
  • 2012-07-06
  • 1970-01-01
相关资源
最近更新 更多