Wednesday, December 03, 2008

Dealing with meetings that run late and run into your meeting

Raymond Chen just posted a great post on his The New Old Thing blog about getting people out of a meeting room when their time is up.  You either barge right in and say “Oops! Sorry about that” and then back right out.  Or you just sit right down and apologize for being late for your own meeting.

If you are in a meeting and your time is up, it’s just proper etiquette to end the meeting if that room is booked for another meeting.  While your topic may be more important for the next meeting, making other people wait will push back everyone’s schedule.  It can ripple through the company and come back and bite you on the Blackberry..  It’s just a poor business decision to make everyone else wait.

Either politely ask if the next meeting can be be delayed a few minutes, or just book another meeting at another time to finish your stuff up.  With so many meetings include people calling in for remote offices, you really need to make an effort to keep your meeting on track.

If your one hour status meeting always seems to run 90 minutes, then you have a time management problem.  Either your meeting isn’t staying on topic, or the scope of the meeting doesn’t fit the time allotted.  Cut back on the scope or just book the room for 90 minutes.

At the last place I worked, our daily team staff meetings were “stand up” meetings.  We all stood in a quite away near our workspace, and we just stood and talked for a few minutes.  No beverages were allowed and off topic conversations were verboten.  This fails when you have remote team mates, then you would need to book a small room and everyone just stares at the conference phone.  The no sitting down and no beverage rules are still in effect.

I still think that Dave Barry said it best:

Meetings are an addictive, highly self-indulgent activity that corporations and other large organizations habitually engage in only because they cannot actually masturbate.

Sunday, November 23, 2008

Some odd TiVo issues

I have  couple a couple of Series2 TiVo DVRs and they just received the TiVo Fall 2008 Service Update for 9.3.2.  It’s basically a few tweaks to the UI, but the odd thing was that I needed to manually restart the TiVo.  Usually the TiVo restarts itself after getting a new system update.  Very odd, but hopefully just a one time glitch.

My in-laws have a TiVO HD and sometime last week it decided to stop recording the shows on the season passes.  I went over and took a look.  The season passes were in order and when you selected view upcoming episodes, the shows would be listed, but not listed as being recorded.  Very odd.  The fix was simple, but annoying.  I selected each season pass and saved it without making any changes.  After saving the pass, the correct shows were marked as going to be recorded.  Fortunately they only had a handful of season passes, it took a minute or two to update all of them. 

After fixing the season passes, I tried to bring up YouTube on the TiVo HD.  When I selected YouTube from the menu, the TiVo froze and stopped responding.  I gave it a few minutes to figure it on it’s own and I restarted their TiVo the hard way.  Thanks to TiVo not having a reset button, I had to unplug and plug it back in again.  After waiting a few minutes to boot abck up, it was back to normal.

That was the first time I have ever had to reboot a TiVo, their software has been very stable.  As with my Series2 units, I’m hoping that this was a one time glitch caused by system updates being pushed down the to TiVo.

Thursday, November 20, 2008

Fast way to resize a virtual disk with VMware ESX Server

We’re starting some SharePoint development and I needed to create a development environment on Windows Server 2003.  So I created a new virtual machine (VM) of Server 2003 on our VMware ESX box and gave it a 1GB of RAM and 8GB of disk space.  I installed the OS and configured it for Windows SharePoint Services (WSS) and then installed Visual Studio 2008.  That left us with about 1.5GB of disk space.  Oops, time to resize the drive.

The beauty of working with virtual machines is that it’s relatively easy to increase or decrease the memory and disk storage.  In this case, I wanted to add another 4GB to the virtual disk.  I powered down the virtual machine and went into the “Virtual Machine Properties” from the VMware Infrastructure Client (VIC).  I selected the hard drive and it provided a entry field for the new size.  I increased the size to 12GB, adding an additional 4GB.

That takes us part way there.  I increased the size if the virtual disk from 8GB to 12GB, but it still has an 8GB partition, the OS wont see the additional space.  I saw all some tips on that Series of Tubes that recommended downloading Linux boot disks and boot the the VM from the Linux CD images as an .ISO file.

Meh, that’s too much work.  I took a simpler path.  I powered down another Server 2003 VM that was already running on the ESX box and added new VM’s virtual disk as a second virtual drive.  I booted up the second VM and opened up a command shell.  From the command shell, I ran the diskpart utility to extend the partition.  I did the following commands through diskpart:


Microsoft DiskPart version 5.1.3565

Copyright (C) 1999-2003 Microsoft Corporation.

On computer: XXXXX

DISKPART> list volume


  Volume ###  Ltr  Label        Fs     Type        Size     Status     Info

  ----------  ---  -----------  -----  ----------  -------  ---------  --------

  Volume 0     E                       DVD-ROM         0 B
  Volume 1     C NTFS   Partition     12 GB  Healthy    Boot
  Volume 2     D NTFS   Partition    8 GB  Healthy



DISKPART> select volume 2
Volume 2 is the selected volume.
DISKPART> extend



Leaving DiskPart...

I basically typed that in from memory, some of the numbers may be off, but it shows how to extend the size of the partition.  After exiting out of diskpart, I then shut down the second VM.  Next, I removed the virtual drive that belongs to the new VM.  Remember to select remove only and not remove and delete.  At this point I was able to power both VM’s back up.  The second VM will be slightly confused about the missing drive, but it was back to normal.  The new VM took some time to check out the resized partition after I logged back in.  With my VM, it declared it to be new hardware and wanted to reboot.  After it rebooted, it was happy and recognized that it had a 12GB partition.

Tuesday, October 21, 2008

DevTrack woes with build 1833 of mfc80.dll

We use TechExcel’s DevTrack tool to track our defects and project modifications.  A few weeks ago, one of our QA specialists installed SQL Server 2008 Express.  That broke DevTrack.  After SQL Express 2008 was installed, DevTrack would crash after loading.  After contacting DevTrack support, we were advised that the mfc80.dll installed with SQL Express was causing the problem. 

Their suggested work around?  They asked us to overwrite the version of mfc80.dll (8.0.50727.1833) located in one of the SQL Express folders with an older one (8.0.50727.762).  Ok, there is something wrong this picture.  You don’t replace a dll in another application’s folder.  That violates the integrity of the installation of the other application.  You have no idea of what the possible consequences will be for that application.  It could work fine, it could blow up in your face, or something in between.

The problem is that when DevTrack requests mfc80.dll, it’s being redirected through the WinSxS policy files to the latest and greatest version, version 8.0.50727.1833.  And there is something in MFC 1833 that just kills DevTrack.  The problem isn’t specific to DevTrack, apparently Corel’s WinDVD has the same problem.  I read a thread about people hacking the WinSxS policy files to force calls to mfc80.dll to use an older version.  That might work under XP, but will really break things under Vista.

I thought the Side-by-Side assembly model was supposed to eliminate “DLL Hell”.  For DevTrack to work, they have two choices.  They can patch their code so that it doesn’t crash with the 1833 version of mfc80.dll, or they can install their own local copy and not use the WinSxS version.  We’ve been waiting for a few weeks for a solution, that’s been a real frustrating point.

Monday, October 20, 2008

Installation is not configuration

Christopher Painter has a good post about the problems inherent with with having installers run SQL scripts.  Having an installer communicate with a database server just opens the door to all sorts of issues.  Just handling the connection to the server requires making sure that you have all of the required bits installed and that you can locate, and connect to the server.  None of that code is rocket science, we’ve been using it for years. I just don’t think having it in an installer is the right place for that type of code.

The problem is that you are running that code from inside a relatively fragile box, your installer.  Most installer authoring tools provide rudimentary support for running SQL scripts at install time.  They work just fine when all of your ducks are lined up in a row.   However your clients may be missing an odd duck or two, and you end up with fragile code wrapped inside a DLL that your installer will call.

I’ve always treated the installer package as just part of the actual installation process for the end user.  The main task of the installer is to get the bits of your application in place and handle any prerequisite runtime library your code may need.  When it comes to initializing or updating a database, I leave that to the main application and/or it’s support utilities.  if a SQL script is flawed and or doesn’t handle some edge condition that only one customer has, you can break the install.

By using a full blown application to handle the database task, your life (and your customer’s life) becomes much easier.  By running your own application, you have (or should have) a much richer environment for developing code.  You have complete control over the UI and you do not have to be concerned with trying match the UI style of the installer.   Also the testing and debugging of the database utility code becomes much easier as no longer need to account for the installer.

You also have the ability to run the application at any time after the install, without having to invoke the installer.  If it turns out the problem was a SQL script that didn’t work for that customer, you can immediately email or post online an updated SQL script, without forcing the user to run the installation process again.

We use a mixture of script based installers and Windows Installers and none of them make any attempt to run a SQL script.  I wrote a database utility application that gets launched after an install.  I wrote it when our company supported the MSDE, back in the day of SQL Server 7.  Back then, Microsoft provided absolutely zero for tools to manage the MSDE.  So this utility, by necessity needed to be able to attach and detach databases, back up and restore databases, manage the server and database logins, and perform schema updates. 

Over the years, this utility has matured and is very easy for the end user to use.  We provide all of schema updates in a single, compressed file.  For the use to apply an update the database schema, they just run my utility and it reads the update file and it knows which updates have already been applied and only runs the ones it needs to.

All very easy for the end use, but it would have been a nightmare to get that level of functionality running as part of the installer.  As soon as you add an outside dependency (in this case, the database server), you have added a point of failure that you will have absolutely no control over.

Friday, October 17, 2008

Strange 64-bit error with LayoutKind.Explicit

I have a C# service that collects data from another company that we do business with.  They send the data in a binary format from one of their C++ applications.  To read their data with .NET, I needed to marshal their data to a set of structs defined in C#.  I created a structure that looked something like this. 

    [StructLayout(LayoutKind.Explicit, Size = 48)]
public struct SampleHeader
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] RecordType;

public uint Version;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] SystemCode;

public uint LocalID;

public uint HostID;

The actual struct had more fields, but this is enough to show the the problem. During development and testing, the code worked fine. Until we tried it on a 64-bit edition of Windows Server 2003. That's when it broke. As soon as I instantiated an instance of this struct, the service would throw an error. Something like this:

Could not load type 'SampleNameSpace.SampleHeader'
from assembly ''Sample, Version=, Culture=neutral, PublicKeyToken=null'
because it contains an object field at offset 12 that is incorrectly aligned or overlapped by a non-object field.

To get it to fail, all I needed to do was to create a SampleHeader like this:

SampleHeader sh = new SampleHeader();

That didn't make any sense.  I couldn’t see any reason why it would work in 32-bit land, but not in 64-bit.  Since it was complaining about the “SystemCode” field, I commented out the other fields and played with the field offsets.  If I changed the offset from 12 to 16, I could create a SampleHeader object without any runtime errors.  Mind you, I could actually use it in my code, those offsets had to match the data my service was receiving.

So I went to plan “B”, getting rid of the explicitly laid out struct.  I created a new one without the StructLayout, MarshalAs, and FieldOffset attributes.  It looked like this:

    public struct SampleHeader
public byte[] RecordType;
public uint Version;
public byte[] SystemCode;
public uint LocalID;
public uint HostID;

Pretty much the same thing, except .NET defined the field alignments.  Instead of using marshalling to copy the data, I just used the BitConverter class.  I had already put the received data into a byte[] array, that made it easy to use BitConverter.  For this struct, I only needed the LocalID and HostID fields, so the following code was all that I needed:

    MyHeader.LocalID = BitConverter.ToUInt32(RawData, 20);
MyHeader.HostID = BitConverter.ToUInt32(RawData, 24);

This replaced the marshalling code that looked like this:

    GCHandle handle = GCHandle.Alloc(RawData, GCHandleType.Pinned);
SampleHeader MyHeader = (NewStuff)Marshal.PtrToStructure(handle.AddrOfPinnedObject(), typeof(SampleHeader));

I still don’t understand why Windows 64-bit  requires fields in a struct to be aligned on 4 byte boundaries, but the replacement code works and is easier to follow.

Tuesday, October 14, 2008

Restoring missing Build Events in Delphi 2007

If you have a Delphi 2007 project that was ported from Delphi 2006, then you may be missing the build event project options.  The .dproj file that Delphi 2006 creates is does not have a final XML element named PropertyGroup that Delphi 2007 uses.  Without that final PropertyGroup, Delphi 2007 will not enable Build Events as an option.  If you manually edit your .dproj file, just the following lines:


So that the .dproj files looks like this at the end of the file:


After making that change, the next time you open that project with Delphi 2007 and select Options from the Project menu, you’ll see Build Events listed.  This only appears to happen if you migrate a Delphi 2006 project over to Delphi 2007.  If you create the project from scratch, you’ll see Build Events list.  That’s how I was able to determine what was missing, I just created a new project and compared the .dproj files.

Saturday, September 06, 2008

"Everything That Happens Will Happen Today" by Byrne and Eno

David Byrne and Brian Eno have a new album out, "Everything That Happens Will Happen Today".  It's available exclusively through their web site,  You can listen to the entire album on their site, or by using their streaming player right below this text.

I've been listening to it while writing this post and it's pretty good. It's a nice mix of Eno's music and Byrne's lyrics and singing.

You can order the album from their website in various formats. They have 320kbps MP3 and FLAC, without any DRM. for $8.99. Yu can also get it as a CD plus the downloadable versions for $11.99. There is a deluxe package for $69.99 with all sorts of stuff for the diehard Byrne and Eno fans. It's cool that they are selling it themselves. If they sold it through a record label on iTunes, they would get a tiny fraction of the $0.99 a song that iTunes charges.

This is their first collaboration since 1978's My Life in the Bush of Ghosts.

Friday, September 05, 2008

Old School modeming

The always entertaining DadHacker has a great post on how he used to write code in the old days at 300 baud.   When he was in school, he had to submit course source code by punch card.  That’s a death by a thousand paper cuts.  To avoid having to use punch cards, he would dial in over the ancestor to the Internet and edit the code at 300 baud.   You should read his post to see all the steps he had to do.  It would have made Rube Goldberg proud.

He gets extra bonus points for using a terminal emulator that he wrote himself.  Double extra bonus points for writing it on a machine that didn’t have a UART chip.  UART chips are used to hand communications over a serial port.  The UART handles the timing and buffer requirement of sending bits over the wire.  Not having one, means you have to handle all of the ugly details yourself.  That means you can’t just write code that says “send this sequence of bits over there, at 300 baud”.  You had to write the code to control the timing of 300 baud and sends the bits at that rate and handle all of the flags and registers being set by the serial hardware.

I remember 300 baud.  At that speed (or lack of speed), you could watch the characters come in and fill the screen.  I had a Commodore 64 and my first modem was the Commodore 1650.  300 baud and pulse dialing, that was life online in 1985.  Over the years, I kept getting faster and faster modems.  I went from 300 baud to 1200 baud on the Commodore 64.  Stayed at 1200 on my Commodore 128.  I jumped to 2400 baud when I got my first Amiga.  I went from 2400 to 19,200 when I moved to the PC platform.  Then it moved to 33,600 and finally 56,200 before I jumped to broadband. 

I remember buying a serial port card for my 486sx just to get a 16550 UART to use instead of the cheesy 8250 UART that was on the motherboard.  The 8250 had a one byte buffer and you would start dropping characters at speeds higher than 9600 baud.  The 16550 had a 16 byte buffer. That doesn’t sound large, but it was enough to let you handle much higher baud rates.  The Commodore 64 didn’t even have a UART, it emulated one and the CPU had to do all of the processing.  That was good to only 2400 baud before it would fall apart,

Getting a faster modem was one of those devices where you saw a clear and immediate improvement.  I still have the last modem I bought back in the early 90’s.  It was a US Robotics V.Everything Courier modem, an external one.  A giant black slab, squatting on top my PC.  It had firmware that could be “flashed” to a new version.  I think I did it it about three or four times.  Each it got faster and more reliable.  I real man’s mode,  It ate through line noise and spat out clean bits.  Even though I have no need of it, I refuse to get rid of it.  It’s the oldest bit of functional computer equipment that I own.  My current home PC doesn’t even have a serial port, I would have to get some odd USB to Serial dohickey if I even wanted to use it.

Thursday, August 21, 2008

Refreshing a SOAP WSDL import file with Delphi

I’m consuming a web service from a Delphi desktop app and both the web service and the desktop app are being developed at the same time.   Because the WSDL generated by the web service can change, I need to refresh the service interface code that the Delphi code uses to access the web service.  It corresponds to the web references class that a .NET app would use to consume a web service.

You typically create the web service interface code by bringing up the WSDL Import Wizard from the File->New->Other menu in Delphi.  You get a dialog that prompts you for the location of the WSDL file or URL.  From the WSDL, it generates a unit with interfaces defined for the classes and objects exposed by the web service.  It creates the file with the name of the service, plus “.pas”.

It works pretty well, but if you need to refresh that file due to changes in the web service, you don’t need to use that wizard to update the file.  There is a command line tool that will generate a new output file from a specificied WSDL.  This tool is named WSDLImp.exe, and is located in the bin folder of your Delphi installation.

The typical syntax is

WSDLImp.exe -P http://localhost/somefolder/someservice.asmx?WSDL

That will generate a file named someservice.pas.  If you want to specify a different name for the file, you can use the “-=” command line parameter like this"

WSDLImp.exe -P -= http://localhost/somefolder/someservice.asmx?WSDL=myservice.pas

That will create the file myservice.pas.  Very handy if you want to use a different name than the default.  Now when you update the service interface, you can just run WSDLImp to reimport the web service interface.

Using the test form from remote connections for .NET web services

I’m working on a web service using C# and targeting the .NET 2.0 Framework.  Nothing terribly fancy, but it has some code to log the caller’s IP address (via HttpContext.Current.Request.UserHostAddress).  While testing the code, I like using the test form functionality that .NET provides with web services.  By design, it only works locally.  If you try to use the test form from a remote machine, you’ll get the error:

The test form is only available for requests from the local machine

That’s fine, when you expose a web service you don’t want to make it too easy for people to start poking at your web service methods with a pointy stick.  Still, I wanted to test it from another machine and it saves time being able to enter in different values without having to code up a test framework.  Plus, I wanted to make sure that my code was reliably picking up the caller’s IP address.

After just a tiny bit of searching in the series of tubes, I found how to easily enable the web service test form for remote connections.  Juan Ignacio Gelos posted what you need to add to the web service web.config file to enable the test form.

<add name="HttpGet"/>
<add name="HttpPost"/>

You are still limited to run methods that have simple data types as input, but it’s very handy for testing.  Since this setting lives in web.config, it’s easy to remove it when I run a build.  I’m using FinalBuilder on a dedicated build box and it’s easy to clean up .config files so that developer settings get scrubbed before the files get packages into an installer.

Wednesday, August 13, 2008

Using Delphi in a team

I was just reading

Tuesday, August 12, 2008

Get ready to say good bye to Google Page Creator

When I get some spare time, I plan on revamping the layout of this blog.  Right now, it’s an ugly mess of hacks placed in Blogger templates.  I want to make use of external CSS and Javascript files, but Blogger doesn’t allow you to upload those types of files.  Since of the design goals for this blog is to run it for free, I wanted to have a way of hosting CSS and Javascript files without having to use a paid hosting account.

I read a cool blog article writen by Lars Gersmann on how to add WordPress style calendar pages to Blogger based blogs to jazz up the blog post timestamp.  Lars provided the links the .css and .js files, hosted on his Google Page Creator account.  That looked vaguely familiar, I have a Google Page Creator account gathering virtual dust out in the cloud.  I logged in my Google Pages account and saw an announcement that Google was pulling the plug on Google Page Creator.  if you don’t have a Google Page Creator account now and go to the site, Google Page Creator, you’ll see one of the messages.

On August 4th, Google posted an announcement that they would be shutting down Google Page Creator later this year in favor of Google Sites.  Both sites let you create simple web sites very easily, but Google Sites, will not let you host your own .css or .js files.  Sometime later this year, Google will be shutting down Google Page Creator and I’m assuming that any site left there will be purged.  Google Page Creator was part of, which basically means it was a beta project with no guarantee that it would be around as a permanent fixture.

Monday, August 11, 2008

Why doesn’t an OS that backs your OS have any means of backing itself up?

Steve Tibbets has been writing about his troubles with Windows Home Server.  His homebrew Windows Home Server box had a failing power supply and it hosed the registry on the way out.  When he replaced the power supply, he was forced to reinstall Windows Home Server and he’s facing the fun task of trying to recover the data across 4 drives.   Windows Home Server is based on Windows Server 2003, which has the System Restore functionality.  He should have been able reboot the Windows Home Server in recovery mode and restore the OS from the last good system backup.  But that was not the case.

That stuff kind freaks me out about Windows Home Server.  I was in the beta and I had taken my last development machine at home and configured it for Windows Home Server.  The machine had motherboard issues and went to the land where DOS is eternally blessed after a few weeks.  While it was running, I have to say Windows Home Server is pretty cool.  It has a set and and forget it approach for doing bare metal backups of your home machines.  Since it’s Server 2003 based, you get some of the Server 2003 functionality, like a full blown version of IIS.

I’ve been running a FreeBSD solution called FreeNAS to back key files on my home machines.  It doesn’t have the cool features of Windows Home Server, but the price was right and it just works.  FreeNAS will boot from a CD, if the current FreeNAS box dies, I can just slap the drives in another box and install FreeNAS in just a few minutes.  I’ve been toying with the idea of buying one of the HP MediaSmart Home Server with Windows Home Server, but for the amount of money one of those boxes cost, I can hang 1TB external drivers off each machine at home and run scripts every night to RoboCopy every thing to the external drives.

Why wont load with IE7 on Vista (and how to get around it)

My kids wanted to watch the Olympic swimming events going on in Beijing.  Since NBC is streaming all the venues, I figures I would just fire up the web browser and wander over to   We have a “family” pc that everyone can use and it runs Vista Home Premimum (32-bit), with Service Pack 1 installed.  Since I knew that NBC was going to be using the Microsoft stack with Silverlight to stream the video, I figured I would have the least amount of headaches with Internet Explorer 7.  Wrong!

When I entered in into IE, I got the following error: “Internet Explorer cannot display the webpage”.  I figured I mistyped the URL, that wasn’t it.  Out of the relatively small combinations that the letters N, B, and C can be arranged, I did have the right URL.  Could it be that was done?  Nope, I tried “ping –n 1” and received the following

Pinging [] with 32 bytes of data:                               
Reply from bytes=32 time=44ms TTL=55                                            
Ping statistics for                                                             
    Packets: Sent = 1, Received = 1, Lost = 0 (0% loss),                                         
Approximate round trip times in milli-seconds:                                                   
    Minimum = 44ms, Maximum = 44ms, Average = 44ms                                                

That tells us that their site is live and responding to requests.  Just for giggles, I launched FireFox 3 and entered in the URL.  Sure enough, that worked just fine.  What was the problem with and IE7?  I did a search with Google (and Yahoo for a change of pace) and saw that a number of people were reporting the same problem.  No one knew the cause and the only resolution was “just use Firefox”.  Normally, that would be an acceptable answer for me.  Today, I’m feeling a bit cranky and I want to know what the problem is between and IE7.  The odds are it’s something trivial on the nbc,com side.  We haven’t had any problems with IE7 on Vista before.

I did notice that a lot of people reporting the problem had Tablet PC’s. I don’t have a Tablet PC, it’s just an plain ol’ Dell desktop.  But I did install a Wacom Bamboo tablet and installing it’s drivers did activate some user input functionality in Vista that wasn’t there before.  Why would this affect the browser?  As it turns out, when Vista thinks it’s now a Tablet PC the user agent string sent by IE changes.

Here’s the typical user-agent string sent by IE7 for various operating systems.

For Windows XP SP2: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)

For Windows 2003 Server: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.2)

For Windows Vista: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)

Note, these are the base strings, different applications can change or add to these values.  On my machine, the user agent has some information:

Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; Media Center PC 5.0; .NET CLR 3.0.04506; .NET CLR 3.5.21022; Tablet PC 2.0; Creative ZENcast v2.01.01)

That says that I’m running IE7 on Vista, with .NET 2, 3, and 3.5 installed.  Media Center extension are installed, it thinks it’s a Tablet PC, and I have Creative’s Zencast (a podcast download app).

Notice the text in bold, “Table PC 2.0”.  When that text is submitted to as part of the user agent, the website is doing some sort of re-direct that is failing.  So we have what appears to the cause of the problem, now how do we fix it.  I tried faking out the user agent string with a download from Microsoft called the User Agent String Utility, version 2.  Don’t event bother with that one.  It opens up a new browser window that has been tweaked to report itself as IE 6.0 but that’s the only part of the user agent string that gets modified.  It still uses “Table PC 2.0”, so the problem still remains.

In theory, you can edit the list of items that get tacked on the user agent string by hacking at the registry.  With IE7, the list of fields added to the user agent string are defined as REG_SZ values in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\5.0\User Agent\Post Platform.  I tried removing “Tablet PC 2.0” from the list, but the OS kept putting it back in.  Plus, we really shouldn’t have to modify our systems, the problem is due to not sniffing the user agent string correctly.

I did a little searching on the Internet and I found a working solution here.  Instead of using as the starting URL, use  That site bypasses the user agent check and it allowed me to the live feeds of the Olympic events.  A very simple solution, but a typical home user would never figure it out on his own and just blame Vista for it.

Thursday, August 07, 2008

How to log the TIDSmtp component

I have some Delphi code that needs to send a quick mail message so I was using the Indy 10 TIdSmtp component.  The code was working just fine for a few months, but this week it would fail with an EIdSMTPReplyError exception.  The message property of the exception was a empty string, not terribly useful.  After a bit of googling, I found references to using one of the Indy TIdLogXXXX components.  Sure enough, there is a TIdLogFile component that will log messages to a file.  That sounded like what I needed, but the help file did not make it clear on how to hook up a TIdLogFile to a TIdSmtp component.

I did some searching and found a blog post by Marshall Fryman on his Ruminated Rumblings blog that a great example of how to hook up one of the Indy logging components.  What I needed to do was to create an instance of the TIdSmtp’s IOHandler property and assign the TIdLogFile to the IOHandler.Intercept property.  He also recommended assigning the IOHandler.OnStatus event to TIdLogFile.OnStatus event

The way my code ended up was something like this:

          IdLogFile.Active := true;
          fsmtp.IOHandler := TIdIOHandler.MakeDefaultIOHandler(fsmtp);
          fsmtp.IOHandler.Intercept := IdLogFile;
          fsmtp.IOHandler.OnStatus  := fsmtp.OnStatus;
          on e: exception do begin
            MessageDlg('Error sending message: ' + e.Message, mtError, [mbOK], 0);
        if fSMTP.Connected then
        IdLogFile.Active := false;

Monday, August 04, 2008

How to disable the Windows Shutdown Tracker Dialog

Rick Strahl posted a great tip on how to disable the Windows Shutdown Tracker Dialog. That’s the dialog that Serer 2003 and Server 2008 make you respond to when you reboot or power down the server.  As Rick noted, usually the only time that you need to reboot a Windows Server is when you install an update from Microsoft.  It’s collecting information that you’ll never use.  You can disable that dialog by making a change in the local computer Group Policy.

To disable the dialog, do the following:

  • Run the Group Policy Object Editor by typing “gpedit.msc” from the “Run…” dialog.
  • Navigate down to Local Computer Policy\Computer Configuration\Administrative Templates\System
  • Double-click on “Display Shutdown Event Tracker” and click on the “Disabled” radio button
  • Click the “Ok” button to close the dialog with the new setting.
  • Close the Group Policy Object Editor.

This will work for both Server 2008 and Server 2003.

Tuesday, July 29, 2008

Delphi Win32 gets a TStringBuilder class

The next version of Delphi, code named “Tiburon”, is getting some cool new features.  One of these will be the TStringBuilder class and Andreano Lanusse (a CodeGeart Evangelist Leader) blogged about it.  Basically, it’s a Delphi implementation of the .NET StringBuilder class.  Only it’s available in the managed and unmanaged versions of Tiburon.  Why is this cool?  If you have code that does a lot of string manipulation, using the string class gets expensive, performance-wise.  If you are building up a string piece by piece, each time you add or modify a string, the previous version of the string is discarded and a new string is created.

The StringBuilder class pre-allocates the memory so that you avoid the constant creating and freeing up of string objects.  If you have code running in aloop, you can get real performance benefits by using StringBuilder.  I’m looking forward to getting Tiburon when it’s released.

Friday, July 25, 2008

How to shoot yourself in the foot with regular expressions

I had some Delphi code that is used a user entered text string as a key. After the user entered in the text, my code would force it to uppercase and strip out any characters outside of A-Z and 0-9. This was for a very specialized task and the following Delphi code did the job.

function GetStrippedValue(const value: string): string;
i: integer;
result := '';

// strip punctuation out of the name and force to uppercase
for i := 1 to length(value) do
if value[i] in ['A'..'Z', 'a'..'z', '0'..'9'] then
result := result + Uppercase(value[i]);

Nothing elegant, and performance wasn’t an issue as it was rarely used. I wrote that code in the spring of 2000 and it hasn’t been touched much since then. I now have a C# application that needs to work with the same data, so I to perform the same functionality using C#. Since C# does not have the set operators that Delphi has, I had to strip out the characters in a different way. I figured that I could use a simple regular expression and match the characters that way. I should have remembered that old quote attributed to Jamie Zawinski:

Some people, when confronted with a problem, think “I know, I'll use regular expressions.”

Now they have two problems.

I had decided to make the expression as simple as possible. I used the following function to accomplish what I had done years earlier in Delphi:

private string GetStrippedValue(string value)
string pattern = @"[^\w]";

string result = Regex.Replace(value.Trim().ToUpper(), pattern, "");

return result;
What I am doing here is to replace any text that matches the Regex expression with an empty string. The “^” caret character negates the expression, in other words replace anything that doesn’t match the “\w” token with an empty string. I had found the “\w” documented to match any non-word character, but I didn’t look too closely to the definition. I was using the syntax defined at, where it is documented which matches letters ,digits and whitespace. That turned out to be different from the definition used by .NET and Python.

With .NET, that pattern allows alphanumeric characters, PLUS the ”_” underscore character. A slight, but fatal flaw on my part. I didn’t catch it when I wrote because my sample data didn’t have any underscores in them. I found it today while adapting that code for a new task, where the data can have underscores.

Einstein put it best, “Everything should be made as simple as possible, but not simpler.”. My attempt to write the least amount of code was flawed. What I should have done was to use the following syntax:
private string GetStrippedValue(string value)
string pattern = @"(?i)[^A-Z0-9]";

string result = Regex.Replace(value.Trim().ToUpper(), pattern, "");

return result;
This way, I am explicitly defining the allowable characters and now I’m getting the results that I wanted. Since I am passing in a string that is being forced to uppercase, I don’t need to test for lowercase letters (“a-z”). An alternative version that produces the same results would be:
private string GetStrippedValue(string value)
string pattern = @"[^A-Z0-9]";

string result = Regex.Replace(value.Trim().ToUpper(), pattern, "",System.Text.RegularExpressions.RegexOptions.IgnoreCase);

return result;
I’m not sure if one way is better than the other. The “(?i)” is equivalent to the System.Text.RegularExpressions.RegexOptions.IgnoreCase RegexOption. For this project the performance of the code is not an issue, it only gets called a few times.

The moral of this story is if you need to use regular expressions, check the syntax for the implementation that you are using.

Thursday, July 24, 2008

Black Crayons and the school psychologist, a true story (just not mine)

I follow Raymond Chen’s blog (required reading if you program for Win32) and the other day he had a link to a story that was both hysterical and scary.  My first thought that it was another urban legend.  After a bit of searching, I tracked down the author, Deirdre Sholto-Douglas, and she confirmed that the story was true and gave me permission to repost it here.

It had been originally posted in the alt.peeves newsgroup on USENET back in 1994.  Click here for a reasonable definition of alt.peeves or here to access that group. I’ve included the text as posted, with the exception of the email addresses.  It was posted before the spammers started harvesting email addresses out of USENET and I see no reason to make these addresses public.

Forwarded-by: bostic@CS… (Keith Bostic)
Forwarded-by: good@p…. (Craig Good)
From: finch@M… (Deirdre Sholto-Douglas)
Newsgroups: alt.peeves

W. Blair Haworth Jr. (bhaworth@a…) wrote:
: In article 331ipk$omb@v.’.. finch@… (Deirdre
: Sholto-Douglas) writes:

: >You go ahead with your kidlessness and while you do so, I'll continue to
: >kiss skinned knees, assemble bicycles, and enthusiastically accept popsicle
: >stick 'ashtrays'. 

: Ashtrays!  Godamightydamn, things being what they are these days, I'd've
: figured that any kid that turned out an ashtray in arts'n'crafts would be
: immediately sent to Special Ed. for re-grooving and Social Services
: notified to investigate the home environment. 

<sigh> Your comment reminds me of one of the run ins I've had with the school psychologist.  After our disscussion, I've gained a reputation of being unreasonable and my daughter has gained the freedom to construct anything short of atomic bombs without psychological interference.

If I haven't peeved about this in the past, I certainly should have and if I have, I beg the readers' indulgence.

It all started shortly after my ill-fated Parent-Teacher Conference (as did my public school reputation for being unreasonable).  Within a week of this conference, I received a phone call from said 'psychologist'  requesting that I present myself in his office to discuss my daughter's 'problem'.  When questioned, he indicated that the 'problem' was different than the one the teacher and I discussed (which was not addressing adults by first name), but coyly refused to 'discuss a situtation of this magnitude over the phone'.

The following day, at the appointed time, I appeared with offspring in tow. Horrified looks resulted and said offspring was shuttled off to play in the gym.  Apparently these discussions are SECRET.

He began by folding his hands on top of his desk and wearing his 'saintly, patient' expression.  *This* is a man who has not only READ the psych books but *believes* them.

"Has Lauren appeared depressed or been behaving unusually at home?"

"No, she has not."

"Her behavior *hasn't* changed?!"

"No it hasn't.  Pardon my abruptness, but precisely *what* are you driving at?"

He is now refusing to meet my eyes and fiddling with a paperclip on the desk.  Hmmm.  I should have trundled my copy of 'Body Language' along with me.  He could have fidgeted and I could have merrily looked up all the  underlying pyschological causes. 

"Well, see, Lauren is using only black crayon when she's drawing and studies have indicated that when this occurs the child is usually depressed and attempting to deal with repressed emotions."


At this point, I was having considerable difficulty repressing one of my own emotions....namely laughter.  What rocks do these nitwits crawl out from under?  Realising that my original response would be a Bad Thing, I quickly pasted my Concerned, But Amused Parental Expression on and continued:

"Have you considered asking Lauren her reasons for using black crayon?"

Shock.  Horror.  Complete dismay.  He actually began stammering.  One does NOT ask the child.  It could cause deep-seated emotional problems, stunt their growth, cause them to suffer from low self-esteem and possibly begin hanging about on street corners with gangs of second graders. 

I excused myself from his office, obstensibly to collect myself, in actuality to collect my offspring from the gym.  I arrived at said gym to find my depressed, repressed, emotionally devasted monster attempting to deal with her deep-seated frustration at not being able to reach the rings.  Was she crying, fussing or sulking?  Nope.  She was trying to negotiate with the custodialdrone for a stepladder.  At this point, I decided she was entitled to draw with black crayons the rest of her life, if that's what she wanted.

We meandered back to the office and I ignored the look of distress that was shot at me.  I parked my recombinant DNA in a chair with orders to 'Behave like a lady.' (Yeah, I know.  So sue me.)  The conference resumed, this time I addressed my questions to Lauren.

"Lauren, Mr. Shit-for-Brains indicates that you only use blackcrayon when you're drawing."


"Do you *like* drawing in black?"


"Then why do you do it?"

I was treated to the expression that is reserved for humouring slightly thick parents and watched as my offspring pasted on her Mom's Old Lady But Harmless Expression:

"They make us line up in alphabetical order when they pass out the crayons.  And I'm always last in line...there's nothing left *but* black!"

I turned to witness what our psychological brainchild is making of all this.  He has gone strangely quiet.  Fine.  This interview is over as far as I'm concerned. Although I confess, I couldn't resist lobbing one more over the fence at him.

"Thank you sooooo much for your concern regarding my daughter's emotional well-being.  I suppose your job would be *much* easier if all depressions could be cured by simply starting the crayon box from the other end of the queue.  In the future however, do you think you could at least ask *her* before you haul me in here?"

He managed to mutter something which I took for assent neither Lauren or myself has heard anything from him since.

ObPeeve:  School Psychologists that are looking for deeper meanings in simple kids' actions.

!Peeve:   He now scuttles around the nearest corner whenever he sees me coming.  I think the poor man probably suffers from deep-seated, repressed emotions.

Wednesday, July 23, 2008

Playing with a new toy, a GPS device

While on vacation in Hyannis, I got annoyed with the one way streets odd layouts so I went out and bought a GPS unit.  I had wanted one for a while, and this was a first good excuse to get one.  The Hyannis Staples had a Magellan RoadMate 1412 on sale, so I bought one.  Staples had it for $250, but you can get it cheaper online.  It’s your basic consumer GPS, nice big screen and text to speech (TTS).  It doesn’t have Bluetooth, MP3, or any other non-GPS functionality.  I would have liked having Bluetooth, so I could use it as a speaker for my cell phone, but that would have jacked the price outside the range we wanted to pay.

It worked pretty well and made it a lot easier to get around Cape Cod.  It did have an annoying habit of trying to send me down a one way street the wrong way, but after I ignored that direction a few times it stopped sending me that way.  That would be a fault of the NAVTEQ map used by the Magellan, if you look at Pine Ave on Google Maps (also using NAVTEQ maps), it’s not labeled as one way for any stretch of it.

While writing this post, I visited the NAVTEQ site and found that they have a form for submitting feedback on their maps.  I decided to let them know about the missing one way restriction.  The first thing that I found is that the feedback page fails with Firefox 3.0.1.  As part of the data entry, it loads a map based on the address that you are reporting feedback on.  With FF3.0.1, it never loaded the map and just displayed the text “Please wait. Map applet is loading”.  After a few attempts, I filed it under the “EPIC FAIL” category and launched the page with IE7.  It worked with IE7 and I was able to report the missing road restriction without any problems.  When it prompted me for the GPS device, it did not have the 1412 model listed, but I was able to enter it in manually.  When I tried to save the report, it threw an IE runtime error message: “Object doesn't support this property or method”, but it processed the report.  Many of the links on NAVTEQ’s site threw runtime error dialogs, it got annoying after a while.

After some poking around on the Internet, I found a site called, a fan site for GPS devices.  They had a section for Magellan RoadMate units, so I started browsing the messages.  I learned that there was a newer firmware, 1.34, than the one I had (1.28).  According to the message thread, the newer firmware has a faster touch screen response time plus a few other features.  In this case, faster is better, so I grabbed the firmware.

The 1412 has a standard mini-USB connector, but does not come with a USB cable.  If you have any device that uses mini-USB, then the odds are that the cable that came with that device will work. I keep a USB to mini-USB cable with each PC that I use, it just makes life easier.  If you need one, look for a “A Male” to “Mini B, 5 pin Male”.  Something like this.  It shouldn’t cost more than a couple of bucks.

The installation instructions included a note about having the battery in the 1412 at full charge before upgrading.  Don’t ignore that warning.  When you run the firmware upgrade, you connect the GPS unit to your PC, but you have to unplug it after the firmware has been transferred over to the device.  When the GPS unit is plugged into a PC, it runs in a “USB Connected” mode and normal GPS functionality is disabled.  It has to be disconnected from the PC to complete the firmware upgrade.  That means it’s on battery power.  Magellan claims a full charge will last up to 3 hours.  The only way that is going to happen is if the screen brightness is turned all the way off.  You’ll want to lower the brightness down to the dimmest level that you can still read before doing the upgrade.  After you unplug the cable, the installation process continues on the device and it rebotts a couple of time.  It didn’t take long and the battery held out.

After the upgrade was complete, I started up the 1412.  I brought up the map and the there were no streets.   It appears to be lost.  Being a fan of The IT Crowd, I immediately turned it off and back on again.  No change, just a relatively blank display.  I pressed the little tow truck icon at the bottom of the display to bring up current location.  That showed a blank street location and the while the latitude was correct, the longitude was very close to 0.  Well a longitude of 0 degrees is at the prime meridian, so I started zooming out on map display.  When I zoomed out far enough, I could see that I was in the Pyrénées, in central France.

That’s not good.  France is a non-trivial distance from upstate New York.  I was doing this inside an office building during a heavy rainstorm and it looked like the GPS unit was only picking up four satelites, where it usually picks up quite a bit more.  After some poking around on the unit, I found a “Set GPS Position” option where I could enter in a street address to reset it’s position.  I entered in my office street address and the map went back to normal.  I though that I had somehow toasted the GPS device, but it was back to normal.  All in all, it’s a cool device.

Tuesday, July 22, 2008

Live from Daryl Hall's House

I came across an interesting site while looking for something else on Wikipedia....
Daryl Hall, of Hall & Oates fame, has had a hobby of restoring historic homes here in the US and in England.  Down in Dutchess County, he restored two houses and moved them from separate locations to one property.  These houses were built in 1771 and 1780 and have been joined together by a common room that Hall now uses to perform with friends for a monthly webcast.  The site is and the streaming content is free.  You can download the content for a fee as mp3 or iPod friendly video.  It's worth watching just hear his older stuff reinterpreted by guest artists.  And it's not just his material, I got a big kick watching him sing "Cruel to be Kind" with Nick Lowe.
I'm not huge Hall & Oates fan, but they had some really good songs back in the 70'a and he can still hit the notes.  I really liked Hall's Sacred Songs solo CD from 1980 more than I like the duo's music.  I'm not a big fan of watching musical performances on the computer, but this is good stuff.
The interesting thing is Hall is paying the all of the costs out of his own pocket.  He's going straight to the consumer without involving any record company.  Of course, the more popular his site gets, the bigger his bill will be for the bandwidth costs.  The production quality is very good, that can't be cheap.  I hope than he can make enough money from the on-line sales to keep doing new shows.  Since he's his own publisher, he can do as many or as few webcasts that he wants.  That's one of the cool things about this format, he has no obligation to perform on any arbitrary schedule.  That should keep the shows fresh.

Sunday, July 13, 2008

Bonus TVUG presentation by John Papa

On Tuesday, July 22nd, we will be having a bonus Tech Valley User Group meeting.  We usually skip the summer months, but John Papa is going to be in town and he offered to do a presentation how to consume WCF web services from Silverlight applications

John is currently working on new book, Data Services with Silverlight 2, so we get to see first hand what will be in the book.  He posted on his blog what the presentation will cover, anyone interested in doing Silverlight development should attend. 

John has posted an abstract for his presentation:

Silverlight enables developers to use their .NET and XAML skills to develop Rich Internet Applications and to build data driven Silverlight applications that communicate with multi-tier architectures. This session will show how to build Silverlight 2 applications that communicate with and consume REST services and use LINQ to XML to manage XML content, show the various data binding techniques, and show how to use WCF to talk to various middle tier services including custom entity models and the Entity Framework.

If you would like to attend, TVUG meets at VersaTrans Solutions, at 4 British American Blvd, in sunny Latham.  Click here for a map of how to get there.

Friday, July 11, 2008

Dr. Horrible’s Sing-Along Blog is coming to an Internet near you.

I can't pass this one up.  “Dr Horrible’s Sing-Along Blog” is a direct to the Internet miniseries from the mind of Joss Whedon.  It stars Neil Patrick Harris and Nathan Fillion and NPH has a knack for playing crazy.

Act One will start streaming on July 15th.  Act’s Two and Three will follow on July 17th and July 19th, respectively.  After the 19th, they will be take down, but they will be available for purchase at a later date/

Here’s a teaser:

Teaser from Dr. Horrible's Sing-Along Blog on Vimeo.

Thanks to Marc for the link.

Thursday, July 10, 2008

Handling collation sequences with temporary tables and table variables with SQL Server

When building complex stored procedures that span multiple tables, you will probably need to store some intermediate results in a local buffer and process them before returning the final output.  SQL Server lets you do this through temporary table and table variables.  

Usually table variables offer faster performance (less locking and logging are required), but they have more restrictions than temporary tables.  Common to both types is where they are located.  When you create a table variable or temporary table, it gets created in the tempdb database, not in the current database.  This can affect the collation sequences applied to character fields  If the SQL Server was installed using one collation and your database uses a different collation, joins from tables in your database with temporary tables will fail if you join on character fields.  The tempdb database will use the server default collation sequence. That collation may not be the same collation used by your database if your created your database on a different server that used a difference collation.  The server collation is used for all of the system databases (including tempdb) and for any newly created user databases.  Databases that are attached or restored from a backup keep the collation that they were created with.

Gregory Larsen posted some sample SQL code on that will demonstrate the error.  If you run the following SQL:

create table #a (char_set1 varchar(50) collate Latin1_General_CI_AS) 
create table #b(char_set2 varchar(50) collate Latin1_General_BIN)
insert into #a values ('collate')
insert into #b values ('collate')
select * from #a join #b on char_set1 = char_set2

You will an error message like the following:

Msg 468, Level 16, State 9, Line 5

Cannot resolve the collation conflict between "Latin1_General_BIN" and "Latin1_General_CI_AS" in the equal to operation.

That example is used to show the type of error you would get in your code.  The actual code that would throw that error would be comparisons between character fields in a temporary table/table variable and with a permanent table in your database.  If you are deploying databases to servers where the server’s default collation sequence could be different than the collation sequence used by your database, then you want to add “COLLATE database_default” to all of your character field definitions when you define a temporary table or table variable.  Using “COLLATE Database_Default” will assign the collation sequence of the current database to the field.  This will allow field comparisons between character fields in temporary tables/table variables and permanent tables to execute with triggering the “collation conflict” error.

Instead of using syntax like:

create table #a(SomeID integer, SomeCharValue varchar(20)) 

declare @a TABLE(SomeID integer, SomeCharValue varchar(20))

Use the following:

create table #a(SomeID integer, SomeCharValue varchar(20) COLLATE database_default) 

declare @a TABLE(SomeID integer, SomeCharValue varchar(20) COLLATE database_default)

This will work no matter what the collation sequence for either tempdb or your database.  You don’t need to query the server to check what the sequence.  The big limitation is that you have to explicitly define the columns in the temporary table.  If you were using SELECT INTO syntax to create the temporary table implicitly by the columns in the SELECT statement, the temporary table will use the collation of tempdb.  You would need to structure the SQL.  For example, if you were using syntax like this:

select name, crdate, filename
into #a
from master.dbo.sysdatabases
drop table #a

You would need to rewrite it to look like this:

create table #a(
name sysname collate database_default,
crdate datetime,
filename nvarchar(260) collate database_default
insert #a(name, crdate, filename)
select name, crdate, filename
from master.dbo.sysdatabases
drop table #a

You pay a small penalty by the extra SQL to explicitly define the temporary table, but you gain with having code that will work on any server.

Wednesday, July 09, 2008

A nice article about using Custom Attributes in your own code

I was poking around the blogs posts on the Falafel site and I came across a nice concise example by John Waters of how to define and use custom attributes in your own code.  His example shows how to use custom attributes as a simple way to define tag values in sub classes without having to write the same code over and over again for each subclass.  It’s a short enough read that there’s no point in excerpting any of it here.

Tuesday, July 08, 2008

Still time to enter the Darwin Race of Languages

Do you think that hand tweaked C code runs circles around managed code (C#, Java, VB.NET)?  Or do you think that your Just In Time compiled managed code gets the job done more securely than those bit sniffing dinosaurs?  Anxious to prove that Delphi is still relevant?  Want to win some cutting edge component libraries from DevExpress?

If you answered “yes” to any of those questions, there is still time to enter the Darwin Race of Languages.  The brainchild of Sevensteps CTO Bart Roozendaal, the Darwin Race is pitting a slate of challengers using the compiler and IDE of their choice to write a utility that will solve one of three problems.  The projects are the following:

  • Temperatures and CPU load
    A utility that will measure CPU temperatures and CPU load on remote computers
  • Multi clipboard utility
    The utility should hold several entries that were place on the clipboard earlier. In effect it should replace the clipboard.
  • GUI to a command line program
    A GUI front end for the gbak database command line driven program for the Firebird database.

Each entry will be judged on the software itself and how you documented the design and development of the application.  The goal is not to see which development is best tool, but to see what tools are the best for different types of jobs.  To see where the strengths are and where are the weaknesses of each tool, using real world types of the problems.  The documentation part will share the development process and show how different people come up with solutions for similar problems.

There are already a bunch of sponsors lined up.  DevExpress will be giving away a a license for DXperience Enterprise or the VCL Subscription.  If you wint, you get to pick one of them.  I have DXperience and most of the VCL components, you can’t go wrong with either one of them.

The race is on already, but there is still time to join.  There are a bunch of participants already signed up, covering C#, Delphi, VB, and something on the Mac platform.  Java is not yet represented, does someone out there want to pick up the Java gauntlet?