multiple windows again and again

So,

I get this strange error once again. Please give some directions what is the cause of it and how it can be circumvented.

I create Word project drag some bookmark controls from my data source and then I create an Actions pane with Binding navigator control in it. The Binding navigator controls is bound to the binding source of the bookmark controls in Word document. Just for the sake of concept proof I make my dataset to be Cached and public also. I build the project and close VS.NET IDE. Then I open the Word document from bin folder load the dataset from database, save the document and close MS Word. After that I stop the SQL Server just to make sure that my dataset is really cached and the data can be used offline. Then I open the .doc file again. But - no luck. The dreaded error is still here:

"You are currently viewing this document in multiple windows. To attach an XML expansion pack, you must first close all additional windows so that you are viewing the document in only one window."

Please let me know how to proceed and resolve this issue.

Thanks,

Martin Kulov

http://www.codeattest.com/blogs/martin

[2477 byte] By [MartinKulov] at [2008-2-22]
# 1
Hey Martin,

I think the problem will go away if you will not use the tools to data-bind your dataset to the bookmark, but would rather do the data-binding manually after you have already shown the ActionsPane in the ThisDocument_Startup method.

I am following your posts to this forum and I see you go through a lot of pain with this and no one so far gave you any explanation on what is going on. So I will try to help you understand what is really happening.

In Word it is possible to view the same document in multiple windows (just open a new document and choose either Split or New Window in the Window menu). However, Word does not allow displaying the Document Actions Task Pane when document is being viewed in several windows. Also notice that Document Actions Task Pane would only appear if there is a SmartDoc solution attached to the document. ActionsPane utilizes the Document Actions Task Pane and is built on top of the SmartDoc infrastructure. VSTO under the covers attaches a Microsoft ActionsPane SmartDocument solution to the document when ActionsPane.Control.Add(somecontrol) is called. This triggers Word's SmartDoc initialization logic. This logic checks whether document is currently opened in multiple winows and ,if it is, smart doc initialization fails. But you did not do anything that would have mulitple windows for this document, right? The reason for the failure is that there are few operations in Word (and modifying a text in the bookmark is one of those operations) that create some auxiliary windows that are intenrally linked to the Word document. Normally, those windows should not be exposed to the end-user, but the smart doc initialization incorrectly accounts this auxiliary windows for the real ones. This is a bug and as much as we wanted in VSTO to workaround this bug we could not have done it in all the situations. I would not list here all the possible scenarios that would lead to the creation of the auxiliary windows. It should suffice to say that we made Word aware of the problem and Office SP2 should contain a fix for this bug.

There is something in the user code you could do though to workaround this.
The solution is to force the initialization of the smart document solution in an earlier stage - before those auxiliary windows are created.

If you use the visual tools to databind cached datasets to a bookmark the text in the bookmark will be changed prior to ThisDocumen_Startup call and hence the auxiliary window will be created before you have any chance to force ActionsPane initialization. Hence, I suggest to do databinding to bookmarks manually in ThisDocument_Startup event (you can look at ThisDocument.designer.cs file to see the code the designer is generating and do similar stuff).

Now, there is one more scenario when this technique fails. And this is when you add SmartTags into the picture. This is because when SmartTags are used VSTO runtime will reload all the SmartTags objects (and its cousine SmartDocs objects) after ThisDocument_Startup completes. This causes the SmartDocs to be re-initialized after you have already created all the auxiliary windows. In this case the below workaround worked for me OK. I highlighted the tricky part. Here I am actually exposing some of the VSTO SmartTags implementation details that are not guaranteed to work in the final version VSTO 2005 - so use with caution.

Hope this helps.
Misha

using System;

using System.Data;

using System.Drawing;

using System.Windows.Forms;

using Microsoft.VisualStudio.Tools.Applications.Runtime;

using Word = Microsoft.Office.Interop.Word;

using Office = Microsoft.Office.Core;

using Microsoft.Office.Tools.Word;

using Microsoft.Office.Interop.SmartTag;

using System.Runtime.InteropServices;

using System.Runtime.InteropServices.ComTypes;

namespace WordDocument8

{

public partial class ThisDocument

{

private void ThisDocument_Startup(object sender, System.EventArgs e)

{

SmartTag st = new SmartTag("moo#moo", "Moo");

st.Terms.Add("Foo");

st.Terms.Add("Bar");

st.Actions = new Action[] { new Action("Dummy action") };

this.VstoSmartTags.Add(st);

this.ActionsPane.Controls.Add(new Button());

this.ActionsPane.Controls.Add(new TextBox());

ISmartTagSite site = this.RuntimeCallback.GetService(typeof(ISmartTagSite)) as ISmartTagSite;

site.ResumeReload();

site.SuspendReload();

site.SuspendReload();

moo.Text = "GMMM";

}

private void ThisDocument_Shutdown(object sender, System.EventArgs e)

{

}

}

[

ComImport,

Guid("8b189642-3252-4214-b153-87fcdb178e75"),

InterfaceType(ComInterfaceType.InterfaceIsIUnknown)

]

internal interface ISmartTagClient

{

string SmartTagType { get; }

string Caption { get; }

int ActionsCount { get; }

string GetActionCaption(int idx, string Text, ISmartTagProperties properties, [In, MarshalAs(UnmanagedType.IUnknown)] object range);

void OnRecognize(string Text, ISmartTagRecognizerSite site, ISmartTagTokenList tokens);

void OnExecute(int idx, string Text, ISmartTagProperties properties, [In, MarshalAs(UnmanagedType.IUnknown)] object range);

}

[

ComImport,

Guid("c84484f6-52d3-46c7-857c-2fef0564e989"),

InterfaceType(ComInterfaceType.InterfaceIsIUnknown)

]

internal interface ISmartTagSite

{

void Add([In, MarshalAs(UnmanagedType.Interface)] ISmartTagClient smartTagClient);

void Remove([In, MarshalAs(UnmanagedType.Interface)] ISmartTagClient smartTagClient);

void RemoveAll();

void SuspendReload();

void ResumeReload();

}

}

MishaShneerson at 2007-9-8 > top of Msdn Tech,Visual Studio Tools for Office,Visual Studio Tools for Office...
# 2

Thanks a lot Misha,

I got it and it makes much more sense now.

I need this for a presentation tomorrow and my primary goal was to show drag and drop coding Big Smile

I will have to find some other ways to do it.

I hope you can fix this in future releases.

Thanks again,

Martin Kulov

http://www.codeattest.com/blogs/martin

MartinKulov at 2007-9-8 > top of Msdn Tech,Visual Studio Tools for Office,Visual Studio Tools for Office...
# 3

Hi Misha,

It worked like a charm.
I got very frustrated in 2am trying to convert this code to VB.NET. I am not a casual VB dev, but I had to make my presentation in VB. So I am posting your code translated to VB.NET so others can save some time.
BTW: the most frustrating part was trying to find VB equivalent of "typeof" in C#. It happend to be "GetType", but I do not why in the world I could not find it in MSDN Library.
Here is the code in VB.NET:


Imports Microsoft.Office.Tools.Word
Imports Microsoft.Office.Interop.SmartTag
Imports System.Runtime.InteropServices
Imports System.Runtime.InteropServices.ComTypes
Imports System.Text.RegularExpressions

Public Class ThisDocument

Private WithEvents convertTime As Action

Private Sub ThisDocument_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup

Dim timeTag As SmartTag = New SmartTag("http://wwww.codeattest.com/vstodemo#timetag", _
"Time Converter")
timeTag.Expressions.Add(New Regex("(?'time'.*CET)"))

Me.convertTime = New Action("Convert to BG time")
timeTag.Actions = New Action() {convertTime}

Me.VstoSmartTags.Add(timeTag)
Me.RecheckSmartTags()

ActionsPane.Controls.Add(New ProductInfoPane)

Dim smartTagSite As ISmartTagSite = CType(Me.RuntimeCallback.GetService(GetType(ISmartTagSite)), ISmartTagSite)
smartTagSite.ResumeReload()
smartTagSite.SuspendReload()
smartTagSite.SuspendReload()

End Sub

<ComImport(), Guid("8b189642-3252-4214-b153-87fcdb178e75"), _
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Friend Interface ISmartTagClient
ReadOnly Property SmartTagType() As String
ReadOnly Property Caption() As String
ReadOnly Property ActionsCount() As Integer
Function GetActionCaption(ByVal idx As Integer, ByVal Text As String, ByVal properties As ISmartTagProperties, <[In](), MarshalAs(UnmanagedType.IUnknown)> ByVal range As Object) As String
Function OnRecognize(ByVal Text As String, ByVal site As ISmartTagRecognizerSite, ByVal tokens As ISmartTagTokenList)
Function OnExecute(ByVal idx As Integer, ByVal Text As String, ByVal properties As ISmartTagProperties, <[In](), MarshalAs(UnmanagedType.IUnknown)> ByVal range As Object)
End Interface


<ComImport(), Guid("c84484f6-52d3-46c7-857c-2fef0564e989"), _
InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Friend Interface ISmartTagSite
Function Add(<[In](), MarshalAs(UnmanagedType.Interface)> ByVal smartTagClient As ISmartTagClient)
Function Remove(<[In](), MarshalAs(UnmanagedType.Interface)> ByVal smartTagClient As ISmartTagClient)
Function RemoveAll()
Function SuspendReload()
Function ResumeReload()
End Interface

End Class



MartinKulov at 2007-9-8 > top of Msdn Tech,Visual Studio Tools for Office,Visual Studio Tools for Office...
# 4

This is great. Thanks for posting the VB version.

MishaShneerson at 2007-9-8 > top of Msdn Tech,Visual Studio Tools for Office,Visual Studio Tools for Office...