How could something so simple turn into something so complicated?
One of my most popular (perhaps the most popular) post on this site is my tee utility for Windows. I wrote it back in 2003 using the Visual Studio vintage of the same year. Rather than including stdio.h and writing it in good old plain vanilla C code, I decided to employ the then-new managed extensions for C++ so it could <scare-quotes> benefit from </scare-quotes> the .NET Framework 1.1. That’s where my troubles were begotten – but it took a while for them to gestate.
The first problem I encountered was trying to run it from a network share. Microsoft, in a truly dramatic performance of security theater, decided to treat network shares as “Intranet Zone” and untrusted by default. Sure, there were ways to establish a trusted zone, but it was a pain to remember. Thankfully, they’ve solved that one for me.
Then recently, user Alex Armstrong noticed a few anomalies when using tee with ping. He likes to use ping –t to repeat until interrupted, at which point ping prints out its statistics and then stops. But when ping was piped to tee, Ctrl+C would interrupt tee instead – which closed the pipe and killed ping before it could relieve itself of its statistics. Not only that, but since tee’s output files were not flushed, some of the output that had already been displayed on the console would not make it to the file(s).
I tried setting the Console property TreatControlCAsInput to true, but when the input stream is a pipe that caused tee to go into la-la land. Reading further, I found the CancelKeyPress event – but for some reason I couldn’t get it to compile with the old syntax that I had used back in 2003. With a little research, I found that the only reason why the compiler was tolerating most of my code was because the project upgrade wizard had added the /clr:oldSyntax switch when upgrading to VS2008. When I removed that switch, all hell broke loose. How could they change the syntax for writing managed code in C++ so drastically? This little utility, which is only about 35 lines of real code, required changes on 15 of those lines. Yes, they were mostly trivial – but how annoying. It’s not the same language. Yes, it’s probably better syntax, but it’s not the same language.
One change I would have liked to make is to use List<T>.ForEach to iterate through the list, rather than a for loop. But I couldn’t find any way to write the Action code inline until lambdas arrive in VS2010. Now that’s a syntax change I could get excited about.
Long story short, canceling the CancelKeyPress event (is that a double negative?) worked — Ctrl+C is now seen by ping, which prints out its statistics and closes the pipe, which stops tee normally. If you should ever need to interrupt tee itself, use Ctrl+Break.
One more thing (as Columbo says) – Alex also noticed that ping’s output is double-spaced when piped through tee. That’s because ping ends each line with a double carriage-return. Console::ReadLine treats each of those as a terminator. I don’t know why the command prompt window doesn’t have an issue with that, but I do. I can’t just ignore zero-length lines, because then I’d lose spacing from other programs that don’t use a double carriage-return. Any ideas? This is supposed to be simple.