none
Restore Dynamic WinForm control in Word document throws Value out of Range Exception RRS feed

  • Question

  • Hello VSTO community, been a while, I have encountered a problem that I would like some feedback on, here are the details:

     

    Office 2007 (12.0.6545.5000) SP2 MSO (12.0.6545.5004)

     

    VSTO 3.0 Word 2007 Template Document Level Add-in (created VS 2008 with the .NET 3.5 SP1 installed)

     

    Problem:

    Custom WinForm Control, when being dynamically added back into the document after being saved as a DOCX, results in a “value out of range” if the document is not saved twice before closing Word (once saving the Template as a DOCX and again, saving the document when Word is being closed).

     

     

    Details:

    Everything I am about to discuss is based off the Dynamic Controls example provided in the MSDN as the following link http://msdn.microsoft.com/en-us/library/ms269112(v=VS.90).aspx

     

    I have created a Word template with an Action Pane that allows a user to insert content into a Word document. In this case, they are creating a Word Template that has a native word Frame control in it, with a merge field within that, used as a place holder to insert a picture into later, and a Custom WinForm Control (in this example I will use a Panel, but any WinForm control will do).

     

    When the user opens the template (new document from that template) we restore the dynamic controls back into the document without a problem. We insert an image into the document using the Frame as the bounding container, for the given Merge Field; in my example code, this is hard coded to a local image file. The user clicks a button on the action pane to save the document as a DOCX (in code, we’re doing a SaveAs and then an Application.Quit, telling word Not to save, since we just did so).

     

     

    Now, if I open that saved DOCX file, the image displays properly, but when the WinForm control is being inserted back into the document the the Word.Range function is throwing a “Value out of Range” Exception using the persisted Controlinfo from the WinForm control.

    I have learned, through much trial and error, that if I save the DOCX twice, once doing a SaveAs and then again, on Application.Quit, passing wdSaveChanges, that this problem magically, and unexplainably, “goes away”.

     

     

    Note: If I do this exact same thing in Office 2003, using a VSTO 2 add-in, without saving the document twice, it all works without an error, which leads me to believe this is a bug in with Word 2007 or the VSTO framework; or both.

     

     

    A larger problem at hand is while I have been able to “fix” this in my test application, in my real world application, my fixes do not seem to resolve the problem, and I am still seeing an out of range exception.

     

    In closing

    At this point, I have tried just about everything I can think of, in an attempt to resolve this problem. I am deeply concerned that our customers will see this in the field, if they go back and open any existing documents they have already saved in Office 2007 using the DOCX format, and I will be unable to correct those documents.

     

     

    I am hoping that someone here that knows more than I do about the VSTO, can offer up a fix or suggestions, because I am currently at a loss.

     

    NOTE: I have a working example, based off the MSDN code example, that reproduces this problem, if you would like to see it happen first hand (could not figure out how to add an attachment, doesn't look like that is supported).

     

    Thank you for your time and consideration,

    Douglas H Troy, Sr Application Developer

     

     


    -dhtroy
    Monday, March 21, 2011 6:28 PM

All replies

  • Hi Douglas,

    Thanks for posting in the MSDN Forum.

    I’m not able to reproduce your issue. I download the sample from http://msdn.microsoft.com/en-us/library/ms269112(v=VS.90).aspx and I found I’m not able to save the dynamic control which generated in the document. Would you clarify how you save it?

    Have a good day,

    Tom


    Tom Xu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, March 23, 2011 11:37 AM
    Moderator
  • Tom

    The Code Example provided at the link has a bug, I posted a comment at the bottom of that page discussing how to fix it; the original code makes use of a List of KeyValuePair, which is not serializable. Once that problem is fixed, the controls will properly persist.

    Probably the simplest way would be for me to just Email you the example code I have (I'll only send code, no binaries). Is there a way I can send that to you? I have clearly commented the code where the problem exists, and I'll send you the steps to reproduce. 

    Outside of that, the way I save is as follows:

    When just saving the document template that the user has designed, when the "OK" their changes, I quit word, telling it to save as follows:

     

     object saveChanges = Word.WdSaveOptions.wdSaveChanges;
       object originalFormat = Word.WdOriginalFormat.wdOriginalDocumentFormat;
       object routeDocument = false;
    
       try
       {
        // down cast to resolve ambiguity calling ThisApplication.Quit
        ((Word._Application)Globals.ThisDocument.Application).Quit(ref saveChanges, ref originalFormat, ref routeDocument);
       }
       catch (Exception ex)
       {
        MessageBox.Show(ex.Message, "Save Error",
         MessageBoxButtons.OK, MessageBoxIcon.Stop);
       }
    

     

    That works just fine. However, when the user is creating a new document from that template, that's where I have the problem. I save the document using SaveAs as follows:

     

    Object FileName = @"c:\__Test__\VstoTest.docx";
       Object FileFormat = Word.WdSaveFormat.wdFormatXMLDocument; // save in DOCX format
       Object LockComments = System.Type.Missing;
       Object Password = System.Type.Missing;
       Object AddToRecentFiles = false;
       Object WritePassword = System.Type.Missing;
       Object ReadOnlyRecommended = System.Type.Missing;
       Object EmbedTrueTypeFonts = System.Type.Missing;
       Object SaveNativePictureFormat = System.Type.Missing;
       Object SaveFormsData = System.Type.Missing;
       Object SaveAsAOCELetter = System.Type.Missing;
       Object Encoding = System.Type.Missing;
       Object InsertLineBreaks = System.Type.Missing;
       Object AllowSubstitutions = System.Type.Missing;
       Object LineEnding = System.Type.Missing;
       Object AddBiDiMarks = System.Type.Missing;
    
       Globals.ThisDocument.SaveAs(ref FileName, ref FileFormat, ref LockComments, ref Password, ref AddToRecentFiles, ref WritePassword, 
        ref ReadOnlyRecommended, ref EmbedTrueTypeFonts, ref SaveNativePictureFormat, ref SaveFormsData, ref SaveAsAOCELetter, ref Encoding, 
        ref InsertLineBreaks, ref AllowSubstitutions, ref LineEnding, ref AddBiDiMarks);
    
    

     

    If I just quit word immedately after that SaveAs, telling word NOT to save on exit, then when the document is reopened, the persisted WinForm controls will not properly insert back into the document. So if I do this, it does not work:

     

     object saveChanges = Word.WdSaveOptions.wdDoNotSaveChanges;  // NOTE: if this is set to wdSaveChanges the Range Exception is not thrown
       object originalFormat = Word.WdOriginalFormat.wdOriginalDocumentFormat;
       object routeDocument = false;
       ((Word._Application)Globals.ThisDocument.Application).Quit(ref saveChanges, ref originalFormat, ref routeDocument); 
    

     

     

    Like I said, i will gladly send you the code example I wrote up, if you want me to.

     

    Thank you for your help.

     

    EDIT: something I did not reiterate in this post, that I explained in my original post, is that I have a native Word frame above the WinForm control in this example. The to code to create that frame is as follows:

     // get the current insert selection
    Word.Selection wordSelection = Globals.ThisDocument.ThisApplication.Selection;
    Word.Frame frame = Globals.ThisDocument.Frames.Add(wordSelection.Range);
    // set some default frame properties
    frame.LockAnchor = false;
    frame.TextWrap = false;
    // inject the mergetag into the frame (this is where the image will be insert later)
    Globals.ThisDocument.MailMerge.Fields.Add(frame.Range, mergetag);

     


    -dhtroy
    • Edited by Douglas H. Troy Wednesday, March 23, 2011 6:27 PM Added more details
    Wednesday, March 23, 2011 3:19 PM
  • I have discovered a workable solution to my problem outlined in the posts above, I am going to share that solution here along with some other oddities I discovered:

     

    In my original post, I explained that I was able to create a test Document Level Add-in with which to reproduce the issue, and that I was able to “fix” said problem by saving the Document twice: doing a SaveAs from the Document Template and then upon Application.Quit telling it to save again, passing the wdSaveChanges parameter. This did not work on my deployed solution, however, much to my surprise and dismay.

     

    The only difference remaining between my test application and deployed solution is that with our deployed solution I target the x86 processor, since we use several 32-bit external database drivers, whereas my test program is defaulted to AnyCPU. Again, I wouldn’t expect the Save functionality to change what-so-ever between targeting x86 verse AnyCPU, especially considering that I am on a Windows XP 32-bit install running, obviously, a 32-bit version of Office 2007. But apparently it does matter, because if I take our deployed application and build it to target AnyCPU, my solution works; if I target x86, doesn’t matter which save method I use, I get Index out of Range.

     

    Hopefully one of you Microsoft types will pass this information along to the VSTO development team, because something isn’t right somewhere in the VSTO/Word chain. Again, I will gladly supply source code example that reproduces this problem at will, just send somewhere to send it.

     

    So, summing up: solution – targeting AnyCPU, doing a SaveAs() and Save() resolve the problem under Office 2007. I still have to retest this all under Office 2010, but at least this is progress of some kind.

     

     


    -dhtroy
    Thursday, March 24, 2011 4:44 PM
  • Hi Douglas,

    I found I take a mistake on this issue. I ran the demo http://msdn.microsoft.com/en-us/library/ms269112(v=VS.90).aspx under Office 2003, so I get incorrect result. When I ran it under Office 2007 or Office 2010, it works fine. I ran it under Office 2007, windows xp sp3, Visual Studio 2008 and Office 2010, Windows 7, Visual Studio 2010. And I’m not able to reproduce your issue on my side. Would you please tell me your operation system’s information to me for reproduce it?

    Have a good day,

    Tom


    Tom Xu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Monday, March 28, 2011 11:06 AM
    Moderator
  • Tom

    Here is the information you requested:

     

    Windows XP SP3 with all of the latest Security Updates installed (for both windows and office). Office 2007 (12.0.6545.5000) SP2 MSO (12.0.6545.5004). Visual Studio 2008 with .NET 3.5 SP1 installed. While language should not matter, I'm using C#.

    Order of operations to reproduce this:

    Using a VSTO Document-Level DOTX programmatically add a Frame control, within that control a merge field. Press ENTER to move to next line. Insert a Custom WinForm control. Save the template.

    Create a new document from that template. When that document opens, the merge field is replaced with an image. Do a SaveAs on that document, saving it as a DOCX. Quit Word telling it NOT to save on exit (since you just did a SaveAs you should not have to save the document a second time)

    Now open that saved DOCX, and you'll get an index out of range. 


    -dhtroy
    Wednesday, March 30, 2011 2:25 PM
  • Hi Douglas,

    This is my video which record my reproduce steps, would you tell the different between us?

    http://cid-bfdf05e934413519.office.live.com/self.aspx/Sample%20Code%20for%20MSDN%20Forum/myVideo.mp4

    Have a good day,

    Tom


    Tom Xu [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, March 31, 2011 11:55 AM
    Moderator
  • Tom

    Thank you for the response; I had an emergency come up so I have been away for a few days. I will review the video you made and get back with you late today.

     

    Thank you again for your continued interest in this problem,

    D.

     

    [edit]

     

    Tom

     

    I reviewed the video you made, thank you for taking the time to do that, however, what you are doing isn't going to reproduce the problem. While I started with that Example program, I have extended (as I mentioned in my posts from above) to allow a user to insert a Frame control, with a MergeField tag inside that control, and then a Custom WinForm control below that.

    The user then saves that template design (DOTX), and then opens a new document from that template; at which point an image is programmatically inserted into the bounds of the frame control, replacing the merge field, the document is then saved as a DOCX. When the user opens that saved DOCX document, it is at that point we're seeing an index out of range.

    I am going to make a video tonight, as you did, showing the code and steps to recreate. I'll post the video along with the code, as you did, and then post the link back here once I've done that.

    Thank you again for taking your time to review this.

     

     


    -dhtroy
    • Edited by Douglas H. Troy Wednesday, April 6, 2011 1:48 PM Follow-up to my reply
    Wednesday, April 6, 2011 1:12 PM