DCOM Config settings for Microsoft Interop Word Automation

teenup picture teenup · May 17, 2014 · Viewed 10.2k times · Source

I am using Microsoft Office Interop Word to generate documents using C#. In order for the document generation to work, there should be an entry for the "Microsoft Office Word 97 - 2003 Document" under the Dcom Config Settings as shown below:

enter image description here

The Local Path under the General Tab has a correct path when Microsoft Office is first installed. If I then join the computer to a Domain, and then restart the system with a Domain user, the Local Path becomes blank and the application doesn't generate the documents and gives error.

Even if I join the computer to Domain first and then login with Domain user and then install the Microsoft Office, the Local Path appears correct first and then after a restart, it becomes blank again. While, at the same time, if I login with the Local User, the Path is still there.

What is causing the value of Local Path to go blank?

This all setup is on virtual machines and the word automation works on a domain account as I have seen it working on a physical machine joined to domain.

UPDATE: What my application is doing:

There are 4-5 components in my application.

The first is a VSTO Word AddIn, which integrates with Microsoft Word, where we create new documents that contain some Expressions that are also saved in the database. There are also conditions on the Expressions and they can be nested also. Expressions contain schema elements from XSD files which are saved in database. Once this type of document is created, its WordML is saved in the database. This all is done in VSTO AddIn.

The second is a Web Service which receives an input xml from another component that confirms to the XSD above from which the schema elements were embedded into the expressions in the document created through VSTO addIn. This web service checks for the validations and several other tasks. It then gets the WordML of the corresponding word document from the database and passes it to the Word Interop which using its APIs, iterates through it recursively to replace the schema elements with their actual values from the input xml. This then saves the WordML to a file as word document.

This also attaches a template to the document before saving it. It uses the SaveAs functionality of Word Interop to also save the file as PDF.

UPDATE: I have again gone through my complete application and came to know that we are doing all things by parsing the Office Open XML (e.g. for feeding the input to the word document), but the only things that we are doing using Word Automation are following:

  1. Using Word Interop to save the generated WordML as one of the Word Format Files.
  2. Exporting the generated WordML to the PDF file.
  3. Merging several WordMLs into a single word document file.
  4. Fetching the XML for it.

All these four codes are shown below with only relevant parts of code:

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);

For Merging several files:

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;
}

Right now, I am receiving the following error:

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

Can this all be done without using the Word Automation?

Answer

Jo&#227;o Pinho picture João Pinho · Jun 6, 2014

Instead of trying to fix and deal with that error, I think you should read this and then try another approach to your problem:

(...) Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when run in this environment. (...)

Some of the alternatives recommended in that KB are:

(...) Microsoft strongly recommends a number of alternatives that do not require Office to be installed server-side, and that can perform most common tasks more efficiently and more quickly than Automation. Before you involve Office as a server-side component in your project, consider alternatives.

Most server-side Automation tasks involve document creation or editing. Office 2007 supports new Open XML file formats that let developers create, edit, read, and transform file content on the server side. These file formats use the System.IO.Package.IO namespace in the Microsoft .NET 3.x Framework to edit Office files without using the Office client applications themselves. This is the recommended and supported method for handling changes to Office files from a service. (...)

And

(...) Microsoft provides an SDK for manipulating Open XML file formats from the .NET 3.x Framework. For more information about the SDK and about how to use the SDK to create or edit Open XML files, visit the following Microsoft Developer Network (MSDN) Web sites:

Note, that even if you get your problem fixed, your solution will hardly be stable... In essence what, it seems to be happening is that you messed your registry and it seems that your Word reinstallation is not fixing your registry, and that is problematic.

Based on this, I recommend you to read the above documentation and to try put together a more stable solution using the above alternatives, as Automation of Microsoft Office applications from any unattended, non-interactive client application or component, which is your case, may exhibit unstable behaviors.

UPDATE 1

You have an Hello World example here. Creating a document with Open XML can be as easy as doing this:

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(); 
  } 
}

Note

I could spent here hours, trying to solve your registry, but as you can see in this article in my blog, those problem are huge headaches, and in your case, even if you find a way to solve it, it will not be a maintainable or either scalable solution, in my opinion of course.

UPDATE 2

According to this, those configurations such as local path are extracted from the registry and are not modifiable:

(...) The General tab provides general information about the application. This tab displays the Application name, type (local server or remote server), and location (local path or remote computer). These settings are not modifiable through the DCOM Config interface.

The General Tab retrieves all of its information from subkeys of the following registry key: HKEY_CLASSES_ROOT\CLSID{...CLSID...} where {...CLSID...} is the unique CLSID for the Object Server currently being viewed. (...)

So! Run > regedit > Go to HKEY_CLASSES_ROOT\CLSID, then go to Edit menu and click Find, filter by key and put your ApplicationID there. You should find it this way.

Now after finding the registry entry for your DCOM, expand it, you should see a LocalServer32, the property (Default) holds your Local Path value, try change it the same path as in your new Oracle Virtual Box.

If this works, test if the value hold after restarting and logging in with you Domain User account if it does, great, if not, run a batch to run a .reg file to perform this modification, on every login.

Warning: Nevertheless, this is bad stuff, I strongly, strongly encourage you to go the other way around, this is not the way to do it.

UPDATE 3

Regarding the "MS-WORD AUTOMATION ERROR : "The message filter indicated that the application is busy", you have a very good reply to that problem here. I'll cite a bit of the above link, for further understanding of why that error happens:

(...) That issue is the fact that the Word objects you are calling into do not support multiple threading. Since they are exposed to arbitrary clients via COM, the possibility exists that multiple threads could attempt to simultaneously execute code within the object. To prevent this from happening, will serialize all incoming calls by queuing them up and only allowing one call at a time to execute. This is done by packaging up the details of each call and posting a message to Word. When Word processes, the message, the call will execute on Word's own main thread. The problem with this approach is that if Word is busy doing something else when the call comes in, the caller will have to wait. (...)

About the merging, this tool claims to be capable of merging OpenXML documents, I never used it, but I would give it a try (if I were you).

(...) PowerTools for Open XML contains source code and guidance for accomplishing various common tasks using the Open XML SDK, such as: - High-fidelity conversion of DOCX to HTML/CSS using HtmlConverter.cs; - Merging and splitting DOCX documents using DocumentBuilder.cs; - Merging and splitting PPTX presentations using PresentationBuilder.cs; - Accepting tracked revisions in DOCX documents using RevisionAccepter.cs; - Searching and replacing text in DOCX documents using TextReplacer.cs (...)

Finally to generate PDFs, from your word documents, you can use this tool here.

So as you can see, once more, you can keep dealing with Word Automation (Dark Side), or you can join the Light Side of the Force :).