none
Accessing HeaderFooter.Range leaves header/footer open (VSTO, .NET, Word) RRS feed

  • Question

  • Hi,

    we have an addin which lets the user put a textbox with a string into the header on every page.

    The problem is if you access HeaderFooter.Range or .Shape the header gets activated but will not be deactivated anymore after you accessed it.

    This is apparent if you have the page margin set to 0 and header / footer also to 0.

    So to reproduce:

    - Create a document with no margin and no header and footer height.

    Write something into the first line to see the header later.

    Save the doc.

    Create an addin with the following code.

    private void ThisAddIn_Startup(object sender, System.EventArgs e)
            {
                Globals.ThisAddIn.Application.DocumentOpen += new Word.ApplicationEvents4_DocumentOpenEventHandler(Application_DocumentOpen);
            }
            void Application_DocumentOpen(Word.Document doc)
            {
                foreach (Word.Section section in doc.Sections)
                {
                    foreach (Word.HeaderFooter header in section.Headers)
                    {
                        var rng = header.Range;
                    }
                }
            }

    and open the label document.

    You see a small header on top of the page which comes from activating the header.Range but word does not deactivate it after accessing.


    Is there a possibility to close the header after accessing it?

    Thank you very much

    Best regards

    Mark


    Regards Mark




    • Edited by Wompi Thursday, August 27, 2015 2:30 PM
    Thursday, August 27, 2015 2:19 PM

Answers

  • Hi,

    here's a short summary to close this issue:

    To close the header/footer after accessing you have to:

    - Marshal.ReleaseComObject all used objects in header/footer

    - Set the seek view

    here's a good introduction for releasing com objects: http://jake.ginnivan.net/vsto-com-interop/

    and use for instead of foreach as foreach leakes.

    see the example code for more infos.

    It is possible to use textboxes in the header but you can't use an anchor as it seems that the anchor object leaks and after this you cannot close the header.

    To delete all textboxes we run through ShapeRange collection.

    There are the same rules. Clean up every object you use, change the seek view and the header closes.


    Regards Mark

    • Marked as answer by Wompi Friday, September 4, 2015 9:02 AM
    Friday, September 4, 2015 9:01 AM

All replies

  • Hi Mark,

    What’s the version of your office, it seems that I can’t reproduce that issue.

    For this issue, I think you could change SeekView property.

    this.ActiveWindow.ActivePane.View.SeekView = Word.WdSeekView.wdSeekMainDocument;

    Regards

    Starain


    We are trying to better understand customer views on social support experience, so your participation in this interview project would be greatly appreciated if you have time. Thanks for helping make community forums a great place.
    Click HERE to participate the survey.

    Friday, August 28, 2015 7:05 AM
    Moderator
  • Hi Starain,

    thank you very much for your answer.

    I tried to set the property but nothing changed.

    I tried this issue with Word 2007 SP3 and Word 2013 but I saw that on Word 2013 to reproduce this issue is a bit different.

    - First create the doc with no margin and no header / footer. I have put a prepared doc here: https://secure-filexchange.com/hvs-consulting/Download.aspx?id=807e3e81-616b-4496-8eb5-ca80cd25c0eb-25cd27c6d050981c

    It should look like here:

    The difference in Word 2013 is:

    - first open Word

    - and then File -> Open -> Open the document.

    Now you should see a small header which you cannot close.

    This happens if you access HeaderFooter.Range or HeaderFooter.Shape. If there is a possibility to close / deactivate the header this would be great.

    Thank you very much

    Mark


    Regards Mark


    • Edited by Wompi Friday, August 28, 2015 12:45 PM
    Friday, August 28, 2015 12:44 PM
  • Hi Mark

    I hesitated to answer this yesterday because this is a known behavior of Word and sometimes you can "fix" it, other times not. It depends on the version of Word and I can't remember which ones behave in what manner.

    Best, of course, would simply be to not execute querying the header/footer at all. I don't really understand why your code would do so...?

    Anyway, the header/footer aren't "open" in the sense I would understand it (activated for editing, like when the user would type in it. I believe the better term would be "initiated": As soon as Header/Footer is addressed it exists in the document. And any "document story" that exists is going to have a paragraph mark. This paragraph mark (ANSI 13) is what causes the header/footer to require space.

    As best I recall, the way to get rid of a header/Footer is to DELETE that paragraph mark, so you could TRY something like: header.Range.Delete(); No guarantees it will work, but you can try it.

    Beyond that, an approach that might be satisfactory would be to change the Header and/or Footer style. For example, you could format the Font.Size to be .5 points (smallest font size Word will accept), remove SpaceBefore and SpaceAfter from the paragraph formatting, etc. Or you could try setting Font.Hidden = True and see if that helps.


    Cindy Meister, VSTO/Word MVP, my blog

    Friday, August 28, 2015 3:08 PM
    Moderator
  • Hi Cindy,


    thank you very much for your detailed answer.

    We have a quite complex addin where there user can add/change/delete a label in the header/footer on different positions. e.g. top-left, top-center, bottom-right etc. to label the document. To not overwrite existing header/footer entries we create a textbox with headerFooter.Shape.AddTextbox so the new label is floating over existing text. If the user adds a textbox it has to be on every page in the header/footer (main, even pages and odd pages). Due to this functionality we have to access the header/footer to put the textbox in there and also delete it if the user wants it to.


    I managed to find a partial solution (at least for Word 2007, didn't try it with other versions) for all who only access the Range or Shapes in Header/footer.

    You have to release all com objects you work with in header/footer and after this if you change the SeekView (thanks to Starain) and the header/footer closes.

    Here is a snippet.

    private void ThisAddIn_Startup(object sender, EventArgs e) { Application.DocumentOpen += Application_DocumentOpen; } private void Application_DocumentOpen(Document doc) { try { foreach (Section section in doc.Sections) { HeaderFooter headerFooter = section.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary]; Shapes shapes = headerFooter.Shapes; Range range = headerFooter.Range;

    //Do something

    Marshal.ReleaseComObject(range); Marshal.ReleaseComObject(shapes); Marshal.ReleaseComObject(headerFooter); } Application.ActiveWindow.ActivePane.View.SeekView = WdSeekView.wdSeekPrimaryHeader; Application.ActiveWindow.ActivePane.View.SeekView = WdSeekView.wdSeekMainDocument; } catch (Exception ex) { MessageBox.Show(ex.ToString()); } }



    But unfortunately this doesn't work if I add a textbox and later delete it. Then the behaviour is still the same and the header stays open after deletion. It feels like the textbox object leaks internally and cannot be released later.


    Is there any other possibilty to add textboxes to header footer e.g. StoryRanges or similar? Any thoughts on this?


    I will try further and keep you up to date if I manage to find a solution.

    -------------------------------------

    Update:

    It doesn't seem that the textbox leaks but the anchor. If I use the textbox without anchor and save the textbox object in a list and later just delete the textbox it works after changing the seekview. But if I add an anchor (Header.Range) the behaviour comes back. Even if I release the range it seems word copies the anchor internally and so it leaks.

    As far as I can remember we put in the anchor because we had problems positioning the textboxes in the header/footer. Tomorrow I will take a look if I manage to position the textboxes right without the anchor.

     foreach (Section section in doc.Sections)
                        {
                            HeaderFooter headerFooter = section.Headers[WdHeaderFooterIndex.wdHeaderFooterPrimary];
                            Shapes shapes = headerFooter.Shapes;
                            var rng = headerFooter.Range;
                            
                            textBox = shapes.AddTextbox(MsoTextOrientation.msoTextOrientationHorizontal, 0, 0, 10, 10, rng);
                            //if the range is added the behaviour persists even if we release the range later.
    
                            textBox.Delete(); //Delete the textbox to see if the behaviour persists
                            Marshal.ReleaseComObject(rng);
                            Marshal.ReleaseComObject(shapes);
                            Marshal.ReleaseComObject(headerFooter);
                        }
    
                        Application.ActiveWindow.ActivePane.View.SeekView = WdSeekView.wdSeekPrimaryHeader;
                        Application.ActiveWindow.ActivePane.View.SeekView = WdSeekView.wdSeekMainDocument;

    ----------------------------------

    Thanks all

    Best regards

    Mark



    Regards Mark





    • Edited by Wompi Monday, August 31, 2015 2:03 PM
    Monday, August 31, 2015 1:10 PM
  • Hi Mark

    <<But unfortunately this doesn't work if I add a textbox and later delete it. Then the behaviour is still the same and the header stays open after deletion. It feels like the textbox object leaks internally and cannot be released later. >>

    The only thought I have, looking at your code, would be to reverse the order in which you create and release Range vs. Shapes. A Shape must anchor to a Range so, if this approach does work, then logically you'd need to release the Shape before releasing the Range.

    FWIW, Shape objects are managed in a different document "layer" than the text (Range). In addition, the way they're stored and managed in the Header/Footer is a bit "weird". It tends to be "central" rather than specific to a StoryRange. This is just a bit of trivia and may well be affecting the behavior but I don't know exactly how.


    Cindy Meister, VSTO/Word MVP, my blog

    Monday, August 31, 2015 1:47 PM
    Moderator
  • Hi Cindy,

    thank you very much for your answer.

    I didn't see your post until I updated my answer.

    The problem seems to be the Range in the anchor. Without range it worked fine.

    I will have a look into it tomorrow.

    Thank you very much


    Regards Mark

    Monday, August 31, 2015 2:15 PM
  • Hi,

    here's a short summary to close this issue:

    To close the header/footer after accessing you have to:

    - Marshal.ReleaseComObject all used objects in header/footer

    - Set the seek view

    here's a good introduction for releasing com objects: http://jake.ginnivan.net/vsto-com-interop/

    and use for instead of foreach as foreach leakes.

    see the example code for more infos.

    It is possible to use textboxes in the header but you can't use an anchor as it seems that the anchor object leaks and after this you cannot close the header.

    To delete all textboxes we run through ShapeRange collection.

    There are the same rules. Clean up every object you use, change the seek view and the header closes.


    Regards Mark

    • Marked as answer by Wompi Friday, September 4, 2015 9:02 AM
    Friday, September 4, 2015 9:01 AM