Installing VS 2008 SP1 and I’m bored


Before leaving last night, I uninstalled all of the appropriate bits, and then fired off the installation for VS 2008 SP1.  I had heard it took a couple of hours, so I wanted to let it do its work while I was gone.

This morning, I arrived to find that the installation had paused, waiting for me to close down Word, Outlook and Internet Explorer.  So now I’ve closed those apps down and resumed the installation.

So, when I cannot use Office or IE, what should I be doing?  I don’t have Firefox installed, so I cannot even browse with that.

Before I closed IE, I saw that Ayende has already posted a Connect bug for SP1.  I’ll tell you what, it seems like he should be a Beta tester for every release and service pack—he always seems to find a way to break something!

Technorati Tags:

author: Jeff Handley | posted @ Wednesday, August 13, 2008 10:28 AM | Feedback (0)

Headless Horseplay - MediaSmart Home Server Status Indicators


I posted an entry that Google Reader isn't picking up for some reason.  Go check it out here.

author: Jeff Handley | posted @ Wednesday, August 13, 2008 7:29 AM | Feedback (0)

NIN Concert Review


It was a couple of weeks ago now, but Kelly and I went to the Nine Inch Nails concert in Seattle.  I had really been looking forward to going, and let me tell you, Trent did not disappoint me one bit.  The show was absolutely amazing.

I must admit, and offer as a disclaimer, that I'm not much of a concert-goer.  I think my last concert before this one was seeing Dishwalla perform in a dive bar in Cincinnati after winning 2 tickets from Q102--that was in either 1996 or 1997.  I think there were 20 people there to see them.  Before that, I saw Live perform at Miami University (Oxford, OH); that was a good show.  I've been to only a few other concerts, so altogether, I don't have much of a baseline to compare NIN's Lights in the Sky show to.  That being said...

The show blew me away.  Not only was Trent and his band playing an outstanding mix of old and new, and doing so really well, the visual effects used were simply mind-boggling.  They had what appeared to be a translucent stage-width touch-screen display that they repeatedly used in front of the stage.  They also had a huge screen behind the stage, and they used the 2 in unison very well.

The screen in front of the stage was often displaying effects such as rain, which made it look like the band was playing outside in a storm.  But there were many times when Trent and others would get really close to, or touch the screen (which appeared to be flexible), and it would react to them in spectacular ways.

I don't want to give away any more spoilers, so I won't say anymore regarding the details of the show.  But if you are a NIN fan of any sort, do yourself a favor and buy some tickets for the show nearest you.  And give Trent a break about having to reschedule a couple of the shows already... he is really pushing his voice to the max with this performance, and he needs to take care of his throat!  He's simply incredible and it was great to see him perform live.  Oh, and his band did a great job too. :-)


I was going to link to the Q102 website (WKRQ.com), but MAN is it hideous! 

author: Jeff Handley | posted @ Wednesday, August 13, 2008 12:29 AM | Feedback (0)

My first panoramic picture


A few weeks ago, we took a day trip down to the Mt. Rainier National Park.  We took tons of pictures and some of the views were absolutely spectacular.  At one point, we walked down a trail onto the river bed of the White River, and there was a log bridge going over the river.  The scene was just breathtaking.  I hadn't ever used the Stitch Assist feature on our Canon PowerShot S3 IS, and I decided that was the time to try it out.

I took 3 pictures, using the highest resolution in the "Landscape" mode.  The other night, I finally got around to trying to stitch them together.  I went and grabbed Windows Live Photo Gallery for the task, and it did a great job for me.  Here's the result.  This is now the desktop background on my machine at home and at work.  At work, I have resized and rescaled the picture to fit my 3360x1050 needs.

White River Mt. Rainier National Park

author: Jeff Handley | posted @ Tuesday, August 12, 2008 11:55 PM | Feedback (0)

Headless Horseplay - MediaSmart Home Server Status Indicators


I am working on a Family Photos application that organizes digital pictures into a chronological structure.  I had created thrown together an application like this years ago, but it was no longer going to cut it, especially with the new Windows Home Server in the mix.  One key requirement for Family Photos is to very easily move pictures off of the SD card from the camera, queuing them up for organization, and allowing the SD card to be taken back and put back into the camera.  Our old process involved the following:

  1. Unlock the screen for Jeff's computer
  2. Plug the SD card into the SD->USB adapter
  3. Double-click an icon on the desktop (minimizing windows if needed)
  4. Watch the console window and wait for it to print a message stating that the program has finished moving all files off the drive
  5. Take the SD card out and be on your way

While a little clumsy, it had a high WAF.  Kelly knew how to do it, and it allowed her to be on her way in minutes, with a clear indication as to when she could take the card out.  Family Photos needs to offer the same benefits while ideally simplifying the process even further.

The HP MediaSmart Windows Home Server adds an interesting twist on this problem too: it's headless.  No monitor, keyboard or mouse.  That means there's no icon on the desktop, no mouse to click with anyway, and no console window to offer status indicators.  There's no user input and no output.  So how can we tell the server, "Hey, I just put in a drive that has photos.  Take the photos off of there as quickly as possible and let me know when you're done so that I can take the drive back.  Then, after I'm gone, organize all of the pictures for me.  Thanks!"  I haven't done any recreational coding since we moved, but this problem has been stirring in the back of my head for months.  I'm finally working on it, and it feels great.

It boils down to the two requirements: the server needs to accept input, and it needs to give output.  The rest of this article will focus on the output aspect, and we'll leave the input for another post.  We need to think hard about ways the home server can provide status indicators as its output.  Let's consider some options, ignoring the user input problem.

  1. Require a remote desktop session into the server to perform the task so that a console window can show status, just like the old process
  2. Send an email or IM when completed
  3. Send a network message to the family laptop, triggering it to pop up a dialog

None of those is good.  This is where I was stuck for a long time.  But the other night, I thought of option 4, and it was the clear winner.

  1. Find a way to programmatically flash the LEDs on the MediaSmart server

The MediaSmart server console provides a slider that adjusts the brightness of the LEDs for the drives.  The idea was to crank the brightness all the way up while the files were being moved over, and then dim the lights way back down when finished.  I'd tell Kelly, "When the lights basically turn off, you can take the card back out."  So, how can the brightness be controlled programmatically?  Let's ask Google.

Shiver me timbers!  An Easter Egg!?  That lets you perform light shows on your MediaSmart Server?  Go read this post and watch the video real quick to see what I’m talking about.

Now, that's just cool!  And boy does that offer up some new possibilities!  It turns out that the MediaSmart servers support an array of light themes, along with the variable brightness.  Instead of just changing the brightness, I can alter the light theme to give clues as to what the server is doing.

Specifically, when the process is copying files up from the USB stick, I'll have bright, red lights ascend over the USB drive.  When that's finished and the server begins doing some crazy processing of the photos, I'll have the server put on a holiday light show.  The dramatic change in theme will clearly indicate that the server is finished copying the files and it's off doing work--take the card out whenever you'd like.

It only took a minute to find that the LED settings are stored in the registry under HKLM.  And it was pretty straight-forward to determine the values of the themes and the brightness.  With this information in hand, the HomeServer.Notifications.Lights class is born.

   1: using System;
   2: using Microsoft.Win32;
   3:  
   4: namespace HomeServer.Notifications
   5: {
   6:     /// <summary>
   7:     /// Manipulate the lights on an HP MediaSmart Windows Home Server
   8:     /// </summary>
   9:     public class Lights : IDisposable
  10:     {
  11:         // Registry LocalMachine key path where the values are stored (as DWORD values)
  12:         private const string _key = @"SOFTWARE\Hewlett-Packard\HP MediaSmart Server\LEDs";
  13:  
  14:         // The registry key that we'll work against
  15:         private RegistryKey _leds;
  16:  
  17:         // Whether or not the key is currently opened for writing
  18:         private bool _isWriting;
  19:  
  20:         /// <summary>
  21:         /// Gets whether the lights are available on the current system.
  22:         /// </summary>
  23:         /// <remarks>
  24:         /// When unavailable, any attempt to read or write values will
  25:         /// result in an InvalidOperationException.
  26:         /// </remarks>
  27:         public bool Available
  28:         {
  29:             get
  30:             {
  31:                 // Try to open the registry key for reading
  32:                 OpenForReading();
  33:  
  34:                 // If we found the key, then indicate that the lights are available
  35:                 return _leds != null;
  36:             }
  37:         }
  38:  
  39:         /// <summary>
  40:         /// Gets or Sets the native value for the brightness
  41:         /// </summary>
  42:         private object BrightnessValue
  43:         {
  44:             get
  45:             {
  46:                 return Read("Brightness");
  47:             }
  48:             set
  49:             {
  50:                 Write("Brightness", value);
  51:             }
  52:         }
  53:  
  54:         /// <summary>
  55:         /// Gets or Sets the native value for the theme
  56:         /// </summary>
  57:         private object ThemeValue
  58:         {
  59:             get
  60:             {
  61:                 return Read("Theme");
  62:             }
  63:             set
  64:             {
  65:                 Write("Theme", value);
  66:             }
  67:         }
  68:  
  69:         /// <summary>
  70:         /// The current brightness value: 0-9
  71:         /// </summary>
  72:         public Int32 CurrentBrightness
  73:         {
  74:             get { return Convert.ToInt32(BrightnessValue); }
  75:             set
  76:             {
  77:                 if (value < 0 || value > 9)
  78:                 {
  79:                     throw new ArgumentOutOfRangeException("Brightness values must be 0-9");
  80:                 }
  81:  
  82:                 BrightnessValue = value;
  83:             }
  84:         }
  85:  
  86:         /// <summary>
  87:         /// The current Theme of the lights
  88:         /// </summary>
  89:         public Theme CurrentTheme
  90:         {
  91:             get { return (Theme)Convert.ToInt32(ThemeValue); }
  92:             set { ThemeValue = (Int32)value; }
  93:         }
  94:  
  95:         /// <summary>
  96:         /// Open the registry key for reading
  97:         /// </summary>
  98:         /// <remarks>
  99:         /// Store the open key in a member variable, and don't re-open
 100:         /// the key if it's already open
 101:         /// </remarks>
 102:         private void OpenForReading()
 103:         {
 104:             if (_leds == null)
 105:             {
 106:                 _leds = Registry.LocalMachine.OpenSubKey(_key, false);
 107:             }
 108:         }
 109:  
 110:         /// <summary>
 111:         /// Read a native value from the registry key
 112:         /// </summary>
 113:         /// <remarks>
 114:         /// Will ensure the lights are available and then open the key
 115:         /// for reading in order to get the value
 116:         /// </remarks>
 117:         /// <param name="valueName"></param>
 118:         /// <returns></returns>
 119:         private object Read(string valueName)
 120:         {
 121:             EnsureAvailable();
 122:             OpenForReading();
 123:  
 124:             return _leds.GetValue(valueName);
 125:         }
 126:  
 127:         /// <summary>
 128:         /// Write a native key value
 129:         /// </summary>
 130:         /// <remarks>
 131:         /// Will ensure the lights are available and that the key
 132:         /// is presently opened for writing.  If it was previously
 133:         /// opened for reading, it will be closed and then re-opened
 134:         /// for writing.
 135:         /// </remarks>
 136:         /// <param name="valueName"></param>
 137:         /// <param name="value"></param>
 138:         private void Write(string valueName, object value)
 139:         {
 140:             // Make sure the lights are available
 141:             EnsureAvailable();
 142:  
 143:             // If we already had the key open for reading, close it
 144:             if (_leds != null && !_isWriting)
 145:             {
 146:                 _leds.Close();
 147:                 _leds = null;
 148:             }
 149:  
 150:             // If we don't have the key open, open it for writing
 151:             if (_leds == null)
 152:             {
 153:                 _leds = Registry.LocalMachine.OpenSubKey(_key, true);
 154:                 _isWriting = true;
 155:             }
 156:  
 157:             // Set the value and flush to disk
 158:             _leds.SetValue(valueName, value);
 159:             _leds.Flush();
 160:         }
 161:  
 162:         /// <summary>
 163:         /// Ensure the lights are available.  When unavailable, throw
 164:         /// InvalidOperationException.
 165:         /// </summary>
 166:         private void EnsureAvailable()
 167:         {
 168:             if (!Available)
 169:             {
 170:                 throw new InvalidOperationException("Lights not available.  Maybe this isn't a MediaSmart server.");
 171:             }
 172:         }
 173:  
 174:         /// <summary>
 175:         /// Implement IDisposable, properly disposing of resources
 176:         /// </summary>
 177:         public void Dispose()
 178:         {
 179:             // Close the registry key if still open
 180:             if (_leds != null)
 181:             {
 182:                 _leds.Close();
 183:                 _leds = null;
 184:             }
 185:         }
 186:  
 187:         /// <summary>
 188:         /// Offer some helper values for brightness, allowing for consistent usage
 189:         /// </summary>
 190:         /// <remarks>
 191:         /// This is a static class with these readonly properties instead of an enum
 192:         /// because an enum would have required constant casting.
 193:         /// </remarks>
 194:         public static class Brightness
 195:         {
 196:             public static readonly Int32 Off = 0;
 197:             public static readonly Int32 Low = 1;
 198:             public static readonly Int32 MediumLow = 3;
 199:             public static readonly Int32 Medium = 4;
 200:             public static readonly Int32 MediumHigh = 5;
 201:             public static readonly Int32 High = 7;
 202:             public static readonly Int32 Max = 9;
 203:         }
 204:  
 205:         /// <summary>
 206:         /// The list of themes supported by the server
 207:         /// </summary>
 208:         public enum Theme
 209:         {
 210:             Default = 0,
 211:             HolidayLights = 1,
 212:             DescendingChaserBlue = 2,
 213:             AscendingChaserBlue = 3,
 214:             DescendingChaserPurple = 4,
 215:             AscendingChaserPurple = 5,
 216:             DescendingChaserRed = 6,
 217:             AscendingChaserRed = 7,
 218:             PulsingColors = 8,
 219:             PulsingBlue = 9,
 220:             PulsingPurple = 10,