December 2008 - Posts

Windows Installer Custom Actions, Windows Vista and Terminal Server

Using a setup project in Visual Studio is a nice and easy way of creating a deployment solution for your application. In some cases, built-in features such as file copy, GAC registration and registry modification are good enough but there are cases where you need to perform a custom action such as configuring CAS or running a script.

If you have used Visual Studio 2005 to build the setup package (with custom actions) and have tried to run your setup package on Windows Vista with UAC enabled, then you may already know that the setup can fail. This is because Windows Vista is enforcing an architectural intent according to Robert Flaming's blog post. So in order to make sure your custom action runs on Windows Vista without a problem, you need to edit the MSI package and change the custom action type flag to include msidbCustomActionTypeNoImpersonate (see here for the list of options). So for example, if your custom action is defined in a class library, this is how you can calculate the type value for Windows Vista:

msidbCustomActionTypeDll + msidbCustomActionTypeInScript + msidbCustomActionTypeNoImpersonate = 0x00000001 + 0x00000400 + 0x00000800 = 3073

(Note that Visual Studio 2008 sets this value correctly to 3073).

You can then update the type value for this custom action in the Orca tool:

And instead of performing this step manually, you can use a script that does this for you and then run this script as a post-build event of your setup project. Aaron Stebner has a great blog post on this.

So now all is good and we have an automated process for setting the right value for the custom action type. Now what happens if you want to run the same setup package on Terminal Server? If you are performing a per-machine install, the custom action runs with no user impersonation by default and you may need to perform some tasks that rely on the user being the administrator. In order to force the custom action to run with user impersonation, you need to include another flag (msidbCustomActionTypeTSAware), which is ignored if msidbCustomActionTypeNoImpersonate is already present. This makes sense as one is forcing impersonation and the other one is preventing it. But now the challenge is, how can we create a setup package that runs on both platforms?

Windows Vista needs: msidbCustomActionTypeDll + msidbCustomActionTypeInScript + msidbCustomActionTypeNoImpersonate = 0x00000001 + 0x00000400 + 0x00000800 = 3073
Terminal Server needs: msidbCustomActionTypeDll + msidbCustomActionTypeInScript + msidbCustomActionTypeTSAware = 0x00000001 + 0x00000400 + 0x00004000 = 17409

This is where the deployment conditions come to the rescue. First, a bit of background on deployment conditions:

All setup project deployment artifacts such as files, folders, registry entries and custom actions have a Condition property, which will determine whether that item will be installed/run. These properties tell you about the hardware configuration (memory size, CPU type), OS (version, service pack and build number) and other information elements such as user name and computer name. The property reference section on MSDN has a full list of property values you can use. You are not limited to one condition and you can perform logical operations and equality checks too (see Conditional Statement Syntax and Examples of Conditional Statement Syntax).

So let's go back to our scenario. We were looking for a solution that allows a single setup project to be used on Windows Vista and Terminal Server. There is a deployment condition called TerminalServer, which is defined only if we are running on Terminal Server. The deployment condition "TerminalServer" will be true in a Terminal Server environment and the "NOT TerminalServer" will be true in all other environments, including Windows Vista. So we can achieve our objective by creating the following two custom actions:

  • One for Terminal Server environments, Condition: TerminalServer, Type: 17409
  • One for other environments, Condition: NOT TerminalServer, Type: 3073

This doesn't necessarily mean you need to create two installer classes though. You can add the default output of your class library (which contains the installer class) to the setup project twice and then add two custom actions, each of which uses one of those outputs. You can then use the Orca tool to set the types manually (make sure you set the right type for each action) or use the scripting approach as explained by Aaron Stebner (note that you will need to change the script to satisfy the requirements).

Other links:
Operating System property values for deployment conditions

Posted by Mehran Nikoo | 2 comment(s)
Filed under:

Application Architecture Guide 2.0 - Final Release

The Application Architecture Guide 2.0 is out and you can now download it from here. As J.D. writes in his post, there are some changes since the Beta 2, including the foreword by Scott Guthrie (which follows the foreword by Soma added in the Beta 2 timeframe) and the incorporated feedback from the long list of internal and external reviewers.

Working on this guide has been a great experience in the past few months, working with the core team and the contributors and reviewers from various product and consulting teams at Microsoft as well as partners and customers. Since this is an architecture guide, it is all about best practices and general guidance and it was amazing to see how we started with varied (and sometimes conflicting) views on different subjects and how we came to an agreement in those areas as we came closer to the release date and we all learnt new ways of looking at various architectural topics.

One of the interesting challenges for us during the development of this guide was to make sure we keep it up-to-date as we announced new products and technologies and made decisions about our development platform roadmap. Clearly, the Microsoft application platform will evolve and we have a long list of products to be released in the next couple of years so the p&p team will be working with various product teams to publish prescriptive guidance and best practices and to revise the existing guides where necessary.

We hope that you enjoy reading this guide and please keep your feedback coming via the CodePlex site.

Sending Office Documents with VSTO Customisation to Other Parties

When you create a document-level customisation for Office using VSTO, the customisation is compiled into a .NET assembly and the location of this assembly is stored in a custom document property called _AssemblyLocation. When loading the document, Office first checks to see whether this custom property is present and if it is, it tries to load the customisation. Now what if you are going to send this document to another organisation or department who don't have (or don't want to have) that customisation (assembly)? Since they don't have the assembly on their machine, they will see an error message presented via a dialog box saying that the assembly could not be found, which is not nice.

One way to prevent the code from running but without receiving an error message is to hold down the SHIFT key (as described on MSDN) when you are opening the document via the File menu. Note that this solution does not work if you are opening the document using the "Getting Started" task pane. This solution works but it requires the user to open the document using the File menu and they need to remember to hold down the SHIFT key so it is not necessarily a desired solution.

The alternative solution is to remove the custom document property that points to the customisation assembly. This way Office will not try loading the customisation assembly on the end-user's machine so they will not get the error message. However, you may need to put those custom properties back in the document if they user modifies the document and returns the document back to you.

So how can you remove the custom properties?

Manually
Open the document in the Office application (Word, Excel or PowerPoint), go to Properties -> Advanced Properties -> Custom and remove the assembly location custom property.

ServerDocument Class in VSTO
Both versions of VSTO (VSTO 2005 SE and VSTO 3.0) come with their own version of this class and have a very similar functionality. Note that you don't need to have Office installed on the machine that is trying to modify the document using the ServerDocument class so you can perform this process on a server machine as part of an automated process that you run before sending out Office documents. You can find more information on this approach here.

OpenXML
If you are using Office 2007, you can access and manipulate the custom document properties by using the types in the System.IO.Packaging namespace or by using the Open XML Format SDK. Again, you don't need to have Office installed on the machine that is using these components to manipulate the Office documents.

As I mentioned earlier, when you receive the document from the other party, you may want to add the VSTO customisation again. You can use any of the approaches mentioned above to put the custom properties back on.

(Thanks to Mary Lee for the pointers)

Posted by Mehran Nikoo | with no comments