cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
CodeGuru
Level 4

Integrating Installshield 2011 with Team Foundation Server (TFS) 2010

First, let me say that if I had any idea using installshield was going to take this many man hours to impelement (and so far unsuccessfully), we would have gone a different route. Not only that, but Installshield wanted $1999 for another license just so I could assign another developer to helping me fix this problem. 😞

That aside, I might as well post my work in hopes to save another team the headaches of getting as far as I have, and perhaps with newer versions of software, actually successfully completing the task.


The Goal:
Using TFS build to build multiple assemblies and pack them into an installshield msi where each assembly and the installer itself all share the same version number.


My Environment:
Server: Windows 2008 R2 x64, TFS 2010, Installshield 2011
TFS Builds: MSBuild Platform forced to x86
Dev Box: Windows 7 x64, Visual Studio 2010, Installshield 2011


My Visual Studio Solution:
App1: .net 2.0 exe compiled as x86
App2: .net 2.0 exe compiled as x86
InstallShield Basic MSI Project

Creating the solution with all of your deployed assemblies and adding the installshield project is very easy. The next step is how do you tell installshield to deploy your assemblies?

1. Open the Project Assistant of Installshield in the visual studio IDE.
2. Navigate to the Application Files window.
3. Click Add Project Outputs near the lower right hand corner of the window.
- I added content files and primary output only

At this point you should be able to build your entire solution and have a proper .msi generated with the project outputs (and content files).

Once you have this step working, we can move on to versioning.


Pushing a version through your build process
Now, its very unfortunate that we spend all this money on TFS and have no way to actually version our version controlled software. To do this I used two links as reference:

This link gives pretty good instructions on how to add your own action (compiled in a dll) and reference that action on your workflow.
What it doesn't mention is that you need to check in the dll you build into the location specified under "Using The New Build Process". Version control path to custom assemblies:. Check in your dll to the same location you specify here. The xml you create can be checked in anywhere.
http://www.richard-banks.org/2010/07/how-to-versioning-builds-with-tfs-2010.html

After I had a handle on the above, I actually ended up using this method to version distributions:
http://agilescmtalk.com/node/42

I have attached my working implementation of the above methods as CustomActivities.zip

In Team Explorer, edit your build definition and change the name to the following format:
MyApp-1.2-Rel where 1 is the major version and 2 is the minor version. Rel can be anything you want to describe the build such as Rel, Dev, Test, etc..

Under Process, you need to set it to use the new XAML you created (in my zip this is in the template folder). Check the xaml you create into the BuildProcessTemplates folder.

You might also have to change the MSBuild platform to x86. Mine is already set that way for other reasons.

At this point you should be able to queue your team build. It might build for you, but certainly doesn't for me.

If you are having problems, open the xaml I provided and using the first link, go to the area where we're adding our actions, and remove the installshield action. It should build with all of your assemblies with the same version, and conveniently the build name also shows the build #.

If you get an error trying to build with the installshield action, such as the following:
UpdateInstallShieldVersion ERROR. Exception: System.Runtime.InteropServices.COMException (0x80040154): Retrieving the COM class factory for component with CLSID {23473F79-0333-4A92-9823-DCD9B4509227} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)). at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache) at System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache) at System.Activator.CreateInstance(Type type, Boolean nonPublic) at BuildTasks.Activities.UpdateInstallShieldVersion.Execute(CodeActivityContext context)

I don't have a solution yet. I can get the same code compiling and working on my dev box no prob. It just won't work on the TFS server when called using team build. pasted here for reference:
[CODE]using System;
using System.Activities;
using System.Diagnostics;
using System.IO;
using System.Text.RegularExpressions;
using Microsoft.TeamFoundation.Build.Client;
using ISWiAuto17;

namespace BuildTasks.Activities
{
[BuildActivity(HostEnvironmentOption.Agent)]
public sealed class UpdateInstallShieldVersion : CodeActivity
{
// The file mask of all files for which the build number of the assembly version must be increased
[RequiredArgument]
public InArgument InstallShieldFileMask { get; set; }

// BuildDetail.BuildNumber
[RequiredArgument]
public InArgument BuildNumber { get; set; }

[RequiredArgument]
public InArgument SourcesDirectory { get; set; }

private ISWiAuto17.ISWiProject ISWiProject;

protected override void Execute(CodeActivityContext context)
{
try
{
// Obtain the runtime value of the input arguments
string installShieldFileMask = context.GetValue(this.InstallShieldFileMask);
string buildNumber = context.GetValue(this.BuildNumber);
string sourcesDirectory = context.GetValue(this.SourcesDirectory);

// Get all AssemblyInfo files
foreach (string file in Directory.EnumerateFiles(sourcesDirectory, installShieldFileMask, SearchOption.AllDirectories))
{
// Update build increment number in the version and write out to AssemblyInfo files
Version newVersion = BuildInfo.GetVersionNumber(buildNumber);

FileProperties.SetReadOnlyFlag(file, false);

// Replace the version number
ISWiProject = new ISWiAuto17.ISWiProject();
ISWiProject.OpenProject(file, false);
ISWiProject.ProductVersion = newVersion.ToString();
ISWiProject.SaveProject();
ISWiProject.CloseProject();

FileProperties.SetReadOnlyFlag(file, true);
}
}
catch (Exception ex)
{
throw new ArgumentException("UpdateInstallShieldVersion ERROR. Exception: " + ex.ToString());
}
}
}
}
[/CODE]

At this point I've tried basically everything, short of installing Installshield 2011 full onto the TFS server. I even checked the registry and show the assembly GUID it throws out in the error as registered.

I'm at my wits end, but hopefully this writeup helps others error free.
Labels (1)
0 Kudos
(4) Replies
CodeGuru
Level 4

Automation interface IS installed and registered on the server.

I just built a simple forms app with the following code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ISWiAuto17;

namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private ISWiAuto17.ISWiProject ISWiProject;


private void button1_Click(object sender, EventArgs e)
{
// Replace the version number
ISWiProject = new ISWiAuto17.ISWiProject();
ISWiProject.OpenProject("Setup.ism", false);
ISWiProject.ProductVersion = "1.2.3";
ISWiProject.SaveProject();
ISWiProject.CloseProject();
}
}
}


The app runs and modifies the .ism file on BOTH my dev and server machines.

Its only when the automation interface is run using TFSBuild that the error occurs.
0 Kudos
CodeGuru
Level 4

Should I be seeing this GUID in the dcomcnfg window? Because I don't.
{23473F79-0333-4A92-9823-DCD9B4509227}

I do see it in the registry in these locations:
HKLM\software\classes\wow6432Node\ClSID\{ID}
HKLM\Software\wow6432node\classes\clsid\{ID}
0 Kudos
Copernicus
Level 3

The problem is that ISWiAutomation17.dll is a 32-bit assembly, and the TFS build agents are 64-bit processes. So even though the "MSBuild Platform" parameter is set to X86, the parent process which actually uses the BuildTasks.dll still runs as a 64-bit application.
Compiling the BuildTasks.dll as a 32-bit (X64) assembly is no solution either, because then the 64-bit TFS Build agent process will fail to load the assembly.
Setting the "MSBuild Platform" parameter to X86 is a requirement to be able to build InstallShield solutions in TFS, but it does not allow you to call 32-bit assemblies in the xaml build script.
I guess creating a PowerShell (or vbscript) and calling the 32-bit version of the executable (in the SysWow64) folder in the TFS build script could be a workaround.
InstallShield should release an automation interface which works natively from 64bit processes (e.g. compiled with AnyCPU), so that it can be used by the TFS build agents, and by the 64bit version of MSBuild.
0 Kudos
Copernicus
Level 3

You could also install the TFS Build Service on a 32-bit Windows edition. I'm pretty sure that the InstallShield Automation interface will work via a 32bit TFS build engine.

http://msdn.microsoft.com/en-us/library/dd578619.aspx
0 Kudos