The promise of xcopy deploy, the ability to simple copy your files onto a destination machine and have your problem run was one of .net's big attractions after the pain of COM, installers and the wrestling match that dllhell produced. As you can reading having to force Crystal Reports onto NT4 threw the concept of xcopy deployment away for that application.

An added hurdle is use of the Windows Event Log. The .net framework provides the System.Diagnostics.EventLog classes to enable you to easily write (and read) events. Merrily you scatter log events throughout your code;

// Put my really important message in the event log.
EventLog.WriteEntry("MyAppName", "I have just done something.", EventLogEntryType.Information);

Each event log entry has a source, which is registered on the local computer. When you call EventLog.WriteEntry with a source that is not registered on the current computer the .net framework will create it for you. However only users with Administrator privileges can create event sources; they are created as registry key entries under

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application

If your code tries to create a new event source whilst running under a normal user context an exception will be thrown;

The event source MyAppName does not exist and cannot be created with the current permissions

So we must create our event sources at install time, using MSI custom install actions, or the installutil command utility that is part of the .net framework. Both approaches have the same requirement, a class compiled somewhere in the assemblies that comprise your program. The class itself is easy;

using System;
using System.Configuration.Install;
using System.Diagnostics;
using System.ComponentModel;

namespace idunno.CreateEventSourceInstaller
{
  [RunInstaller(true)]
  public class MyEventLogSourceInstaller: Installer
  {
    public override void Install(System.Collections.IDictionary stateSaver)
    {
      try
      {
        base.Install (stateSaver);
        EventLog.CreateEventSource("MyEventSource", "Application");
      }
      catch (Exception e)
      {
        throw new InstallException("Cannot create event sources for Exception Publisher", e);
      }
    }
  }
}

The System.Configuration.Install namespace provides support for custom install actions; you must inherit the Installer class, override the Install method (and preferably the Commit, Rollback and Uninstall methods), apply the RunInstaller attribute and set it to true and finally include your new derived class in your application, or an assembly installed with your application.

To test your installer works you can invoke installutil [filenameContainingInstallerClass], to test the uninstall use installutil / u [filenameContainingInstallerClass]. Once you're sure it works you can include it in your MSI. Right click on your setup project and select View / Custom Actions. The custom actions editor will appear. Right click the custom actions node, choose the "Add Custom Action" menu item then when prompted choose the assembly containing your installer class.

Not exactly xcopy <g>