Problem: We need to display HTML documents in our windows forms application targeting ..NET Framework version 2.0 (build 50727). We are using MSHTML (mshtml.dll, version 6.00.2900.2802 (xpsp_sp2_gdr.051123-1230)) and the Web Browser control (shdocvw.dll, version 6.00.2900.2805 (xpsp_sp2_gdr.051130-1554)) to load and process the HTML documents. The user is allowed to select an arbitrary piece of text and tag it (annotate). Since more than one user can work simultaneously on the document the annotation/tagging related details can not be immediately saved in the HTML document. Whenever the same document is opened the next time we need to display the tags captured earlier (during the previous run) with some highlighting. We also need to handle events on such markup to allow the user to see the details of annotation. We add an Anchor across the snippet selected by the user. The anchor allows us to register event-handlers which provide the above required functionality of highlighting etc. (for example changing the background color on mouseover). Since the details of the snippet mark-up can not be saved in document immediately we save the rendered character position (start and end offset of the snippet) in a database such that they can later be retrieved when loading the document again and used to highlight the snippet during the next user session. The problem is that the character offsets obtained are not same and consistent across multiple sessions and thus our highlighting / snippet identifying goes wrong. Implementation detail a.. To obtain the rendered character position of the selected text in the browser control window, we use IHTMLTxtRange. Following steps are involved: 1. From the "HTML selection object" create a "Range object" (instance of IHTMLTxtRange) 2. Use the moveStart and moveEnd methods to move the selection end points by maximum number of characters like range.moveStart("character" -0x7FFFFFFF). 3. This call SHOULD return the actual number of characters that can be moved which indicates the offset of the first rendered character. 4. A similar method is used and moveEnd is invoked to get the offset of the last rendered character of the selection. a.. Highlighting the snippet using the saved character offsets that were obtained using the steps identified above. When re-opening the document in the application the character offsets saved in database are read and using the IHTMLTxtRange a corresponding range is created. Following are the steps: 1. Get the body element of the document (IHTMLBodyClass) 2. Create a range form the body by using the createTextRange method 3. Move the range to the start character offset using the move method of the IHTMLTxtRange. 4. Move the end of the range by number of characters corresponding to the length of the snippet using the moveEnd method of the IHTMLTxtRange. This SHOULD result in a range corresponding to the selection the user had done in previous sessions. 5. On the range object thus created we use the execCommand method with command identifier as "CreateBookmark". 6. On the anchor element that is created by the above steps, we register events like mouse over, click etc. for further processing. There are two variations of the above methods where-in we do not try to identify the snippet using the absolute character positions but do it based on the relative position of the previously marked snippet. Other relevant information: - We never re-size browser control window on the form. - The problem is not always reproducible. 85% of the times the saved character positions can be re-obtained without any discrepancies. - The actual physical HTML document is never modified. - We have observed that Range shifting happens many times when we add a couple of anchors and <font> tags (in-memory) to documents. - If the selected range ends with special html tags such as a <P> or a <Table> tag then invoking the method Range.MoveEnd("character", -1) does not change Range.Text. Hereafter Range.Select() still shows the same selection on the screen. Getting bookmarks this way changes the offset by 1 (even if it has no effect on the rendered text). In the absence of pre-processing prior to obtaining the bookmarks, the range shifting occurs. - The range shifting problem is only observed when the current session is closed after snippet captures, and the saved snippets are used for highlighting the captured ranges.