See attached project. This is a very small test project so I can learn. Here are my questions:

1) I've overridden the Install and Uninstall in my Installer component based class, but they don't seem to get called...why? I am setting a breakpoint in the Install override and running in debugger--you can do that right?:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Runtime.InteropServices; // Deploying a .NET component customization

namespace CustomAction1
{
    [RunInstaller(true)]
    public partial class Installer1 : Installer
    {
        public Installer1()
        {
            InitializeComponent();
        }

        public override void Install(System.Collections.IDictionary stateSaver)
        {
            base.Install(stateSaver);
            RegistrationServices regSrv = new RegistrationServices();
            regSrv.RegisterAssembly(base.GetType().Assembly,
              AssemblyRegistrationFlags.SetCodeBase);
        }

        public override void Uninstall(System.Collections.IDictionary savedState)
        {
            base.Uninstall(savedState);
            RegistrationServices regSrv = new RegistrationServices();
            regSrv.UnregisterAssembly(base.GetType().Assembly);
        }
    }
}

2) How do I invoke the following CustomAction (see below)? It doesn't matter to me whether before or after install, though I would like to know how you tell the setup to do it both ways. I assume you cannot invoke a CustomAction while it performs the actual installation--is that correct assumption?

[CustomAction]
        public static ActionResult CustomAction1(Session session)
        {
            session.Log("Begin CustomAction1");

            string[] arguments = GetCustomActionDataArguments(session);

            string body = "Arguments:\n";
            foreach (string s in arguments)
                body += "\t" + s + "\n";
            MessageBox.Show(body, "CustomAction1");

            return ActionResult.Success;
        }

3) How or can I view the msi script directly to see declarations and logic in the IDE? I used to work with InstallShield and you could view and edit the script file directly, which was often easier to find what you are looking for and understand the settings than it is to sift through all the different views in the IDE.

Thanks!

Recommended Answers

All 7 Replies

Installer Portion

My progress thus far is I have figured out how to utilize the Install component added to my CustomAction1 project, as well as the limitations associated with it only being callable after the install has installed everything designated in the setup. I understand why this is. I am able to retrieve setup parameters and pass in user-defined parameters from the setup--mission accomplished here.

My only remaining question in this area is whether anyone knows a technique for substituting a debugger instance of the CustomAction1 library at runtime of Setup so that breakpoint debugging can occur when setup calls the Install override? Although the capability is more of a luxury than a necessity at this point, for this portion at least, I am still curious to know.

I am reposting this portion of the code for anyone who happens along this thread because I know how difficult it is to find information on this subject that is correct and up-to-date; and, although my contribution is by no means a complete one, it does provide some insight to things I would have liked to have run into during the research. I am also attaching the current project for the same purpose.

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Runtime.InteropServices; // Deploying a .NET component customization
using System.Windows.Forms;
//using Microsoft.Deployment.WindowsInstaller; // creates a conflict with "Install" def

namespace CustomAction1
{
    [RunInstaller(true)]
    public partial class Installer1 : Installer
    {
        // Only method that gets generated when you add this class to the project as Install Component
        public Installer1()
        {
            InitializeComponent();
            MessageBox.Show("Install contsructor called...", "Debug"); // my debug message...
        }

        public override void Install(System.Collections.IDictionary stateSaver)
        {
            /* Below are messagebox's to indicate what's happening, when,
             * and shows how to retrieve a parameter passed in from the setup.
             * 
             * Most are useless once you know what is happening, but I left them in
             * for the benefit of anybody else trying this stuff out for the first time.
             * 
             * I could not find a way to work with breakpoints, but it might be possible to insert 
             * this instance or something at runtime while in the debugger.
             */

            MessageBox.Show("Begin Install Override!\n\nNOTE: All files added to setup, if any, have already been installed!", "Debug");

            // Let's see what parameters are passed in from setup:
            string msg = "Parameters Passed In:\n\n";
            foreach (string key in Context.Parameters.Keys)
            {
                string s = Context.Parameters[key];
                msg += "\t" + key + "=" + s + "\n";
            }
            MessageBox.Show(msg, "Debug");


            // MESSAGE parameter:
            //
            // This parameter is user-defined in Custom Action Properties's CustomActionData
            // under the Install category item
            // as: /Message="[MESSAGE]"
            //
            // It is set from the TextBoxes (A) generic dialog added to the User Interface View
            // under the Start category following the default Welcome dialog added when the 
            // project is created.
            msg = Context.Parameters["MESSAGE"];
            MessageBox.Show("Message From Setup entered from TextBoxes (A), in Edit1Value Textbox:\n\n" + msg, "Debug");

            // change the value of the CustomActionData parameter for MESSAGE just for hell of it
            Context.Parameters["MESSAGE"] = "New Message Text, but can it be used by Setup at this point?";// -- save for future ref

            // How do you get access to the Session's handle?
            //Microsoft.Deployment.WindowsInstaller.Session session = Microsoft.Deployment.WindowsInstaller.Session.FromHandle(this., false);

            // This remaining code is original method body that I copied off the web somewhere...
            base.Install(stateSaver);
            MessageBox.Show("Return from Install base.Install", "Debug"); // except for this debug statement.
            RegistrationServices regSrv = new RegistrationServices();
            regSrv.RegisterAssembly(base.GetType().Assembly,
              AssemblyRegistrationFlags.SetCodeBase);
        }

        public override void Uninstall(System.Collections.IDictionary savedState)
        {
            MessageBox.Show("Begin Uninstall Override!", "Debug");
            base.Uninstall(savedState);
            RegistrationServices regSrv = new RegistrationServices();
            regSrv.UnregisterAssembly(base.GetType().Assembly);
        }
    }
}

[CustomAction] Portion

I still would like to know how I can invoke the [CustomAction] I referred to when starting this thread, especially when user presses the next button on one of the setup dialogs and before the actual install starts. If anyone has an idea, I would really appreciate suggestions.

[CustomAction]
        public static ActionResult CustomAction1(Session session)

Comments:

After refamiliarizing myself with setup, it occurs to me that this is not an ideal forum for these types of questions, but a reasonable alternative forum does not appear to present itself on this website either I don't think. If anyone knows of a website pertaining to this subject that is free and has a good amount of traffic with dedicated followers, please tell. Also, special thanks to anyone who has and will take the time to look at any of this thread because it is probably an area that most programmers are not interested in.

I figured serkan would be all over this thread :P I hate installers

As far as I know you can't set a break point but what you can do is make a call to Debugger.Break()

namespace daniweb.installerex
{
  [RunInstaller(true)]
  public partial class Installer1 : Installer
  {
    public Installer1()
    {
      InitializeComponent();
    }
    public override void Install(IDictionary stateSaver)
    {
      System.Diagnostics.Debugger.Break();
      base.Install(stateSaver);
    }
  }
}

When you're installing the installer will come up with a message about hitting a break point, tell it to debug and open a new instance of visual studio.

Also with the installer -- I tried to go down the road you're going but I hit a problem and decided it wasn't worth it. Lets say your application is already installed on a machine and you have a custom action setup for Install() in the output of an assembly.

Version A - Installed
Version B - Want to install this version

You install version A, life is good.

You install version B which detects that version A is installed and it loads up your assembly in to the installers AppDomain. It uninstalls the old version and now proceeds to install the new version. Problem: Version "A" of your assembly is already loaded so when it calls the new custom install action is will actually call the actions on your old installer and not your new one. I don't know if this has been fixed yet but as far as I know it hasn't.

This can lead to a lot of head aches.

[edit]
To be more clear on the AppDomain issue.

As you can tell you can set up a custom action for uninstall. When you uninstall it launches the logic for the old uninstaller because the new uninstall logic pertains to the new assembly, and likewise with the old. When it loads up the assembly to uninstall the old version is where the problem occurs because you cannot load two assemblies with different versions in the same app domain. And you can also not unload an assembly in your main application domain, you have to create a new app domain and you tear down the entire domain.
[/edit]

Thanks Scott! I tried that Debugger.Break() and it worked fine. Also, thanks much for sharing your past experience. That could save a whole lot of time for me or someone else that might run into that situation.

I have no plans to use the setup and really only started down this path to help figure out a question serkan had, but you never know when you might find yourself (perhaps forcibly) trying to do something like this so I don't mind learning it.

DdoubleD i appreciate your hardwork, i will look at it carefully in couple days. As Scott said, i will be all over this thread :)

ok DdoubleD, i investigated your demo application and unfortunately it didnt solve my problem. I know you can pass parameter values from setup project to custom installer project, my question was this : how do you pass the version information that is embedded in to setup project. for example you pass the target directory like this : /yourCustomParameter="[TARGETDIR]\" , like wise i want to be able to pass that embedded version information.

Thanks.

I have not figured out yet how to include more than one custom action, but I have figured out how to call my property [CustomAction]:

1) Must be only custom action in selected library (as far as I can figure it out)
2) Set EntryPoint to method name. In my case: CustomAction1
3) Set InstallerClass to False

A free website I found with good information and links on installers: http://www.installsite.org/

Person most likely to ask you questions about installers, but never answer any of yours: serkan;)

I took the time to wrap up this exercise. The setup can now:

User Interface View - Look at the properties for TextBoxes (A) under Start category to see how:
1) 2nd dialog (from predefined template) prompts for a message and will store the result in a property called [MESSAGE].

Custom Actions View - look at order in interface and properties of each to see how:
1) calls a custom action, which will display parameter [MESSAGE]
2) calls a custom action override for Install and Uninstall methods; Install method will display all session parameters available when called.
3) calls another custom action that does nothing except to demonstrate this sequence of CA/Install/CA

This is trivial exercise at this point, but getting here was a pain in the arse!

Cheers!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.