If the installer isn't registering the COM objects using the default mechanism, you can try forcing it using a custom action. An extra benefit of this technique is that you can single-step through the custom action to work out what is going on.
Add a class to your project that inherits from Installer,is decorated with this attribute
[RunInstaller(true)]
and overrides one or more of the following methods:
Install()
Uninstall()
Commit()
Rollback()
Here's a complete example that performs registration with COM Interop. It's sprinkled with trace output which (contrary to some opinions) will show up in Sysinternals DebugVw. When built in Debug configuration, it'll put up a dialog box that allows you to attach a debugger and single step the custom action.
using System.ComponentModel;
using System.Configuration.Install;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace TiGra
{
/// <summary>
/// Custom install actions that must be carried out during product installation.
/// </summary>
[RunInstaller(true)]
public class MyInstaller : Installer
{
/// <summary>
/// Custom Install Action that performs custom registration steps as well as
/// registering for COM Interop.
/// </summary>
/// <param name="stateSaver">Not used<see cref="Installer"/></param>
public override void Install(System.Collections.IDictionary stateSaver)
{
Trace.WriteLine("Install custom action - Starting registration for COM Interop");
#if DEBUG
MessageBox.Show("Attach debugger to this process now, if required", "Custom Action Debug", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
#endif
base.Install(stateSaver);
RegistrationServices regsrv = new RegistrationServices();
if (!regsrv.RegisterAssembly(this.GetType().Assembly, AssemblyRegistrationFlags.SetCodeBase))
{
Trace.WriteLine("COM registration failed");
throw new InstallException("Failed To Register for COM Interop");
}
Trace.WriteLine("Completed registration for COM Interop");
}
/// <summary>
/// Custom Install Action that removes the COM Interop component registrations.
/// </summary>
/// <param name="savedState">Not used<see cref="Installer"/></param>
public override void Uninstall(System.Collections.IDictionary savedState)
{
Trace.WriteLine("Uninstall custom action - unregistering from COM Interop");
try
{
base.Uninstall(savedState);
RegistrationServices regsrv = new RegistrationServices();
if (!regsrv.UnregisterAssembly(this.GetType().Assembly))
{
Trace.WriteLine("COM Interop deregistration failed");
throw new InstallException("Failed To Unregister from COM Interop");
}
}
finally
{
Trace.WriteLine("Completed uninstall custom action");
}
}
}
}
One final thing left to do. The custom actions will not run unless the installer is configured to do so. Here's how:
- In your Visual Studio installer project, right click on the project name and select View -> Custom Actions. You'll see a tree view something like this:
- Custom Actions
- Install
- Uninstall
- Commit
- Rollback
- Right click the very top node (Custom Actions) and select Add Custom Action.
- Navigate to the file or project output that contains your class that's decorated with the [RunInstaller(true)] attribute, highlight it and click OK.
- Your project output should then appear under each of the four nodes. This means that your custom action class will be called during each of the four installer phases.
If you need finer control over this, you can add the custom action class to some of the installer phases but not others. For example, if installation and uninstallation are handled by different assemblies, you migth add one assembly under the Install and Commit nodes and the other assembly under the Uninstall and Rollback nodes.
So that's it, your custom actions will now be called during setup. A quick tip for debugging custom actions. Use a conditional directive (as in the above example) to display a message box when in the debug build. This message box will then be displayed during setup. That effectively pauses the setup process until you click OK on the message box, this gives you what you might call "a window of opportunity" (pun intended) to attach the debugger to the msiexec.exe process. There will be several msiexec.exe processes running, you need to pick the one that says it is managed code. The debugger will attach and your breakpoints will 'light up', so you can then intercept execution and single step through your custom action.