Wednesday, November 26, 2008

Vista Frustration

Vista is a well beaten dead horse.  Microsoft is embarassed of it, and is rushing to get Windows 7 out the door in the hopes that the world will forget Vista ever happened.  In the meantime, the world is largely ignoring Vista and staunchly sticking to their XP installations.  Personally, I've installed Vista on my work laptop and on my home PC, while leaving the PCs that my wife and kids use on XP.  

For the typical home user there is no compelling reason to upgrade to Vista.  There is nothing that Vista offers you that you aren't already getting from your Windows XP machine.  If you are one of those hold-outs hanging on to your Windows 95/98/Me edition could get a lot of of XP, but don't go all the way to Vista yet.

One feature that I have grown to like in Vista is the universal search on the Start button.  Hit your Windows key and you can start typing.  Type the name of the application you want to run, and it hunts down the shortcut.  Type the name of the document you want and it lists all matching files.  Type in a URL and it gives you a link to that website.  It is really handy, and I find myself missing it when I move back to an XP box.  Aside from that, the Aero interface is pretty but adds no tangible value.  You would be hard pressed to name any other Vista improvements that would compel you to switch.

What you will find are a bunch of frustrations though.  First, most of your older hardware just flat won't work.  Have a printer that is more than a couple of years old?  Won't work.  How about that scanner you've had for three years?  Nope, that won't work either.  Webcam?  No.  Grrr..  Vista will also gladly gobble up any extra memory you have around.  Remember two years ago when the whole Vista Capable effort started?  At the time, Vista was just on the horizon and PC manufacturers were selling units with the Vista Capable sticker to let you know that it would run Vista perfectly well.  Not so much.  These machines, outfitted with modest graphics cards and 1GB of memory or less, were horrible Vista platforms.  Vista gladly gobbled up that 1GB of memory for itself and then asked hungrily for me, denying the applications that you wanted to run any memory for themselves.  It consumed the majority of your hard disk, and it busied your graphics cards with moronic things to do like rendering the desktop in 3D, or animating your wallpaper.

On top of those intentional frustrations, there are also a number of unintended frustrations.  For one, you may notice that after time the Network, Sound, and Battery indicator icons in your system tray fall of the end never to be seen again.  For reasons unknown, Vista will occassionally reset the preference to display these, forcing you to find the arcane place where you can ask to have them displayed again.

One frustration I recently dealt with had to do with my CD drive and iTunes.  When iTunes installs, it installs a custom CD driver to assist in burning discs.  Unfortunately, this driver is exactly comfortable running on Vista x64.  Recent revisions of iTunes are much better, but the hangup is that if you ever decide to uninstall iTunes, your CDROM is going away with it.  You see, the custom driver doesn't uninstall properly along with iTunes, and it leaves Vista thinking that the drive is broken.  You have to perform a registry hack to get it back (documented here).

So here's some friendly advice from a geek.  If you have never owned a PC before, and you have no existing equipment that you want to run on a new PC, go ahead and purchase a PC with Vista installed.  Most PC's today with Vista installed have the necessary memory and graphics to get the job done, and you won't experience the pain of trying to get all of your old stuff to work.  If, however, you've been using a PC for more than 2 years, don't bother with Vista.  If you absolutely must buy a new PC, ask for it to be downgraded to XP, or see if you can get a refund for Vista and use the money to buy a copy of XP.  You'll save yourself a ton of frustration, and won't be missing anything.

Thursday, November 20, 2008

BeginRead Weirdness

I've run into a bit of an interesting problem with some code I'm working on.  It deals with asynchronous reads on a stream.  Here is a simplified version of the problem:

I have a network device that communicates by a TCP socket.  The client software connects to that TCP socket and issues commands.  Every command should receive a response from the device.  A new command must not be sent until the response to the last command was received.

So initially I wrote some code that looked like this:

public class Reader
private readonly Stream inStream;

public Reader( Stream in )
inStream = in;

public byte[] ReadResponse()
byte[] buffer = new byte[256]; 
inStream.Read(buffer, 0, buffer.Length);
return buffer;

This code worked just long as the device responded to my command.  Sometimes, the device wouldn't respond.  This might be because the device was unplugged before the response was sent (in which case my Read attempt would eventually return indicating the end of the stream was reached) or the device simply failed to respond to the command.

So now what I wanted was a way to deal with the device simply not responding to a command.  I needed some mechanism that would allow me to block on the read for only a little while.  A perfect place to use the asynchronous read!  So I modified my code to this:

public byte[] ReadResponse()
byte[] buffer = new byte[256]; 
IAsyncResult waitHandle 
= inStream.BeginRead(
bool waitResult 
= waitHandle.AsyncWaitHandle.WaitOne(
return buffer;

This change will read back the response if one is returned, or stop blocking after 5 seconds elapses without a response.  This works as I expected - the WaitOne returns as soon as data is available, or after the timeout period.  If the waitResult indicates that the timeout occurred, I can send my next command.  Here is where the weirdness is: the BeginRead attempting to read the response to the first command now reads the response to the second command!  This results in my latest command never receiving a response. 

So my question is, how can I block on a read for a specified period of time and avoid consuming the next byte arriving on the stream if the timeout occurs?  

I've tried a couple of things, and I have a working solution, but I'm not satisfied with it.  My current solution is to use a NetworkStream rather than a base Stream.  I would prefer to use the basic Stream type as it allows me to apply this reader to any Stream source and not just NetworkStream sources.  The NetworkStream has a DataAvailable property that returns true when data is available to be read on the stream.  I poll the DataAvailable property until data arrives or my 5 second timeout occurs.  This avoids the erroneously consumed byte.  However, in addition to the reliance on a NetworkStream source, it also introduces inefficiency as I poll the DataAvailable property.  I can either cause the CPU to spike by continuously polling the property, or I can introduce a Sleep.  The Sleep will allow the CPU usage to remain low, but also means that if the data becomes available while the thread is sleeping, I'm wasting time that could be spent processing the data.

What I really need is a way to cancel the thread that is waiting for the response asynchronously.  Unfortunately, the .NET framework doesn't support this concept.  So my only option to get this working the way I really want is to craft up my own Asynchronous read method.  Unfortunately, I can't think of a way to do this that avoids the polling scenario I have already implemented.