Tuesday, January 12, 2010

Dot NET 2.0 Generics and Windows 98

One of my customers asked me to write a .NET application which is capable to run on old Windows 98 machines. This request came to me last year but don't ask me about the reasons of doing such a thing :).

Only .NET 2.0 is running on Windows 98

But not any .NET 2.0 release will do so. You have to consider the first .NET 2.0 release (having no Service Packs) for building a Windows 98 capable application.

The plain .NET 2.0 Generics have bugs

It seems that the complex object structures based on multiple layers of generalization can't be digested by the original .NET 2.0. Of course, the first Service Pack is fixing this problem but .NET 2.0 SP1 doesn't run on Windows 98 !! That came as a big surprise to me because everywhere on the Microsoft site you can read that .NET 2.0 is the only version able to run on Windows 98. But the .NET 2.0 SP1 is still 2.0 (is not 2.1 or anything above !!). Anyway. These were the facts and I needed to deal with them.

System.BadImageFormatException

Here is a similar structure of what I wrote for my first .NET 2.0 Windows 98 application :).

C# .NET

1publicinterfaceIDbItem<T>

2 {

3bool IsSimilar(T item);

4 }

5

6publicinterfaceIDbItemManager<T>

7where T : IDbItem<T>

8 {

9ReadOnlyCollection<T> Items { get; }

10

11eventEventHandler<DbItemActionEventArgs<T>> ItemAdded;

12

13void Add(T item);

14 T NewItem();

15 }

So I have some contracts for a generic item (IDbItem) which is handled by a generic manager (IDbItemManager). Now here is the implementation for each of these contracts:

Instantiating the DbItemManagerBase class on a .NET 2.0 Framework will end up with this error:

System.BadImageFormatException: An attempt was made to load a program with an incorrect format. (Exception from HRESULT: 0x8007000B)

The workaround

The solution to this is rather simple: just remove the generalization from the IDbItem and DbItemBase and ajust the IDbItemManager and the DbItemManagerBase to reflect this change.
Note that you have to handle manually any required casting in the IDbItem methods that were using the generics!