Visual Studio Installer > How To Launch App at End of Installer

C#Visual Studio-2010Windows InstallerSetup Project

C# Problem Overview


This is probably a stupid question and my Googling just is not functioning today.

I have an application I added a Visual Studio Installer > Setup Wizard project to. I am wondering how to add a button or check box that would launch the application after successful install. This would be located on the last page of the MSI Installer Package. I am using Visual Studio 2010 Ultimate.

I am needing this so that when the application does an automatic update, it auto launches the installer. I just need the installer to relaunch the app after the update.

This is probably very simple but for the life of me I cannot figure it out. Thanks in advance for you help.

C# Solutions


Solution 1 - C#

> Warning: The application will end up running as a high privilege account, which has security and user experience implications.

To run any application after the installation is complete,

  1. Right-click on your setup project, click on Custom Actions.
  2. Then right-click on Commit, Add Custom Action, and choose the file you would like to run. (Note that it has to be in your application folder already, which shouldn't be a problem in your case since you are running your program anyway.
  3. Simply choose the output of your project.
  4. Then, click on this added .exe, and change InstallerClass to false. This is crucial because it will look for an installer program otherwise.
  5. You could even pass parameters to your .exe by adding them to the Arguments property

Solution 2 - C#

The solution from https://blogs.msdn.microsoft.com/astebner/2006/08/12/mailbag-how-can-i-customize-an-msi-in-the-visual-studio-setupdeployment-project/ adds a checkbox at the end of the setup to choose if you want to start the application or not. You can modify the script to be checked by default...or even hide it.

The big advantage here is, that the application won't run with elevated rights like Maurice Flanagan mentioned.

The required script you need is:

// EnableLaaunchApplication.js <msi-file>
// Performs a post-build fixup of an msi to launch a specific file when the install has completed


// Configurable values
var checkboxChecked = true;			// Is the checkbox on the finished dialog checked by default?
var checkboxText = "Launch [ProductName]";	// Text for the checkbox on the finished dialog
var filename = "WindowsApplication1.exe";	// The name of the executable to launch - change this to match the file you want to launch at the end of your setup


// Constant values from Windows Installer
var msiOpenDatabaseModeTransact = 1;

var msiViewModifyInsert         = 1
var msiViewModifyUpdate         = 2
var msiViewModifyAssign         = 3
var msiViewModifyReplace        = 4
var msiViewModifyDelete         = 6



if (WScript.Arguments.Length != 1)
{
	WScript.StdErr.WriteLine(WScript.ScriptName + " file");
	WScript.Quit(1);
}

var filespec = WScript.Arguments(0);
var installer = WScript.CreateObject("WindowsInstaller.Installer");
var database = installer.OpenDatabase(filespec, msiOpenDatabaseModeTransact);

var sql
var view
var record

try
{
	var fileId = FindFileIdentifier(database, filename);
	if (!fileId)
		throw "Unable to find '" + filename + "' in File table";


	WScript.Echo("Updating the Control table...");
	// Modify the Control_Next of BannerBmp control to point to the new CheckBox
	sql = "SELECT `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_`='FinishedForm' AND `Control`='BannerBmp'";
	view = database.OpenView(sql);
	view.Execute();
	record = view.Fetch();
	record.StringData(11) = "CheckboxLaunch";
	view.Modify(msiViewModifyReplace, record);
	view.Close();

	// Resize the BodyText and BodyTextRemove controls to be reasonable
	sql = "SELECT `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_`='FinishedForm' AND `Control`='BodyTextRemove'";
	view = database.OpenView(sql);
	view.Execute();
	record = view.Fetch();
	record.IntegerData(7) = 33;
	view.Modify(msiViewModifyReplace, record);
	view.Close();

	sql = "SELECT `Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help` FROM `Control` WHERE `Dialog_`='FinishedForm' AND `Control`='BodyText'";
	view = database.OpenView(sql);
	view.Execute();
	record = view.Fetch();
	record.IntegerData(7) = 33;
	view.Modify(msiViewModifyReplace, record);
	view.Close();

	// Insert the new CheckBox control
	sql = "INSERT INTO `Control` (`Dialog_`, `Control`, `Type`, `X`, `Y`, `Width`, `Height`, `Attributes`, `Property`, `Text`, `Control_Next`, `Help`) VALUES ('FinishedForm', 'CheckboxLaunch', 'CheckBox', '18', '117', '343', '12', '3', 'LAUNCHAPP', '{\\VSI_MS_Sans_Serif13.0_0_0}" + checkboxText + "', 'Line1', '|')";
	view = database.OpenView(sql);
	view.Execute();
	view.Close();



	WScript.Echo("Updating the ControlEvent table...");
	// Modify the Order of the EndDialog event of the FinishedForm to 1
	sql = "SELECT `Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering` FROM `ControlEvent` WHERE `Dialog_`='FinishedForm' AND `Event`='EndDialog'";
	view = database.OpenView(sql);
	view.Execute();
	record = view.Fetch();
	record.IntegerData(6) = 1;
	view.Modify(msiViewModifyReplace, record);
	view.Close();

	// Insert the Event to launch the application
	sql = "INSERT INTO `ControlEvent` (`Dialog_`, `Control_`, `Event`, `Argument`, `Condition`, `Ordering`) VALUES ('FinishedForm', 'CloseButton', 'DoAction', 'VSDCA_Launch', 'LAUNCHAPP=1', '0')";
	view = database.OpenView(sql);
	view.Execute();
	view.Close();



	WScript.Echo("Updating the CustomAction table...");
	// Insert the custom action to launch the application when finished
	sql = "INSERT INTO `CustomAction` (`Action`, `Type`, `Source`, `Target`) VALUES ('VSDCA_Launch', '210', '" + fileId + "', '')";
	view = database.OpenView(sql);
	view.Execute();
	view.Close();



	if (checkboxChecked)
	{
		WScript.Echo("Updating the Property table...");
		// Set the default value of the CheckBox
		sql = "INSERT INTO `Property` (`Property`, `Value`) VALUES ('LAUNCHAPP', '1')";
		view = database.OpenView(sql);
		view.Execute();
		view.Close();
	}



	database.Commit();
}
catch(e)
{
	WScript.StdErr.WriteLine(e);
	WScript.Quit(1);
}



function FindFileIdentifier(database, fileName)
{
	var sql
	var view
	var record

	// First, try to find the exact file name
	sql = "SELECT `File` FROM `File` WHERE `FileName`='" + fileName + "'";
	view = database.OpenView(sql);
	view.Execute();
	record = view.Fetch();
	if (record)
	{
		var value = record.StringData(1);
		view.Close();
		return value;
	}
	view.Close();

	// The file may be in SFN|LFN format.  Look for a filename in this case next
	sql = "SELECT `File`, `FileName` FROM `File`";
	view = database.OpenView(sql);
	view.Execute();
	record = view.Fetch();
	while (record)
	{
		if (StringEndsWith(record.StringData(2), "|" + fileName))
		{
			var value = record.StringData(1);
			view.Close();
			return value;
		}

		record = view.Fetch();
	}
	view.Close();
	
}

function StringEndsWith(str, value)
{
	if (str.length < value.length)
		return false;

	return (str.indexOf(value, str.length - value.length) != -1);
}

Edit the file to show your desired name and the name of the executable, put that file beside your .vdproj Setup project and in the postbuild add following line:

CALL cscript.exe "$(ProjectDir)EnableLaunchApplication.js" "$(BuiltOuputPath)"

Solution 3 - C#

> Warning: The application will end up running as a high privilege > account, which has security and user experience implications.

In Visual Studio 2010 here it is easy...

Step1: Add a new installer class to the application project that you wish to run after install, call it what you like.

Step2: Add the following code to the Installer class you just added replcaing MyApplication.exe with the name of yours.

Public Overrides Sub Commit(ByVal savedState As System.Collections.IDictionary)

	MyBase.Commit(savedState)
	System.Diagnostics.Process.Start(System.IO.Path.GetDirectoryName(Me.Context.Parameters("AssemblyPath")) + "\MyApplication.exe")

End Sub

Compile and go...

Solution 4 - C#

In my case, I was fighting with this for a while and the solution was just there. The solution provided using the custom action directly to the application primary output wasn't good for me, since the install app remains until you leave the main app. So, the issue could be solved using the next approach:

  1. Add an Install class to your project;
  2. In the new class, override the Commit method, like Jarrod talked above. >System.Diagnostics.Process.Start(System.IO.Path.GetDirectoryName(this.Context.Parameters["AssemblyPath"]) + @"\MyApplication.exe");
  3. Now the trick: go to the "Custom Actions" pane in the Installer project and add the primary output of your project to "Commit" and "Install" folders. Don't change anything in the properties. It will work just like that. As default, it will get the installer class where you inserted the code, in the previous point;
  4. Build your setup package and install it. You should notice that the app will start at the end;
  5. Just close the successful installation warning and go for it.

To know more about this and where I got it, please visit this.

PS.: I made it using VS2017 and Framework 2.0.

Solution 5 - C#

Try checking out this blog post: http://blogs.msdn.com/b/astebner/archive/2006/08/12/696833.aspx

I can't attest for if it works for 2010 or not; I'm still stuck using 2008 until my TFS server gets upgraded. Also, I use WiX for my installers. But, it's just a custom action, so I think it should still be supported.

Hope this helps!

(By the way, while practicing my googling to find this, your question was showing up on the first page of Google for this question.)

Solution 6 - C#

Adding another answer because none of the previous answers address the checkbox or button question in the original post.

You'd add one of the canned dialogs to your setup project, something like CheckBoxes(A) by right-clicking the Start button in the User Interface view. Right-click the dialog after adding to move it up. You need only one checkbox for the question to ask about running the program so eliminate the others. The default property name is CHECKBOXA1, so add a condition to the custom action that fires off your code CHECKBOXA1=1 meaning it was checked.

Solution 7 - C#

first generate installer class. in that override the install method. and paste the following command.

  public override void Install(IDictionary stateSaver) {
        
    System.Diagnostics.Process.Start(System.IO.Path.GetDirectoryName(this.Context.Parameters["AssemblyPath"]) + @"\windowsAgent.exe");   
              
 }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionThaKidd KG5ORDView Question on Stackoverflow
Solution 1 - C#sbenderliView Answer on Stackoverflow
Solution 2 - C#JayTeeView Answer on Stackoverflow
Solution 3 - C#JarrodView Answer on Stackoverflow
Solution 4 - C#Artur GomesView Answer on Stackoverflow
Solution 5 - C#fire.eagleView Answer on Stackoverflow
Solution 6 - C#PhilDWView Answer on Stackoverflow
Solution 7 - C#Hirusha RandunuView Answer on Stackoverflow