HoganRich

Hi

I have written a word addin in VSTO 2005 which when loads adds a custom toolbar

to word. This allows users to load template document, with a custom action pane.

This part works fine. However when users save a document, and subsequenlty re-

load it, or send it to someone else, the document produces an error due to it

looking for the application manifest\customisation DLLs (I think).

I have written some code on my action pane control to strip the document of any

customisation when it is saved (see below). which works fine.

Imports W = Microsoft.Office.Tools.Word

Private ThisDoc As W.Document

Public Function SaveDoc() As Boolean

Try

ThisDoc.RemoveCustomization()

ThisDoc.XMLSchemaReferences.Item("ActionsPane").Delete()

ThisDoc.SaveAs(_FileName)

Return True

Catch ex As Exception

Return False

Finally

End Try

End Function

Unfortunately the users want this on the toolbar:-) and when I try to get this to run

from the there it does not work, firstly I get a implicit conversion error and

secondly the customisation is not removed. does anybody have an idea why

Cheers Richard



Re: Visual Studio Tools for Office VSTO - Removing document customisation

Cindy Meister

Hi Richard

Well, to start with you don't show us how you assign the document object to ThisDoc. But as I understand it, RemoveCustomization can run only within the VSTO document. So you might want to create a toolbar just for the VSTO project. Or have you add-in save, close and use the ServerDocument functionality remove the customization from the closed document. Then re-open it again, if the user wants to continue working with it.

Another possibility would be to have VSTO add the button to the toolbar (and remove it). Since the CustomizationContext should be the VSTO document, itself, the button should only be visible when in the VSTO document. The trickiest part could be removing the button when the customization is removed from the document.






Re: Visual Studio Tools for Office VSTO - Removing document customisation

HoganRich

Thanks for your response.

In answer to your first question you can see the code below:

'Actions Pane Constructor

Public Sub New(ByRef ThisDocument As W.Document)

InitializeComponent()

' Add any initialization after the InitializeComponent() call.

cDocs.GetUserCredentials()

PopulateCombos(Me.cboSelectPartner, cDocs.GetPartners)

Me.cboSelectPartner.Text = cDocs.DefaultUserCode

ThisDoc = ThisDocument

End Sub

'Document Template Start Up Code

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

ucActionPane = New TaskPane(Me)

Me.ActionPane.Controls.Add(ucActionPane)

If Me.ProtectionType = Word.WdProtectionType.wdNoProtection Then

Me.Protect(Word.WdProtectionType.wdAllowOnlyFormFields, False

End If

Me.Tag = "Agreement Header"

Me.ActiveWindow.View.Type = Word.WdViewType.wdPrintView

End Sub

Anyway, I have tried using the ServerDocument functions, but initially I was getting a lock violation error, and when I found a work-

around it did not remove the customisation or the attached XML, it did not crash or throw any errors but the customisation was still

there. I did think that this may have been because the document is protected, but I changed this and it did not seem to make any

difference.

As to creating another toolbar, I would prefer to only present one toolbar to the end users, and this needs to be visible regardless of

whether a VSTO based document is currently loaded, however if the only way to do this is too progromaticalloy add a button to this at

runtime then perhaps this is a the way to do it. Unfortunately this project contains 50+ documents, would I need to add this toolbar

button to each document and if so how would this be done

Thanks Richard





Re: Visual Studio Tools for Office VSTO - Removing document customisation

Cindy Meister

<<Unfortunately this project contains 50+ documents, would I need to add this toolbar

button to each document and if so how would this be done >>

You mean you have 50+ VSTO documents, each with its own code base And you'd rather not open each of them to make this change

You could create a managed code DLL to contain any shared functionality, then have each of them call into that You just have to make sure it's fully trusted (same as the VSTO projects).






Re: Visual Studio Tools for Office VSTO - Removing document customisation

HoganRich

Hi Cindy

Thanks for your response.

I have got a class library which is used to manage a majority of the functionaliy of both the VSTO documents and the addin code (for the toolbar). However if I add the code to remove the document customisation to the class I get the same error I get when the code is in the addin module (i.e. implicit conversion errors and ServerDocument not removing customisation). So I may not have much choice, but to try and run this command from within the VSTO docs, or to add a toolbar button (if I can work out how to do this:-)).

Thanks Richard





Re: Visual Studio Tools for Office VSTO - Removing document customisation

Cindy Meister

I actually meant to put the code that adds the toolbar button into the dll. But yes, you'd have to have the object and the event handler in the VSTO solution. So maybe it would be just as quick to add it all to the VSTO solution... How about if you put it all in a separate, partial class, then all you'd need to do is import the class Insert a single line of code in the Startup procedure that calls the code to create the button. You should even be able to do it directly in the files, without needing to open Visual Studio

If you put creating the button "outside" the VSTO solution, then you need to be careful to set the CustomizationContext = this.InnerObject (Me.InnerObject) so that the button is specific to the VSTO document. (By default, Word will probably try to put it in Normal.dot). Pass InnerObject to the method as an argument of the Word.Document variable type.






Re: Visual Studio Tools for Office VSTO - Removing document customisation

HoganRich

Hi Cindy

I have added some code to my document which adds a commandbar button and the code which handles the click event (see below).

Private Sub AddCommandButton()

MyCommandBar = ThisApplication.CommandBars("SDT - Pitmans Tools")

SaveButton = MyCommandBar.Controls.Add(Office.MsoControlType.msoControlButton, Temporary:=True)

With SaveButton

.BeginGroup = True

.Caption = "&Save && Close"

.FaceId = 2649

.Visible = True

End With

AddHandler SaveButton.Click, AddressOf SaveDoc

End Sub

Private Sub SaveDoc(ByVal ctrl As CommandBarButton, ByRef Cancel As Boolean)

Try

Me.RemoveCustomization()

Me.XMLSchemaReferences.Item("ActionsPane").Delete()

Me.Save()

Me.Close()

Catch ex As Exception

Finally

End Try

End Sub

This works fine, apart from if a document or another VSTO document is added\created duplicate buttons are added to the toolbar, which I can get around by checking if it exists before creating it. However, if more than one instance is open the click event is not fired, how can I ensure that the click event fires and it is using the correct document.

Cheers

Richard





Re: Visual Studio Tools for Office VSTO - Removing document customisation

Cindy Meister

With Word, you must consider CustomizationContext (look it up in Word's object model Help). You either add the buttons within the context of a specific document (or the template to which it is attached), or you place them in a globally loaded template. If you don't specify, the Word may put them in one place, then remove them somewhere else, or tell you it exists when, in reality it doesn't in the particular context.

So, first you must decide about the context, then specify it in your code. Currently, what you have is a lottery and chances of getting it properly under control are slim, at best.

Once you've made a decision we can discuss the details of how to properly execute it.

FWIW, you need to assign "shared" commandbar buttons in Word a TAG property if you want them to be recognized correctly. And the object variable must be declared at the class level.






Re: Visual Studio Tools for Office VSTO - Removing document customisation

HoganRich

Thanks Cindy

I think it might be best to try and describe the project and hopefully you may be able to help with the best way of actually proceeding with it.

What I need to do is have a toolbar loaded up in word, which is accessible all of the time. This toolbar gives the users the option to load various document templates (the toolbar structure is stored in a SQL database, and the contents will vary depending on the users location and rights). It also currently contains commands for printing, saving and closing documents.

At the moment the toolbar is being created by an addin (created in VSTO), and apart from the Save and Close button (as this needs to remove the customisation) works fine. As stated this toolbar needs to be visible and working regardless of what they are currently using word for. However, It does not necessarily have to display all of the buttons all of the time. As some of the buttons, i.e. print, save and close etc... are only relevant to the VSTO Docs.

The document templates are relatively straight forward protected form field documents, the only slight complication is that each document loads an action pane which allows the users to add information from a CRM style database i.e. addresses, telephone numbers etc¡­

To be honest this is my first attempt to develop a word solution using VSTO, as you can probably tellJ so any assistance would be appreciated.

Cheers

Richard





Re: Visual Studio Tools for Office VSTO - Removing document customisation

Cindy Meister

Hi Richard

If I were designing this from scratch, I'd probably say distribute an additional template with the "solution" (thinking of the entirety). Have your VSTO COM-Add-in load this template as a template Add-in (see the Addins collection of the Word object model) so that everything in that template is available to all documents. Create and save the CommandBar in that template (you can use Tools/Customize for that, if you like). That will save your code needing to create it, and also save you the question about WHERE it's stored (you don't interfere with the user's Normal.dot)

.

Let your COM Add-in add the non-VSTO-specific buttons to it, as required, same as you're doing now except set the CustomizationContext to this template object. (Once you've loaded the template addin you should be able to access it over the Templates collection.)

Then you have a choice:

- add the document-specific buttons as required, on a per-document-basis

- add one button for VSTO documents, only, making sure you hook up the Click event only once (track it with a global variable)

In either case, you want to check what kind of document and make the button(s) visible accordingly. Here's a simplified code sample (missing most of the exception handling, for example) that uses the first approach. Note the generic List and the Class that handle the set of opened VSTO documents.

Code Snippet

Imports Word = Microsoft.Office.Interop.Word
Imports Office = Microsoft.Office.Core

Public Class ThisAddIn

Dim cb As Office.commandBar
Dim btnAll As Office.CommandBarButton
Dim btnDoc As Office.CommandBarButton
Dim ad_in As Word.AddIn
Dim addinTemplate As Word.Template
Dim VSTODocList As System.Collections.Generic.List(Of VSTO_Docs)

Private Sub ThisAddIn_Startup(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Startup
Try
ad_in = Me.Application.AddIns.Add("C:\VS-Projekte\Buch\TestAddin.dot", True)
addinTemplate = Me.Application.Templates(ad_in.Path & "\" & ad_in.Name)
Me.Application.CustomizationContext = addinTemplate
cb = Me.Application.CommandBars("Add-in Test")
btnAll = cb.Controls.Add(Type:=Office.MsoControlType.msoControlButton)
With btnAll
.Caption = "Click me"
.Tag = "TestAdd-in"
.Visible = True
.Style = Microsoft.Office.Core.MsoButtonStyle.msoButtonCaption
End With
AddHandler btnAll.Click, AddressOf TestbtnAll_Click

addinTemplate.Saved = True
VSTODocList = New System.Collections.Generic.List(Of VSTO_Docs)
Catch ex As Exception
MessageBox.Show(ex.Message)

End Try
End Sub

Private Sub TestbtnAll_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, _
ByRef CancelDefault As Boolean)

MsgBox("Button in all documents")
End Sub

Private Sub btnDoc_Click(ByVal Ctrl As Microsoft.Office.Core.CommandBarButton, _
ByRef CancelDefault As Boolean)

MsgBox(Me.Application.ActiveDocument.FullName & vbCr & Ctrl.Tag)
End Sub

Private Sub ThisAddIn_Shutdown(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Shutdown
Me.addinTemplate.Saved = True
End Sub

Private Sub Application_DocumentBeforeClose(ByVal Doc As Microsoft.Office.Interop.Word.Document, ByRef Cancel As Boolean) Handles Application.DocumentBeforeClose

'Check if it's a VSTO document, retrieve which one and remove the button
Dim shp As Word.Shape
If Doc.Shapes.Count > 0 Then
For Each shp In Doc.Shapes
If Me.IsVSTODocument(shp) Then
Dim vstodoc As VSTO_Docs
Dim item As Integer
Dim itemsCount As Integer = VSTODocList.Count
For item = 0 To itemsCount - 1
vstodoc = VSTODocList(item)
If vstodoc.Doc Is Doc Then
vstodoc.Btn.Delete()
VSTODocList.Remove(vstodoc)
Exit For
Else
vstodoc.Btn.Visible = False
End If
Next
End If
Me.addinTemplate.Saved = True
Next
End If
End Sub

Private Sub Application_DocumentChange() Handles Application.DocumentChange
Dim doc As Word.Document = Me.Application.ActiveDocument
Dim docName As String = doc.FullName
Dim shp As Word.Shape
Dim btn As Office.CommandBarButton

'Hide all VSTO buttons, first
For Each btn In cb.Controls
If btn.Parameter.Contains("VSTO") Then btn.Visible = False
Next

'Now check whether it's a VSTO document, retrieve which one and make its button visible
If doc.Shapes.Count > 0 Then
For Each shp In doc.Shapes
If Me.IsVSTODocument(shp) Then
Dim vstodoc As VSTO_Docs
Dim item As Integer
Dim itemsCount As Integer = VSTODocList.Count
For item = 0 To itemsCount - 1
vstodoc = VSTODocList(item)
If vstodoc.Doc Is doc Then
vstodoc.Btn.Visible = True
Exit For
Else
vstodoc.Btn.Visible = False
End If
Next
End If
Me.addinTemplate.Saved = True
Next
End If
End Sub

Private Sub Application_DocumentOpen(ByVal Doc As Microsoft.Office.Interop.Word.Document) Handles Application.DocumentOpen
Me.CreateVSTODocButton(Doc)
End Sub

Private Sub Application_NewDocument(ByVal Doc As Microsoft.Office.Interop.Word.Document) Handles Application.NewDocument
Me.CreateVSTODocButton(Doc)
End Sub

Private Function IsVSTODocument(ByVal shp As Word.Shape) As Boolean
If shp.OLEFormat.ClassType.Contains("VSTO.RuntimeStorage") Then
Return True
Else
Return False
End If
End Function

Private Sub CreateVSTODocButton(ByVal doc As Word.Document)
'If it's a VSTO document, add the button, add the document to the List
Dim shp As Word.Shape
If doc.Shapes.Count > 0 Then
For Each shp In doc.Shapes
If Me.IsVSTODocument(shp) Then
Me.Application.CustomizationContext = doc
btnDoc = cb.Controls.Add(Type:=Office.MsoControlType.msoControlButton)
With btnDoc
.Caption = "Button in doc"
.Parameter = "VSTO"
.Tag = Replace(doc.FullName, " ", "_")
.Style = Microsoft.Office.Core.MsoButtonStyle.msoButtonCaption
End With

AddHandler btnDoc.Click, AddressOf btnDoc_Click

Dim vstoDoc As VSTO_Docs = New VSTO_Docs(doc, btnDoc)
VSTODocList.Add(vstoDoc)
Me.addinTemplate.Saved = True
Exit For
End If
Next
End If
End Sub

End Class

Class VSTO_Docs
Private m_doc As Word.Document
Private m_btn As Office.CommandBarButton

Public Sub New(ByVal newDoc As Word.Document, ByVal newBtn As Office.CommandBarButton)
m_doc = newDoc
m_btn = newBtn
End Sub

Public ReadOnly Property Doc() As Word.Document
Get
Return m_doc
End Get
End Property

Public ReadOnly Property Btn() As Office.CommandBarButton
Get
Return m_btn
End Get
End Property
End Class






Re: Visual Studio Tools for Office VSTO - Removing document customisation

HoganRich

Hi Cindy

Thanks for this, I really appreciate the effort you went to.

I have implmeneted a version of the code you posted and it works perfectly, apart from I still can¡¯t remove the customisation from the documents.

I have tried the code shown below, but it does not appear to remove the XMLSchemaReference,

Code Snippet

Try

Me.Application.ActiveDocument.XMLSchemaReferences.Item("ActionsPane").Delete()

Me.Application.ActiveDocument.Save()

Dim strPath As String = Me.Application.ActiveDocument.Path & "\" & Me.Application.ActiveDocument.Name

If strPath = "" Then Exit Sub

Me.Application.ActiveDocument.Close(True)

If (ServerDocument.IsCustomized(strPath)) Then

ServerDocument.RemoveCustomization(strPath)

End If

Dim sd As ServerDocument = Nothing

Try

sd = New ServerDocument(strPath)

sd.AppManifest.Clear()

sd.Save()

Catch ex As Exception

Finally

sd.Close()

End Try

Finally

End Try

With this code when I re-open a saved document I get a ¡°The supplied application manifest is not valid.¡± Error, any ideas

Cheers

Richard





Re: Visual Studio Tools for Office VSTO - Removing document customisation

Cindy Meister

Hi Richard

Sorry about the delayed response, I was away for a few days.

The following works for me

Me.RemoveCustomization()
ActionsPane.Clear()
Me.XMLSchemaReferences("ActionsPane").Delete()

Note that this leaves a custom document property named "Solution ID" in the document so that the document will pick up the VSTO solution whenever it's present. If you want to fully remove the VSTO reference you can delete that property then link the document to a different template (usually NormalTemplate).






Re: Visual Studio Tools for Office VSTO - Removing document customisation

HoganRich

Hi Cindy

Thanks for your reply, I think I was being a bit thick:-)

I had this code in the toolbar button, which wasn't working, but I just moved the code to the VSTO documents,

ThisDocument_BeforeSave procedure and ran it from there and it worked fine.

Thanks for all you help.

Cheers

Richard