Category Archives: Reference - Page 3

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

Start or stop BizTalk Applications using PowerShell

This is not actually something new but for anyone else that wants to quickly have a reference to it, here are two PowerShell scripts to stop and start BizTalk applications.

Stopping a specified Application:

if ($args.count -eq 0) {
  "You must specify the BizTalk Application name to stop!"
}
else{
    $BTSAppName = $args[0]
    $SQLInstance = "."
    $BizTalkManagementDb ="BizTalkmgmtdb"
    [void] [System.reflection.Assembly]::LoadWithPartialName("Microsoft.BizTalk.ExplorerOM")
    $Catalog = New-Object Microsoft.BizTalk.ExplorerOM.BtsCatalogExplorer
    $Catalog.ConnectionString = "SERVER=$SQLInstance;DATABASE=$BizTalkManagementDb;Integrated Security=SSPI"

    $BTSApp = $Catalog.Applications[$BTSAppName]
    if ($BTSApp.Status -ne "stopped")
    {
        "Stopping" + $BTSApp.Name
        $BTSApp.Stop("StopAll")
        $catalog.SaveChanges()
    }
    else
    {
        $BTSApp.Name + " is already stopped"
    }
}

Starting a specified Application:

</pre>
<pre>if ($args.count -eq 0) {
  "You must specify the BizTalk Application name to start!"
}
else{
    $BTSAppName = $args[0]
    $SQLInstance = "."
    $BizTalkManagementDb ="BizTalkmgmtdb"
    [void] [System.reflection.Assembly]::LoadWithPartialName("Microsoft.BizTalk.ExplorerOM")
    $Catalog = New-Object Microsoft.BizTalk.ExplorerOM.BtsCatalogExplorer
    $Catalog.ConnectionString = "SERVER=$SQLInstance;DATABASE=$BizTalkManagementDb;Integrated Security=SSPI"

    $BTSApp = $Catalog.Applications[$BTSAppName]
    if ($BTSApp.Status -ne "started")
    {
        "Starting " + $BTSApp.Name
        $BTSApp.Start("StartAll")
        $catalog.SaveChanges()
    }
    else
    {
        $BTSApp.Name + " is already started"
    }
}

List all .Net versions using PowerShell

A quick tip (script) how to list all the .Net (major) versions of a list of machines.

$serverListFile = "<Path to file>\computers.txt";
$computers = Get-Content -path $serverListFile

$BASEDOTNETPATH = "\c$\Windows\Microsoft.NET\Framework\"

function CheckNet45($computerName){
  $NETROOTKEY = "SOFTWARE\\Microsoft\\NET Framework Setup\\NDP\\v4"
  $keyname = $NETROOTKEY + "\\Full"
  try{
    $reg = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey("LocalMachine", $computerName)
    if ($reg -ne $null){
      if ($reg.OpenSubKey($keyname).GetValue("Version").ToString().StartsWith("4.5")){
        return $True
      }
    }
  }
  catch {
    #do nothing
  }
  return $False
}

foreach($computer in $computers)
{
  $computer
  $ok = Test-Connection $computer -Count 1 -Quiet
  if ($ok) {
    $computerBasePath = "\\" + $computer + $BASEDOTNETPATH
    $versionStr = ""
    if (Test-Path ($computerBasePath + "v1.0.3705")){
      $versionStr = $versionStr + "1.0,"
    }
    if (Test-Path ($computerBasePath + "v1.1.4322")){
      $versionStr = $versionStr + "1.1,"
    }
    if (Test-Path ($computerBasePath + "v2.0.50727")){
      $versionStr = $versionStr + "2.0,"
    }
    if (Test-Path ($computerBasePath + "v3.0")){
      $versionStr = $versionStr + "3.0,"
    }
    if (Test-Path ($computerBasePath + "v3.5")){
      $versionStr = $versionStr + "3.5,"
    }
    if (Test-Path ($computerBasePath + "v4.0.30319")){
      $versionStr = $versionStr + "4.0,"

      if (CheckNet45($computer)){
        $versionStr = $versionStr + "4.5,"
      }
    }
    $versionStr = $versionStr.TrimEnd(',')
    "  Installed version(s): " + $versionStr

  }
  else{
   " Is not pingable!"
  }
}

All you have to do is create a text file with a list of machine names (one name per line). It does assume you have Admin rights so you can access the C$ share and read the remote registries.

How to install Access 64-bit driver with Office 32-bit on same machine

Firstly I’ll be frank and say this whole issue stink – just another nice Microsoft bugger-up. By default you cannot install the x64 driver for Access (AccessDatabaseEngine_x64.exe) on a machine that already has a standard 32-bit version of Office (which should be for the majority of users). However, if you run any 64-bit apps they won’t be able to access any ODBC/OLEDB drivers like for Access or CSV and so on. Yes, you can explicitly run the app as a 32-bit app and then access those 32-bit drivers again but then any 64-bit functionality goes out the door. (aka in .Net you can set the target platform to x86 and then it should work).

Now, there is a way to install AccessDatabaseEngine_x64.exe on a machine that has 32-bit Office (2010 I tested with) without the installer freaking out and gives you the error that it cannot continue because a 32-bit version of office is installed. To do it run this:

AccessDatabaseEngine_x64.exe /passive

That will give you the ability to open the 64-bit ODBC data Sources app and add DSNs. Wonderful except for one MAJOR big problem. If you now open up any office application if will freak out – something about some odbcij.dll missing or something. You can try a repair install but that will break the 64-bit ODBC/OLEDB drivers again. Bugger!

Fortunately there is a way around that problem as well. This will work if you don’t have Access installed (I have not tried it with Access installed and it might break Access altogether).

Open regedit and go to “HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\14.0\Common\FilesPaths“. If there is a key to mso.dll delete it (at your own risk of course).

Now you should be able to open Office without it complaining and the 64-bit ODBC driver tool will also work. If for some reason you did an Office repair and it broke the AccessDatabaseEngine_x64.exe install you must first uninstall it from control panel (something like Microsoft Access database engine 2010) and then rerun the AccessDatabaseEngine_x64.exe /passive command.

Lets hope Microsoft will find a better way to fix their own mess.

Update: BTW in Windows 7 64-bit (probably Vista as well) you can create a shortcut to the 64-bit ODBC control panel tool using this link: C:\WINDOWS\SysWOW64\odbcad32.exe. In Windows 8 at least they have separate entries (well I’m using classic shell…).

Update2: To use the 64-bit OLEDB provider for Access use the provider string “Microsoft.ACE.OLEDB.12.0“. Using the old string “Microsoft.Jet.OLEDB.4.0” does not work anymore (on 64-bit)

Update3: It seems newer versions of Office does some kind of check/repair after reboots and so returning the mso.dll registry value and breaking 32-bit Office applications again. To fix this use a registry file like this:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\14.0\Common\FilesPaths]
“mso.dll”=-

Possibly you can put it in a batch file that runs during startup (or scheduled task with Admin permissions)

Deleting a folder with path that is too long

Just a quick tip I came across today after having a problem where I found a directory where some tool went nuts and kept on creating subdirectories recursively. Trying to delete this directory will give you an error – something like ‘Path is too long…’

Lets say the path is something like d:\directory1\directory1\directory1\directory1…..\directory1

Windows Explorer and even Command prompt won’t allow you to delete d:\dir1 (No not even right-click delete will work).

A simple solution is to recursively go and rename all the directories to something much shorter so the overall length is less that the maximum (260 characters).

Like this: rename d:\directory1 0  , rename d:\0\directory1 0 etc.

The end result should be like this: d:\0\0\0\0… \0

Now you can simply delete it in Windows Explorer without any ‘Path Too long’ errors.

How to get the full update for VS2013

This tip applies to all editions and even previous versions (2012, 2012) of Visual Studio.

Since Microsoft has been releasing these updates e.g. VS2013.1 etc) the default behavior for these installers are to just download what is need at the time they are run. This is all good and well if you have only one machine that needs updating. What happens if you have to update a whole bunch of installs?

Luckily the VS2013.x installers support an undocumented (or not well) command line parameter ‘/layout’ that allows you to have the full update downloaded to a local folder. From there you can run the same installer without the parameter and it won’t download any additional stuff again.

Full command: VS2013.1.exe /layout

Happy downloading… only once.

VS 2013 Express tips

Just thought to share a tip or two about making the user experience better. The following applies to the desktop version but should also work (with some minor adjustment) to the other editions as well.

Change the all UPPERCASE main menus

In the registry, find the key HKEY_CURRENT_USER\Software\Microsoft\WDExpress\12.0\General. Add a (32-bit) DWORD value named SuppressUppercaseConversion and give it a value of 1. Next time you open the IDE the menu’s will be normal Title case again. It also applies to VS2012 editions as well (just change the version number to 11.0). For web express just change the ‘WDExpress’ part.

Update: If you are using the Web express edition the registry path for the change upper case menus are: HKEY_CURRENT_USER\Software\Microsoft\VWDExpress\12.0\General

Adding more themes

By default there are only 3 themes (for the express versions). To add some more options go to http://alinconstantin.blogspot.com/2012/09/using-color-themes-with-visual-studio.html?_sm_au_=isV7sFqHt8JbtbNM

Adding my Source backup tool

My source backup tool id aware of the desktop express version and can automatically add itself as one of the custom tools of the IDE. See SourceBackup.

If I come across more tips I’ll add them here as well.

 

Command line and strings

I’ve blogged about this some time ago under another topic (Creating-daily-log-files) but I find myself regularly searching for it again when I have to create a new batch file for something plus have to output some uniquely named log file.

Situation:

You have some script/batch file that does some stuff/maintenance/imports whatever. It runs from some kind of scheduler unattended so you need to have it generate a log file in case there were errors/issues. Creating an output log file is fairly easy but having it create a new name each day/time is a bit more tricky.

Possible solution:

This script assumes a date time format of yyyy/mm/dd

SET UNIQUESTR=%date:~0,4%%date:~5,2%%date:~8,2%%time:~0,2%%time:~3,2%
MyTool.exe > MyTool%UNIQUESTR%.log

This will create a log file with a date and time stamp each time it is run (assuming you don’t run it twice in the same second)

Have fun kids!

Update: a nice site with some helpful info -> http://www.dostips.com/DosCommandIndex.php

List all servers where I have an RDP session on (even ones where I’m disconnected)

This is something more than just one administrator has had trouble with. How do you find out what servers/machines you have worked on at some point and happened to simply use the ‘disconnect’ feature because you still had windows open? So far I have not found a simple way to do this – however I have created a script that helps with this. Unfortunately it still requires you to specify a list (input text file) of possible servers than needs to be checked. I would have liked if it was possible to have it automatically discover all machines with RDP sessions that use my logon…

The solution I created is simply a powershell script that takes an input text file with the list of machines you want to test connections with. This list would probably contain the usual machines you connect to. The other bit of the ‘solution’ is calling the ‘qwinsta’ utility that queries a specified machine and returns some details about RDP connections active on that machine. The script must then parse the output to figure out if your username is one of them…

param (
    $myAccount #(Read-Host -Prompt "Enter a user name")
    ,$serverListFile #(Read-Host -Prompt "File with list of servers")
)
if ($myAccount -eq $null){
    $myAccount = $env:username
}
if ($serverListFile -eq $null){
    $scriptpath = $MyInvocation.MyCommand.Path
    $dir = Split-Path $scriptpath
    $serverListFile = $dir + "\myservers.txt"
}

$showDebugInfo = $false
$reader = [System.IO.File]::OpenText($serverListFile)
"Listing RDP sessions for " + $myAccount
try {
    for(;;) {
        $server = $reader.ReadLine()
        if ($server -eq $null) { break }
        # process the line
        if(!(Test-Connection -Cn $server -BufferSize 16 -Count 1 -ea 0 -quiet))
        {
            " Error accessing " + $server
        }
        else
        {
            try
            {
                if ($showDebugInfo){
                    "Checking " + $server + "..."
                }
                $qwinstaResults = (qwinsta /server:$server | foreach { (($_.trim() -replace “\s+”,”,”))} | ConvertFrom-Csv)
                ForEach ($queryResult in $qwinstaResults)
                {
                    if ($queryResult -CMatch $myAccount)
                    {
                        "Logged on to " + $server
                    }
                }
            }
            catch
            {
                " Error processing " + $server
            }
        }
    }
}
finally {
    $reader.Close()
}
"Done"

Then using this script is as easy as calling it from (say) a batch file like this:

powershell.exe .\MyRDPConnections.ps1 myusername myservers.txt

Not perfect but at least it helps.

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