I have written an installation class that extends Installer and overrides afterInstall, but I'm getting a null pointer exception. How can I go about debugging my class?
14 Answers
Something that is handy for hard to debug sections of code is
System.Diagnostics.Debugger.Break()
Will throw a breakpoint caught by any installed debugger (VStudio, WinDbg, Remote debugger etc...).
Use it to debug really tricky areas where regular F5+Go or "Attach to Process" is difficult or impossible to perform, some examples include:
- short-lived processes
- time-sensitive processes
- breaking into spawned sub-processes
- installers
- service stop/start
- distributed systems

- 5,072
- 26
- 42
-
11Didn't work for me, with out first doing System.Diagnostics.Debugger.Launch() – Mark Lakata Feb 13 '12 at 22:23
-
1Hey Mark - Break tries to launch whichever debugger is specified in Automatic Debugging Reg Keys. I can imagine if there is no debugger specified it'd do nothing - then try to attach it - result nothing. Where as by launching it explicitly you attach that instance. http://msdn.microsoft.com/en-us/library/windows/desktop/bb204634(v=vs.85).aspx has more details. There was a buried dialog for specifying the default debugger too - escapes me at the moment. – stephbu Feb 13 '12 at 23:55
-
1Also, be sure to build the installer in debug mode so the debug files are there. And I also had to [disable "Enable Just My Code"](http://stackoverflow.com/questions/31580182/visual-studio-2015-rtm-debugging-not-working). Worked like a charm! Thanks! – JohnnyFun Sep 17 '16 at 13:05
The best way I've found is to write a unit test, and new up and initialize your installer class from your unit test:
[TestClass] public class InstallerTest {
[TestMethod]
public void InstallTest() {
// substitute with your installer component here
DataWarehouseInstall installer = new DataWarehouseInstall();
string assemblyDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
string installLogFilePath = Path.Combine(assemblyDirectory, "install.log");
installer.Context = new System.Configuration.Install.InstallContext(installLogFilePath, null);
// Refactor to set any parameters for your installer here
installer.Context.Parameters.Add("Server", ".");
//installer.Context.Parameters.Add("User", "");
//installer.Context.Parameters.Add("Password", "");
installer.Context.Parameters.Add("DatabaseName", "MyDatabaseInstallMsiTest");
//installer.Context.Parameters.Add("DatabasePath", "");
// Our test isn't injecting any save state so we give a default instance for the stateSaver
installer.Install(new Hashtable());
} }
At least then it takes advantage of the IDE tooling better. This is especially helpful for very large installers with LOTS of components. Then you can also create ordered unit tests and run them in sequence to mimic your installer during debug or your automated builds.
Another tip would be general SOLID/GRASS software principles...develop in neat/thin layers, keeping your actual "custom action" installer logic very simple and instead call into any reusable API stuff you have that is specific to your installer(s), just as we are used to with UI development. (The installer is just another UI anyway.) This is especially key if your goal is to have a certain UI experience shared across all installers of your products.

- 121
- 1
- 4
Surprised no one has actually answered. Put a MessageBox.Show("hello") into your custom action's Install() member. Build the deployment in debug config. Install. When the MessageBox appears, go into VS IDE, Debug, Attach Process and look for the instance of msiexec that is labeled "Managed". Attach the debugger to that instance of msiexec. Now go back to the source of your custom action and place a breakpoint right after the call to MessageBox.Show(). Close the MessageBox and your breakpoint will be hit, and you're debugging in the IDE!

- 1,306
- 1
- 11
- 18
-
4+1: although it might be noteworthy to ensure that the `Show All Processes` checkbox *is* checked. In addition, one could `GetCurrentProcess` and positively identify the correct process with the `Id`. :) – IAbstract Oct 18 '12 at 19:54
-
Why use this when you can call `System.Diagnostics.Debugger.Break()`? You have to add WindowsForms dll in order to use MessageBox. Also, for CustomInstallers, the process name will be InstallUtil. – daniloquio Nov 10 '15 at 22:51
In your installer method add Debugger.Launch() statement which will launch "Visual Studio just in time debugger" where you can attach an instance of visual studio and debug your installer class (MSI). This should work in Visual Studio 2010 as well. But you need to have administrative rights to do this. If you don't have administrative rights, you might have issues. So, log in as administrator for debugging MSI. For example:
public override void Install(System.Collections.IDictionary stateSaver)
{
Debugger.Launch();
base.Install(stateSaver);
}
In visual studio 2005, even Debugger.Break() use to work but somehow this does not work with Visual Studio 2010.

- 39,603
- 20
- 94
- 123

- 1,591
- 1
- 21
- 18
-
+1 _But you need to have administrative rights to do this_. This is the only answer that's said this, and I think that's my problem. – transistor1 May 24 '13 at 13:17
attach the installer process to Visual studio in Debug->Processes->Attach or CTRL + ALT + P set the breakpoint and you should be able to go

- 4,168
- 8
- 29
- 49
This is what actually worked for me.
System.Diagnostics.Debugger.Launch();
Then right click on the Installer Project and press "Install"

- 483
- 4
- 10
None of above worked for me. This is what actually worked. Note that you need to put insert "both" lines.
using System.Diagnostics;
MessageBox.Show("Test is about to begin");
Debugger.Launch();

- 7,694
- 5
- 42
- 44
Write the following code in the beginning of the method that you want to debug
#if DEBUG
MessageBox.Show(Process.GetCurrentProcess().Id.ToString());
#endif
So when your method is called, the above code will be hit and you can then attach the debugger to the process(ctrl+alt+p) using the above process ID. You may have to start VS with elevated permissions.

- 177
- 2
- 6
I use the following class to write a simple log into the target directory. In my opinion, it's easier than trying to use the Visual Studio debugger.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace MyCompany.Deployment
{
/// <summary>
/// Enables a quick and easy method of debugging custom actions.
/// </summary>
class LogFile
{
const string FileName = "MyCompany.Deployment.log";
readonly string _filePath;
public LogFile(string primaryOutputPath)
{
var dir = Path.GetDirectoryName(primaryOutputPath);
_filePath = Path.Combine(dir, FileName);
}
public void Print(Exception ex)
{
File.AppendAllText(_filePath, "Error: " + ex.Message + Environment.NewLine +
"Stack Trace: " + Environment.NewLine + ex.StackTrace + Environment.NewLine);
}
public void Print(string format, params object[] args)
{
var text = String.Format(format, args) + Environment.NewLine;
File.AppendAllText(_filePath, text);
}
public void PrintLine() { Print(""); }
}
}

- 5,370
- 7
- 50
- 81
For logging purposes (in 3.5) what about using:
Context.LogMessage("My message");

- 5,695
- 3
- 31
- 35
I use EventLog.WriteEntry("source", "message"), and check the EventLog when installing. Maybe not optimal, but works for me :)
-
I would do the same .... write to log and check the log once the application has finished executing so get a cleat picture what is going .... asserting the fact that your a pedantic enough! – IbrarMumtaz May 05 '10 at 21:41
You might automate debugging of installer projects by adding following section to either .csproj or .csproj.user file:
<PropertyGroup Condition="'$(Configuration)' == 'Debug'">
<StartAction>Program</StartAction>
<StartProgram>$(MSBuildBinPath)\installutil.exe</StartProgram>
<StartArguments>$(AssemblyName).dll</StartArguments>
</PropertyGroup>
Use project file if you want other developers benefit from this change and .user file if you want to use it by yourself.

- 346
- 5
- 7
build a VM, install Visual studio, make a copy of it (or create a differencing Virtual HDD) and run the installer under the debugger under the VM.
That is what I would do (but I'm no expert).

- 75,627
- 68
- 187
- 294
-
1Combine this with the System.Diagnostics.Debugger.Break() tip and life gets really good at producing debuggable repros. – stephbu Nov 11 '08 at 06:49
You can also use the installUtil.exe utility to test your installer component.
In case you created a c# class assembly with your Installer class, Change your debug settings to start the external program 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\InstallUtil.exe' and enter your commandline arguments accordingly (e.g. /Args=myargument "path to the assembly")
As last set your breakpoints, press f5 and you're set to debug your code. --paralax

- 1
- 1