Friday, September 28, 2007

One of the banes of my existence (okay, not that bad but fun to say) is supporting Windows 2000 at work. Yes, there are still Win2K machines out there - not many, but enough to make a difference. One problem is that .NET 3.0/3.5 isn't supported on Win2K, so we're limited in what we can do, at least on the client-side. Another problem is just strange issues with the framework. 99% of the stuff we write works great, but there are a few things that don't.

Here is one that caused mass confusion recently.

Check out the code for this incredibly simple console application that I wrote:

Module Module1
 
    Sub Main()
 
        Console.WriteLine(">>Environment.CommandLine = {0}", Environment.CommandLine)
        Console.WriteLine(">>Environment.GetCommandLineArgs()(0) = {0}", Environment.GetCommandLineArgs()(0))
 
        Dim commandLineFileName As String = System.IO.Path.GetFileName(Environment.GetCommandLineArgs()(0))
        Console.WriteLine(">>commandLineFileName = {0}", commandLineFileName)
 
        Console.WriteLine(">>ProcessName = {0}", Process.GetCurrentProcess.ProcessName)
 
        Console.WriteLine("Press enter to continue....")
        Console.ReadLine()
 
    End Sub
 
End Module

What would you expect the output to be?

Here's what it does on Windows XP:

>>Environment.CommandLine = ConsoleApplication1.exe
>>Environment.GetCommandLineArgs()(0) = ConsoleApplication1.exe
>>commandLineFileName = ConsoleApplication1.exe
>>ProcessName = ConsoleApplication1
Press enter to continue.... 

On Windows 2000, it does the same thing. Super.

Let's change the name of the executable to ThisIsALongNameForAnExe.exe and run it again.

>>Environment.CommandLine = ThisIsALongNameForAnExe.exe
>>Environment.GetCommandLineArgs()(0) = ThisIsALongNameForAnExe.exe
>>commandLineFileName = ThisIsALongNameForAnExe.exe
>>ProcessName = ThisIsALongNameForAnExe
Press enter to continue.... 

Once again, Windows 2000 behaves the same way. Great.

Let's try one more thing. Let's change the name of the executable to This.Is.A.Long.Name.For.An.Exe.exe and run it one last time.

Windows XP looks like this:

>>Environment.CommandLine = This.Is.A.Long.Name.For.An.Exe.exe
>>Environment.GetCommandLineArgs()(0) = This.Is.A.Long.Name.For.An.Exe.exe
>>commandLineFileName = This.Is.A.Long.Name.For.An.Exe.exe
>>ProcessName = This.Is.A.Long.Name.For.An.Exe
Press enter to continue.... 

However, Windows 2000 looks like this:

>>Environment.CommandLine = This.Is.A.Long.Name.For.An.Exe.exe
>>Environment.GetCommandLineArgs()(0) = This.Is.A.Long.Name.For.An.Exe.exe
>>commandLineFileName = This.Is.A.Long.Name.For.An.Exe.exe
>>ProcessName = This.Is.A.Long
Press enter to continue.... 

Can you tell the difference? System.Diagnostics.Process.ProcessName is truncated when running on Win2K. The only thing I can tell is that the periods in the process name throw it off. Granted, hopefully you don't have anything secure relying on the name of your process (cough, rename, cough), but it still came across as very unexpected.

Note - the results can be different depending on how you actually execute the program. The command line and command line arguments are literally what was typed when the program is executed.

posted on Friday, September 28, 2007 1:21:13 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, September 26, 2007

I am a moron.

Like so many of the millions of other Halo fans, I preordered my copy of Halo 3 literally months ago. I've been waiting impatiently for months (years?) for it to release and now it is out.

And I haven't got to play it yet.

Because it still hasn't shipped to my door.

I should have chosen in-store pickup.

*sigh*

posted on Wednesday, September 26, 2007 8:05:44 PM (Central Standard Time, UTC-06:00)  #    Comments [0]

Yesterday, I had a somewhat strange experience. I was helping someone with a problem they were having and, almost as a side note, this individual thought he would share some code with me that he was particularly proud of. He even prefaced the story with the "not to brag or anything" phrase. He had written some custom code to help text boxes grow or shrink depending on how the user resized the window. If you know anything about WinForms, you'll know that some simple anchoring techniques and good use of the SplitContainer will solve this problem for you - please, please, please don't go writing custom mathematical equations when the framework can take care of it for you.

At the time, I was pretty annoyed with it, because this individual was bragging about something that I considered "the wrong way to do it." In retrospect, this probably was the wrong response. Why? Because he was proud of some of the code he had written. He actually cared about it enough to not just treat it as something to toss off on to someone else when he moved to the next project.

The projects that have turned out best that I've worked on the ones where I was really proud of the code. That doesn't mean I did it the right way. I'm thinking of one example where I wrote this crazy elaborate dynamic menu system in JavaScript. It even worked in both Firefox and Internet Explorer. It had a full blown object model and made use of closures and more - it was great. Here's a complete example of usage of the menu:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
   <head>
      <title>clsNavBar</title>
      <script language="JavaScript" src="clsMenu.js"></script>
      <link href="styles.css" rel="stylesheet" type="text/css">
   </head>
 
   <body>
      <script language="JavaScript">
        var nav = new clsMenu();
        nav.setContainer(document.body);
        nav.setXMLUrl("NavBar.xml");
        //nav.setHorizontal(false)
        nav.buildMenu();
      </script>
   </body>
</html>

It had one problem. Maintenance. Maintenance on the system will be nigh impossible for the next guy. From the very beginning, I should have used CSS for the entire menu structure. When and if someone ever decides to change the way the menus look, well... good luck. However, it was still a good experience. I learned more about the inner workings of JavaScript from working with that than I did from any blog post or book I've ever looked at. I would have never learned what exactly 'this' references in JavaScript without that example (see this post on JavaScript gotchas and refer to the section on 'this').

In all of this, I have learned to be very careful of the code I'm proud of. Inevitably, if you're growing as a developer by "sucking less every year," you're not going to be too proud of your code in a year or two anyway.

Do you have any code you're particularly proud of? If it turned out to be the "wrong way to do it" but you learned a lot from the experience, you get bonus points.

posted on Wednesday, September 26, 2007 7:17:19 AM (Central Standard Time, UTC-06:00)  #    Comments [2]
 Monday, September 24, 2007

Reading posts like this one from Jeremy Miller really make me wish I could make it to the ALT.NET conference in Austin. There are almost too many good points in his post for me to comment on, but I'll go ahead and try.

I completely and wholeheartedly agree with his comments on the general lack of knowledge that developers have regarding real OOP and software design concepts. Many of the developers I work with are terrified of the upcoming releases of the .NET framework. The thing is, they're just new releases in tools and libraries. Sure, they provide value - I don't know how many times I realize that some UI I'm trying to work with in WinForms would be ridiculously easy to build in WPF. And WCF does a great job at abstracting the goo that connects all of my objects. However, if I don't have a good background in solid OOP design and separation of concerns, WCF won't help me at all anyway. These new tools aren't going to do anything to make me a better developer. I'll still be able to write awful code.

I commend these guys for trying to get to the heart of the issues in the .NET community and I hope that the solution isn't to just move to Ruby and Ruby on Rails. My opinion is that we have to fix the problems in our community - if we just migrate to another community, the problems and lack of knowledge will eventually follow us. I can still write bad code in Ruby, too.

Being one of the guys who won't be able to make it, I have a few requests. I would really like to see the content from the conference posted online or made accessible to those of us who won't be able to make it, particularly considering the fact that the conference sold out. Microsoft did a good job in posting content from both MiX and TechEd this year and I think that would be a welcome addition from this conference as well.

Keep pushing this knowledge out - I'm optimistic that things will improve.

posted on Monday, September 24, 2007 7:02:45 AM (Central Standard Time, UTC-06:00)  #    Comments [5]
 Friday, September 14, 2007

Well, I got back from the .NET Roadshow last night. It went really well, too. The conference lasted two days with three tracks.

The first day was all WCF with Juval Löwy. Juval is a great speaker and really knows his stuff. I mean, seriously, the guy is a genius. There is a reason that Scott Hanselman put him on his list of "Smart People and their pages for Utils they Wrote" (a subitem of his Ultimate Tools). He really pointed out how WCF will change the way we write code. Your implementation of a service might look like a class, smell like a class, quack like a class and walk like a class... but it isn't a class anymore. It is a service. What does this really mean? Well, it means this thing that looks like a class now inherently supports transactions, threading, queuing, throttling, security, and more. Now, I'm going to insert my little bit of reality here - this service functionality isn't all magic. You have to configure your service and you have to host it. You don't just say myVar = new myService() or something like that. But there is still a ridiculous amount of power that WCF gives you out of the box. I like it.

The second day, we got to choose between a security-focused track by Michèle Leroux Bustamante and a Workflow/WPF track by Brian Noyes. I chose Brian's track simply because I know we'll be using WPF soon and because I have zero background in Workflow. Workflow really is pretty cool, though it is a little hard to explain. The benefits, as far as I'm concerned, come in visualizing business processes so that you can verify functionality with your users via a flow chart instead of trying to explain through code. The more activities that you create, the closer that your workflow can get to true business/domain terms. Also, I didn't realize it until Brian mentioned it, but Workflow supports persistence, so you could conceivably have a 6 month long workflow that persists between machine reboots and all of your logic still flows without any problems. Very cool.

I had the most background in WPF ahead of time, so I didn't really learn anything new. Having purchased Adam Nathan's book on WPF as well as having watched a multitude of dnrTV episodes on WPF, I had a pretty good background on what WPF is capable of. Needless to say, WPF is awesome. I still couldn't use Expression Blend to safe my life, but the entire platform is sweet. I think my favorite example of what you can do with WPF is the example from Adam's book on customizing the ToolTip so that it looks like the tooltips from Office 2007. It doesn't sound like something to get all that excited about, but the ease with which it is done really shows just how powerful the WPF composition engine is.

All in all, I really enjoyed the Roadshow. If you've already got some background in .NET 3.0 or are using it, I don't know if you would gain much; however, if you're like me and haven't had a chance to really dig in, you can really learn a lot and see some of the capabilities that .NET 3.0 will give you.

posted on Friday, September 14, 2007 4:06:42 PM (Central Standard Time, UTC-06:00)  #    Comments [1]
 Tuesday, September 11, 2007

I'm off to .NET Roadshow 2007 in Dallas! The speakers are Juval Löwy, Michèle Leroux Bustamante, and Brian Noyes. My hope is we'll be doing some pretty heavy .NET 3.0 development at work soon (primarily WPF and WCF I would guess), so watch for some .NET 3.0 related content. I'll post when I get back about how it was and, if I get a chance, I'll try to post some updates from the conference as well.

posted on Tuesday, September 11, 2007 2:02:45 PM (Central Standard Time, UTC-06:00)  #    Comments [2]
 Wednesday, September 05, 2007

When I was in high school, my first job was preparing food at a local Taco Mayo. I didn't last long there. Soon afterwards, I began working at a local ISP doing tech support. I still remember all of the problems that brand new 56K modems had, because the v92 standard hadn't really been standardized yet.

Anyway, all that to say my first real job was tech support at an ISP. Tonight, I was practicing my troubleshooting skills on my internet connection. I got home from work and couldn't connect to anything except my router.

Here are the steps I took:

1) Opened Outlook and IE and tried to go somewhere. Nothing happened.

2) Recognized there was a problem.

3) Pulled up a command prompt and tried to ping www.google.com and then my ISPs website. No dice.

4) I rebooted.

5) I pulled up an admin command prompt (UAC) and tried pinging again with no success.

6) I released my IP address and then renewed it (ipconfig /release and then ipconfig /renew - this is why I needed an elevated prompt).

7) I tried pinging again without success.

8) I unplugged my cable modem, waited for 15 seconds, plugged it back up and then tried again... without success.

9) I navigated to my router's page in my browser which came up great.

10) I released and renewed my IP address from the router. Then I tried pinging... once again without success.

11) I bypassed my router and connected my ethernet cable directly to my cable modem.

12) I unplugged and then plugged back in my cable modem and tried pinging without success.

13) I got frustrated and tried most of the above things in random order to try to get it to work.

14) I called tech support.

15) I got more frustrated dealing with the automated answering system.

16) I got FAR more frustrated dealing with the automated tech support - that had me do everything I had already tried.

17) The automated tech support finally asked if I'd like to speak with a real person - I said yes.

18) The real tech support picked up quickly (thankfully) and had me power off my modem and bypass my router (already done) and then try pinging which didn't work.

19) Then he asked me to reboot.

20) Knowing that this was my second reboot, I was skeptical but I went ahead with it for the real tech support guy's benefit.

...

21) It starts working.

22) I look and feel like an idiot.

Moral of the story - rebooting always fixes the problem. Just try it over and over and over again. Until it starts working.

*sigh*

posted on Wednesday, September 05, 2007 9:28:34 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, August 30, 2007

I was messing around with some unit tests this week and I came across an unexpected benefit while working on code that worked with a COM object. When you add a reference to a COM library in .NET, you'll get an interface as well an implementation of that interface that forwards the calls to the COM objects.

Because an interface is created for the COM objects as well as the implementation, you can mock the COM dependency with Rhino Mocks or some other mocking framework. Just code against the interface instead of the concrete implementation and inject the concrete implementation via dependency injection for the normal scenario.

Let's say you wanted to unit test some code that had a dependency on the Windows Media Player COM object. Here's how you could do it.*

image

// Code to be tested
public class SomeClass
{
   private WMPLib.WindowsMediaPlayer _player;

   public SomeCode(WMPLib.WindowsMediaPlayer player)
   {
      _player = player;
   }

   public void DoSomething()
   {
      _player.enabled = false;
   }
}

// Unit test
[TestFixture()]
public class SomeCodeTest
{
   [Test()]
   public void PlayerEnabledShouldBeSetCorrectly()
   {
      MockRepository mocks = new MockRepository();

      // Mock the WMP interface... note that even 
// though it doesn't start with an 'I', // it is still an interface... WMPLib.WindowsMediaPlayer player = mocks.CreateMock(); // Inject the mocked WMP object SomeClass sc = new SomeClass(player); using (mocks.Record()) {
// Expect player.enabled to be set to false player.enabled = false; } using (mocks.Playback()) { sc.DoSomething(); } } }

I tried this code out and the test runs fine. Note the comment where the mock object is actually being created. For some reason, the interface to the COM object isn't named with an 'I'. It still is an interface, though. And you can create the COM object by saying 'new WMPLib.WindowsMediaPlayer' though I think that is some COM interop magic going on there (I'm guessing the CoClass attribute on the interface has something to do with this magic).

* I'm not actually mocking Windows Media Player in any of my code and I have no idea how well it will work. I do know that I can mock some of our own COM objects without any problems, though.

posted on Thursday, August 30, 2007 3:36:44 PM (Central Standard Time, UTC-06:00)  #    Comments [0]