[Edit May 2008] I no longer use MSI.Interop. That interop was full of bugs, lacked many features and was no longer actively being developed or supported. Instead I reccomend the new DTF SDK from Microsoft as released by WiX. DTF brings a new Microsoft.Deployment.WindowsInstaller library that just runs circles around MSI.Interop.
http://blog.deploymentengineering.com/2008/05/deployment-tools-foundation-dtf-custom.html
One of the nice things about Per-Machine installations is that they are always managed. So provided that you get your ducks in a row following proper design patterns ( for example: Deferred Custom actions with the msidbCustomActionTypeNoImpersonate execute option and the SecureCustomProperties property ) you can simply advertise the package with the msiexec /JM command or run it as an Administrator and future upgrades can be serviced from the same source location without Administrative privileges by simply executing the update package with the REINSTALLMODE=vomus REINSTALL=ALL properties.
But wouldn't it be nice if the user didn't have to manually run the installation to perform the upgrade? Well, they don't. :) When you install your application you can save the OriginalDatabase or the ProductCode property somewhere your application can access it. With this information available to your application at runtime you can go find the MSI database and determine if there is a newer version available.
The following example in C# uses MSI.Interop.
using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using Pahvant.MSI;
namespace TestApp
{
class Program
{
static void Main(string[] args)
{
string msiPath = "C:\\TestApp.msi"; // Get this as described in the blog
Pahvant.MSI.Database database = new Pahvant.MSI.Database( msiPath, Pahvant.MSI.Database.OpenMode.ReadOnly );
Pahvant.MSI.View view = new Pahvant.MSI.View( database, "select `Value` from `Property` where `Property`='ProductVersion'");
view.Execute();
Record record = view.Fetch();
string productVersion = record.GetString(1);
if( Application.ProductVersion != productVersion )
// Call Prompt For Upgrade Method
}
}
}
If your upgrade method, you'll probably want to shell out to msiexec async and terminate to avoid a locked file during Costing. Bonus points will be awarded by your user if you also pass a public property to indicate that an automatic upgrade is occuring so that your install restarts the application when it's finished upgrading.
Christopher,
ReplyDeleteShould this code work in C# 2005 expesss edition?
Thanks,
Tony
The code is really just an outline of what needs to be done. It'll need to be tweaked to fit your situation. I've never used C# express but I imagine it should still work. Just make sure you have the approriate MSI Interop assembly downloaded and referenced otherwise the namespace won't be available.
ReplyDeleteIf you're going to put my name on your blog, you could at least spell it properly. No 'p' in Thomson.
ReplyDelete