1 out of 2 rated this helpful - Rate this topic

Walkthrough: Copying a Document to the End User Computer after a ClickOnce Installation

Updated: September 2010

Using a ClickOnce post-deployment action, you can install document-level Office solutions, and then copy the document to the end user computer. This requires that you modify the application manifest, and re-sign both the application and the deployment manifests before installation.

Applies to: The information in this topic applies to document-level projects and application-level projects for Microsoft Office 2010 and the 2007 Microsoft Office system. For more information, see Features Available by Office Application and Project Type.

This walkthrough illustrates the following tasks:

  • Creating an Office solution to deploy.

  • Implementing a post-deployment action that copies a document to the end user's desktop.

  • Modifying the application manifest of the Office solution to run the post-deployment action.

  • Re-signing the application and deployment manifests.

NoteNote

Your computer might show different names or locations for some of the Visual Studio user interface elements in the following instructions. The Visual Studio edition that you have and the settings that you use determine these elements. For more information, see Visual Studio Settings.

You need the following components to complete this walkthrough:

First, create an Excel workbook project.

To create a new Excel project

  • Create an Excel document-level project. Name the project ExcelWorkbook, and save the project to the %USERPROFILE%\Documents\Visual Studio 2010\Projects directory. For more information, see How to: Create Office Projects in Visual Studio.

    Visual Studio opens the new Excel workbook in the designer and adds the ExcelWorkbook project to Solution Explorer.

You must define the post-deployment action in a separate class library. The post-deployment action performs copies the document to the end user computer.

To create a class library for the post-deployment action

  1. In the File menu, point to Add, and then click New Project.

  2. In the Add New Project dialog box, in the Installed Templates pane, click Windows.

  3. In the Templates pane, click Class Library.

  4. In the Name field, type FileCopyPDA, and then click OK.

  5. In Solution Explorer, click FileCopyPDA.

  6. On the Project menu, click Add Reference.

  7. In the Add Reference dialog box, in the .NET tab, add the following references:

    • If your Excel project targets the .NET Framework 3.5, add references to Microsoft.VisualStudio.Tools.Applications.Runtime.v10.0 and Microsoft.VisualStudio.Tools.Applications.ServerDocument.v10.0.

    • If your Excel project targets the .NET Framework 4, add references to Microsoft.VisualStudio.Tools.Applications.Runtime and Microsoft.VisualStudio.Tools.Applications.ServerDocument.

  8. In the Class1 code file, add the following using or Imports statements to the top of the code file.

    
    using Microsoft.VisualStudio.Tools.Applications.Deployment;
    using Microsoft.VisualStudio.Tools.Applications;
    using System.IO;
    
    
    
  9. Rename the class to FileCopyPDA, and then add the following code to the FileCopyPDA class. This code indicates that FileCopyPDA class inherits from IAddInPostDeploymentAction.

    
    public class FileCopyPDA : IAddInPostDeploymentAction
    
    
    
  10. Add the following code to implement the IAddInPostDeploymentAction.Execute method. This code performs the following tasks:

    • Copies the Excel workbook file to the user's desktop if the solution is installed or updated.

    • Changes the _AssemblyLocation property from a relative path to a fully qualified path for the deployment manifest. This is done using the AddCustomization and RemoveCustomization methods.

    • Deletes the file if the solution is uninstalled.

      Note Note

      The post-deployment action is run during the uninstall step for .NET Framework 3.5.

    
    public void Execute(AddInPostDeploymentActionArgs args) 
    {
        string dataDirectory = @"Data\ExcelWorkbook.xlsx";
        string file = @"ExcelWorkbook.xlsx";
        string sourcePath = args.AddInPath;
        Uri deploymentManifestUri = args.ManifestLocation;
        string destPath = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
        string sourceFile = System.IO.Path.Combine(sourcePath, dataDirectory);
        string destFile = System.IO.Path.Combine(destPath, file);
    
        switch (args.InstallationStatus)
        {
            case AddInInstallationStatus.InitialInstall:
            case AddInInstallationStatus.Update:
                File.Copy(sourceFile, destFile);
                ServerDocument.RemoveCustomization(destFile);
                ServerDocument.AddCustomization(destFile, deploymentManifestUri);
                break;
            case AddInInstallationStatus.Uninstall:
                if (File.Exists(destFile))
                {
                    File.Delete(destFile);
                }
                break;
        }
    }
    
    
    

Use the Publish Wizard or the Project Page to build and publish the Office solutions to your development computer.

To publish the Excel project

  1. In Solution Explorer, right-click the FileCopyPDA project, and then click Build.

  2. In Solution Explorer, right-click the ExcelWorkbook project, and then click Build.

  3. In Solution Explorer, right-click the ExcelWorkbook project, and then click Add Reference.

  4. In the Add Reference dialog box, click the Projects tab.

  5. Click FileCopyPDA, and click OK.

  6. In Solution Explorer, click the ExcelWorkbook project.

  7. On the Project menu, click New Folder.

  8. Type Data and press the Enter key.

  9. In Solution Explorer, click the Data folder.

  10. On the Project menu, click Add Existing Item.

  11. In the Add Existing Item dialog box, browse to the output directory for the ExcelWorkbook project.

  12. Click ExcelWorkbook.xlsx, and click Add.

  13. In Solution Explorer, click ExcelWorkbook.xlsx.

    Note Note

    If you modify this file later, make sure to update the file by adding the latest version of the file.

  14. In the Properties window, change the Build Action property to Content, and the Copy to Output Directory property to Copy if newer.

  15. Publish the ExcelWorkbook project to the c:\publish folder. For more information, see How to: Publish an Office Solution by Using ClickOnce.

Use the XML editor in Visual Studio to modify the application manifest to run the File Copy post-deployment action. The content of an application manifest is similar to a bill of materials, which lists the entire contents of a box; an application manifest lists all dependent and prerequisite assemblies. The application manifest for an Office solution also lists the assemblies that should be loaded by an Office application for application-level add-ins and document-level customizations.

To add the installation dependencies to the application manifest

  1. Open the c:\publish directory through Windows Explorer.

  2. Open the Application Files folder and then open the ExcelWorkbook_1_0_0_0 folder.

  3. Open the ExcelWorkbook.dll.manifest file in a text editor.

  4. Add following code after the </vstav3:update> element. For the class attribute of the <vstav3:entryPoint> element, use the following syntax: NamespaceName.ClassName. In this example, the namespace and class names are the same, so that the resulting entry point name is FileCopyPDA.FileCopyPDA.

    <vstav3:postActions>
      <vstav3:postAction>
        <vstav3:entryPoint
          class="FileCopyPDA.FileCopyPDA">
          <assemblyIdentity
            name="FileCopyPDA"
            version="1.0.0.0"
            language="neutral"
            processorArchitecture="msil" />
        </vstav3:entryPoint>
        <vstav3:postActionData>
        </vstav3:postActionData>
      </vstav3:postAction>
    </vstav3:postActions>
    

The following procedure signs the application manifest and updates the deployment manifest. This ensures that tampered files are not installed on end user computers.

To re-sign the application and deployment manifests

  1. Copy the ExcelWorkbook_TemporaryKey.pfx certificate file from the %USERPROFILE%\Documents\Visual Studio 2010\Projects\ExcelWorkbook\ExcelWorkbook solution directory into the c:\publish\Application Files\ExcelWorkbook_1_0_0_0 directory.

  2. Open the Visual Studio command prompt.

  3. Change to the c:\publish\Application Files\ExcelWorkbook_1_0_0_0 directory.

  4. Sign the modified application manifest with the following command:

    mage -sign ExcelWorkbook.dll.manifest -certfile ExcelWorkbook_TemporaryKey.pfx
    

    The message "ExcelWorkbook.dll.manifest successfully signed" appears.

  5. Change to the c:\publish directory.

  6. Update and sign the deployment manifest with the following command:

    mage -update ExcelWorkbook.vsto -appmanifest "Application Files\Ex
    celWorkbook_1_0_0_0\ExcelWorkbook.dll.manifest" -certfile "Application Files\ExcelWorkbook_1_0_0_0\ExcelWorkbook_TemporaryKey.pfx"
    

    The message "ExcelWorkbook.vsto successfully signed" appears.

  7. Copy the ExcelWorkbook.vsto file to the c:\publish\Application Files\ExcelWorkbook_1_0_0_0 directory.

The following procedure ensures that the updated manifest installs the Excel workbook and copies the workbook to the end user's desktop.

To test the post-deployment action

  1. Copy the c:\publish directory to a test computer.

  2. Run the Setup.exe program, or if the prerequisites are already installed on the test computer, double-click the ExcelWorkbook.vsto deployment manifest.

    The Microsoft Office Customization Installer appears.

  3. Click Install.

    The Microsoft Office Customization Installer dialog box shows the following message: "The Microsoft Office customization was successfully installed." The Excel workbook is copied to the end user's desktop.

  4. Open the ExcelWorkbook.xlsx file from the desktop.

Date

History

Reason

September 2010

Changed %USERPROFILE%\Documents\Visual Studio 10\Projects to %USERPROFILE%\Documents\Visual Studio 2010\Projects.

Content bug fix.

Did you find this helpful?
(1500 characters remaining)
Community Content Add
Annotations FAQ
RE: copy a document template
You are correct. If a document is open, it cannot be overwritten. This is functionality built into Windows. No post deployment process (as far as I know) can change that. Therefore, This post-deployment action would work well for the initial copy. If the document or template is updated, this error will occur. To resolve the error, you would have to copy the updated version over manually.
Copy a document template

I sort of got this working.  I had a to make some tweaks to the Select code in FileCopyPDA:

 

 

SelectCase args.InstallationStatus

 

 

 

CaseAddInInstallationStatus.InitialInstall, AddInInstallationStatus.Update

 

2) System.IO.

 

File.Copy(sourceFile, destFile, True)

 

 

 

1) IfServerDocument.IsCustomized(destFile) Then

 

 

 

ServerDocument.RemoveCustomization(destFile)

 

 

 

EndIf

 

 

 

ServerDocument.AddCustomization(destFile, deploymentManifestUri)

 

 

 

Exit Select

 

 

 

CaseAddInInstallationStatus.Uninstall

 

 

 

If System.IO.File.Exists(destFile) Then

 

System.IO.

 

File.Delete(destFile)

 

 

 

EndIf

 

 

 

Exit Select

 

 

 

EndSelect

 

This was because 1) I was getting an error telling me that the destFile didn't have any customisations, and also 2) I wanted the .dotx file to replace the existing one if it already existed.

My main problem is that I set the update property to 'Check every time the customization runs'.  So when you use the template, it checks for updates.

If you have changed the .dotx file, it tries to copy it onto your machine as an update, but obviously it is in use as you have just created a document from it.

Am I missing something obvious?

Many thanks for any help!!
PowerShell Script to modify and re-sign manifests

Here is a short(ish) PowerShell script that will modify the manifests and re-sign them as part of a post build event. This is only tested with VS2010. The PowerShell script will check the Assembly for the class that impliments the IAddInPostDeploymentAction interface add it to the manifest and then re-sign it and the vsto with the key file.

Add a "PostBuildEvent.ps1" file to your project and put the below script in it.

# This script is invoked via a post build event and is a script implimentation of http://msdn.microsoft.com/en-us/library/dd465291.aspx
# Startup Environment:
# $MSBuildProjectFullPath = The full path to the project file being built
# $OutputPath = The output path of the built project relative to $MSBuildProjectFullPath
# open project file as xmldocument and read key properties out of it
$ProjectFile = new-object System.Xml.XmlDocument;
$ProjectFile.Load($MSBuildProjectFullPath);
$ProjectFileNamespaceManager = new-object System.Xml.XmlNamespaceManager $ProjectFile.NameTable;
$ProjectFileNamespaceManager.AddNamespace('ns', 'http://schemas.microsoft.com/developer/msbuild/2003');
$AssemblyName = $ProjectFile.SelectSingleNode('/ns:Project/ns:PropertyGroup/ns:AssemblyName', $ProjectFileNamespaceManager).InnerText;
$ApplicationVersion = $ProjectFile.SelectSingleNode('/ns:Project/ns:PropertyGroup/ns:ApplicationVersion', $ProjectFileNamespaceManager).InnerText;
$ManifestKeyFile = $ProjectFile.SelectSingleNode('/ns:Project/ns:PropertyGroup/ns:ManifestKeyFile', $ProjectFileNamespaceManager).InnerText;
# create paths to key directories and files
$ProjectPath = [System.IO.Path]::GetDirectoryName($MSBuildProjectFullPath) + '\';
$BuildDir = $ProjectPath + $OutputPath;
$MainDll = $BuildDir + $AssemblyName + '.dll';
$VSTOFile = $BuildDir + $AssemblyName + '.vsto';
$ManifestFile = $BuildDir + $AssemblyName + '.dll.manifest';
$ManifestKeyFilePath = $ProjectPath + $ManifestKeyFile;
$windowsSdkKey = Get-ItemProperty -path "HKLM:\SOFTWARE\Microsoft\Microsoft SDKs\Windows\v7.0A\";
$windowsSdkPath = $windowsSdkKey.InstallationFolder;
$mage = $windowsSdkPath + "bin\mage.exe";
$ildasm = $windowsSdkPath + "bin\ildasm.exe";
# open the manifest file and add post action to call IAddInPostDeploymentAction after the app has been deployed on the client machine
$manifestXmlDocument = new-object System.Xml.XmlDocument;
$manifestXmlDocument.Load($ManifestFile);
#find the class in the assembly that impliments the IAddInPostDeploymentAction
$decompiledMainDll = & $ildasm /text /nobar "$MainDll";
$classWithAction = ([regex]'\.class[^{]*IAddInPostDeploymentAction').matches($decompiledMainDll);
if($classWithAction.Count -gt 0)
{
$className = ([regex]'beforefieldinit([^\[]*)extends').matches($classWithAction[0].value)[0].groups[1].value.trim();

$manifestPostActionFragment = $manifestXmlDocument.CreateDocumentFragment();
$manifestPostActionFragment.InnerXml = '<vstav3:postActions xmlns:vstav3="urn:schemas-microsoft-com:vsta.v3"><vstav3:postAction><vstav3:entryPoint class="' + $className + '"><assemblyIdentity name="' + $AssemblyName + '" version="' + $ApplicationVersion + '" language="neutral" processorArchitecture="msil"
xmlns="urn:schemas-microsoft-com:asm.v2" /></vstav3:entryPoint><vstav3:postActionData></vstav3:postActionData></vstav3:postAction></vstav3:postActions>';
$namespaceManager = new-object System.Xml.XmlNamespaceManager $manifestXmlDocument.NameTable;
$namespaceManager.AddNamespace('vstav3', 'urn:schemas-microsoft-com:vsta.v3');
$updateNode = $manifestXmlDocument.SelectSingleNode('//vstav3:update', $namespaceManager);
$updateNode.ParentNode.InsertAfter($manifestPostActionFragment, $updateNode);
}
$manifestXmlDocument.Save($ManifestFile);
# re-sign the manifest file and vsto file because the manifest was changed
& $mage -sign $ManifestFile -certfile $ManifestKeyFilePath
& $mage -update $VSTOFile -appmanifest $ManifestFile -certfile $ManifestKeyFilePath

Lastly add a post build event with the below definition.

powershell.exe "$MSBuildProjectFullPath='$(MSBuildProjectFullPath)'; $OutputPath='$(OutputPath)'; $script = [System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)\PostBuildEvent.ps1'); invoke-expression $script;"

 

Uninstall of copied file not working
This is a very helpful post.  However, the .xlsx file that was copied to the desktop is not removed when I uninstall the app.  Any ideas?