Tag Archives: C#

How to build an C# Application that can relaunch itself in Admin mode – without UAC prompt

Lets start by emphasizing that this is NOT a way to create a hack. In order for this to work you (the user) needs to be an Administrator and access to be able to launch applications in ‘Admin mode’ anyway. The first time when the application needs to set up this functionality it needs to run in Admin mode as well (for which you’ll have to be prompted by UAC). Only after this and for the future the application in ‘Non-admin’ mode can then relaunch itself in ‘Admin mode’ without showing the UAC prompt.

The ‘trick’ (not hack) is to use the built-in Windows Task scheduler that can launch applications with the ‘highest’ priority setting. Take note that this also stops you from launching the app with any command line parameters – but there are other ways an application can ‘communicate’ with itself/another instance of itself e.g. by saving its own settings before launching the second instance and the second instance reading those settings again.

So how can a (C#) application integrate this easily? My first idea was to call the Task scheduler (Schtasks.exe) manually with the required parameters to create a task of launching the app again later in admin mode. The problem part is finding out if the task already exists or not. Then I came across an article that showed how the COM+ library for the Task Scheduler can be used from .Net which make it a whole lot easier to interact.

Task Scheduler COM+ library

In your application’s references add a reference to ‘TaskScheduler 1.1 Type Library’ (Interop.TaskScheduler.dll) usually located on ‘c:\Windows\SysWow64\taskschd.dll (on 64-bit at least). Then you can add the following type of code in your project:

Code

To test if task exists or is running already:


private string myLaunchTaskName = "RunMeAsAdmin";

private bool LaunchTaskExist()
{
  try
  {
    TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
    ts.Connect(null, null, null, null);
    if (ts.Connected)
    {
      TaskScheduler.ITaskFolder root = ts.GetFolder("\\");
      TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);
      if (task != null)
        return true;
    }
  }
  catch { }
  return false;
}
private bool TaskAlreadyRunning()
{
  try
  {
    TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
    ts.Connect(null, null, null, null);
    if (ts.Connected)
    {
      foreach (TaskScheduler.IRunningTask td in ts.GetRunningTasks(0))
      {
        if (td.Name == myLaunchTaskName)
          return true;
      }
    }
  }
  catch { }
  return false;
}

To create the task the first time:

function CreateSelfLaunchTask()
{
  try
  {
    if (AdminModeTools.IsInAdminMode()) //Different library to test if app is in Admin mode
    {
      TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
      ts.Connect(null, null, null, null);
      if (ts.Connected)
      {
        TaskScheduler.ITaskDefinition task = ts.NewTask(0);
        task.RegistrationInfo.Author = "Me";
        task.RegistrationInfo.Description = myLaunchTaskName;
        task.Principal.RunLevel = TaskScheduler._TASK_RUNLEVEL.TASK_RUNLEVEL_HIGHEST;
        task.Settings.MultipleInstances = TaskScheduler._TASK_INSTANCES_POLICY.TASK_INSTANCES_IGNORE_NEW;
        TaskScheduler.ITimeTrigger trigger = (TaskScheduler.ITimeTrigger)task.Triggers.Create(TaskScheduler._TASK_TRIGGER_TYPE2.TASK_TRIGGER_TIME);
        trigger.Id = "NoTime";
        trigger.StartBoundary = "2000-01-01T12:00:00";
        trigger.StartBoundary = "2000-01-01T12:00:00";
        TaskScheduler.IExecAction action = (TaskScheduler.IExecAction)task.Actions.Create(TaskScheduler._TASK_ACTION_TYPE.TASK_ACTION_EXEC);
        action.Id = "Run exe";
        action.Path = System.Reflection.Assembly.GetExecutingAssembly().Location;
        action.WorkingDirectory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);

        TaskScheduler.ITaskFolder root = ts.GetFolder("\\");
        TaskScheduler.IRegisteredTask regTask = root.RegisterTaskDefinition(
          myLaunchTaskName,
          task,
          (int)TaskScheduler._TASK_CREATION.TASK_CREATE_OR_UPDATE,
          null,
          null,
          TaskScheduler._TASK_LOGON_TYPE.TASK_LOGON_INTERACTIVE_TOKEN);
      }
    }
    else
    {
      MessageBox.Show("To create the task you must start this program in 'Admin' mode.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
  }
  catch(Exception ex)
  {
    MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}

Then to call the task:

function void RunAppAsAdmin()
{
  try
  {
    if (LaunchTaskExist())
    {
      if (!TaskAlreadyRunning())
      {
        TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
        ts.Connect(null, null, null, null);
        if (ts.Connected)
        {
          TaskScheduler.ITaskFolder root = ts.GetFolder("\\");
          TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);
          TaskScheduler.IRunningTask runTask = task.Run(null);
        }
      }
      else
      {
        MessageBox.Show("The task is already running!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
      }
    }
    else
    {
      MessageBox.Show("The task does not exist yet!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
  }
  catch (Exception ex)
  {
    MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
  }
}

If for some reason you need to delete the task you can use this:

private void DeleteRunAsAdminTask()
{
    try
    {
        if (AdminModeTools.IsInAdminMode())
        {
            if (LaunchTaskExist())
            {
                TaskScheduler.TaskScheduler ts = new TaskScheduler.TaskScheduler();
                ts.Connect(null, null, null, null);
                if (ts.Connected)
                {
                    TaskScheduler.ITaskFolder root = ts.GetFolder("\\");
                    TaskScheduler.IRegisteredTask task = root.GetTask(myLaunchTaskName);
                    if (task != null)
                    {
                        root.DeleteTask(myLaunchTaskName, 0);
                    }
                }
            }
            else
            {
                MessageBox.Show("The task does not exist!", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }
        else
        {
            MessageBox.Show("To delete the task you must start this program in 'Admin' mode.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString(), "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

With all these ‘bits’ you can build an application that can launch itself in ‘Admin’ mode. Have fun kidz but not too much!

I’ve tested this on Windows Vista, 7, 2008/R2 and 8. I don’t have access to any XP machines anymore but I doubt it will work on XP (or 2003)… duhh.. Just remembered XP and 2003 does not have ‘Admin’ mode anyway so this does not apply… silly me.

Update: I now have one of my utilities actually using this code: Service Monitor

A little (versioning) pain with Powershell

First thing to mention is I’m not complaining about PowerShell itself or functionality provided with PowerShell. Rather, this is a problem with referencing it from .Net (C#) and versioning when used on another machine where the .Net App was deployed and happen to have an older version of PowerShell (PS for short).

Scenario

If you want to run PowerShell scripts from a C# program like I’m doing in QuickMon now, you have to add a reference to “System.Management.Automation.dll“. I happen to have Version 4.0 of PowerShell on the computer where the C# app is compiled. Now, this is all fun and games until you want to run the same app on another machine that only have, say Version 2.0 of PowerShell. PS 2 does have a version of System.Management.Automation.dll but somehow it is not compatible (at run time). When I compiled the same app on a computer that only has V2.0 of PowerShell and deploy that app to machines that has either PS v2.0 or v4.0 it works on all of them.

If this was C++ it would have made sense (dll versioning very strict) but this is a C# app that supposively should not care about the version of the referenced assembly (and yes, this is a .Net assembly). The methods (I) used in the dll are all the same of both versions.

I even tried generating the System.Management.Automation.dll file manually on the ‘target’ machine and copy that dll to the App’s directory (using the PS “Copy ([PSObject].Assembly.Location) C:\” command) but this gave other versioning referencing errors.

Possible solution

The solution that seems to work for now is to set the ‘Specific Version‘ property on the referenced dll in the C# project to true (making sure it points to the PS 2.0 related version – dll version 6.1.7601.17514). Interestingly enough when switching the project to ‘release’ configuration it display pointing to ‘C:\Windows\assembly\GAC_MSIL\System.Management.Automation\1.0.0.0__31bf3856ad364e35\System.Management.Automation.dll’. That tells me the PS version ‘2.0’ of that assembly is still available (on my PS 4.0 computer). As a safety precaution I also set the ‘Copy Local’ property on this referenced dll to True to have it deployed with the app.

Deploying this combination seems to work on all ‘target’ machines – I even saw it working on a computer that only has PS 1.0!

All fun and joy… as long as there’s no lawyer sitting on a loo in the bush… with an angry T-Rex nearby…

ListViewEx – Auto resize selected column

What do you do when you get fed up having to write the same code over and over again? Write a base class for it… of course.

I regularly use the WinForms ListView control and often want to specify a specific column (in detail view) that must auto resize when the whole control resize. Therefore I created the following class that does all that (and more stuff) to make life easier.

public class ListViewEx : ListView
    {
        public ListViewEx()
            : base()
        {
            DoubleBuffered = true;
            View = View.Details;
            resizeTimer.Tick +=  resizeTimer_Tick;
        }

        [Description("Use one column to auto resize in detail view")]
        public bool AutoResizeColumnEnabled { get; set; }
        [Description("Column index of auto resize column")]
        public int AutoResizeColumnIndex { get; set; }
        public event MethodInvoker EnterKeyPressed;
        public event MethodInvoker DeleteKeyPressed;
        protected override void OnKeyPress(KeyPressEventArgs e)
        {
            if (e.KeyChar == '\r')
                if (EnterKeyPressed != null)
                {
                    EnterKeyPressed();
                    e.Handled = true;
                }
            base.OnKeyPress(e);
        }
        protected override void OnKeyDown(KeyEventArgs e)
        {
            if (e.KeyCode == Keys.Delete)
                if (DeleteKeyPressed != null)
                {
                    DeleteKeyPressed();
                    e.Handled = true;
                }
            base.OnKeyDown(e);
        }
        private Timer resizeTimer = new Timer() { Interval = 100, Enabled = false };
        private void resizeTimer_Tick(object sender, EventArgs e)
        {
            resizeTimer.Enabled = false;
            try
            {
                if (AutoResizeColumnEnabled && View == System.Windows.Forms.View.Details &&
                    AutoResizeColumnIndex > -1 && this.Columns.Count > AutoResizeColumnIndex)
                {
                    int columnsWidth = 0;
                    Application.DoEvents();
                    for (int i = 0; i < this.Columns.Count; i++)
                    {
                        if (i != AutoResizeColumnIndex)
                            columnsWidth += this.Columns[i].Width;
                    }
                    this.Columns[AutoResizeColumnIndex].Width = this.ClientSize.Width - columnsWidth - 2;
                }
            }
            catch { }
        }
        protected override void OnResize(EventArgs e)
        {
            resizeTimer.Enabled = false;
            resizeTimer.Enabled = true;
            base.OnResize(e);
        }
    }

Now all you have to do is set the AutoResizeColumnEnabled property to true and specify a column index for AutoResizeColumnIndex and there you go. Easy hey?

Should I handle Exceptions or not?

I’ll start this post with a statement or answer that might seem controversial.

The answer is ‘NO’

Why? Let me explain. If your code has reached a state where an Exception has been thrown it means you have already missed something (possible) important that should have been addressed. Sure, throwing (excuse the pun) a ‘try… catch’ around every block of code is nice and all – and you should do it anyway (for other reasons) but it is no excuse for writing bad code.

More details

One reason I say these things I recently (re)discovered myself… again is that ‘Performance’ in an application can greatly be influenced by exceptions since the whole process of encountering/throwing an exception in code is a slow thing. When you have code that relies on catching an exception in order to handle an (possibly) expected condition of some variables it is a sign that you are doing it wrong… It may not be a big issue if the affected code is called only once in a blue moon but once it is in a section that is called repeatedly and is expected to perform at speed it becomes a huge issue.

Have a look at this code. It will run fine but and actually be usable but…

try
{
   SomeType tp = SomeObject.SomeVar;
}
catch // null reference exception or something expected the first time
{
  SomeObject = new SomeObjectType();
  ...
}

Now look at a better way

if (SomeObject == null)

SomeObject = new SomeObjectType();

SomeType tp = SomeObject.SomeVar;

...

This code will actually run faster and does not rely on an Exception to handle something that should be done right to start with.

Ok, there you have it…

Adding performance counters to your application (C#)

Nothing about this is exactly new or ground breaking but few developers (enterprise) these days add proper monitoring abilities to their apps. We (now that I mostly do administration and management of other peoples apps) that has to support these things don’t come equipped with x-ray eyes or ESP pills so knowing how the the internals of ‘your’ works is an issue…

Classically developers tend to use stuff like log file, event log and so on to ‘see’ what is going on inside their apps. However, these things also pick up a lot of noise so they usually get turn off for production use but that still leaves us with the requirements that we want to know ‘what your app is doing all the time’ – when we want to track it. Ok, to make a long story shorter, there is such a thing like performance counters that can help us to know if your app is performing or not. What they are and what they can do for you you can go read up on MSDN, Google etc.

Now, it appears most developers are scared of these things – or just too lazy to implement them. I’ve created a little helper class that makes it at least a little easier to implement – without all the worries about what happens if things blow up etc. It is written is such a way that if itself ‘breaks’ it should not break the rest of the app (don’t contribute to a bigger problem).

Setting it all up.

Creating a ‘Category’ is the first step in setting up a performance counter. Once it is created you don’t have to recreate it again (unless you go and delete it which would be rather stupid). The following routine do just that.

PerformanceCounterCategory InitializeCategory(string category, CounterCreationData[] creationData, string instance = "")
        {
            PerformanceCounterCategory pcc = null;
            if (!PerformanceCounterCategory.Exists(category))
            {
                if (instance.Length > 0)
                    pcc = PerformanceCounterCategory.Create(category, category, PerformanceCounterCategoryType.MultiInstance, new CounterCreationDataCollection(creationData));
                else
                    pcc = PerformanceCounterCategory.Create(category, category, PerformanceCounterCategoryType.SingleInstance, new CounterCreationDataCollection(creationData));
            }
            else
                pcc = new PerformanceCounterCategory(category);
            return pcc;
        }

All this does is create the category for you if it doesn’t exist yet or else just returns the existing one. All you specify is the name and the definitions of the counters you want to use. Optionally you can specify an ‘instance name’ which is handy if you have multiple instances of the same set of ‘things’ you want to ‘monitor’. The default is a single instance (e.g. like a global instance). Keep in mind that a single category can only have counters of one of two types – either single instance or multi-instance counters. This cannot be changed unless the whole category is deleted and recreated again.

The next step is to create run-time ‘instances’ of the counters.

PerformanceCounter InitializePerfCounter(string categoryName, string counterName, string instanceName = "")
        {
            PerformanceCounter counter = null;
            try
            {
                if (instanceName.Length > 0)
                {
                    if (IsCategoryMultiInstance(categoryName))
                        counter = new PerformanceCounter(categoryName, counterName, instanceName, false);
                    else
                        RaiseWarningMessage(string.Format("Performance category '{0}' is not set up for multiple instances! ({1})", categoryName, counterName));
                }
                else
                {
                    if (!IsCategoryMultiInstance(categoryName))
                        counter = new PerformanceCounter(categoryName, counterName, false);
                    else
                        RaiseWarningMessage(string.Format("Performance category '{0}' is not set up for single instance use! ({1})", categoryName, counterName));
                }
                if (counter != null)
                {
                    counter.BeginInit();
                    counter.RawValue = 0;
                    counter.EndInit();
                }
            }
            catch (Exception ex)
            {
                RaiseErrorMessage(string.Format("Error initializing performance counter '{0}'!\r\n{1}", counterName, ex.ToString()));
            }
            return counter;
        }

There are a couple of sub-routines not listed yet. Please just ignore for now – they will be included in the attached sample code.

Next step is just how to use them – setting the values. I tend to only use two types of counters – a ‘rate of’ and absolute values. The ‘rate of’ type of counters are typically used to track the number of events or sum of something per second while absolute values track the actual value of something as it is ‘now’ at that moment of tracking – e.g. CPU % usage.

void SetCounterValue(PerformanceCounter counter, long value)
        {
            try
            {
                if (counter == null)
                {
                    RaiseWarningMessage("Performance counter not set up or installed!");
                }
                else
                {
                    counter.RawValue = value;
                }
            }
            catch (Exception ex)
            {
                RaiseErrorMessage(string.Format("Increment performance counter error! : {0}\r\n{1}", counter.CounterName, ex.ToString()));
            }
        }
void IncrementCounter(PerformanceCounter counter)
        {
            IncrementCounterBy(counter, 1);
        }
void IncrementCounterBy(PerformanceCounter counter, long incBy)
        {
            try
            {
                if (counter == null)
                {
                    RaiseWarningMessage("Performance counter not set up or installed!");
                }
                else
                {
                    counter.IncrementBy(incBy);
                }
            }
            catch (Exception ex)
            {
                RaiseErrorMessage(string.Format("Increment performance counter error! : {0}\r\n{1}", counter.CounterName, ex.ToString()));
            }
        }

Events
In order to provide all this functionality without ‘breaking’ anything else I make use of ‘events’ e.g. RaiseWarningMessage and RaiseErrorMessage. The calling class/code don’t have to make use of the events but of course that would make troubleshooting a bit harder if needed. The code for this is fairly simple:

        public event MessageRaisedDelegate ErrorRaised;
        internal void RaiseErrorMessage(string message)
        {
            if (ErrorRaised != null)
            {
                ErrorRaised(message);
            }
        }
        public event MessageRaisedDelegate WarningRaised;
        internal void RaiseWarningMessage(string message)
        {
            if (WarningRaised != null)
            {
                WarningRaised(message);
            }
        }

Implementation
It is possible to use the utility class ‘as is’ but I would recommend doing the following to provide ‘cleaner’ code. Inheriting from the class ‘PerfCounterUtilBase’ (not shown in above code) and implementing all the specific performance counter functionality ‘you’ need is a better way to so it. The following is just example code to initialize the performance counter category and counters you want to use:

void InitializePerformanceCounters()
        {
            string lastErr = "Create performance counter category error!: {0}";
            try
            {
                CounterCreationData[] creationData = new CounterCreationData[]
                    {
                        new CounterCreationData("Clicks/Sec", "Clicks per second", PerformanceCounterType.RateOfCountsPerSecond32),
                        new CounterCreationData("Total X value/Sec", "Sum of X values per second", PerformanceCounterType.RateOfCountsPerSecond32),
                        new CounterCreationData("Total Y value/Sec", "Sum of Y values per second", PerformanceCounterType.RateOfCountsPerSecond32),
                        new CounterCreationData("Last X value", "Last X value", PerformanceCounterType.NumberOfItems32),
                        new CounterCreationData("Last Y value", "Last Y value", PerformanceCounterType.NumberOfItems32)
                    };
                InitializeCategory(Category, creationData, Instance);

                lastErr = "Initialize performance counter(s) error!: {0}";
                clicksPerSecond = InitializePerfCounter(Category, "Clicks/Sec", Instance);
                xValuePerSecond = InitializePerfCounter(Category, "Total X value/Sec", Instance);
                yValuePerSecond = InitializePerfCounter(Category, "Total Y value/Sec", Instance);
                lastXValue = InitializePerfCounter(Category, "Last X value", Instance);
                lastYValue = InitializePerfCounter(Category, "Last Y value", Instance);
            }
            catch (Exception ex)
            {
                RaiseErrorMessage(string.Format(lastErr, ex.Message));
            }
        }

Then you can simply have specific methods like these to use in your own code:

public void IncClicks()
        {
            IncrementCounter(clicksPerSecond);
        }
        public void IncXValues(long value)
        {
            IncrementCounterBy(xValuePerSecond, value);
        }
...

In ‘your’ code you simply do this then:

pcu = new PerfCounterExampleImplemetation();
pcu.ErrorRaised += new MessageRaisedDelegate(pcu_ErrorRaised);
pcu.WarningRaised += new MessageRaisedDelegate(pcu_WarningRaised);
pcu.Category = txtCategory.Text;
pcu.Instance = txtInstance.Text;
pcu.InitializePerformanceCounters();
...
void pcu_ErrorRaised(string message)
        {
            MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }

void SomeMethod()
        {
            long val = GetSomeValue();

            if (pcu != null)
            {
                pcu.IncClicks();
                pcu.IncXValues(val);
                ...
            }
        }

Now go have fun…

Example code: ShowPerfCounterUtils

Creating a Multi-instance self registering service

This is one of those things I’ve been wanting to do for a long time for my Event Scavenger pet project. Basically the requirement is this:

“Being able to have one executable (.exe) file that can be used multiple times for different service instances.”

It turns out it is not too hard to achieve this using C# and .Net 4.0 (might even work with older frameworks but haven’t tried it). It is an extension of my already improved self registering Windows Service extensions which make it possible to simply run the Service exe with a ‘-install’ command line parameter. With the latest additions a ‘named’ instance can also be specified. This means, in the Service Manager of Windows you can see the Service executable plus a command line parameter that makes it unique. It allows you to stop/start/manage it separately as an entity. This is exactly the same as how Microsoft BizTalk Server implements ‘Host Instances’.

Now lets get dirty with some code samples. The first code snippet shows (an example) part of main program.cs that handles the command like parameters.

string collectorName = "Default";		

if (args.Length > 0)
{                
  if (args[0].ToUpper() == "-INSTALL")
  {
              string serviceParameters = "";
    if (args.Length > 1)
    {
      collectorName = args[1];
                  serviceName = "Event Reaper - " + collectorName;
      displayName = "Event Reaper - " + collectorName;
                  serviceParameters = "\"-Collector:" + collectorName + "\"";
    }
    if (args.Length > 2)
      displayName = args[2];
    if (args.Length > 3)
      description = args[3];

    HenIT.Services.ServiceRegister.InstallService(
      System.Reflection.Assembly.GetExecutingAssembly().Location,
      serviceName,
      displayName,
      description,
                  serviceParameters);
    return;
  }
  else if (args[0].ToUpper() == "-UNINSTALL")
  {
    if (args.Length > 1)
    {
      collectorName = args[1];
                  serviceName = "Event Reaper - " + collectorName;
    }
    HenIT.Services.ServiceRegister.UnInstallService(
       System.Reflection.Assembly.GetExecutingAssembly().Location,
                 serviceName);
    return;
  }
  collectorName = HenIT.CommandLineUtils.GetCommand(args, "", "-Collector:");
}
if (collectorName.Length == 0)
  collectorName = Properties.Settings.Default.CollectorName;

ServiceBase[] servicesToRun;
servicesToRun = new ServiceBase[] 
{ 
  new EventReaperService() { CollectorName = collectorName }
};
ServiceBase.Run(servicesToRun);

All this section does is to check for the “-INSTALL” or “-UNINSTALL” parameters and then call the helper class that does the registration/unregistration. The Display name of the service instance is always prefixed with “Event Reaper – ” to grouped all instances visually together in Service manager.

InstallService

The ServiceRegister class only has two methods. InstallService is the first one and handles all the bits to gather login details, set properties and then register the service.

public static bool InstallService(string serviceExePath,
        string serviceName,
        string displayName,
        string description,
        string serviceParameters)
{
    bool success = false;
    try
    {
        string workingPath = System.IO.Path.GetDirectoryName(serviceExePath);
        string logPath = System.IO.Path.Combine(workingPath, "Install.log");
        ServiceStartMode startmode = ServiceStartMode.Automatic;
        ServiceAccount account = ServiceAccount.LocalService;
        string username = "";
        string password = "";
        bool delayedStart = true;

        InstallerForm installerForm = new InstallerForm();
        installerForm.StartType = ServiceStartMode.Automatic;
        installerForm.AccountType = ServiceAccount.User;
        installerForm.BringToFront();
        installerForm.TopMost = true;
        if (installerForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
        {
            startmode = installerForm.StartType;
            account = installerForm.AccountType;
            delayedStart = installerForm.DelayedStart;
            if (installerForm.AccountType == ServiceAccount.User)
            {
                username = installerForm.UserName;
                password = installerForm.Password;
            }


            Hashtable savedState = new Hashtable();
            ProjectInstallerForHelper myProjectInstaller = new ProjectInstallerForHelper(delayedStart);
            InstallContext myInstallContext = new InstallContext(logPath, new string[] { });
            myProjectInstaller.Context = myInstallContext;
            myProjectInstaller.ServiceName = serviceName;
            myProjectInstaller.DisplayName = displayName;
            myProjectInstaller.Description = description;
            myProjectInstaller.StartType = startmode;
            myProjectInstaller.Account = account;
            if (account == ServiceAccount.User)
            {
                myProjectInstaller.ServiceUsername = username;
                myProjectInstaller.ServicePassword = password;
            }
            myProjectInstaller.Context.Parameters["AssemblyPath"] = serviceExePath + " " + serviceParameters;

            myProjectInstaller.Install(savedState);
            success = true;
        }
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message, "Install service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    }
    return success;
}

The class InstallerForm is simply a plain Windows Form to capture service properties like the username/password etc. I’m not showing its code here now. AssemblyPath is the actual property that Service manager use to launch the executable plus its parameters.

ProjectInstallerForHelper is an utility class that simply inherits from System.Configuration.Install.Installer. It looks like this:

internal class ProjectInstallerForHelper : System.Configuration.Install.Installer
{
    private ServiceProcessInstaller processInstaller;
    private System.ServiceProcess.ServiceInstaller serviceInstaller;

    public ProjectInstallerForHelper(bool delayedAutoStart = true)
    {
        processInstaller = new ServiceProcessInstaller();
        serviceInstaller = new System.ServiceProcess.ServiceInstaller();
        serviceInstaller.DelayedAutoStart = delayedAutoStart;

        Installers.AddRange(new Installer[] {
                processInstaller,
                serviceInstaller});
    }

    #region Added properties
    public string ServiceName
    {
        get { return serviceInstaller.ServiceName; }
        set { serviceInstaller.ServiceName = value; }
    }
    public string DisplayName
    {
        get { return serviceInstaller.DisplayName; }
        set { serviceInstaller.DisplayName = value; }
    }
    public string Description
    {
        get { return serviceInstaller.Description; }
        set { serviceInstaller.Description = value; }
    }
    public ServiceStartMode StartType
    {
        get { return serviceInstaller.StartType; }
        set { serviceInstaller.StartType = value; }
    }
    public ServiceAccount Account
    {
        get { return processInstaller.Account; }
        set { processInstaller.Account = value; }
    }
    public string ServiceUsername
    {
        get { return processInstaller.Username; }
        set { processInstaller.Username = value; }
    }
    public string ServicePassword
    {
        get { return processInstaller.Password; }
        set { processInstaller.Password = value; }
    }
    #endregion
}

UnInstallService

This is essentially just the reverse of InstallService.

public static bool UnInstallService(string serviceExePath, string serviceName)
{
    bool success = false;
    try
    {
        ServiceController sc = new ServiceController(serviceName);
        if (sc == null)
        {
            System.Windows.Forms.MessageBox.Show("Service not installed or accessible!", "Stopping service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Warning);
            return true;
        }
        if (sc.Status == ServiceControllerStatus.Running || sc.Status == ServiceControllerStatus.Paused)
        {
            sc.Stop();
        }
    }
    catch (Exception ex)
    {
        if (!ex.Message.Contains("was not found on computer"))
        {
            System.Windows.Forms.MessageBox.Show(ex.Message, "Stopping service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
        }
        else
            return true;
    }
    try
    {
        string workingPath = System.IO.Path.GetDirectoryName(serviceExePath);
        string logPath = System.IO.Path.Combine(workingPath, "Install.log");

        ServiceInstaller myServiceInstaller = new ServiceInstaller();
        InstallContext Context = new InstallContext(logPath, null);
        myServiceInstaller.Context = Context;
        myServiceInstaller.ServiceName = serviceName;
        myServiceInstaller.Uninstall(null);
        success = true;
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message, "Uninstall service", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    }
    return success;
}

Summary

And this is basically the whole thing that allows you to create a Windows Service in C# that can handle multiple instances. There are a few things to keep in mind like the fact that all instances share the same config file unless you make a physical copy of the exe and config file to another directory and register it from there. Using this you can multiple services using different config all running side by side not affecting each other (hopefully hehe)

VS2012 Express for Desktop

I’ve been waiting for this for a while so I was glad when they finally released this. Now for some initial feedback.

First off, the download was reasonable – size and speed wise. The installation was, lets just say ok – as I had to reboot since it had to update some libraries that were is ‘use’ at the time. Registration was also not too bad – since I have an old existing Hotmail/Live account where more of the details were already populated. Running it for the first time is where the shock comes in… it is as ugly as hell (reminds me death, all grey and boring). Unfortunately the same would apply to any of the other Express and even full versions of VS2012.

VS2012 Express For Desktop development

Functionality wise it provides just the very basics – not that you can expect anything more. Since I haven’t installed the ‘full’ express version I cannot comment on any other functionality that version might have. Anyway, The only templates worth mentioning is the Windows Forms, WPF and Console ones. Again, one cannot expect anything more of this release. Interestingly enough, when creating a new project the framework version cannot be changed on the ‘create project’ dialog screen. You can only change this ‘after’ the project has already been created.

One nice thing is that you can still create custom toolbars with ‘external’ commands – I use it to run a source backup tool I created some time ago. Another thing to remember is that this tool can be installed in Windows 7, unlike the full Express version that can ONLY be installed on Windows 8. The Web express version can also be installed on 7 (plus the TFS Express version).

If you excuse the way it looks (wearing shades to protect your eyes) then this tool is not that bad… Just wish they allowed old fashioned ‘themes’ to change the look and feel of the entire editor. Ah well, it is an ‘Express’ product… Fortunately you can import your VS 2010 color and font settings to get all your customizations back (even though it does moan about a whole bunch of settings that are not applicable to this edition which you can ignore)

In order to try it out you can follow this link.

Update:
If you like to change the overall theme and don’t like the built-in Light or Dark there are some more options if you look at this blog entry.

HTMLWriter 1.7

Just a quick refresh on my HTMLWriter utility library. Some minor changes/additions:

1. Added support for the NOBR tag

2. Improved the special character functions including ignoring the ‘&’ sign when needed.

Latest version here.

Rumours of desktop development death greatly exaggerated

Ok, Microsoft has restored some faith from my side in them – after announcing that the new Visual Studio 11 (now called VS 2012) would NOT support any desktop development anymore.

They eventually changed their minds due to a lot of pressure and decided to release a desktop specific version as well – see this.

A quote from the article:

With this new Express edition, developers will be able to use C++, C#, or Visual Basic to create Windows desktop and console applications. Developers will also get access to new advances available across the Express family in Visual Studio 2012, such as the latest compilers and programming language tools, integrated unit testing, and the ability for small development teams to collaborate via Team Explorer and TFS Express.

Now, we just need to get MS to drop Metro and BioWare to fix Mass Effect 3’s ending… and the world could be a happy place again… hehe

Provide “Export to CSV” functionality on an ASP.Net page

I don’t do (or particularly like) ASP.Net development often but recently had to quickly add some ‘Export to CSV’ functionality of a displayed table to a page. Personally I would have just used ‘copy and paste’ to do it (the export) but since the user isn’t in the habit of thinking for themselves I had to create new functionality which turn out to be very nice – and even opens the door for some future more advanced functionality.

Anyway, to achieve this is really easy if you use the¬†HttpContext.Current.Response class and add an attachment ‘header’ to your page. The header must be named ‘content-disposition‘ and ContentType ‘text/csv‘. See the following methods I created to simply take a DataSet and convert it to ‘CSV file’:

public class CSVExportUtils
{
    public void ExportDataSetToCSV(string title, DataSet ds, string columnNamesCSV = "")
    {
        string attachment = "attachment; filename=" + title.Replace(",", "").Replace(".", "") + ".csv";
        HttpContext.Current.Response.Clear();
        HttpContext.Current.Response.ClearHeaders();
        HttpContext.Current.Response.ClearContent();
        HttpContext.Current.Response.AddHeader("content-disposition", attachment);
        HttpContext.Current.Response.ContentType = "text/csv";
        HttpContext.Current.Response.AddHeader("Pragma", "public");
        if (columnNamesCSV.Length == 0)
        {
            WriteColumnName(ds);
            foreach (DataRow r in ds.Tables[0].Rows)
            {
                if (ds.Tables[0].Columns.Count > 0)
                {
                    string value = r[0].ToString();
                    if (value.Contains(","))
                        value = "\"" + value + "\"";
                    HttpContext.Current.Response.Write(value);
                    for (int i = 1; i < ds.Tables[0].Columns.Count; i++)
                    {
                        value = r[i].ToString();
                        if (value.Contains(","))
                            value = "\"" + value + "\"";
                        HttpContext.Current.Response.Write("," + value);
                    }
                }
                HttpContext.Current.Response.Write(Environment.NewLine);
            }
        }
        else
        {
            HttpContext.Current.Response.Write(columnNamesCSV);
            HttpContext.Current.Response.Write(Environment.NewLine);
            string[] columns = columnNamesCSV.Split(',');
            foreach (DataRow r in ds.Tables[0].Rows)
            {
                string value = r[columns[0]].ToString();
                if (value.Contains(","))
                    value = "\"" + value + "\"";
                HttpContext.Current.Response.Write(value);
                for (int i = 1; i < columns.Length; i++)
                {
                    value = r[columns[i]].ToString();
                    if (value.Contains(","))
                        value = "\"" + value + "\"";
                    HttpContext.Current.Response.Write("," + value);
                }
                HttpContext.Current.Response.Write(Environment.NewLine);
            }
        }

        HttpContext.Current.Response.End();
    }
    private static void WriteColumnName(DataSet ds)
    {
        StringBuilder sb = new StringBuilder();
        if (ds.Tables[0].Columns.Count > 0)
        {
            string value = ds.Tables[0].Columns[0].Caption;
            if (value.Contains(","))
                value = "\"" + value + "\"";
            HttpContext.Current.Response.Write(value);
            for (int i = 1; i < ds.Tables[0].Columns.Count; i++)
            {
                value = ds.Tables[0].Columns[i].Caption;
                if (value.Contains(","))
                    value = "\"" + value + "\"";
                HttpContext.Current.Response.Write("," + value);
            }
        }
        HttpContext.Current.Response.Write(Environment.NewLine);
    }
}

This method also allows you to specify the fields you want to export – or alternatively it just use the ones in the DataSet. For example, you can use it like this:

if (Request.QueryString["csvexport"] != null)
{
    CSVExportUtils csvExportUtils = new CSVExportUtils();
    csvExportUtils.ExportDataSetToCSV(fileName, dataSet, "Field1,Field2,...");
}

The calling page can then simply have a hyperlink like this:

SomePage.aspx?csvexport=Yes