none
using interop/.net to combine multiple word docs into one jacks up the formatting RRS feed

  • Question

  • using .net 4.0/vs2010, office 2007

    Note that I'm open to any other method to accomplish the final result.  I'm not married to Word, but I do have the restriction of not being able to include any licensed third party tool (no Aspose) and I'd like to minimize any installatio on the user's machine.  this is a corporate environment, so i do have some control.

    I need to print 2 or 3 word documents as a single document.  My code follows and it works.... except that the formatting of the second document is always a little off (paragraph spacing, fonts, margins ).  Oddly enough the third document (it has a different page orientation) comes out fine.  Sometimes the user needs to send the document to a fax server, so the first page will be a fax cover sheet.

    Where am I failing?? The method KillCom(object o) calls System.Runtime.InteropServices.Marshal.ReleaseComObject(o);

            public void CombineMultipleDocuments(string coverSheetPath, string[] documentPaths, string destinationFile, bool makeVisible)
            {
                List<string> docs = new List<string>();
    
                if (string.IsNullOrWhiteSpace(destinationFile))
                    throw new ArgumentException("The destinationfile is required");
                try
                {
                    //strip invalid paths
                    foreach (string p in documentPaths)
                    {
                        if (!string.IsNullOrWhiteSpace(p) && File.Exists(p))
                        {
                            docs.Add(p);
                        }
                    }
    
                    if (docs.Count == 0)
                        throw new ArgumentException("There are no documents to print");
                    //open the cover sheet
                    wrdApp = new Word.Application();
                    wrdApp.Visible = makeVisible;
    
                    //if there is no cover sheet open the first document and append the remaining docs to it
                    if (string.IsNullOrWhiteSpace(coverSheetPath))
                    {
                        coverSheetPath = docs[0];
                        docs.RemoveAt(0);
                    }
                    wrdDoc = wrdApp.Documents.Open(coverSheetPath, 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, ref oMissing);
                    wrdRange = wrdDoc.Content;
    
                    //a little space
                    wrdRange.InsertParagraphAfter();
                    //attach the rest of the documents
                    foreach (string path in docs)
                    {
                        //open the new source document to be inserted
                        Word._Document newDoc = wrdApp.Documents.Open(path, 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, ref oMissing);
    
                        //continues page break
                        wrdRange.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
                        wrdRange.InsertBreak(Microsoft.Office.Interop.Word.WdBreakType.wdSectionBreakNextPage);
    
                        //create a new section for our new content
                        Word.Section sec = wrdRange.Sections.Add(ref oMissing, ref oMissing);
    
                        //copy the source document's styles, fonts, etc
                        sec.PageSetup.Orientation = newDoc.PageSetup.Orientation;
    
                        sec.Range.Font = newDoc.Content.Font;
    
                        //unlink footer and headers
                        sec.Footers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].LinkToPrevious = false;
                        sec.Footers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.FormattedText = newDoc.Sections[1].Footers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.FormattedText;
    
                        sec.Headers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].LinkToPrevious = false;
                        sec.Headers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.FormattedText = newDoc.Sections[1].Headers[Word.WdHeaderFooterIndex.wdHeaderFooterPrimary].Range.FormattedText;
    
                        wrdRange.FormattedText = newDoc.Content.FormattedText;
    
    
                        //close
                        newDoc.Saved = true;
                        newDoc.Close(ref oFalse, ref oMissing, ref oMissing);
                        newDoc = null;
                        KillCOM(newDoc);
    
                    }
    
                    //the diary function needs these variables to be set
                    Word.Variables wrdVars = wrdDoc.Variables;
    
                    wrdVars.Add("Letter", WrdPropLETTER_NAME);
                    wrdVars.Add("FileKey", WrdPropFILE_KEY);
                    wrdVars.Add("LetterTo", WrdPropLETTER_TO);
                    wrdVars.Add("LetterFirstName", WrdPropLETTER_FNAME);
                    wrdVars.Add("LetterLastName", WrdPropLETTER_LNAME);
                    wrdVars.Add("LetterCompany", WrdPropLETTER_COMPANY);
                    wrdVars.Add("LetterCategory", WrdPropLETTER_CATEGORY);
                    wrdVars.Add("CurrentHeaderDoc",WrdPropCUR_HEADERDOC);
                    wrdVars.Add("CurrentDataDoc", WrdPropCUR_DATADOC);
    
    
                    wrdDoc.Protect(Word.WdProtectionType.wdAllowOnlyFormFields, ref oMissing, "mojojojo");
                    wrdDoc.SaveAs(destinationFile, 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, ref oMissing);
    
                    //close if hidden
                    if (!makeVisible)
                    {
                        wrdDoc.Saved = true;
                        wrdDoc.Close(ref oFalse, ref oMissing, ref oMissing);
    
                        wrdApp.Quit(ref oFalse, ref oMissing, ref oMissing);
                        wrdDoc = null;
                        wrdApp = null;
                    }
    
                    //clean up
                    if (File.Exists(coverSheetPath))
                        File.Delete(coverSheetPath);
                    foreach (string path in documentPaths)
                    {
                        if (File.Exists(path))
                            File.Delete(path);
                    }
                }
                catch (Exception e)
                {
                    string error = e.ToString();
                }
                finally
                {
                    wrdRange = null;
                    wrdDoc = null;
                    wrdApp = null;
                    KillCOM(wrdRange);
                    KillCOM(wrdDoc);
                    KillCOM(wrdApp);
    
                }
    
            }


    Thank Kevin

    Thursday, April 19, 2012 9:02 PM

Answers

  • Hi Kevin

    It's important to understand how Word was designed to work. The underlying philosophy is that, when you import something into a document it should integrate seamlessly. So, "by default", anything document you insert into another will take on the basic formatting of the main document already open.

    In order to have something different, you specific criteria need to be met. For font and paragraph formatting in the document you're inserting, you need a differently named set of styles that define the formatting. Word will then import these styles with the document and the formatting will be retained. If the formatting is defined by styles of the same name in both documents, then the formtting in the main document will take precedence and override what's coming in.

    Margins, headers, footers and page orientation are all section-level formatting and are controlled by "section breaks". In a document with only one section (the default for a new blank document), the last paragraph mark in the document is also the section break. When a document is inserted into another, this last paragraph mark is snipped off. So the last section of the document being inserted will comply to the section settings of the main document.

    Without analyzing the documents you're starting from, it's not possible to determine exactly what's happening in your particular scenario. But if the user is being provided with templates for the three different pages, you should be able to achieve the result you want by defining the templates correctly.

    If you need to be able to work with "any" document the user selects, then your task is going to be practically impossible using Word as it simply wasn't designed to combine multiple documents as "snapshots". In that case, what might work best would be to convert each document to a PDF file, then combine those.


    Cindy Meister, VSTO/Word MVP

    • Marked as answer by kevcoder Wednesday, April 25, 2012 9:18 PM
    Wednesday, April 25, 2012 8:26 AM
    Moderator

All replies

  • Hi Kevin,

    Thank you for posting.

    I am unable to reproduce the problem on my side. It will be nice if you can show us the detailed reproducible steps list or upload your project to the skydirve: http://www.skydrive.com and share it with me so that we can reproduce and analyze the problem more quickly.
    I will try to reproduce on my side with your project.

    Best Regards,


    Bruce Song [MSFT]
    MSDN Community Support | Feedback to us

    Monday, April 23, 2012 2:54 AM
  • Thanks for the help Bruce,

    I've uploaded the relevant  parts of my project here.  I ran my code against two templates that ship with word. 

    Eager to hear what you have to say.

    Thanks

    kevin


    Thank Kevin

    Tuesday, April 24, 2012 1:43 PM
  • Hi Kevin

    It's important to understand how Word was designed to work. The underlying philosophy is that, when you import something into a document it should integrate seamlessly. So, "by default", anything document you insert into another will take on the basic formatting of the main document already open.

    In order to have something different, you specific criteria need to be met. For font and paragraph formatting in the document you're inserting, you need a differently named set of styles that define the formatting. Word will then import these styles with the document and the formatting will be retained. If the formatting is defined by styles of the same name in both documents, then the formtting in the main document will take precedence and override what's coming in.

    Margins, headers, footers and page orientation are all section-level formatting and are controlled by "section breaks". In a document with only one section (the default for a new blank document), the last paragraph mark in the document is also the section break. When a document is inserted into another, this last paragraph mark is snipped off. So the last section of the document being inserted will comply to the section settings of the main document.

    Without analyzing the documents you're starting from, it's not possible to determine exactly what's happening in your particular scenario. But if the user is being provided with templates for the three different pages, you should be able to achieve the result you want by defining the templates correctly.

    If you need to be able to work with "any" document the user selects, then your task is going to be practically impossible using Word as it simply wasn't designed to combine multiple documents as "snapshots". In that case, what might work best would be to convert each document to a PDF file, then combine those.


    Cindy Meister, VSTO/Word MVP

    • Marked as answer by kevcoder Wednesday, April 25, 2012 9:18 PM
    Wednesday, April 25, 2012 8:26 AM
    Moderator
  • ...

    If you need to be able to work with "any" document the user selects, then your task is going to be practically impossible using Word as it simply wasn't designed to combine multiple documents as "snapshots". In that case, what might work best would be to convert each document to a PDF file, then combine those.


    Cindy Meister, VSTO/Word MVP

    Cindy thanks for the information.  You hit the nail on the head: I need to work with "any" document.

    Last night i abandoned this approach and have instead converted each word doc as XPS and then combined those.  So far so good.


    Thank Kevin

    Wednesday, April 25, 2012 2:19 PM
  • Hi Kevin

    <<have instead converted each word doc as XPS and then combined those. >>

    Yes, this sounds like a reasonable approach :-)

    If you're satisfied that this discussion is closed, please take a moment to drop by and mark the relevant messages as "Answers".


    Cindy Meister, VSTO/Word MVP

    Wednesday, April 25, 2012 4:55 PM
    Moderator