views:

341

answers:

1

I am trying to write an Setup Project/Installer for a class library driver that I wrote in C# using Visual Studio 2008. The driver project has a section of code that looks like this...

    [ComRegisterFunction]
    public static void RegisterASCOM(Type t)
    {
        Trace.WriteLine("Registration Started.");
        DoRegistration(true);  
    }

In the driver project Properties -> "Assembly Information" I have set checked the box that says Make COM-Visible = true.

I added a Setup Project to the solution in VS, added the output dll from the driver project so that it installs on the target machine and set the Register property of the dll to "vsdraCOM". So, my understanding is that when the installer runs it SHOULD execute the methods of the dll that are marked with [COMRegisterFunction].

Using SysInternals Debug View I can monitor when the above code snippet is hit by watching for the "Registration started" text to show up in the window. When I build the solution, I can see the text show up so I know the driver is registering properly. The problem is that when I run the installer, I don't think it is doing the registration bit. I see nothing show up in Debug View. And if i try to access my driver via another application I get an error saying it "Cannot create ActiveX object". Why does the registration not occur during the install process?

The driver does register for COM but it does NOT call my custom registration method.

Does anyone have and suggestions of what I could be missing? Is there another way I can debug this?

(I can provide more code if anyone want's to take a look!!)

+3  A: 

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.

Tim Long