VSTO Load On Demand - ms-word

I have a Word 2016 VSTO that I developed using VS2015 and deployed to a Windows 10 machine using InstallShield. If I set the LoadBehavior to 3 it loads and works fine.
What I need is for it load on demand. I've tried just setting LoadBehavior to 9 but no dice. The web application that is creating the Word document (that ultimately loads the VSTO) was originally written for Word 2010 and is embedding the VSTO path in the Word document with an added GUID (C:\myAddIn.vsto|GUID|vstolocal). Opening the document created by the web application in Word 2016 throws this error when the VSTO tries to load:
Microsoft.VisualStudio.Tools.Applications.Runtime.CannotCreateStartupObjectException:
Could not create an instance of startup object myAddin.ThisAddIn
Any tutorials I've seen for VS2013/2015 do not reference embedding a GUID in the VSTO path; just set the LoadBehavior to 9.
There is no Publisher listed in File -> Options ->AddIns. The VSTO is listed under Inactive AddIns which I would expect until it is loaded on demand.
Any help is greatly appreciated.

If you want code to only execute with certain documents, such as you describe (from Comments)
I only want the AddIn to load for Word documents created by the web
application. Opening Word from the Start menu should not load the
AddIn.
then it is probably better to use a document-level customization, rather than an add-in.
The code attached to a document-level customization will load with the document, and unload when the document is closed. It's possible to create a document-level customization and distribute the document, or to attach the code at a later time using VSTO's ServerDocument class.
Since in your case the documents are being generated by a web app, using ServerDocument is indicated.
Here's the main content of the MSDN article:
=============================================
To attach managed code extensions to a document
In a project that does not require Microsoft Office, such as a console application or Windows Forms project, add a reference to the
Microsoft.VisualStudio.Tools.Applications.ServerDocument.dll and
Microsoft.VisualStudio.Tools.Applications.Runtime.dll assemblies.
Add the following Imports or using statements to the top of your code file.
using Microsoft.VisualStudio.Tools.Applications;
using Microsoft.VisualStudio.Tools.Applications.Runtime;
Call the static AddCustomization method.
The following code example uses the AddCustomization overload. This overload takes the full path of the document and a Uri that specifies the location of the deployment manifest for the customization you want to attach to the document. This example assumes that a Word document named WordDocument1.docx is on the desktop, and that the deployment manifest is located in a folder that is named Publish that is also on the desktop.
string documentPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.Desktop) + #"\WordDocument1.docx";
int runtimeVersion = 0;
try
{
runtimeVersion = ServerDocument.GetCustomizationVersion(documentPath);
// Make sure that this document does not yet have any Visual Studio Tools
// for Office customizations.
if (runtimeVersion == 0)
{
string deployManifestPath = System.Environment.GetFolderPath(
Environment.SpecialFolder.Desktop) + #"\Publish\WordDocument1.vsto";
Uri deploymentManifestUri = new Uri(deployManifestPath);
ServerDocument.AddCustomization(documentPath, deploymentManifestUri);
System.Windows.Forms.MessageBox.Show("The document was successfully customized.");
}
else
{
System.Windows.Forms.MessageBox.Show("The document is already customized.");
}
}
catch (FileNotFoundException)
{
System.Windows.Forms.MessageBox.Show("The specified document does not exist.");
}
catch (DocumentNotCustomizedException ex)
{
System.Windows.Forms.MessageBox.Show("The document could not be customized.\n" +
ex.Message);
}
Build the project and run the application on the computer where you want to attach the customization. The computer must have the Visual Studio 2010 Tools for Office Runtime installed.

Did you try to set LoadBehaviour to 0x10 => Load first time, then load on demand? This should make Office load your addin the first time you execute it and internally cache it. It will then change the value to 0x9... The subsequent times, the app will load on demand.

Related

Word addin, set filename

If one starts a blank file on Word you can usually see in the top bar a name such as "Document1", "Document2" and so on.
Yet, if you attempt to open a file using the Word JS API like this:
Word.run((context) => {
context.application.createDocument(documentB64).open()
return context.sync()
})
The top bar comes out like this:
No filename is set.
To set a filename/handle(?), I tried using the code given here Office JS - Add customProperty to new document but that didn't help.
My addin is usually used in conjunction with another (VSTO) add-on and that add-on can't work properly with the documents opened by my addin and I believe the lack of a filename (/handle?) explains it to some extent.
Is there something I can do about this?
Thank you
Currently you can't do this because the newly created document is just a temporary file and not saved. can you try to call the following code to make sure the newly created file is saved?
const documentCreated = context.application.createDocument(externalDoc);
documentCreated.save();
documentCreated.open();

Can OpenXML be used to launch a new Word instance?

I'm able to generate Word documents without issue. I save the resulting *.docx file to a temporary location and then need to launch the file in Word.
The requirement is to not "open" the file in Word (easily done with a Process.Start) but to have load into Word as a new unsaved file. This is because certain propriety integrations for Word need to take over when a user saves the file and don't kick in if the file is ready saved but to a location on disk.
I've achieved this by using Interop calls to the Word application, adding the new document to Word's workspace. My problem is with Interop which tends to break on various client machines, particularly when Office upgrades take place (say a client had 32-bit office but upgraded with a 64-bit version).
I'm somewhat new to OpenXML, but can it be used to automate Word or is Interop my only real option?
object oFilename = tmpFileName;
object oNewTemplate = false;
object oDocumentType = 0;
object oVisible = true;
Document document = _application.Documents.Add(ref oFilename, ref oNewTemplate, ref oDocumentType, ref oVisible);
No, the Open XML technology has no way of interacting with the Office (Word) application - it's for file creation/manipulation, only. The interop is required in order to do anything with the Word application.
There is sort of a way around this - and it's only possible with Word, no other Office application has this - is to convert the Open XML content to the OPC flat-file format. This "concatenates" the various packages that make up the zip file to a pure text string, essetially a single XML file.
XML content in the OPC flat-file format can then be written to an already opened (even newly created) Word document using the Range.InsertXML method via "the interop". In a way, this "streams" the Open XML content into the opened Word document.
The problem with this approach is that certain document-level properties are not written to the target document, so not all aspects of the opened document can be changed. For example: page size, orientation, headers, footers... So if this kind of thing also needs to be affected the interop is required for such settings.

VSTO Word add-in - new document event not firing if Word is launched from the executable

In my add-in, I need to create a task pane for each open document. In the add-in's startup method, I subscribe to the ApplicationEvents4_Event.NewDocument and Application.DocumentOpen events, and then create a task pane for each opened document:
((ApplicationEvents4_Event)Application).NewDocument += CreateTaskPaneWrapper;
Application.DocumentOpen += CreateTaskPaneWrapper;
foreach (Document document in Application.Documents)
{
CreateTaskPaneWrapper(document);
}
This covers cases for opening or creating a document through Word's menu, or opening an existing document file in the OS. However, if Word is already opened, launching WINWORD.EXE (or accessing it through a shortcut, which is a pretty common scenario) doesn't trigger either event, despite a new window with a new document being opened. How can I react to this scenario and create a task pane for a document created this way? I'm using VSTO 3 and Visual Studio 2008, targeting Word 2007.
If Word is started, a new document is created BEFORE the Add-In loads, therefore this event can not be trapped.
If you need to work with the initially created document, just take a look at the Documents collection - if Count is greater zero, this document is the one created by Word before your Add-In was loaded.
So I solved this problem in my solution, although I'm not sure it will be cross applicable. Sadly, mine is in VB.Net, so there may need to be some translation.
First, I ended up not using ApplicationEvents4_Event Instead there are other built in event triggers you can use via "ThisAddIn"
Private Sub Application_NewDocument(ByVal Doc As Word.Document) Handles Application.NewDocument
'MsgBox("I opened something")
myCustomTaskPane = Me.CustomTaskPanes.Add(New MyCustomTaskPaneClass, "TaskPane", Doc.ActiveWindow)
myCustomTaskPane.Visible = True
End Sub
Using this method I did have a similar challenge. Running winword.exe, and thereby opening a new word document, did not trigger the NewDocument event. Luckily, there was another event to use - Document change.
Private Sub Application_DocumentChange() Handles Application.DocumentChange
'function to test if the ActiveDocument has a taskpane from my add-in, and then a function to add one
If Not HasMyCustomTaskPane() then AddCustomTaskPane()
End Sub
So - bottom line, regardless of if you keep using ApplicationEvents4_Event you should see if you can use the DocumentChange event. It triggers when a new word window is selected.
Handling task panes for more than one window in Word is fairly complicated, because of how Word loads and re-uses open windows. To do it correctly, you have to consider different actions:
The user takes an action to display or hide a task pane.
The user creates a new document.
The user opens an existing document.
The user closes an open document.
There's a tutorial that explores all the details, both in VB and C#: https://msdn.microsoft.com/en-us/library/bb264456%28v=office.12%29.aspx
I also found a similar answer on SO.

Append Pub file to other MS Publisher 2010 file with PowerShell

In MS Publisher 2010, you can add a PUB file (a catalog publication which merge a template with data coming from Excel file) to the end of an existing pub file.
Quite convenient to compose a Catalog book. I can do it by hand with Publisher user interface and I would like to automate this task (there is 26 chapters).
Unfortunately, I was not able to locate the automation function, neither a simple example.
Did someone could help me with some automation sample for this task?
Thanks,
Can you access the Publisher interop library with PowerShell?
This is how I'd go about it if so (untested C#, but it should give you an idea of how to go about it if you read up on it in MSDN's Publisher VBA reference):
Publisher.Application firstPubApp = new Publisher.Application(); //open a new publisher instance
Publisher.Document sourcePublication = firstPubApp.Open("sourcefile.pub"); //open your publisher document
Publisher.Application otherPubApp = new Publisher.Application();
Publisher.Document targetPublication = otherPubApp.Open("targetfile.pub");
targetPublication.Pages.Add(1, 1); //add one page after page 1
foreach (Publisher.Shape shape in sourcePublication.Pages[1].Shapes) //loop through all pages on page 1
{
shape.Copy(); //copy the shape
otherPubApp.ActiveDocument.Pages[2].Shapes.Paste(); //paste it in the other document
}
It is quite possible that a better way to do it than looping through all shapes on all pages is hidden somewhere in that documentation though. It's always hard to find samples for Publisher compared to Excel or Word.

how to stop macros running when opening a Word document using OLE Interop?

As the title suggests, I have a .Net application which uses interop to open documents in Word. I have set
app.AutomationSecurity = Microsoft.Office.Core.MsoAutomationSecurity.msoAutomationSecurityForceDisable
before opening the document. According to the documentation, thhis "Disables all macros in all files opened programmatically, without showing any security alerts"
However, when I attempt to open one specific document I get a dialog box on the screen that says "could not load an object because it is not available on this machine". It's a customer document but I believe it contains a macro with references to a COM object which I don't have installed.
Am I doing something stupid? is there any way to actually disable macros when opening a Word document?
Try:
WordBasic.DisableAutoMacros 1
Bizarrely, this relies on a throwback to pre-VBA days, but still seems to be the most-reliable way to ensure that no auto macros are triggered (in any document - you may want to turn it back using the parameter "0").
I recently had a project where I had to process 6,000 Word templates (yes, templates, not documents) many of which had oddball stuff like macros, etc. I was able to process all but 6 using this technique. (I never did figure out what the problem was with those 6).
EDIT: for a discussion of how to call this from C#, see: http://www.dotnet247.com/247reference/msgs/56/281785.aspx
For c# you can use
(_wordApp.WordBasic as dynamic).DisableAutoMacros();
The whole code I'm using is:
using Word = Microsoft.Office.Interop.Word;
private Word.Application _wordApp;
...
_wordApp = new Word.Application
{
Visible = false,
ScreenUpdating = false,
DisplayAlerts = Word.WdAlertLevel.wdAlertsNone,
FileValidation = MsoFileValidationMode.msoFileValidationSkip
};
_wordApp.Application.AutomationSecurity = MsoAutomationSecurity.msoAutomationSecurityForceDisable;
(_wordApp.WordBasic as dynamic).DisableAutoMacros();