Creating a File Relay (proxy) using ASP.Net - Part 1 - Serving files.

In this series of posts I will walk you through implementing an ASP.Net based file relay mechanism using aspx pages. This will allow you to serve files hosted in the back-office (behind a firewall) from a frontend webserver.

To implement this solution we need to build two separate webpages, one for the backend server and one for the frontend server.

  • GetFile.aspx – The backend page which will surface the requested file to the frontend server.
  • RelayFile.aspx – The frontend page which will forward (relay/proxy) the request to the backend server.

In this first part I will show you how to send a file using an aspx page.

Implementing GetFile.aspx

The first thing we need to do is create the new aspx page and name it GetFile.aspx.

The Page Markup

Now let’s go ahead and remove all the content from the GetFile.aspx page, except for the Page directive; The purpose of this page is to return to contents of another file, so all the html markup is superfluous.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GetFile.aspx.cs" Inherits="Backend.GetFile" %>

The Code Behind

With the markup out of the way, let’s focus on the actual code behind the page. The only method we will need to implement is Page_Load.

1. Ensure a clean response – We don’t want anything from the aspx processing pipeline to interfere with the result

Response.ClearHeaders();
Response.ClearContent();

2. Determine the target file – In this example the filepath will be passed with the querystring.

string filePath = (Request.QueryString["filePath"] ?? "").Trim();

3. Determine and set the response type – This will allow the browser to display the file correctly. Also, make sure you only serve expected file types! This feature circumvents the basic webserver file security mechanisms, avoid leaking your secrets to the world!

string contentType = null;
string extension = Path.GetExtension(filePath).ToLowerInvariant();
switch (extension)
{
   case ".csv":
      contentType = "text/csv";
      break;
   case ".mp4":
      contentType = "video/mp4";
      break;
   case ".pdf":
      contentType = "application/pdf";
      break;
   default:
      // Unsupported filetype
      // There are serious security implications with
      // serving up files from a webserver. Make sure
      // you do not open yourself up to an attack!
      throw new HttpException(403, "Forbidden."); 
      // Use an empty ContentType if the type is unknown
      //contentType = "";
      //break;
}
   
//Set the ContentType.
Response.ContentType = contentType;

4. Set the response content length so the client knows how much data to expect.

var fileInfo = new FileInfo(filePath);
Response.AddHeader("Content-Length", fileInfo.Length.ToString());

5. Write the file contents to the response stream.

Response.WriteFile(filePath);

6. Flush the output buffers and end the response.

Response.End();

 

It’s a Wrap!

These 6 simple steps (7 if you count the page markup change) are all you need to implement a simple page to serve files from the filesystem. In the next part we will have a look at making this code more production ready by adding error checking and handling.

 

The Complete Page_Load Method

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:     // Clear headers and content to ensure a clean response
   4:     Response.ClearHeaders();
   5:     Response.ClearContent();
   6:   
   7:     // get target file path from querystring
   8:     string filePath = (Request.QueryString["filePath"] ?? "").Trim();
   9:     Debug.WriteLine("GetFile: filePath: '" + filePath + "'");
  10:   
  11:     // determine content type
  12:     string contentType = null;
  13:     string extension = Path.GetExtension(filePath).ToLowerInvariant();
  14:     switch (extension)
  15:     {
  16:        case ".csv":
  17:           contentType = "text/csv";
  18:           break;
  19:        case ".mp4":
  20:           contentType = "video/mp4";
  21:           break;
  22:        case ".pdf":
  23:           contentType = "application/pdf";
  24:           break;
  25:        default:
  26:           // Unsupported filetype
  27:           // There are serious security implications with
  28:           // serving up files from a webserver. Make sure
  29:           // you do not open yourself up to an attack!
  30:           throw new HttpException(403, "Forbidden.");
  31:        // Use an empty ContentType if the type is unknown
  32:        //contentType = "";
  33:        //break;
  34:     }
  35:   
  36:     //Set the ContentType.
  37:     Response.ContentType = contentType;
  38:     Debug.WriteLine("Mapped extension '" + extension 
  39:            + "' to content type '" + contentType + "'.");
  40:   
  41:     // determine and set file length
  42:     var fileInfo = new FileInfo(filePath);
  43:     Response.AddHeader("Content-Length", fileInfo.Length.ToString());
  44:   
  45:     //Write the file directly to the HTTP content output stream.
  46:     Response.WriteFile(filePath);
  47:   
  48:     // flush and end the response
  49:     Response.End();
  50:  }

How To Detect If The Command Prompt Is Running Elevated

As I was setting up my Console2 shell tabs I was curious if running Console2 as an administrator would transfer the elevated privileges token to the tabs as well.

Turns out detecting this was not as straightforward as I thought it would be!

TL;DR

If you need to know how to detect if the command prompt is running elevated (or your script) use the following command:

whoami /groups
If the output contains these lines the process is running elevated:
Mandatory Label\High Mandatory Level Label            S-1-16-12288
                    Mandatory group, Enabled by default, Enabled group

The Long Answer

With the addition of User Account Control to Windows Vista the platform gained integrity levels – an integrity level indicates how much an application can be trusted to perform  actions on the system, e.g. accessing files or the registry and interacting with other processes. By adding this additional security feature to the OS it now has another indicator to help isolate (sandbox) programs and prevent them from going rogue on your system. Very cool!

The following integrity levels are supported:

  • Untrusted – processes that are logged on anonymously are automatically designated as Untrusted
  • Low – The Low integrity level is the level used by default for interaction with the Internet. As long as Internet Explorer is run in its default state, Protected Mode, all files and processes associated with it are assigned the Low integrity level. Some folders, such as the Temporary Internet Folder, are also assigned the Low integrity level by default.
  • Medium – Medium is the context that most objects will run in. Standard users receive the Medium integrity level, and any object not explicitly designated with a lower or higher integrity level is Medium by default.
  • High – Administrators are granted the High integrity level. This ensures that Administrators are capable of interacting with and modifying objects assigned Medium or Low integrity levels, but can also act on other objects with a High integrity level, which standard users can not do.
  • System – As the name implies, the System integrity level is reserved for the system. The Windows kernel and core services are granted the System integrity level. Being even higher than the High integrity level of Administrators protects these core functions from being affected or compromised even by Administrators.
  • Installer – The Installer integrity level is a special case and is the highest of all integrity levels. By virtue of being equal to or higher than all other WIC integrity levels, objects assigned the Installer integrity level are also able to uninstall all other objects.

 

For more info see the Windows Integrity Mechanism Design.

Korg nanoKontrol2 MIDI Not Recognized

I finally got my 2 new toys: a Korg nanoKONTROL2 and a nanoPAD2. The initial installation was quick and painless: unwrap nanoKONTROL2/nanoPAD2, hook it up to the PC with USB a cable, and Windows happily recognized the new devices and installed the default drivers for them. The following installation steps, install the KORG USB-MIDI Driver, update the system software and using Kontrol Editor , proved to be more challenging…

 

Installing the KORG USB-MIDI Driver

I located the support section for the nanoSERIES2 controllers (click on SUPPORT below the product image), downloaded the latest USB-MIDI Driver for PC (1.13-r6 at the time of this writing) and installed the drivers for both controllers. No errors, all seemed well.

 

Controller software updates

imageNext up, updating the controllers with the latest software updates: nanoKONTROL2_Updater_0103 and nanoPAD2_Updater_0104. This is where the trouble started showing itself: Error – Update device is not found. Looking at the “Config…” menu option the only MIDI device recognized was my Yamaha Portable G-1 device. The two nano controllers were nowhere to be found, even when trying to manually select a MIDI device.

imageSimilarly troublesome was the Kontrol Editor device selection dialog at startup, both controllers were not recognized.

 

Troubleshooting

Basic troubleshooting of the issue consisted of un-/reinstalling the device drivers through device manager and un-/reinstalling the USB-MIDI Driver in various orders, with reboots in between, but after a couple of hours going through that with still no results I decided to look beyond the Korg drivers.
The only other thing that could possibly interfere seemed to be the Yamaha Portable G-1 USB-MIDI driver, so as a last resort I uninstalled it, rebooted and reinstalled the Korg USB-MIDI drivers. SUCCESS! The nanoKONTROL2 and nanoPAD2 finally showed up as MIDI devices, allowing me to update the controller software and use Kontrol Editor. This left me without support for my Yamaha keyboard however, so I downloaded and installed the latest Yamaha USB-MIDI Driver,  um310x86 – which was two versions up from my installed version, verified all USB-MIDI devices were still functional. Rebooted. Verified all USB-MIDI devices were STILL functional, and they still were!

 

Afterthoughts

Having to uninstall the Yamaha USB-MIDI driver still seems strange to me, but apparently did the trick. If this trick worked for you, or if it didn’t, please leave me a comment!

Simple, Fast and Accurate Running Average in C#

Running averages, also called rolling average, rolling mean and moving average, can be calculated in several different ways:

  • Simple Moving Average
  • Cumulative Moving Average
  • Weighted Moving Average

For my scenario I needed a simple, fast and accurate average, so I settled on implementing the simple moving average calculator below.

   class SimpleRunningAverage
   {
      int _size;
      int[] _values = null;
      int _valuesIndex = 0;
      int _valueCount = 0;
      int _sum = 0;

      public SimpleRunningAverage(int size)
      {
         System.Diagnostics.Debug.Assert(size > 0);
         _size = Math.Max(size, 1);
         _values = new int[_size];
      }

      public int Add(int newValue)
      {
         // calculate new value to add to sum by subtracting the
         // value that is replaced from the new value;
         int temp = newValue - _values[_valuesIndex];
         _values[_valuesIndex] = newValue;
         _sum += temp;

         _valuesIndex++;
         _valuesIndex %= _size;
        
         if (_valueCount < _size)
            _valueCount++;

         return _sum / _valueCount;
      }
   }
 
 

Here is how to use it:

      SimpleRunningAverage avg = new SimpleRunningAverage(4);
      foreach (int i in new int[] { 1, 2, 3, 4, 4, 4, 4 })
      {
         Console.WriteLine(avg.Add(i));
      }

 

For an implementation with more bells and whistles check out Marc Cliftons great article.

How Music Works – Melody – Recommended Video Series

While researching music I came across this awesome video series “How Music Works”. In this series Howard Goodall does a brilliant job introducing the  components that make up music. A real joy to watch!

 

Melody

In this part of the series Goodall covers Melody. He explains what makes a melody effective, Archetypal patterns (scales), the pentatonic system and how to achieve moods in music.

Enjoy!

 

Melody–Part 1

 

Melody–Part 2

 

Melody–Part 3

 

Melody–Part 4

 

Melody–Part 5

CutterMusic Revitar 2 VSTi Tutorial – How To Use Hammer On/Pull Off

The free Revitar VSTi by CutterMusic (see VstPlanet) supports Hammer On/Pull Off when playing in mono mode. In this tutorial I will show you how to apply these playing techniques through MIDI notes. It is important to note that Revitar makes a distinction between playing single notes using all strings and “mono” mode which plays all notes using a single string.
In chapter 3.1 the manual describes these modes as follows:
When playing single notes two modes are available.  In the first mode, you allow Revitar to select which string each note is played on.  In the second mode “mono” is selected, and Revitar is forced to play all notes on a single string.  In Mono mode, transitions between notes can use slides or hammer on/pull off techniques.  To create a slide effect hold down one key while pressing another.  The type of transition effect is controlled by the slide knob.

 

What is Hammer On/Pull Off:

Guitar Noise has a great lesson on using these techniques and defines them as follows:
  • Hammer on – Note generated by lightly snapping your finger down behind a fret.
  • Pull off – Note generated by removing your finger from a string, slightly pulling the string as you do.

Hammer On

To play a hammer on note with the Revitar VSTi the start of the note has to be played while the previous note is still held. The example below demonstrates this. The first measure plays all notes non-overlapping; each note is strummed. The second measure overlaps most notes, resulting in hammer ons for the 2nd, 3rd, 4th and 6th, 7th and 8th notes. Play the audio example to listen to the difference.
NormalAndHammerOn_500
HammerOn MP3

Hammer On/Pull Off

To play a pull off after a hammer on you need to keep holding the first note until the end of the hammer on note – holding the first note too long will create a hammer on of the first note in addition to the pull off. The example below shows this in action. The second note in each measure is played using hammer on/pull off. Listen to the audio example to hear this in action.
HammerOnPullOff_500
HammerOn PullOff MP3

Controlling Hammer On/Pull Off Amount

RevitarTut_Strings_Slide
The amount of hammer on/pull off is controlled through the Slide control in the Strings section and note velocity.

Slide Control

The manual describes the slide control as follows:
Slide: Default MIDI CC:   2
Controls the type and rate of note transitions.  Note transitions
only occur in Mono and Chord modes.  If the knob is greater than
the 9 o’clock position notes are transitioned by sliding with de-
creasing rates.  A knob position less than the 9 o’clock position
turns on hammer on / pull off transitions.  The amount of hammer
on / pull off increases as the knob is turned counter clockwise. 
The amount of hammer on / pull off is also controlled by the note’s velocity.
This example sweeps from a note Slide rate of 0.01 in the first measure to a Hammer/Pull of 1.00 in the fifth measure. Notice the switch between Slide and Hammer/Pull mode in the second measure when listening to the audio.
HammerPullSweep_500
Slide Sweep MP3

Velocity

The other mechanism to control the hammer on/pull off amount is note velocity. This example sweeps the note velocity of the second note in each measure from minimum (0) through maximum (127). Listen to the audio example.
VelocityIncrease_500
Velocity Increase MP3

I hope this tutorial helps you master this awesome VSTi. Please leave a comment if you have questions or feedback!
Thanks!

P.S. If you are looking for a copy of the manual, you can find it here.

Time To Face The Music

I have picked up creating music again, an old hobby which I used to pour my heart and soul into. 15 years have passed since I was last actively making music and it had been nagging at me to pick it back up. I needed a new passion besides love for coding and 18 months ago I started on my journey from 8-bit Trackers into the Digital  Audio Workstation world of today.

 

Synth 13 - 2011 by zybermark

 

8-bit Trackers

The first tracker I worked with was FAC SoundTracker which sported 9 monophonic FM channels and an ADPCM channel, the resulting output was a mono audio stream. With the release of Moonblaster the MSX scene was propelled into a pseudo stereo universe; the MSX home computer had 2 fairly similar sound expansion cards, by routing the output of these separately to the left and right channels a stereo sound was created. The audio hardware had not changed so this tracker still featured 9 monophonic FM channels and an ADPCM channel, however because 3 channels were used for drums this effectively brought it down to 6 FM channels + drums. This dual sound generator model allowed for some interesting sound design; by detuning one side slightly more or using totally different FM patches some interesting sounds could be created.

These trackers were different from most trackers in the day because they used FM channels instead of sample channels to create the compositions. This still heavily biases my preference towards composing using real notes, as opposed to prerecorded clips.

 

Sequencer 1.0

Cubase1I tinkered around with MIDI and my Yamaha PSS-780 back then (PC + MPU-401 + Cakewalk 1.0, Atari ST 1024 + Cubase), but never ended up doing any serious work with it. Even though I enjoyed my PSS-780, the challenge of composing using MIDI was a lot steeper than using the trackers I had at my disposal. Using a tracker also made my music more portable because within my circle of friends the hardware was much more prolific than my particular MIDI setup.

 

Facing the DAW

My initial focus was on getting (back) up to speed on all the technologies used in creating digital music nowadays. Tweakheadz Labs’ Guide to the Home and Project Studio proved to be an excellent resource for this; Scott McLean at TranceMusicMastery also has some great videos on working with the DAW technology of today. Armed with this newfound knowledge I set off on a project to recreate an old song: “Synth 13”; I considered this song to be “OK” and did not want to burn myself out on my favorite one.

I had purchased a copy of Cakewalk Music Creator 3 a couple of years ago,set it as my goal to use that to recreate the original sound as closely as possible and started recreating the song by ear. Over time I got my hands on the original scores again to help analyze a couple busy parts, but most of the song element were still very vivid in my mind. In retrospect, the size of this learning process was just staggering! Recreating the original score was the easiest part; mastering the sequencer and its quirks, using effects effectively and finding and creating similar sounds turned into a yearlong project! Having wrapped up the initial pass I was fairly content with the final result of this project, recreating the original sound, but I  was far away from the quality I wanted to produce. The tools at my disposal in MC3 felt limiting to me; limited number of virtual synths, limited number of effects, limited number of tracks, etc. etc. I also felt that the synths and host program were not working well together, lots of funny quirks, timing issues, clicks, pops. Maybe it was just my mind rebelling against the DAW but I was fairly comfortable with this new musical creation environment and decided it was time to upgrade. I wanted to be able to take my current projects and seamlessly continue; sticking with a Cakewalk product thus was the best choice, so I invested in a copy of Sonar X1 Producer. That took care of getting better tools: awesome new synths, plugins, unlimited tracks and a fancy new UI. I still needed to improve my mixing skills; The Mixing Engineer’s Handbook turned out to be a great help to sharpen these skills and get really close to the sound I was aiming for: Synth 13 – 2011, which you can find at the beginning of this post.

I will share more about this project in a future post.

Blend Error: The specified solution configuration "Debug|HPD" is invalid.

When trying to compile a project in Microsoft Expression Blend 4 I got the following error:

myproject.sln.metaproj : error MSB4126: The specified solution configuration "Debug|HPD" is invalid. Please specify a valid solution configuration using the Configuration and Platform properties (e.g. MSBuild.exe Solution.sln /p:Configuration=Debug /p:Platform="Any CPU") or leave those properties blank to use the default solution configuration.

To resolve this issue you need to remove an interfering environment variable named “PLATFORM“.
This can be done in three easy steps (without hacking the registry)!

 

image1. Open the Environment Variables dialog.
On the start menu Right-Click on “Computer”, select “Properties”, then click on “Advanced system settings” in the left column and finally locate and click the “Environment Variables…” button.

2. Remove the PLATFORM environment variable.
In the System variables list locate and select the PLATFORM variable and click Delete to remove it. Hit OK to close the Environment Variables dialog box.

3. Make it work.
Now restart Blend and you will be able to compile your projects.

HP a1750e Upgrade to Windows 7

I upgraded my HP Pavilion a1750e machine from Vista to Windows 7 (32 bit) over the weekend, here is how it all went down…

Preparation

Before doing anything I wanted to make sure my system would be able to run Windows 7 so I downloaded the upgrade advisor and performed an analysis. The analysis takes a couple of minutes to do its work before showing you a report with all the (potential) problems you will encounter, allowing you to get your system ready before taking the big leap into an exciting new OS. The report is split up in sections covering the system hardware, devices (drivers) and programs.

One of the first things the upgrade report points out in the system section is the HP webpage describing how to upgrade your system, i recommend you take a look at it.

Drivers were listed as available for all hardware devices that come standard with this system. Two ‘unknown’ devices were listed for me: “HP psc 1600 series” (a printer) and “Yamaha USB-MIDI Driver (WDM)”. I took the opportunity to install the latest USB-MIDI driver from Yamaha (um304x86 at the time of this writing), it still functioned properly after the upgrade. The printer driver was automatically updated by the hardware wizard after the upgrade.

The programs section looked a little more problematic:

  • Canon Camera Window MC 6 for ZoomBrowser EX, version 6.3.0.8, Known issues.
    I uninstalled this program before upgrading.
  • Hardware Diagnostic Tools, version 5.00.4262.12, PC-Doctor, Inc., Update available.
    I have never used this program and did not update it. - If you experienced problems with it please leave me a comment.
  • iTunes, version 7.4.0.28, Apple Inc., Reinstall after upgrade.
    I uninstalled this program before upgrading.
  • Microsoft Expression Web, version 12.0.6215.1000, Microsoft Corporation, Update available.
    I did not bother updating it (yet).
  • Roxio Express Labeler 3, version 2.1.0, Roxio, Update available.
    I did not update this program (yet). - If you experienced problems with this program please leave me a comment.
  • Skype™ 3.8, version 3.8.188, Skype Technologies S.A., Known issues.
    I upgraded Skype to the latest version before upgrading which made the warning go away.
  • Windows Mobile Device Center, version 6.1.6965.0, Microsoft Corporation, Reinstall after upgrade.
    I uninstalled this program before upgrading, then reinstalled Windows Mobile Device Center after the upgrade and connected my iPaq. The driver got automatically installed and it appears to function properly.

Execution

After all this prep work I started the upgrade which completed successfully in approximately three hours.

My system is the lucky owner of two sound devices, onboard “Realtek High Definition Audio” and a “Creative AudioPCI (ES1371,ES1373) (WDM)” card, the settings for these devices were seamlessly transferred during the upgrade and they still function properly. Very impressive. I think it is very cool you can hot-switch default audio output devices while playing sound in Windows 7!

Issues

Two issues I am aware of thus far:

  • Canon Camera Window MC 6 for ZoomBrowser EX
    After upgrading I downloaded the latest ZoomBrowser EX installer from the Canon website: ZoomBrowser EX 6.4.1 Updater, Windows 7 is not available as a supported OS for downloads so I picked the Vista version. Unfortunately the Camera Window application is not functioning.Setting the CameraWindow application to run in Vista SP2 compatibility mode will resolve this issue.
  • Powersaving for the display does not work (NVIDIA GeForce 7900 GT/GTO).
    The display will go black but it never gets turned off
    . -  This issue was caused by the screensaver, changing to a different screensaver resolved the issue.

How To Determine If A Window Is Active (In C)

As promised in my previous blog describing how to add activity notification flash to PuTTY here is another way to check if the window is active. Instead of keeping track of the current window state by handling the WM_ACTIVATE message you can directly query a window for its status with GetWindowInfo(). The WINDOWINFO.dwWindowStatus field will be set to WS_ACTIVECAPTION when the window is active.

Paste the following snippet at the end of window.c:

/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - WINDOW ACTIVE DETECTION2 */
/* SNIPPET ID: {CE84000D-9024-45f1-B0E6-5029AD1B257F} */
BOOL is_window_active()
{
   BOOL bActive=FALSE;
   BOOL bResult;
   WINDOWINFO wi;
 
   memset(&wi, 0, sizeof(wi));
   wi.cbSize=sizeof(wi);
 
   bResult=GetWindowInfo(hwnd, &wi);
 
   if(bResult)
      bActive = (wi.dwWindowStatus==WS_ACTIVECAPTION);
 
   return bActive;
}
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - WINDOW ACTIVE DETECTION2 */

Then add a forward declaration to the forward declarations (Snippet ID: D8B4F4A3-F870-4ded-B298-EEB71701D25D), it will look like this:

/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - FLASH METHODS FORWARD DECLARATIONS AND VARS */
/* SNIPPET ID: {D8B4F4A3-F870-4ded-B298-EEB71701D25D}-20090922*/
static void flash_window_activity(int mode);
static BOOL window_is_active=TRUE;
static BOOL activity_blink_done=FALSE;
BOOL is_window_active();
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - FLASH METHODS FORWARD DECLARATIONS AND VARS*/

 

With this new code in place all that is left is updating the activity detection logic to use it. This is implemented in the from_backend method, replace the use of the window_is_active boolean with the new is_window_active() method call so the code will look like this:

int from_backend(void *frontend, int is_stderr, const char *data, int len)
{
/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - SESSION ACTIVITY DETECTION */
/* SNIPPET ID: {9198643F-09DF-466f-971F-EB05EA15A85E}-20090922 */
   if(!is_window_active())
      flash_window_activity(2);
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - SESSION ACTIVITY DETECTION */
   return term_data(term, is_stderr, data, len);
}

 

All that is left now is compiling the code and firing up PuTTY!

Enjoy!

How to add Activity Notification to PuTTY

For over a decade PuTTY has been my Telnet/SSH client of choice for Windows. I mostly use it as a MUD client nowadays and missed one convenience feature: activity notifications. Chat clients all flash for attention when activity occurs and it would be a great addition to streamline my social mudlife, so I set out on a quest to add it…

First of all you need to have Microsoft Visual C++ installed to compile the sourcecode for Windows which can be found on the PuTTY Download page. Get the sources unzipped and load the workspace “putty-src\WINDOWS\MSVC\PUTTY.DSW”, you will need to go through a conversion to a Visual Studio 2008 solution when using VS2008. All code additions and changes are done in the file WINDOW.C in the “putty” project.

To support activity notification we need to know when there is activity and notify the user by making the window flash if the window is not active and it has not already done a flash. This brings us down to three problems to solve: detecting activity, knowing when the window is not active and flashing the window.

 

Flashing the PuTTY Window

PuTTY already has the option to use the window flash as a visual bell so that code can be used as a template. Notice how this feature also has been implemented in the PuTTY code itself to support flash on older Windows OSes that do not support the FlashWindowEx API method. (I have left this code in place, but it has not been tested.)

The following code snippet must be added at the end of the file:

/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - FLASH METHODS */
/* SNIPPET ID: {34060BBE-6F8C-4bc1-AF1F-97B3FC8D24A4} */
static void flash_window_timer_activity(void *ctx, long now)
{
    if (flashing && now - next_flash >= 0) {
      flash_window_activity(1);
    }
}
 
static void flash_window_activity(int mode)
{
   if(mode==0) {
      /* stop */
   } else if (mode==2)
   {
      /* start */
      if (!flashing && !activity_blink_done) {
         flashing = 1;
         activity_blink_done=TRUE;
         if (p_FlashWindowEx) {
            /* For so-called "steady" mode, we use uCount=2, which
            * seems to be the traditional number of flashes used
            * by user notifications (e.g., by Explorer).
            * uCount=0 appears to enable continuous flashing, per
            * "flashing" mode, although I haven't seen this
            * documented. */
            flash_window_ex(FLASHW_ALL | FLASHW_TIMER,
               (cfg.beep_ind == B_IND_FLASH ? 0 : 2),
               0 /* system cursor blink rate */);
            /* No need to schedule timer */
         } else {
            FlashWindow(hwnd, TRUE);
            next_flash = schedule_timer(450, flash_window_timer_activity, hwnd);
         }
      }
   }
   else if(mode==1)
   {
      /* maintain */
      if (flashing && !p_FlashWindowEx) {
         FlashWindow(hwnd, TRUE);   /* toggle */
         next_flash = schedule_timer(450, flash_window_timer_activity, hwnd);
      }
 
   }
}
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - FLASH METHODS */

 

Add the following snippet to the forward declarations at the top of the file (surrounding code is show for reference to the location where it should be placed and must not be added):

#define TIMING_TIMER_ID 1234
static long timing_next_time;
 
/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - FLASH METHODS FORWARD DECLARATIONS AND VARS */
/* SNIPPET ID: {D8B4F4A3-F870-4ded-B298-EEB71701D25D}*/
static void flash_window_activity(int mode);
static BOOL window_is_active=TRUE;
static BOOL activity_blink_done=FALSE;
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - FLASH METHODS FORWARD DECLARATIONS AND VARS*/
 
static struct {
    HMENU menu;

The activity_blink_done boolean ensures the window flash gets triggered only one time once the window has become inactive and activity occurs.

 

Detecting the Window Active State

There are several ways of doing this, I embarked on the adventure of using a handler for the WM_ACTIVATE message to keep track of the current state because it seemed to blend in well with the rest of the code in place. The handler also clears the activity_blink_done variable so a new flash will be triggered when necessary.

Add the following snippet at the end of the file:

/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - WINDOW ACTIVE DETECTION */
/* SNIPPET ID: {75B2CA9C-49F4-4eb5-AFCF-E3D743C37C44} */
int Do_WM_ACTIVATE(HWND a_hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
   WORD wAction = LOWORD(wParam);
   WORD wMinimized = HIWORD(wParam);
 
   if(a_hwnd == hwnd) {
      switch(wAction)
      {
         case WA_INACTIVE:
            window_is_active = FALSE;
            activity_blink_done = FALSE;
            break;
         case WA_ACTIVE:
         case WA_CLICKACTIVE:
            if(!wMinimized)
               window_is_active = TRUE;
            break;
         default:
            break;
      }
   }
}
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - WINDOW ACTIVE DETECTION */

 

With the message handler in place we need to hook it up in the window procedure. To do this we need to add a case statement for the WM_ACTIVATE message in the WndProc method. Insert the following code snippet right before default case handler (surrounding code shown for reference and must not be copied):

/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - WINDOW ACTIVE DETECTION */
/* SNIPPET ID: {5AFAA3AB-FB28-45e9-9DE7-E56648A1B5AF} */
      case WM_ACTIVATE:
         Do_WM_ACTIVATE(hwnd, message, wParam, lParam);
         break;
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - WINDOW ACTIVE DETECTION */
      default:
         if (message == wm_mousewheel || message == WM_MOUSEWHEEL) {

 

For completeness add a forward declaration below the previous forward declaration snippet we added:

/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - WINDOW ACTIVE DETECTION FORWARD DECLARATION */
/* SNIPPET ID: {D3292300-A6A3-402f-A0A5-CE259BD25EC0} */
int Do_WM_ACTIVATE(HWND a_hwnd, UINT message, WPARAM wParam, LPARAM lParam);
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - WINDOW ACTIVE DETECTION FORWARD DECLARATION */

 

Detecting Session Activity

With the window flash and window state support in place all that is left to do is hooking it up to the session activity detection. Find the from_backend method and insert the code snippet below so the method resembles the code block:

int from_backend(void *frontend, int is_stderr, const char *data, int len)
{
/* MARK SLETTERINK - ACTIVITY NOTIFICATION SUPPORT - SESSION ACTIVITY DETECTION */
/* SNIPPET ID: {9198643F-09DF-466f-971F-EB05EA15A85E} */
   if(!window_is_active)
      flash_window_activity(2);
/* MARK SLETTERINK - END OF ACTIVITY NOTIFICATION SUPPORT - SESSION ACTIVITY DETECTION */
   return term_data(term, is_stderr, data, len);
}

 

Enjoy!

That completes the code additions. Compile the code, fire up PuTTY and enjoy the new activity notification feature!

Quest complete! You gained 1 million XP.

How to parse and modify a URL in .Net

When you need to modify a url string in .Net code the most prudent way to do so is by using the UriBuilder class from the System namespace because it encapsulates all the quirky rules involved in url parsing. However simply creating a new UriBuilder instance initialized with the url string has the potential for throwing a UriFormatException which creates a serious performance hit whether the exception is caught and handled or, even worse, your program will fail on an unhandled exception if your code did not anticipate this.

The UriFormatException can be easily avoided by first converting the url string to a Uri class instance by calling Uri.TryCreate(...) and checking the return value for success. If TryCreate succeeded the resulting Uri instance can then be used to create a UriBuilder instance.

 

The code below shows a C# example of how to modify the hostname in a url without throwing exceptions.

[TestMethod]

public void ModifyUrlHost()

{

   string[] urls ={"http://brokensite.com/test/me.html?a=1&b=2"

                  , "https://brokensite.com"

                  , "https://brokensite.com/"

                  , "http://brokensite.com/default"

                  , "/test/me.html?a=1&b=2"

                  , String.Empty

                  , null

                 };

   string newHostName="www.somesite.com";

 

   foreach (string url in urls)

   {

      Debug.WriteLine("Original Url: " + url);

 

      string newUrl = url;

      Uri uri;

      if (Uri.TryCreate(url, UriKind.Absolute, out uri))

      {

         Debug.WriteLine("Uri.TryCreate succeeded");

         UriBuilder builder = new UriBuilder(uri);

         builder.Host = newHostName;

         newUrl = builder.Uri.ToString();

      }

      else

         Debug.WriteLine("Uri.TryCreate failed");

 

      Debug.WriteLine("New Url     : " + newUrl);

      Debug.WriteLine("");

 

      if(newUrl!=null)

         Assert.IsFalse(newUrl.Contains("brokensite.com"), "url still contains brokensite.com");

   }

}

This test generates the following output:

//Original Url: http://brokensite.com/test/me.html?a=1&b=2

//Uri.TryCreate succeeded

//New Url     : http://www.somesite.com/test/me.html?a=1&b=2

 

//Original Url: https://brokensite.com

//Uri.TryCreate succeeded

//New Url     : https://www.somesite.com/

 

//Original Url: https://brokensite.com/

//Uri.TryCreate succeeded

//New Url     : https://www.somesite.com/

 

//Original Url: http://brokensite.com/default

//Uri.TryCreate succeeded

//New Url     : http://www.somesite.com/default

 

//Original Url: /test/me.html?a=1&b=2

//Uri.TryCreate failed

//New Url     : /test/me.html?a=1&b=2

 

//Original Url:

//Uri.TryCreate failed

//New Url     :

 

//Original Url:

//Uri.TryCreate failed

//New Url     :     

Being Polite Could Get You Killed!

But wouldn't you rather die a gentleman than live as a savage?

--

More British passengers died on the Titanic because they queued politely for lifeboats, researchers believe.

"The American culture was set up to be a more individualist culture and the British culture was more about the gentlemanly behaviour," Mr Savage says.

"You've got to remember that this is the Edwardian period when to be a gentleman was the peak of society."

Mr Savage said: "There was one gentleman who was rather wealthy... who went back downstairs after he put his wife on the [life] boat... put on his tuxedo...went back upstairs and smoked... with the idea that if I am going die, I may as well die as a gentleman and well-dressed."

 

Now THAT is my kind of man! AMEN BROTHER!

Reusable Generic Exception Wrapper in C#

When crossing boundaries between software layers you are sometimes faced with the requirement to wrap a meaningless exception from a lower layer into a more meaningful exception for users from the higher layer. The pattern described below helps with implementing this requirement in a reusable way. It is in no way meant to be a catch-all for every situation where you have to deal with exceptions, but when applied correctly can prove to be an invaluable tool in your toolkit. See Framework Design Guidelines, Chapter 7 (7.2.3) for more one exception wrapping.

The approach used is to wrap the logic that can fail in a delegate and have this delegate executed by the WrapExceptions method. The WrapExceptions method then takes responsibility of handling the exceptions appropriately. It should be modified to handle only the applicable exceptions; some exceptions you might not want to wrap e.g. StackOverflowException, OutOfMemoryException and ThreadAbortException because you cannot recover from them. An added advantage of wrapping the failure prone code in a delegate is that it allows you to easily wrap it around existing code.

The WrapExceptions code snippet:

// public delegate void Action();

public static void WrapExceptions(Action action)

{

   try

   {

      action();

   }

   catch (MyApplicationException)

   {

      // just rethrow exception, it

      // was already properly handled

      throw;

   }

   catch (Exception e)

   {

      throw new MyApplicationException(e);

   }

}

And then you can use it as follows:

public void WrapMyException(string filepath, string myLine)

{

   WrapExceptions(delegate()

   {

      using (TextWriter writer = new StreamWriter(filepath))

      {

         writer.WriteLine(myLine);

      }

   });

}

Let me know your thoughts on this approach. What problems did it solve, and did it introduce new ones?

More pain with NVidia...

It has been a while since I last tried to find a stable video driver and reader Gregg's question made me pull the trigger on another adventure in driver-installation-land. It has been a nightmare!

I started out with trying to reproduce the problem desribed in 'Black Screen after Vista Wakes Up from Sleep with NVidia Driver 7.15.11.7521' by installing the latest NVidia GeForce video driver available: GeForce Release 178 WHQL (Version: 178.24, Release Date: October 15, 2008, Operating System: Windows Vista 32-bit, Language: U.S. English, File Size: 85 MB). A reboot later the version number now was at 7.15.11.7824. A quick cycle through sleep-and-resume confirmed the problem was still there. Ouch! Reader Eddy had spent some time troubleshooting this issue as well and pointed out the resolution played a role in it, I am running in 1280x1024 32 bit color. So I changed the color bits from 32 to 16: problem still there, lowered the resolution to 1152x864: problem gone! (I skipped a number of steps here, if NVidia wants scientific data they can hire me and pay for my precious time). Unfortunately now the screen looks like somebody put Vaseline in my eyes. Yuck!

Ok, so the screen was ugly, but I could go through a sleep-and-resume cycle. Was it worth the ugly screen? Absolutely not! Time to run system restore and get back to my original driver setup...

Unfortunately kicking off system restore to my old restore point presented me with a blue screen during the process.

...

Eventually my system rebooted, Vista prompted me to its awareness of the crash, I sent the crash report and Microsoft pointed the finger at the NVidia SATA driver. Gaaaaa! Oh well, that was fun, I figured I would try system restore again only to find every single restore point had vanished. Automatic, Manual, they are all gone! Somebody pinch me! My screen looks like all pixels are smeared into eachother and I'm stuck with a broken driver setup. Wake me up from this nightmare!

Moving on...

My SATA driver is broken, Microsoft says I need to get latest from NVidia... I figured I could put NVidia to work for me this time and use the wizard from the website to determine the Motherboard software download I needed. The verdict? GeForce 6150LE / nForce 430 (nForce Driver Version 15.24 WHQL, Release Date: September 12, 2008). Sounds good. Download, install, reboot. This installer puts a driver for just about every piece of hardware they created on your system, and as it comes as a package I would expect them to work together very well. (GeForce 6150 LE driver version 7.15.11.7540, SATA driver version 10.3.0.42.) Unfortunately, a 'quick' sleep-and-resume cycle showed the problem was still there and Windows Update tells me there are updated drivers available for my nForce networking and SATA controller.

Installed GeForce 6150LE driver version 178.24 again and rebooted. Worked with the system for a couple of days and on my next reboot I blue-screened again. Installing the latest SATA driver through Windows Update seems to have resolved that issue. But for now I have disabled sleep mode.

Conclusion: Problem still not fixed.

The Pitfall of ICloneable

Or, why you should never use ICloneable.

So I decided I needed to support cloning for my objects so I can modify the object and compare it to the original (very useful for unit-testing, dirty checking, etc.). The .Net framework comes with a handy interface to publish this ability called ICloneable. The documentation states "Supports cloning, which creates a new instance of a class with the same value as an existing instance". Great! It comes with one method: Clone. Can't be too hard to implement this interface, right?

A quick peek at the documentation for the Clone method says the implementation "Creates a new object that is a copy of the current instance". And so every textbook implementation goes on to show you how you do that:

public object Clone()
{
   return this.MemberwiseClone();
}

But what is the point of that, besides adding more code to maintain? EVERY object already supports MemberwiseClone! Oh yes, we were trying to satisfy an interface contract... But hold on, it gets worse as the documentation then opens up an infinite can of worms with this remark:

Clone can be implemented either as a deep copy or a shallow copy. In a deep copy, all objects are duplicated; whereas, in a shallow copy, only the top-level objects are duplicated and the lower levels contain references.

The resulting clone must be of the same type as or a compatible type to the original instance.

The Clone method, and thus the ICloneable interface just became a free-for-all, do as you like, contract. You may deep copy, shallow copy, heck you can even change the type! Technically this can all result in correct code, but the sheer absence of semantics turns the use of this interface into a humongous pitfall. Within your own sphere of influence you can set an expected semantic, but as soon as your code leaves this safe place, or you introduce code from another source which applied different semantics to the ICloneable interface you are in for a debugging session from hell.

ICloneable just became unusable.

Go ahead and mark it as obsolete in your copy of the framework. Not all is lost however, you can work around this issue by defining your own interface contract with its own semantics, but do not inherit it from ICloneable as this would reintroduce the issue. For example:

/// <summary>
/// Supports deep-copy cloning, which creates a 
/// new instance of a class of the same type and 
/// with the same value as an existing instance.
/// </summary>
/// <typeparam name="T">Type of the class 
/// being cloned.</typeparam>
public interface IDeepCloneable<T>
{
   /// <summary>
   /// Creates an equally typed deep-copy clone 
   /// of this object.
   /// </summary>
   /// <returns>An equally typed deep-copy clone 
   /// of this object.</returns>
   T Clone();
}

This interface contract sets a clear copy and type expectation (and gets rid of the pesky Object return type, that was so 1.0 baby!), but defining cloning semantics is not an easy task. Data containers, business- and UI-objects all have different needs and come with different cloning behaviors. Defining an interface for each of those will help keep expectations clear and ease integration with 3rd party components. However, unless you explicitly implement those interfaces on all classes you will also have to make sure the method names in those interfaces are unique else it will still be too easy to mix incompatible implementations. Always keep the consumer in mind while designing your interface!

I'm curious to know how you approached your cloning challenge. Leave me a comment!

 

References

My Latest Track