Date and time format finalized

I spent a little more time on the date and time parsing code that I discussed on December 17.  I have created a .NET structure, called W3CDateTime, which maintains the time and UTC offset.  The class can parse RFC822 format dates as well as W3C date time values.  The structure interface mimics the interface for System.DateTime, including the ability to subtract dates to get a TimeSpan value, to add TimeSpan values to dates, and to compare the date values.  It includes all of the System.DateTime functionality except the internationalization options for input and output and some of the date format conversions (OLE Automation and File Date Time).

Creating the structure was an interesting study in the use of regular expressions and interface design.  It also took a whole lot more code than I expected, mostly because I had to implement a whole lot of simple properties and small methods that take three lines of syntactic sugar for a single line of functionality.

I discussed the development and implementation of the structure, complete with source code in C# and Visual Basic in my .NET Reference Guide column.  The full article is here.

A .NET Cabinet file interface

The third and final installment of my article series on reading and writing Microsoft CAB files from .NET is available now on DevSource.  Creating an Object-Oriented Interface to CAB Files describes the CabCompressor and CabDecompressor objects that I created, which wrap the Cabinet SDK functionality in .NET objects and present a familiar .NET event interface to the callbacks.  Full project source code is available from a link at the end of the article.

Accessing Cabinet Files from .NET, Part 2

Just a quick note to say that the second in my three-part series of articles on accessing cabinet files from .NET is available at DevSource.  This article shows how to implement the callback functions and drive the Cabinet SDK functions.

Reading and Writing CAB Files from .NET, Part 1:  Creating a CABINET.DLL Interface

Reading and Writing CAB Files from .NET, Part 2: Using the CABINET.DLL Interface

You can find the code and Visual Studio project files here.

Accessing Cabinet Files from .NET

One of the things that’s kept me busy the last month or so is a project to access Microsoft cabinet files from a .NET program.  I mentioned this in passing before.  It turns out that interfacing with CABINET.DLL from .NET is much more difficult than from C or Pascal, mostly due to calling conventions and string marshaling across the managed/unmanaged layer.

I’m now working on a three-part series of articles on this topic for DevSource.  The first article, Creating a CABINET.DLL Interface, is now available.  To my knowledge (and I looked pretty hard before taking on the project), this is the only published information about accessing cab files from .NET programs.

Unexplained VersionNotFound Exception with ADO.NET

I’ve run into a problem that has me pretty confused. I’m getting a VersionNotFoundException when trying to change the RowFilter property of a DataView. This happened in a large system that I’m working on, but I’ve been able to duplicate the behavior in a relatively small (80 lines) sample program that’s at the end of this post.

I posted a message on Microsoft’s forum, but haven’t received any helpful responses. Perhaps somebody who reads this can help me out. A Google search revealed a few similar problems (although no exact matches), but I didn’t see a small reproducible case or any kind of resolution to the problem.

Short explanation of problem:

I have a DataSet with two tables: Legislators and Authors. The Legislators table contains a list of all Legislators who can potentially be an author or coauthor on a bill. The Authors table contains a record for each Legislator who has signed onto the bill as an author or coauthor (the Authors table will contain information for one bill at a time). The DataSet enforces a relation: the LegislatorCode value in an Authors record must match a LegislatorCode that’s in the Legislators table. I use a DataView to maintain a view of the Legislators table showing only those legislators who have not signed onto the bill.

This all works on the initial load, as shown in the program below. However, if I then add an Authors record, the DataView isn’t updated to reflect the change. That is, even though there now is an Authors record for a legislator, that legislator still shows up in the DataView. So, figuring I had to trigger a refresh of the DataView, I set RowFilter to string.Empty, and then set it back to what it was. I then get an exception “System.Data.VersionNotFoundException: There is no Original data to access.”

Further testing shows that this only happens if I accept changes on the Legislators table (i.e. the parent table in the relation). It appears that the code which processes the relation is looking for the child record to have an Original version if the parent has an Original version. It seems to me that it should be looking for the Current version.

I have two questions:

  1. Why doesn’t the DataView update when I enter the new Authors record?
  2. Why do I get this exception?

Any help, especially a workaround or somebody pointing out where I’m doing something wrong, would be appreciated.

The sample program:

// C# program to illustrate unexpected behavior in DataView.RowFilter
using System;
using System.Data;
namespace dvTest
{
    class Class1
    {
        [STAThread]
        static void Main(string[] args)
        {
            DataSet myds = new DataSet();
            // Create the tables
            DataTable tblLegislators = new DataTable("Legislators");
            tblLegislators.Columns.Add("LegislatorCode");
            tblLegislators.Columns.Add("DisplayName");
            DataTable tblAuthors = new DataTable("Authors");
            tblAuthors.Columns.Add("BillNumber");
            tblAuthors.Columns.Add("LegislatorCode");
            // AuthorType:  P = Primary author, C = Coauthor
            tblAuthors.Columns.Add("AuthorType");
            // Add tables to dataset
            myds.Tables.Add(tblLegislators);
            myds.Tables.Add(tblAuthors);
            // Add a relationship.
            myds.Relations.Add(tblLegislators.Columns["LegislatorCode"],
                tblAuthors.Columns["LegislatorCode"]);
            // populate the legislators table
            tblLegislators.Rows.Add(new object[] {"A0123", "Smith (A0123)"});
            tblLegislators.Rows.Add(new object[] {"A1234", "Jones (A1234)"});
            tblLegislators.Rows.Add(new object[] {"A5038", "Jackson (A5038)"});
            tblLegislators.Rows.Add(new object[] {"A0191", "Morton (A0191)"});
            // Populate the Authors table.
            // LegislatorCode must be present in Legislators table
            tblAuthors.Rows.Add(new object[] {"001", "A0123", "P"});
            tblAuthors.Rows.Add(new object[] {"001", "A5038", "C"});
            // Accept changes on the dataset.
            myds.AcceptChanges();
            // dvLegislators is a dataview that contains legislators
            // that do not have a record in tblAuthors.
            DataView dvLegislators = new DataView(
                tblLegislators,
                "Count(Child.LegislatorCode)=0",
                "DisplayName",
                DataViewRowState.CurrentRows);
            // Show contents
            ShowLegislators(dvLegislators);
            // Add another coauthor
            Console.WriteLine("Add Legislator 0191 as a coauthor");
            tblAuthors.Rows.Add(new object[] {"001", "A0191", "C"});
            // Show contents -- why is 0191 still in this DataView?
            ShowLegislators(dvLegislators);
            // Re-filter the DataView
            dvLegislators.RowFilter = "";
            try
            {
                // Why does this throw an exception?
                dvLegislators.RowFilter = "Count(Child.LegislatorCode)=0";
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }

            Console.WriteLine("Press Enter");
            Console.ReadLine();
        }

        static void ShowLegislators(DataView dvLegislators)
        {
            // Display contents of dvLegislators
            Console.WriteLine("dvLegislators contains:");
            foreach (DataRowView drv in dvLegislators)
            {
                Console.WriteLine(drv["DisplayName"].ToString());
            }
            Console.WriteLine();
        }
    }
}

Microsoft MapPoint

I spent about 90 minutes on the phone this evening with a representative from Microsoft’s MapPoint technology group.  The purpose was a technology overview for an article I’m writing to be published on DevSource.  On the surface, MapPoint doesn’t look all that exciting.  It’s just another MapQuest knock-off, right?  Wrong.  MapPoint is actually several different products, including MSN MapsStreets and TripsMapPoint 2004MapPoint Web Service, and MapPoint Location Server.  They all provide some type of mapping service, but in very different ways.

MSN Maps provides maps and driving directions in much the same vein as MapQuest.  Streets and Trips is a desktop product that lets you plan trips, print maps, view points of interest, and all that other good stuff people expect from mapping software.  There’s also a Pocket PC version called Pocket Streets.  MapPoint 2004 is business mapping software that lets you put maps into documents and include demographic information on the maps.  The CD product has an astounding amount of demographic information.  You can color-code a city based on demographics:  median income, number of children, etc.

The Web Service is what I find particularly exciting, though.  If your company needs mapping information or wants to provide mapping information to customers through your Web site, you can contract with Microsoft MapPoint to provide the data.  A simple example is providing your Web site visitors the ability to find the store nearest their location.  Given the user’s ZIP code, you can query MapPoint for stores within a given radius and then show a map that pinpoints each store.  You have to put a few pieces together in order for it to work, but it’s pretty simple.

It’s worth checking out if you’re interested in playing with map data.  Go to the Web Service page, download the SDK (requires the .NET Framework), and sign up for an evaluation account.  .NET isn’t required to use MapPoint:  as an XML Web service, it’s platform agnostic.  But the SDK samples and all the documentation are .NET centric, so be prepared to do some translation if you’re doing PHP or something else non-.NETish.

Benefits of Unicode strings

An unsung benefit of programming for Microsoft .NET is that all strings are Unicode.  I didn’t realize just how much of a benefit this is until recently.  I’m in the middle of a Delphi project that has to be “global ready,” which means (among other things) that all the strings have to be localizable.  This is a giant pain.  Writing a localizable application in Delphi requires that I use three different string types (PChar, String, and WideString), and continually convert from one string type to another.  The problem is similar in C and C++.

With .NET, every string is Unicode and all functions that handle strings assume that the strings are Unicode.  One string type.  No conversions.  Life is good.

More on .NET performance counters

Although I still haven’t figured out how to use some of the .NET PerformanceCounter types, I’ve made some progress.  I finally broke out the SDK documentation, examples, and C header files in an attempt to decipher the .NET documentation.  The header file that I located (winperf.h) dates back to 1995.  Comments in that file describe the performance counter registry interface in some detail, and I was able to glean some very interesting, although not terribly useful, information from that.  It turns out, though, that the registry interface is only one of four (that I know of) Windows performance monitoring interfaces.

The Performance Data Helper library is a Windows DLL that wraps the registry interface to make things a bit easier for programmers who want to monitor performance data.  If you’re building your own performance counters you still have to write to the registry interface.  I think.  The PDH library documentation is voluminous and predictably confusing.  In reading through it, I found some interesting mistranslations of information from the winperf.h header file.  Where the header file comments say, for example, “this counter could be used to…”, the PDH documentation says “this counter is used for…”  The PDH documentation implies that the counter has built-in functionality that does not in fact exist.

Windows Management and Instrumentation (WMI) includes a performance counter interface that appears to have been intended to replace PDH, although from my reading of the documentation, PDH can interface either with WMI or with the original registry interface.  Things get kind of confusing there, and if you thought the PDH documentation was large, you do not want to look at the WMI documentation.  Not surprisingly, much of the information in the WMI documentation is poorly adapted from the PDH documentation, which appears to have been written by somebody who didn’t quite understand what the whole thing was about.  The descriptions of using existing Windows performance counters are approachable, just barely, if you have some sample code to look at.  But the descriptions of how to create your own performance counters—especially counter types that aren’t used anywhere else in Windows—are confusing, contradictory, and just plain wrong in some places.  It’s a nightmare.

All of which brings us to the fourth and (for now) final version of Windows performance counters:  the .NET PerformanceCounter and related classes.  It’s a much simplified interface than any of the others, and using it to monitor built-in counters and to create instances of simple counters is quite nice.  But, again, stepping away from the handful of common performance counter types is very difficult.  Even more difficult than with WMI or the registry interface, because there is even less information on the inner workings.  From looking at it more closely, I’d say that the .NET implementation talks to WMI in the background, but I can’t say for sure without a bit more research.

You know, I used to get paid for figuring stuff like this out and writing about it.  I had thought, though, that things were better documented these days and the market for those skills had dried up.  Perhaps it’s time to rethink that.

.NET performance counter documentation

Am I the only one who finds Microsoft’s documentation of .NET performance counters incomprehensible?  I’ve been over and over this and related pages, searched for sample code, spent hours puzzling over my own programs, and have come to the conclusion that either the documentation is flat out wrong, or the performance counters themselves are terribly broken.  Figuring that the .NET implementation is just a wrapper around the Win32 performance counters, I went to the Platform SDK documentation to see if I could glean some information.  No such luck.  The .NET documentation is an incoherent translation of the already incoherent Platform SDK documentation.  Searching the MSDN site for code samples reveals plenty of stuff for the simple counters like Average Timer and Counts per Second, but nothing on most of the others.  I found nothing of relevance on the Microsoft developer forums, and a Google search was equally fruitless.  I keep poking at it, but if anybody out there can shed some light on this topic for me, I’d sure appreciate it.

Exploring the .NET Framework

Perhaps the most frustrating part about learning any new development platform is learning where to find things.  With the .NET platform, for example, I have this wonderful class library that has all manner of classes to access the underlying services.  But without a roadmap, finding things is maddening.  For example, if you want to get the current date and time, you access a static property in the System.DateTime class (System.DateTime.Now).  If you want to pause your program, you call System.Threading.Thread.Sleep()—a static method.  The class library is peppered with these static methods and properties, and ferreting them out is difficult.  What I need is some kind of reference that lists all of the objects that provide similar useful static members, and a cross-reference (maybe an index) that will let me quickly find the appropriate static member for a particular purpose.  As it is, I’m spending untold hours searching the documentation or just randomly picking a topic in the library reference and scanning it for interesting tidbits.

That said, I’m having a ball learning C# and .NET programming.  I’m still not as comfortable with it as I am with Delphi (hardly a surprise, considering I’ve been working with Delphi since its early beta days in 1994), but I can see C# becoming my language of choice very quickly.  C# and the .NET platform have all the ease of use of Delphi, a comprehensive class library, good documentation, and a solid component model that’s supported by the underlying framework (a luxury that Delphi didn’t have).  It’s easy to like this environment, and it’s going to be rather difficult for other compiler vendors to provide tools that programmers will prefer over C# and Visual Studio .NET.  I’m interested to see what Borland comes up with.  Whatever it is, it’ll have to be pretty compelling to get me to switch.