none
Interop.Word Problems RRS feed

  • Question

  • I have a previous thread regarding this issue at http://social.msdn.microsoft.com/Forums/en-US/worddev/thread/87f02efd-3ccf-4c21-8730-028a74bc723c but I am not sure it is monitored anymore as I originally marked it as solved but it turns out not to be, and I have an update on hold due to this so it is urgent.

    I have Office 2007 installed on my development machine and I use Interop.Word v11 in my application to create Word documents from a template, that should be able to be viewed by Word 2003/2007/2010. I am finding that for most people this is working fine, but a small selection of customers who use Word 2003 or Word 2010 get an exception and the Word documents are not created. I even have one customer with three identical computers, with the same Windows & Office 2010 but just one of them is having this problem! He says that when he opens up Word independently it brings up Document Recovery along the left hand side and shows the template ( rather than the new file) in recovery!I cannot understand why this is happening sporadically ( I cannot replicate it on the 4 machines I have tried ) nor why it is happening at all. One customer found that if they installed Word 2007 it resloved the issue. I made the suggested changes to my code but this does not seem to have helped, so here is the method in full in case I am making any glaring errors with my coding:

            public static void MailMergeSingleWordDoc(string wordDocpath, string wordDocDestination, Dictionary<string, string> mailMergeData, bool visible, bool letterHead, List<string[]>[] tableContentsArray, int numBookings, int docType, bool save)
            {
                Object oMissing = System.Reflection.Missing.Value;
                Object oTrue = true;
                Object oFalse = false;
                Microsoft.Office.Interop.Word._Application myWordApp = null;
                Microsoft.Office.Interop.Word._Document myWordDoc = null;

                //CREATING OBJECTS OF WORD AND DOCUMENT         
                try
                {
                    Object oTemplatePath = (object)wordDocpath;
                    Object isTemplate = false;
                    myWordApp = new Microsoft.Office.Interop.Word.Application();
                    myWordDoc = myWordApp.Documents.Add(ref oTemplatePath, ref isTemplate, ref oMissing, ref oFalse);

                    //LOGO
                    if (!letterHead && Global.LogoFileName != "" && Global.LogoFileName != null)
                    {
                        try
                        {
                            string LogoPath = Global.UserFolderPath + @"\" + Global.LogoFileName;

                            //Calculate Logo sizes
                            Image myOriginalLogo = Image.FromFile(LogoPath);
                            Image myScaledImage = StaticMethods.SizeImageForContainer(myOriginalLogo, 150, 150);
                            Object linkToFile = Microsoft.Office.Core.MsoTriState.msoFalse;
                            Object saveWithDocument = Microsoft.Office.Core.MsoTriState.msoTrue;
                            Object imageWidth = myScaledImage.Width;
                            Object imageHeight = myScaledImage.Height;
                            Object left = 0;
                            Object top = 0;


                            myWordDoc.Shapes.AddPicture(LogoPath, ref linkToFile, ref saveWithDocument, ref left, ref top, ref imageWidth, ref imageHeight, ref oMissing);
                        }
                        catch (Exception) { }
                    }


                    //REMOVE UNUSED BOOKING TEXTBOXES
                    if (docType == 0 && numBookings > 1)
                    {
                        object zero = 0;
                        object chars = WdUnits.wdCharacter;

                        for (int i = 2; i > (numBookings - 2); i--)
                        {
                            myWordDoc.Frames[i].Range.Delete(ref chars, ref zero);
                            myWordDoc.Frames[i].Delete();
                        }
                    }
                    else if (docType == 1 && numBookings > 0)
                    {
                        object zero = 0;
                        object chars = WdUnits.wdCharacter;

                        for (int i = 3; i > (numBookings - 1); i--)
                        {
                            myWordDoc.Frames[i].Range.Delete(ref chars, ref zero);
                            myWordDoc.Frames[i].Delete();
                        }
                    }


                    //REPLACE MAILMERGE FIELDS
                    foreach (Field myMergeField in myWordDoc.Fields)
                    {
                        Microsoft.Office.Interop.Word.Range rngFieldCode = myMergeField.Code;
                        String fieldText = rngFieldCode.Text;

                        // ONLY GETTING THE MAILMERGE FIELDS
                        if (fieldText.StartsWith(" MERGEFIELD"))
                        {
                            // THE TEXT COMES IN THE FORMAT OF MERGEFIELD  MyFieldName  \\* MERGEFORMAT
                            // THIS HAS TO BE EDITED TO GET ONLY THE FIELDNAME "MyFieldName"

                            Int32 endMerge = fieldText.IndexOf("\\");
                            Int32 fieldNameLength = fieldText.Length - endMerge;
                            String fieldName = fieldText.Substring(11, endMerge - 11);

                            // GIVES THE FIELDNAMES AS THE USER HAD ENTERED IN .dot FILE
                            fieldName = fieldName.Trim();

                            // **** FIELD REPLACEMENT IMPLEMENTATION GOES HERE ****//
                            myMergeField.Select();
                            myWordApp.Selection.TypeText(" ");


                            foreach (KeyValuePair<string, string> fieldEntry in mailMergeData)
                            {
                                if (fieldEntry.Key == fieldName)
                                {
                                    myWordApp.Selection.TypeText(fieldEntry.Value);
                                    break;
                                }
                            }
                        }
                    }

                    //FILL TABLES
                    if (tableContentsArray != null)
                    {
                        int t = 1;
                        foreach (List<string[]> tableContent in tableContentsArray)
                        {
                            for (int i = 0; i < tableContent.Count(); i++)
                            {
                                if (i > 0)
                                    myWordDoc.Tables[t].Rows.Add(ref oMissing);
                                for (int a = 0; a < tableContent[0].Count(); a++)
                                {
                                    myWordDoc.Tables[t].Rows[i + 1].Cells[a + 1].Range.Text = tableContent[i][a].ToString();
                                }
                            }
                            t++;
                        }
                    }

                    //SAVE THE WORD DOC
                    if (wordDocDestination != "" && save)
                    {
                        Object oSaveAsFile = (object)wordDocDestination;
                        object fileFormat = WdSaveFormat.wdFormatDocument;
                       
                        myWordDoc.SaveAs(ref oSaveAsFile, ref fileFormat, 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);
                    }

                    //SHOW THE APP
                    if (visible)
                        myWordApp.Visible = true;
                    else
                    {
                        //CLOSING THE FILE
                        object saveChanges = WdSaveOptions.wdPromptToSaveChanges;
                        object originalFormat = WdOriginalFormat.wdWordDocument;
                        object routeDocument = false;
                        myWordDoc.Close(ref saveChanges, ref originalFormat, ref routeDocument);
                        //QUITTING THE APPLICATION
                        object noSaveChanges = WdSaveOptions.wdDoNotSaveChanges;
                        myWordApp.Quit(ref noSaveChanges, ref originalFormat, ref routeDocument);
                    }
                }
                catch (Exception)
                {
                    try
                    {
                        //CLOSING THE FILE
                        object saveChanges = WdSaveOptions.wdPromptToSaveChanges;
                        object originalFormat = WdOriginalFormat.wdWordDocument;
                        object routeDocument = false;
                        myWordDoc.Close(ref saveChanges, ref originalFormat, ref routeDocument);
                        //QUITTING THE APPLICATION
                        object noSaveChanges = WdSaveOptions.wdDoNotSaveChanges;
                        myWordApp.Quit(ref noSaveChanges, ref originalFormat, ref routeDocument);
                    }
                    catch (Exception) { }
                    throw;
                }
            }

     

    Thanks

    Thursday, February 2, 2012 5:04 PM

Answers

  • OK it appears to be working, but very curious. I have had to make a seperate section for 2003 that not only calls Shapes.AddPicture the old way ( on its own that still did nothing) but also creates the Word Doc the old way:

                    if (Convert.ToDouble(myWordApp.Version) >= 12)
                    {
                        myWordDoc = myWordApp.Documents.Add(ref oTemplatePath, ref isTemplate, ref oMissing, ref oFalse);
                        //LOGO
                        if (!letterHead && Global.LogoFileName != "" && Global.LogoFileName != null)
                        {
                            try
                            {
                                string LogoPath = Global.UserFolderPath + @"\" + Global.LogoFileName;

                                //Calculate Logo sizes
                                Image myOriginalLogo = Image.FromFile(LogoPath);
                                Image myScaledImage = StaticMethods.SizeImageForContainer(myOriginalLogo, 150, 150);
                                Object linkToFile = false;
                                Object saveWithDocument = true;
                                Object imageWidth = myScaledImage.Width;
                                Object imageHeight = myScaledImage.Height;
                                Object left = 0;
                                Object top = 0;
                                Microsoft.Office.Interop.Word.Range rng = myWordDoc.Paragraphs[1].Range;
                                object oCollapseStart = Microsoft.Office.Interop.Word.WdCollapseDirection.wdCollapseStart;
                                rng.Collapse(ref oCollapseStart);
                                Object range = rng;
                                myWordDoc.Shapes.AddPicture(LogoPath, ref linkToFile, ref saveWithDocument, ref left, ref top, ref imageWidth, ref imageHeight, ref range);
                            }
                            catch (Exception) { }
                        }
                    }
                    else
                    {
                        myWordDoc = myWordApp.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
                        //LOGO
                        if (!letterHead && Global.LogoFileName != "" && Global.LogoFileName != null)
                        {
                            try
                            {
                                string LogoPath = Global.UserFolderPath + @"\" + Global.LogoFileName;

                                //Calculate Logo sizes
                                Image myOriginalLogo = Image.FromFile(LogoPath);
                                Image myScaledImage = StaticMethods.SizeImageForContainer(myOriginalLogo, 150, 150);
                                Object imageWidth = myScaledImage.Width;
                                Object imageHeight = myScaledImage.Height;
                                myWordDoc.Shapes.AddPicture(LogoPath, ref oFalse, ref oTrue, ref oMissing, ref oMissing, ref imageWidth, ref imageHeight, ref oMissing);
                            }
                            catch (Exception) { }
                        }
                    }

    It appears that the less parameters the better as far as 2003 is concerned!

    Will keep testing!

    • Marked as answer by CoppSoft2011 Wednesday, February 22, 2012 6:54 PM
    Tuesday, February 7, 2012 10:46 AM

All replies

  • In which version of Word was the original template created?

    If one of the configurations where this is happening is showing the behavior consistently, ask them to look for the file Normal.dot (or Normal.dotm for 2007/2010) on the machine and rename it to Normal.dot.OLD. This will cause Word to generate a new, clean copy the next time it starts.

    Does the problem go away with the renamed Normal template?

    If not, you'll need to try re-creating your template from a clean Normal.dot(m). How big a job this will be depends on what's in that template that your code needs to have. (Or you need a version of your code that only concentrates on the problem area, but you don't provide the Exception information here so it's difficult to pinpoint.)

    Another thing you can do is ask the customer who gets the document recovery window to look at the "Repairs" made to the template. If we know what area's being repaired it might help narrow down where the problem is.

    FWIW, this problem description sounds like we're dealing with a slightly damaged template file. So it boils down to finding out where the damage is originating: in the user's Normal template, the Normal template used to create your template, or the template itself.


    Cindy Meister, VSTO/Word MVP
    Saturday, February 4, 2012 9:04 AM
    Moderator
  • HI Cindy, OK thanks for your comments. I have just purchased Office 2010 and will recreate the templates from scratch after flushing out all old Word 2007 stuff from my development machine. I will try that route and then if it continues, ask users to rename their normal files. Can you just confirm for me the following:

    1)That you have reviewed my interop code and it appears acceptable?

    2) In order to use Interop.Word by early binding so that users with Word 2003, 2007 or 2010 can use it, I should use the v11 object library?

    3)If I create a new template from the new 2010 version of normal, can I cut and paste the text/mailmerge fields from my old template across or might that be bringing the problem with it?

    Thanks for your help,

    Paul

     

     

    Saturday, February 4, 2012 9:17 AM
  • Hi Paul

    1) I've skimmed your code and I wouldn't do some things in the section for mail merge fields the way you do, but I doubt these are involved in the problem.

    2) You'd need to use the Word 2003 library, yes. But you need to be aware that, unless you're using .NET 4.0 and embedding interop types OR to work with optional/named parameters, you'll potentially run into problems with methods that have added option parameters in later versions. The New, Open and Save commands typically do this, to allow for new functionality. Given the inconsistency of the errors you're seeing (only on some machines) this probably isn't a factor. It would have to be showing up in ALL installations of a particular version.

    3) Merge fields shouldn't be carrying the damage. Usually, this will be in a SectionBreak (which is also part of the last paragraph mark in a document) or, more rarely, in a paragraph mark. It can also be in a table structure and it can be in a field code. This means a merge field as the source can't be ruled out, but statistically it's unlikely. Unless you have code that's actually manipulating the fields.

    Looking again at your code, it's impossible for me to know what the TypeText lines are actually doing, and whether they've been performed on fields in the template (vs. only in a document created from the template). Historically, it's been possible to put text into the "cracks" of a field's structure, but MS has been pretty good about closing these cracks over the last twenty years...


    Cindy Meister, VSTO/Word MVP
    Sunday, February 5, 2012 8:54 AM
    Moderator
  • I have installed Office 2010 now and believe I have traced the problem to this section of my code which attaches the logo to the document created from the template:

                        try
                        {
                            string LogoPath = Global.UserFolderPath + @"\" + Global.LogoFileName;

                            //Calculate Logo sizes
                            Image myOriginalLogo = Image.FromFile(LogoPath);
                            Image myScaledImage = StaticMethods.SizeImageForContainer(myOriginalLogo, 150, 150);
                            Object linkToFile = Microsoft.Office.Core.MsoTriState.msoFalse;
                            Object saveWithDocument = Microsoft.Office.Core.MsoTriState.msoTrue;
                            Object imageWidth = myScaledImage.Width;
                            Object imageHeight = myScaledImage.Height;
                            Object left = 0;
                            Object top = 0;


                            myWordDoc.Shapes.AddPicture(LogoPath, ref linkToFile, ref saveWithDocument, ref left, ref top, ref imageWidth, ref imageHeight, ref oMissing);
                        }
                        catch (Exception) { }
                    }

    The Shapes.AddPicture line not only fires the exception but also makes Word 2010 crash! Any ideas why that might be?

    Monday, February 6, 2012 10:35 AM
  • OK if I try:

    myWordDoc.Shapes.AddPicture(LogoPath, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing,ref oMissing);

    it makes word 2010 crash when that line is run. so we appear to have our culprit. I used this method because I wanted to resize the image and also give an exact location ( top left corner ) where it should go. In Word 2003/2007 this works fine but Word 2010 doesn't like it. I need to find another way

    Monday, February 6, 2012 12:00 PM
  • Using inlineshapes.add picture works fine except that obviously I can't dictate where the logo goes and the text is moved down the page so that is no good.

    Realised I was using MsoTristate parameters which probably wasnt helping but I have found that using:

                        try
                        {
                            string LogoPath = Global.UserFolderPath + @"\" + Global.LogoFileName;

                            //Calculate Logo sizes
                            Image myOriginalLogo = Image.FromFile(LogoPath);
                            Image myScaledImage = StaticMethods.SizeImageForContainer(myOriginalLogo, 150, 150);
                            Object linkToFile = false;
                            Object saveWithDocument = true;
                            Object imageWidth = myOriginalLogo.Width;
                            Object imageHeight = myOriginalLogo.Height;
                            Object left = 0;
                            Object top = 0;

                           myWordDoc.Shapes.AddPicture(LogoPath, ref linkToFile, ref oMissing, ref left, ref top, ref imageWidth, ref imageHeight, ref oMissing);
                        }
                        catch (Exception)
                        {
                            MessageBox.Show("There was a problem inserting the logo", "Error");
                        }

     

    if I make 'saveWithDocument' equal to True it crashes Word 2010. If I make it false ( which it says here is the default ) then I get a 'Bad Parameter' exception. Any suggestions?

     

    Monday, February 6, 2012 12:33 PM
  • Mmm, OK, now that you mention it I do recall there being issues (in various versions of Word) inserting a Shape as the first thing in a document. I can't recall it specifically being an issue in Word 2010, but my memory's not what it used to be :-)

    What to do could depend very much on the template involved - and we could still be dealing with some form of file damaged. But, based on past experience with Word, there are few things I'd try:

    1. Insert the picture as an InlineShape, then use convertToShape method to "float" it, then position it.

    2. Select the second paragraph (or something - just not the first character in the document) as the target Range. Word has always had problems with Shapes anchored to the very start of the document. That last parameter is for the Anchor and you pass it a Range object. So something along these lines to get the Range object:
      Word.Range rng = Doc.Paragraphs[2].Range;
       object oCollapseStart = Word.WdCollapseDirection.wdCollapseStart;
       rng.Collapse(ref oCollapseStart);


    Cindy Meister, VSTO/Word MVP
    Monday, February 6, 2012 3:23 PM
    Moderator
  • :) OK suggestions work fine with Word 2010 and 2007 but now don't work with 2003 - the logo is missing in the new document created!! Same thing happens with all my templates. So it is beginning to look like it isn't possible to insert a logo using the same process for all three versions of Word. I can have 2003&2007 or 2007&2010. May be that I have to stop supporting the use of 2003.
    Monday, February 6, 2012 10:20 PM
  • Interesting. The object model hasn't changed. I know a new graphics engine was (partially) implemented in 2007 (and more fully in 2010), but I hadn't realized it could affect the actions I proposed to the extent the logo would be missing.

    Since I'm skeptical it could really be missing :-), it would be good idea for you to perform a test. I'm sure you know how many members of the Shapes collection should be in the document vs. how many are visible? Let's see what the object model says:
      1. Alt+F11 (VBA Editor); Ctrl+G (Immediate window)
      2. Type: ?ActiveDocument.Content.Shapes.Count
      3. Press Enter. Below the line a number should appear - the result of the query.

    Do you get the number of Shapes you can see, or the number of Shapes you'd expect (including the "missing" logo)? If you get a number that indicates the logo should be there, then it's probably positioned off visible area of the page and it's a question of querying the Left/Top properties to figure out where it is, then setting them to make it visible.

    If it's really not there (and I'm still skeptical), you can check the application version to branch to the code that works for the current version. somethine like (pseudocode!):
      if(wdApp.Version>=12) //Do the 2007/2010 bit else //Do the 2003 bit


    Cindy Meister, VSTO/Word MVP

    • Proposed as answer by Bruce Song Wednesday, February 22, 2012 9:53 AM
    • Unproposed as answer by CoppSoft2011 Wednesday, February 22, 2012 6:54 PM
    Tuesday, February 7, 2012 8:00 AM
    Moderator
  • OK it appears to be working, but very curious. I have had to make a seperate section for 2003 that not only calls Shapes.AddPicture the old way ( on its own that still did nothing) but also creates the Word Doc the old way:

                    if (Convert.ToDouble(myWordApp.Version) >= 12)
                    {
                        myWordDoc = myWordApp.Documents.Add(ref oTemplatePath, ref isTemplate, ref oMissing, ref oFalse);
                        //LOGO
                        if (!letterHead && Global.LogoFileName != "" && Global.LogoFileName != null)
                        {
                            try
                            {
                                string LogoPath = Global.UserFolderPath + @"\" + Global.LogoFileName;

                                //Calculate Logo sizes
                                Image myOriginalLogo = Image.FromFile(LogoPath);
                                Image myScaledImage = StaticMethods.SizeImageForContainer(myOriginalLogo, 150, 150);
                                Object linkToFile = false;
                                Object saveWithDocument = true;
                                Object imageWidth = myScaledImage.Width;
                                Object imageHeight = myScaledImage.Height;
                                Object left = 0;
                                Object top = 0;
                                Microsoft.Office.Interop.Word.Range rng = myWordDoc.Paragraphs[1].Range;
                                object oCollapseStart = Microsoft.Office.Interop.Word.WdCollapseDirection.wdCollapseStart;
                                rng.Collapse(ref oCollapseStart);
                                Object range = rng;
                                myWordDoc.Shapes.AddPicture(LogoPath, ref linkToFile, ref saveWithDocument, ref left, ref top, ref imageWidth, ref imageHeight, ref range);
                            }
                            catch (Exception) { }
                        }
                    }
                    else
                    {
                        myWordDoc = myWordApp.Documents.Add(ref oTemplatePath, ref oMissing, ref oMissing, ref oMissing);
                        //LOGO
                        if (!letterHead && Global.LogoFileName != "" && Global.LogoFileName != null)
                        {
                            try
                            {
                                string LogoPath = Global.UserFolderPath + @"\" + Global.LogoFileName;

                                //Calculate Logo sizes
                                Image myOriginalLogo = Image.FromFile(LogoPath);
                                Image myScaledImage = StaticMethods.SizeImageForContainer(myOriginalLogo, 150, 150);
                                Object imageWidth = myScaledImage.Width;
                                Object imageHeight = myScaledImage.Height;
                                myWordDoc.Shapes.AddPicture(LogoPath, ref oFalse, ref oTrue, ref oMissing, ref oMissing, ref imageWidth, ref imageHeight, ref oMissing);
                            }
                            catch (Exception) { }
                        }
                    }

    It appears that the less parameters the better as far as 2003 is concerned!

    Will keep testing!

    • Marked as answer by CoppSoft2011 Wednesday, February 22, 2012 6:54 PM
    Tuesday, February 7, 2012 10:46 AM