Why?

Posted by

I read quite a few blog posts. Why? Because I find them insightful and interesting.

I don’t get as much time as I’d like to to read them, though. Why? Well, a man’s gotta work.

There’s a theme with these three paragraphs. Why? Because I want to demonstrate a point. And that point is:

I hate, I hate, I hate the single-word sentence “Why?”! To me it’s just a sign of lazy writing. If you make a statement and then want to explain your reasoning, then you don’t need to inject the single-word sentence “Why?” in between. Just explain the sentence!

Blog posts are supposed to be informal, I know, but to me that just means they should read as if I was talking to you. Have you ever said “Why?” to someone and then immediately proceeded to give them the answer? I don’t think so.

I just read this post on the Scobleizer, and he used the “Why?” sentence three times in the one post! Now, I should be the last person to criticize Scoble and the article was otherwise quite interesting ($1,000 for an urn of coffee? Get out of here!) but I just couldn’t get past the over-use of that one-word sentence.

Or maybe I just need to take a break…

Querying the list of configured DNS servers in C#/.NET

Posted by

There’s a really good DNS client library on Code Project. It does have a few issues (like a lack of TXT record support, but that was a piece of cake to add, really), but the big one (in my book) is that it doesn’t automatically detect the configured DNS server (which means you have to manually pass it in).

Now, that’s no good for my needs, so I wrote this small wrapper around a P/Invoke call to GetNetworkParams, which is an API available in Windows 2000 or newer (also Windows 98 or newer).

Now, the call itself is quite simple. You just need to set up the structures properly. It’s fairly simple as they’re all basically flat data structures (almost, but I’ll get onto that in a second). Here’s a definition which works for me:


const int MAX_HOSTNAME_LEN = 128;
const int MAX_DOMAIN_NAME_LEN = 128;
const int MAX_SCOPE_ID_LEN = 256;

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct IP_ADDR_STRING 
{
    public IntPtr Next;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
    public string IpAddress;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=16)]
    public string IpMask;
    public uint Context;
}

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct FIXED_INFO
{
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_HOSTNAME_LEN + 4)]
    public string HostName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_DOMAIN_NAME_LEN + 4)]
    public string DomainName;
    public IntPtr CurrentDnsServer;
    public IP_ADDR_STRING DnsServerList;
    public uint NodeType;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst=MAX_SCOPE_ID_LEN + 4)]
    public string ScopeId;
    public uint EnableRouting;
    public uint EnableProxy;
    public uint EnableDns;
}

Then the P/Invoke method definition:


[DllImport("iphlpapi.dll", CharSet=CharSet.Ansi)]
static extern int GetNetworkParams(IntPtr pFixedInfo, ref uintpBufOutLen);

Note, we have to keep the pFixedInfo parameter left as an IntPtr because we’ll need to dynamically allocate the memory for it in our code. Below is the code for returning all the DNS servers configured for the local machine:


IPAddress[] GetNameServers()
{
    uint bufLength = 0;

    // Call it once to get the size of the buffer
    GetNetworkParams(IntPtr.Zero, ref bufLength);

    // Allocate the buffer in unmanaged memory.
    IntPtr ptr = Marshal.AllocHGlobal((int) bufLength);
    try
    {
        // Call it again with the newly-allocated buffer
        // to get the actual data.
        int ret = GetNetworkParams(ptr, ref bufLength);
        if (ret != 0)
        {
            throw new ApplicationException("Could not query network params: " + ret);
        }

        // Now unmarshal the FIXED_INFO structure
        FIXED_INFO fi = (FIXED_INFO) Marshal.PtrToStructure(ptr,
            typeof(FIXED_INFO));

        // We'll add the IPAddresses to an ArrayList because we don't
        // know the final number of addresses yet.
        ArrayList addrs = new ArrayList();
        IP_ADDR_STRING addr = fi.DnsServerList;
        for ( ; ; )
        {
            addrs.Add(IPAddress.Parse(addr.IpAddress));

            if (addr.Next == IntPtr.Zero)
                break;

            // We'll have to unmarshal the next IP_ADDR_STRING structure as well
            addr = (IP_ADDR_STRING) Marshal.PtrToStructure(addr.Next, 
                typeof(IP_ADDR_STRING));
        }

        return (IPAddress[]) addrs.ToArray(typeof(IPAddress));
    }
    finally
    {
        Marshal.FreeHGlobal(ptr);
    }
}

Now, a few things to note about this code. Note the list of DNS servers are returned as a linked list, so we just need to use Marshel.PtrToStructure to unmarshal each instance of the structure.

Also, on a singly-homed machine (that is, one with only one network interface) this will return the DNS servers configured for the machine (or the DNS servers returned when the machine downloaded it’s DCHP parameters). I haven’t done a whole lot of testing (yet) on a multi-homed machine (that is, one with more than one network interface), but it seems to return all the DNS servers configured for all network adapters (and while each adapter’s DNS servers are returned in order, each adapter is apparently not returned in any particular order).

.NET Histogram Control (ala Task Manager)

Posted by

Update (Jan 2008): I have uploaded a newer version of the histogram control. The only difference is the addition of a Creative Commons Attribution 3.0 Unported license (meaning you can do pretty much whatever you like, as long as you give credit where credit is due). The new version with the licensing information is available here: histogram-1.1.zip. There are no other changes to the code itself.

I was looking for a good histogram control (like the Task Manager’s CPU history graph) but I never really found one. I just wanted something simple, which let me add multiple values to the histogram.

This is the result: I made my own :)

Click for a full-size version

You can download the source for the control and a sample project (which just uses a couple of performance counters to simulate the Task Manager CPU history graph) here: histogram.zip

This control is very simple. Basically, just add it to your form and use the AddHistogram method to add your histograms. You have to supply a delegate to sample your histogram at each update. The delegate has the following form:

delegate double SampleHistogram();

Anyway, enjoy the control, and if you have any problems, feel free to leave a comment!

Note: The control was written with .NET 2.0, and I do use a couple of 2.0-only contructs. It shouldn’t be too difficult to back-port it to .NET 1.x if you needed, though.

Hello, Hotmail!

Posted by

In my previous post, “Hello, Hotmail?” I complained about the fact that Hotmail serves up it’s pages with no charset parameter which makes the browser default to ISO-8859-1, and also since it doesn’t even bother converting emails in other character sets to ISO-8859-1, if you send it a UTF-8 (or other) encoded email, then you just get garbage for any non-ASCII characters.

Well, I recently signed up to the mail.live.com beta, which will eventually replace Hotmail, and I’m very happy to report that it serves up it’s pages at UTF-8!

Not only that, but if you send it an email in a character set other than UTF-8, it’ll convert it for you. Good work, Microsoft! Let’s just hope it comes out of beta soon and everyone can benefit from it.

Virtual Machine as backwards-compatibility shim

Posted by

There’s a bit of discussion over on Larry’s blog post “Young Turks” about the virtues of the Microsoft method of achieving backwards compatibility (i.e. by doing shims and work arounds for individual apps and stuff) and the “virtualization” or “emulation” method, where you run old applications either in a virtual machine running the old operating system, or in an emulated layer, ala the was OSX runs OS9 apps.

Now, I’m going to discount the emulation method pretty much out-of-hand, because I personally feel that the Mac emulation layer was a bit of a failure – it’s pretty much pot luck if your app works or not. And quite frankly, it’s not much different from installing a shim anyway, it’s just a “general” shim rather than an app-specific one.

But the virtualization method seems interesting at first glance. Basically, you can do what you like with new versions of the OS, if old apps don’t work, you can run them in a special virtual machine which just runs the old operating system. Now, obviously the “virtual machine” would have to be some special kind of virtual machine because it would be far too annoying to have to set up networking just to copy files from your VM to your host OS.

But let’s say you get that sorted (perhaps you could have the My Documents folders in the VM map to a drive in the host machine?) there’s one very big program, which I believe makes the idea impossible: security patches.

Let’s just assume for a moment that Microsoft had taken the virtualization approach starting from Windows 95. Let’s also assume you work for a company that has a line-of-business application that was developed on Windows 95, but hasn’t been updated since then (which is surprisingly common). So if you wanted to run your Windows 95 app today, you’d have to run it in a virtual machine running Windows 95 in your host Windows XP OS.

Now let’s imagine that a security vulnerability is found in Windows 95 that makes your application insecure, and a patch is required. Would you expect Microsoft to patch an 11 year-old operating system, just so you can continue to run your application securely? After 11 years, it’s unlikely that you company still has the source code to your application (or maybe you had contracted development of it out to another company, and they’ve since gone out of business).

But by making Windows XP fully backwards-compatible with Windows 95, your line-of-business app from 11 years ago still runs today, and Microsoft don’t have to worry about patching operating system that have gone out of support any more.