Friday 13 April 2012

InstallShield Automation Using c#


For the last few days I did a quick search for a solution to automate my nightly Installshield MSI builds . After going through a few code snippets developed in VBS etc, I decided to create my own using C# which I would like to share.

To start with you need to create a C# project then add a reference for Installshield Automation Library, can be locate at C:\Program Files\InstallShield\[Version]\. Depending on the IS version you are using, the Library name may vary.

It would be more present if Installshield provided a factory to serve up the different automation interface versions since this already presents a challenge of the code being version dependent. In my solution here am using IS 2011 whose reference appears as ISWiAuto17.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ISWiAuto17;


namespace xxx
{
    public delegate void LogStatus(String smessage);
    public delegate void logprogress(int lIncrement);

    class InstallShieldAuto
    {
        private string sProjectFileName;
        private string sISExFilename;
        private string sBuildLocation;
        private string sBuildNumber;


        public event LogStatus log;
        public event logprogress progress;

        public InstallShield() {}

        public InstallShield(string projectName, string isexFileName, string buildLocation, string buildNumber)
        {
            sProjectFileName = projectName;
            sISExFilename = isexFileName;
            sBuildLocation = buildLocation;
            sBuildNumber = buildNumber;
        }


        /// <summary>
        /// Holds the location where the ISM project
        /// </summary>
        public string ProjectFile{
            get{
                return sProjectFileName;

            }
            set {
                sProjectFileName = value;
           
            }
        }
        /// <summary>
        /// Holds the Install Shield Executable file location
        /// </summary>
        public string ISExecutableFile
        {
            get
            {
                return sISExFilename;

            }
            set
            {
                sISExFilename = value;

            }
        }

        /// <summary>
        /// Holds the release location
        /// </summary>
        public string BuildLocation
        {
            get
            {
                return sBuildLocation;

            }
            set
            {
                sBuildLocation = value;

            }
        }
        /// <summary>
        /// Holds the build number
        /// </summary>
        public string BuildNumber
        {
            get
            {
                return sBuildNumber;

            }
            set
            {
                sBuildNumber = value;

            }
        }


        /// <summary>
        /// execute the build process
        /// </summary>
        public void BuildProject()
        {
            ISWiProductConfigs oProdConfigs;
            ISWiProductConfig oProdConfig;
            ISWiRelease oRelease= new ISWiRelease();
            ISWiProject oISWiProj = new ISWiProject();
            try
            {

                //Create IS object
                oISWiProj.OpenProject(sProjectFileName, false);
                oISWiProj.ProductVersion = sBuildNumber;

                oProdConfigs = oISWiProj.ISWiProductConfigs;
                oProdConfig = oProdConfigs[oProdConfigs.Count];


                oRelease = oProdConfig.ISWiReleases[1];

                oRelease.ProgressIncrement += new __ISWiRelease_ProgressIncrementEventHandler(release_ProgressIncrement);
                oRelease.StatusMessage += new __ISWiRelease_StatusMessageEventHandler(this.release_StatusMessages);

                oRelease.BuildLocation = sBuildLocation;
                oRelease.Build();

                 oISWiProj.SaveProject();

                 oISWiProj.CloseProject();
            }
            catch
            {
                log("Build Failed...");
            }
            finally {
                oRelease.ProgressIncrement -= new __ISWiRelease_ProgressIncrementEventHandler(release_ProgressIncrement);
                oRelease.StatusMessage -= new __ISWiRelease_StatusMessageEventHandler(this.release_StatusMessages);
            }
        }
        private void release_ProgressIncrement(int lIncrement, ref bool pbCancel)
        {
            progress(lIncrement);
        }
        private void release_StatusMessages(string sMessage, ref bool pbCancel)
        {
            log(sMessage);
        }
    }
}


As you can see there is nothing much of the code is self-explanatory, Let’s expound on some of the major area in the  Buildproject() method.
1.    Declare and open your project
                        oISWiProj.OpenProject(sProjectFileName, false);

2.    Retrive all the available configurations and pick the right configuration, in this case I have used the last one.
oProdConfigs= oISWiProj.ISWiProductConfigs;
          oProdConfig = oProdConfigs[oProdConfigs.Count];

3.    From the selected configuration, you will have a collection of  releases, pick the release want by providing the index. In my case index one [1] is Release 1.
oRelease = oProdConfig.ISWiReleases[1];

4.    As the build progresses, the process provides status messages and the progress value through events.  
                oRelease.ProgressIncrement += new __ISWiRelease_ProgressIncrementEventHandler(release_ProgressIncrement);
                oRelease.StatusMessage += new __ISWiRelease_StatusMessageEventHandler(this.release_StatusMessages);


5.    Build the release then save ad close the project.
oRelease.Build();
oISWiProj.SaveProject();
              oISWiProj.CloseProject();

One thing that I still haven’t figured out is how to use the names to pick out he configuration and the release from the collection. Once I have that ready I will post my finding but for now I will make do with the indexes




23 comments:

  1. Nice article, especially the automation of builds ....

    ReplyDelete
  2. Great article, would be good if you could talk about how to work with different versions of the automation interface without having to re-compile the code against different DLL versions. i.e. could we use DLLImport with a FileExists statement to search for the relevant version of the DLL to use?

    ReplyDelete
  3. You can iterate over the collection of product configurations or releases and check the name of each of them. I guess this is the only way to get a specific object from the collection by name.

    ReplyDelete
    Replies
    1. Thats correct Vidape, an iteration on the releases will do.

      Delete
  4. Hi, i am using ISWiAutomation16 and when the workflow is about to run my custom activity, i get this error message :

    Retrieving the COM class factory for component with CLSID {8D3073CA-1D88-42B4-8D47-56FE9D633705} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

    ReplyDelete
    Replies
    1. Confirm that the COM component by the class ID {8D3073CA-1D88-42B4-8D47-56FE9D633705} is correctly registered in your machine. If you want to know the component name, you could go to the ProgId table and do a search using the class id.

      Delete
    2. It is ISWiAuto16.ISWiRelease

      Delete
    3. I just found how to solve it.

      ISWiRelease oRelease= new ISWiRelease();

      You can't instanciate an interface.

      ISWiRelease oRelease;

      Delete

  5. Hai Mark Maigua,

    Am Getting this Error COM Exception was unhandled

    Retrieving the COM class factory for component with CLSID {B105BA24-892E-488B-B49D-CA2F3B261D67} failed due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).

    ISWiRelease oRelease = new ISWiAuto17.ISWiRelease();

    In this line am getting this error i tried lot of things but that did not help me can you please help me to over come from this error.

    ReplyDelete
    Replies
    1. Hello Gowthaman, Avoid instantiating the ISWiRelease object, instead assign it a release from the ISWiReleases collection.

      Delete
  6. Hai Mark Maigua,

    ISWiProductConfigs oProdConfigs;
    ISWiProductConfig oProdConfig;
    ISWiRelease oRelease= new ISWiRelease();
    ISWiProject oISWiProj= new ISWiProject();
    //oRelease = new ISWiAuto17.ISWiRelease();
    //oISWiProj = new ISWiAuto17.ISWiProject();
    try
    {

    //Create IS object
    oISWiProj.OpenProject(sProjectFileName, false);
    oISWiProj.ProductVersion = sBuildNumber;

    oProdConfigs = oISWiProj.ISWiProductConfigs;
    oProdConfig = oProdConfigs[oProdConfigs.Count];


    oRelease = oProdConfig.ISWiReleases[1];

    oRelease.ProgressIncrement += new __ISWiRelease_ProgressIncrementEventHandler(release_ProgressIncrement);
    oRelease.StatusMessage += new __ISWiRelease_StatusMessageEventHandler(this.release_StatusMessages);

    oRelease.BuildLocation = sBuildLocation;
    oRelease.Build();

    oISWiProj.SaveProject();

    oISWiProj.CloseProject();
    }
    catch(Exception ex)
    {
    log("Build Failed..."+ex.ToString());
    }
    finally
    {
    oRelease.ProgressIncrement -= new __ISWiRelease_ProgressIncrementEventHandler(release_ProgressIncrement);
    oRelease.StatusMessage -= new __ISWiRelease_StatusMessageEventHandler(this.release_StatusMessages);
    }
    }
    private void release_ProgressIncrement(int lIncrement, ref bool pbCancel)
    {
    progress(lIncrement);
    }
    private void release_StatusMessages(string sMessage, ref bool pbCancel)
    {
    log(sMessage);
    }

    This is my code where i have change can you tell me please

    ReplyDelete
    Replies
    1. ISWiProductConfigs oProdConfigs;
      ISWiProductConfig oProdConfig;
      ISWiRelease oRelease; //= new ISWiRelease(); //Do this change
      ISWiProject oISWiProj= new ISWiProject();
      //oRelease = new ISWiAuto17.ISWiRelease();
      //oISWiProj = new ISWiAuto17.ISWiProject();
      try
      {

      Delete
  7. Hi mark,
    i am getting below error for above code
    .Error 1 Use of unassigned local variable 'oRelease'

    could you please help me

    ReplyDelete
  8. I get below error when I do ISWiProject objISWiProj = new ISWiProject();

    [exec] Installshield Build Failed. Exception : Creating an instance of the COM component with CLSID {} from the IClassFactory failed due to the following error: 800a0035 Exception from HRESULT: 0x800A0035 (CTL_E_FILENOTFOUND).

    Any idea what might be causing this? It's a standalone InstallShield installation on 64 bit machine.

    ReplyDelete
    Replies
    1. Encountered with same error. How did you solved this?

      Delete
  9. How to wrap multiple exe files into msi package with InstallShield at run time..Please help me creating msi package with code at run time instead of manually creating msi package with install shield.

    ReplyDelete
    Replies
    1. Hi Tenkani,
      I am not sure I understand question.
      1. Do you want to automatically create an installshield project for all the exe file or each exe by it's self?
      2. Do you want to package all exe files in one msi and each exe files as a feature?

      Please clarify.

      Delete
  10. Hi Mark,

    Thanks for your response...
    I want the 2nd point you mentioned that is creating an msi package for all exe files and each exe file as a feature with C# code at run time(because its purely user's choice what exe files should be created as a package in web application)
    Also please suggest me whether it is possible or not of creating msi package for multiple exe files at run time in web application.

    Regards,
    Bharathi.

    ReplyDelete
  11. i am getting error methods must have written type:
    Please help me

    public InstallShield() {}

    public InstallShield(string projectName, string isexFileName, string buildLocation, string buildNumber)

    ReplyDelete
  12. if i wont intialise following code:
    ISWiRelease oRelease; //= new ISWiRelease();
    i am getting following error: use of unassgined variable oRealse

    ReplyDelete
  13. after building tis code how to work with install shield project to make it automated. I have compiled above code what next? how to get my install project building automatically
    what are things i need to do Please help me

    ReplyDelete
  14. Mark, Thanks for this... Great info, just needed a small example to get me started.. Was able to use this as a base for automating Package Code and Product version number changes. Thanks!

    ReplyDelete

Comment