Deploy multiple Office Solutions in a single setup

How to deploy multiple Office Solutions in a single setup

After creation of all your MS-Office solutions, they can be configured to be deployed all at once. The steps below walk through how to configure one setup for all MS-Office solutions using a Click Once installer for the .NET Framework:

Step 1: Create a sample Word Add-In project using VS

(File->New Project->Office/SharePoint->Office Add-ins)

Step 2: Add Projects to the Solution

Add all the projects into this solution where the sample add-in is created.

Step 3: Publish project one at a time to the common folder

(For Ex. ‘C:/Publish/’). Publish the sample add-in project last, when you have finished publishing the other projects . (Note: Ensure that publish settings are set correctly. Add the necessary prerequisites to each project, select install prerequisites as the same location as my application. By selecting this one must ensure that all prerequisites are at this location ‘C:\Program Files (x86)\Microsoft SDKs\Windows\v8.1A\Bootstrapper\Packages’) in the appropriate folder.

Screen-Shot: Publishing to common place folder:
Multiple Office AddIn1

Screen-Shot: Here we have taken ‘SetupForAddin’ folder (as the common location) to publish all add-in projects:
Multiple Office AddIn2

Step 4: Modifying the application manifest

  1. From the c:\publish\Application Files folder, move the contents of the {EXCEL_PROJECT}_1_0_0_0 and {WORD_PROJECT}_1_0_0_0 or {PPT_PROJECT}_1_0_0_0 directories to the {SAMPLE_PROJECT}_1_0_0_0 directory.
  2. Open the {SAMPLE_PROJECT}.dll.manifest, {WORD_PROJECT}.dll.manifest, and {EXCEL_PROJECT}.dll.manifest, {PPT_PROJECT}.dll.manifest files in an XML editor.
  3. From the {WORD_PROJECT}.dll.manifest file, copy all install and file dependencies including {WORD_PROJECT}.dll. That is, copy all dependencies that start with
  4. In the {SAMPLE_PROJECT}.dll.manifest file, paste the {WORD_PROJECT}.dll install dependency at the end of the dependency section.
  5. Repeat the previous #3 and #4 for {EXCEL_PROJECT} and {PPT_PROJECT}.

Screen-shot: move files from the add-in projects to our last published sampled project directory. (Files to move from each project are ‘.vsto’, ‘dll.deploy’,’dll.manifest’):

Multiple Office AddIn3

 

Screen-Shot: Copied all the element from all word, excel, PowerPoint add-in projects to sample projects {SAMPLE_PROJECT}.dll.manifest file:

Multiple Office AddIn4

Step 5: Adding the Entrypoints

  1. In the {SAMPLE_PROJECT}.dll.manifest file, remove the text between the and elements.
  2. From the {WORD_PROJECT}.dll.manifest file, copy the text between the and elements.
  3. In the {SAMPLE_PROJECT}.dll.manifest file, paste the code after the element.
  4. Add the id attribute to the element to differentiate this entrypoint from others.
  5. Repeat previous points #2, #3 and #4 for {EXCEL_PROJECT} and {PPT_PROJECT}.

Screen-Shot: Copied all the element from all word, excel, PowerPoint add-in projects to sample projects {SAMPLE_PROJECT}.dll.manifest file.

Multiple Office AddIn5

Step 6: Adding Assemblies

To add the assemblies to the vstov4 namespace in the application manifest

  1. In the {SAMPLE_PROJECT}.dll.manifest file, remove any text between the and elements.
  2. In the {WORD_PROJECT}.dll.manifest file, copy the text between the and elements.
  3. In the {SAMPLE_PROJECT}.dll.manifest file, paste the code after the element.
  4. Add the id attribute to the element to differentiate this customization from others. This id is the same id that was added to the element in the previous step 5.

Screen-Shot: Copied all the element from all word, excel, PowerPoint add-in projects to sample projects {SAMPLE_PROJECT}.dll.manifest file.

Multiple Office AddIn6

Step 7: Sign manifests

To re-sign the application and deployment manifests

  1. Copy the {SAMPLE_PROJECT}_TemporaryKey.pfx certificate file from the {SAMPLE_PROJECT} solution directory into the c:\Publish\Application Files\{SAMPLE_PROJECT}_1_0_0_0directory.
  2. Open the Visual Studio command prompt.
  3. Change to the c:\Publish\Application Files\{SAMPLE_PROJECT}_1_0_0_0 directory.
  4. Sign the modified application manifest with the following command:
    mage -sign ContosoInstaller.dll.manifest -certfile ContosoInstaller_TemporaryKey.pfx

The message “{SAMPLE_PROJECT}.dll.manifest successfully signed” appears.

  1. Change to the c:\Publish directory.
  2. Update and sign the deployment manifest with the following command:

mage -update ContosoInstaller.vsto -appmanifest “Application Files\ContosoInstaller_1_0_0_0\ContosoInstaller.dll.manifest” -certfile “Application Files\ContosoInstaller_1_0_0_0\ContosoInstaller_TemporaryKey.pfx”
The message “{SAMPLE_PROJECT}.vsto successfully signed” appears.

Copy the {SAMPLE_PROJECT}.vsto file to the c:\publish\Application Files\{SAMPLE_PROJECT}_1_0_0_0 directory.

Commands to execute: (Use ‘Developer Command Prompt for VS2013’ command prompt from Visual Studio Tools)

  1. mage -sign XYZOfficeAddIn.OfficeAddInSetup.dll.manifest -Publisher “XYZ Products” -Password xyz@123 -certfile XYZOfficeAddIn.OfficeAddInSetup_TemporaryKey.pfx
  2. mage -update XYZOfficeAddIn.OfficeAddInSetup.vsto -Publisher “XYZ Products” -Password xyz@123 -appmanifest “Application Files\ XYZOfficeAddIn.OfficeAddInSetup_1_0_0_3\ XYZOfficeAddIn.OfficeAddInSetup.dll.manifest” -certfile “Application Files\ XYZOfficeAddIn.OfficeAddInSetup_1_0_0_3\ XYZOfficeAddIn.OfficeAddInSetup_TemporaryKey.pfx”

Screen-Shot: Run the ‘Developer Command Prompt for VS2013’ command prompt from VS tools:

Multiple Office AddIn7

Screen-Shot: Re-sign the application and deployment manifests:

Multiple Office AddIn8

Now your final setup is ready. You can run to install. You should then see the Add-Ins configured; for Word, Excel and PowerPoint

Extending the Outlook Ribbon programmatically

Extending the Outlook Ribbon

The MS-Office ribbon can be extended programmatically. In this article, I add a new tab to the ribbon, and new icons that open links to sites, then create a ClickOnce deployable package. We’ll explore a few tricks including how to import new icons. For a great overview of the Fluent UI, please see: https://msdn.microsoft.com/en-us/library/aa338198.aspx

Ribbon XML

Microsoft designed the Fluent UI (aka Ribbon) to be extensible. The easiest way to do this is via the Ribbon Designer. However I chose to hand-craft the solution based on Ribbon XML. After creating a new Visual Studio 2010 project, ensuring use of .NET 4.0,

To use an existing MS-Office Tab, just reference it by name, using tab idMso:

<customUI
xmlns="http://schemas.microsoft.com/office/2009/07/customui">
<ribbon startFromScratch="false">
<!-- Ribbon XML -->
</ribbon>
<backstage>
<button idMso="FileSave" visible="false"/>
<button idMso="SaveObjectAs" visible="false"/>
<button idMso="FileSaveAsCurrentFileFormat" visible="false"/>
<button idMso="FileOpen" visible="false"/>
<button idMso="FileCloseDatabase" visible="false"/>
<tab idMso ="TabInfo" visible="false"/>
<tab idMso ="TabRecent" visible="false"/>
<tab idMso ="TabNew" visible="false"/>
<tab idMso ="TabPrint" visible="false"/>
<tab idMso ="TabShare" visible="false"/>
<tab idMso ="TabHelp" visible="false"/>
<button idMso="ApplicationOptionsDialog" visible="false"/>
<button idMso="FileExit" visible="false"/>
</backstage>
</customUI>

However you can create your own tab. Just remember to give it a unique ID, and also add the label. Note the use of “id” rather than “idMso”:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customUI onLoad="RibbonOnLoad" xmlns="http://schemas.microsoft.com/office/2006/01/customui">
<commands>
<command idMso="ApplicationOptionsDialog" enabled="false"/>
<command idMso="FileExit" enabled="false"/>
</commands>
<ribbon startFromScratch="true">
<officeMenu>
<button idMso="FileNew" visible="false"/>
<button idMso="FileOpen" visible="false"/>
<button idMso="FileSave" visible="false" />
</officeMenu>
<tabs>
<tab id="MyCustomHomeTab" label="Home" insertAfterMso="TabHome" getVisible="GetVisible" tag="ribhome">
<group idMso="GroupClipboard" />
<group idMso="GroupFont" />
<group idMso="GroupAlignmentExcel" />
<group idMso="GroupNumber" />
<group idMso="GroupStyles" />
<group idMso="GroupCells" />
<group idMso="GroupEditingExcel" />
</tab>
<tab id="MyCustomInsertTab" label="Insert" insertAfterMso="TabInsert" getVisible="GetVisible" tag="ribinsert" >
<group idMso="GroupInsertTablesExcel" />
<group idMso="GroupInsertIllustrations" />
<group idMso="GroupInsertChartsExcel" />
<group idMso="GroupInsertLinks" />
<group idMso="GroupInsertText" />
</tab>
<tab id="MyCustomPageLayoutTab" label="Page Layout" insertAfterMso="TabPageLayoutExcel" getVisible="GetVisible" tag="ribpagelayout">
<group idMso="GroupThemesExcel" />
<group idMso="GroupPageSetup" />
<group idMso="GroupPageLayoutScaleToFit" />
<group idMso="GroupPageLayoutSheetOptions" />
<group idMso="GroupArrange" />
</tab>
<tab id="MyCustomFormulasTab" label="Formulas" insertAfterMso="TabFormulas" getVisible="GetVisible" tag="ribformulas">
<group idMso="GroupFunctionLibrary" />
<group idMso="GroupNamedCells" />
<group idMso="GroupFormulaAuditing" />
<group idMso="GroupCalculation" />
</tab>
<tab id="MyCustomDataTab" label="Data" insertAfterMso="TabData" getVisible="GetVisible" tag="ribdata">
<group idMso="GroupGetExternalData" />
<group idMso="GroupConnections" />
<group idMso="GroupSortFilter" />
<group idMso="GroupDataTools" />
<group idMso="GroupOutline" />
</tab>
<tab id="MyCustomReviewTab" label="Review" insertAfterMso="TabReview" getVisible="GetVisible" tag="ribreview">
<group idMso="GroupProofing" />
<group idMso="GroupComments" />
<group idMso="GroupChangesExcel" />
</tab>
<tab id="MyCustomViewTab" label="View" insertAfterMso="TabView" getVisible="GetVisible" tag="ribview">
<group idMso="GroupWorkbookViews" />
<group idMso="GroupViewShowHide" />
<group idMso="GroupZoom" />
<group idMso="GroupWindow" />
<group idMso="GroupMacros" />
</tab>
<tab id="MyCustomDeveloperTab" label="Developer" insertAfterMso="TabDeveloper" getVisible="GetVisible" tag="ribdeveloper">
<group idMso="GroupCode" />
<group idMso="GroupControls" />
<group idMso="GroupXml" />
<group idMso="GroupModify" />
</tab>
</tabs>
</ribbon>
</customUI>

For your image, you can reference existing MS-Office images, which is easiest and faimilar to users. Note that tag “imageMso” is used. The other advantage, as we’ll soon see, is these images are already sized, and loaded correctly:

imageMso="RecordsAddFromOutlook"

MS-Office has a great set of familiar icons you can leverage. These are easier to use than importing your own (which we will get to shortly). To select from existing icons, check out this great site, which includes the XML to reference the MS-Office images:
Ribbon images

To load your own images, first import the desired images into the Visual Studio project; under Resources is a great place. I recommend right clicking and marking each to “Include”. These images will only ever appear if you explicitly binary stream them in on Ribbon load. Here’s how. At the start of the MyRibbonxml, add a mew reference method called “GetImage” to load the images you will reference in this MyRibbon.xml:

imageMso="RecordsAddFromOutlook"

Rather than using imageMso, just use an image tag:

image="DMFLogo.ico"

Now for every image you reference, the loadImage method will be called, passing in the name of the image as a parameter. Let’s now add the getImage method to the myRibbon.cs:

public Bitmap GetImage(string imageName)
{
Assembly assembly = Assembly.GetExecutingAssembly();
//this is useful for navigating to discover the actual resource name reference
//string[] x;
//x = assembly.GetManifestResourceNames();
Stream stream = assembly.GetManifestResourceStream("MyProjectName.Resources." + imageName);
return new Bitmap(stream);  //uses system.drawing, added for now
}

At runtime, the stream is loaded based on the manifest reference. During initial debugging, it’s great to be able to see the manifest to ensure the path is correct. I’ve found it best to have a few lines of code to give you a handle on the manifest during debugging, if ever you need, just uncomment these and examine at a breakpoint:

//string[] x;
//x = assembly.GetManifestResourceNames();

As the images are stored in a folder, you’ll have to get the project name reference and the “Resources” folder path correct.

One last point is I found ICO files don’t give the best resolution. Microsoft recommends PNGs, which is a good image format to start.

To open a browser as a ribbon action, adapt this function:

public void ActionOpenInsureds(Office.IRibbonControl control)
{
string targetURL = "http ://sharepoint/sites/MySite/SitePages/Index1.aspx";
System.Diagnostics.Process.Start(targetURL);
return;
}

This function is called based on the button onAction tag in myRibbon.xml:

onAction="ActionOpenInsureds"

For completeness, here’s the full sample myRibbon.xml:

<?xml version="1.0" encoding="UTF-8"?>
<button id="textButton"></button>
<button id="DMFButton"></button>
<button id="tableButton"></button>

ClickOnce

ClickOnce is a fabulous technology. Previously we had to build a deployment project, or purchase 3rd-party software. This ribbon can be published to a central location as a ClickOnce install. It will appear in the Control Panel, and it can check in itself for updates. Here’s a great overview of ClickOnce: https://msdn.microsoft.com/en-us/library/t71a733d

To get started, simply select “Build, Publish” in Visual Studio 2010 and follow the menus.

A few things to note:
1. Unless you sign your code with a digital certificate, users will get prompted
2. The cert you use needs to have “code signing” authority, best is to get one issued by the CA (Certificate Authority) in your organization
3. If you set pre-requisites, the user needs admin authority on their machine in order to check-pre-requisites
4. There’s a registry change to control the .NET install prompts
5. Click-once does not support install for “All users” on the machine, only the current user
6. Even trying to run in silent mode still results in a single-acknowledgement window after the install

Silence is golden

I would expect running off My Documents would end up in the MyComputer Zone, which should be “Enabled” as a trusted zone for install without prompt, but here’s the keys to experiment with:

HKLMSoftwareMicrosoft.NETFrameworkSecurityTrustManagerPromptingLevel.

Then add the following string values for one or more of the security zones, as appropriate:

  • MyComputer
  • LocalIntranet
  • Internet
  • TrustedSites
  • UntrustedSites

Set the value of each security zone to one of the following:Enabled. The installation prompts the user if the solution is not signed with a trusted certificate. This is the default for the MyComputer, LocalIntranet, and TrustedSites zones.AuthenticodeRequired. The user cannot install the solution if it is not signed with a trusted root authority certificate. The installation prompts the user if the solution is not signed with a trusted publisher certificate. This is the default for the Internet zone.Disabled. The user cannot install the solution if it is not signed with a trusted publisher certificate. This is the default for the UntrustedSites zone.

The last option is to add this solution to the inclusion list, which is a list of trusted solutions.