Attention: We are retiring the ASP.NET Community Blogs. Learn more >

Fear and Loathing

Gonzo blogging from the Annie Leibovitz of the software development world.

  • Terrarium for Vista, whoops…

    My bad. I don’t run Vista. Really. I don’t like it, it’s glacially slow, and doesn’t give me anything as a developer (except more flashy looking Explorer screens and maybe a Start menu I can search). So I’m an XP boy, however that was a bad mistake on my part with the release of Terrarium.

    Vista users were getting an exception message and it was pretty quick to see that it was a DirectX problem. The problem was a) Vista doesn’t support DirectX 7 which Terrarium requires and b) Bil is an idiot for not thinking about this. Again, my bad and I apologize.

    So first off there’s a quick fix (which I can’t test myself, but according to comments on Scott’s blog it works).

    1. Find an XP machine and grab the following older DirectX DLLs:
    2. d3drm.dll
      dx7vb.dll
      dx8vb.dll

    3. Run regsvr32.exe against the dx7vb.dll and dx8vb.dll
    4. Drop everything in the %SYSDIR%\system32 folder

    That should fix you up in the interim. Unfortunately I cannot redistribute the files to you as they’re MS property and all that jazz.

    For longer term, I’m ripping out the DirectX COM calls (which are actually wrappers to wrappers) that are in the current codebase and calling the DirectX managed ones provided in DirectX 9. This will probably result in not only a more readable codebase (and one that works on Vista) but it might even gain a little performance along the way.

    The managed DirectX classes Microsoft provides in DirectX 9 are pretty nice and rather than a bevy of cryptic constants, enums and ref objects everywhere they’re all wrapped up in a nice OO-like package for you.

    For example here’s the old DX7 code (ugly COM and DirectX goo):

       1: /// <summary>
       2: ///  Determines if the surface is in video memory
       3: ///  or system memory.
       4: /// </summary>
       5: public bool InVideo
       6: {
       7:     get
       8:     {
       9:         if (surface != null)
      10:         {
      11:             DDSCAPS2 ddsc = new DDSCAPS2();
      12:             surface.GetCaps(ref ddsc);
      13:             if ((ddsc.lCaps & CONST_DDSURFACECAPSFLAGS.DDSCAPS_VIDEOMEMORY) > 0)
      14:             {
      15:                 return true;
      16:             }
      17:         }
      18:         return false;
      19:     }
      20: }

    As with most DirectX code you come across, it’s rather cryptic and ugly. Here’s what this method will look like after the conversion to use the DirectX managed classes:

       1: public bool InVideo
       2: {
       3:     get
       4:     {
       5:         if (surface != null)
       6:         {
       7:             SurfaceCaps ddsc = surface.SurfaceDescription.SurfaceCaps;
       8:             return ddsc.VideoMemory;
       9:         }
      10:         return false;
      11:     }
      12: }

    Much nicer and more readable (well, as readable as DirectX code can ever be).

    In any case, this is a better place to be but it’ll be awhile before I can commit all this work (and I’m flying without unit tests which is killing me here). I’m now re-living my past life when I knew what DDSCAPS_VIDEOMEMORY was (and regretting it as it all comes flashing back to me now). This probably won’t get us much closer to an XNA implementation of Terrarium but it’ll cause me to pull out less of my hair when we do (I think).

    This fix will be in a 2.1 release that I’ll pump out when I get back from vanishing into the backwoods of British Columbia next week (sorry, but we geeks do need our downtime once in awhile).

    I really need to sit down with Kyle Baley and Donald Belcham at ALT.NET Canada and have a few beers over this Brownfield effort for sure.

  • Reintroducing Terrarium, now with 2.0 goodness!

    imageTo skip to the chase… http://www.codeplex.com/terrarium2

    Origins

    A long time ago, on a development team far, far, away, some bright dude (or dudette) came up with the idea of Terrarium.

    Terrarium was a .NET 1.x game/learning tool that was aimed at getting people interested in .NET and building cool stuff. In Terrarium, you can create herbivores, carnivores, or plants and then introduce them into a peer-to-peer, networked ecosystem where they complete for survival. Terrarium demonstrates some of the features of the .NET Framework, including Windows Forms integration with DirectX®; XML Web services; support for peer-to-peer networking; support for multiple programming languages; the capability to update smart client, or Windows-based, applications via a remote Web server; and the evidence-based and code access security infrastructure.

    Terrarium was created by members of the .NET Framework team in the .NET Framework 1.0 timeframe and was used initially as an internal test application. At conferences and via online chats, Terrarium provided a great way for developers to learn about the new .NET programming model and languages as they developed creatures and introduced them into a peer-to-peer ecosystem.

    The Windows SDK team evolved the game in the .NET Framework 2.0 timeframe, but it wasn’t worked on for over two years. As a result, the source code for Terrarium 2.0 doesn’t use the very latest .NET technologies.

    Now here we are and it’s 2008, long past that 1.x product. A few months ago I got the bright idea to resurrect the project. After all, 1.x was long gone from the developers toolkit but the premise of building battle bugs and having them duke it out in a virtual eco-system was still just too plain cool to pass up. I thought it would make for an interesting project and get some renewed interest in .NET, and more specifically upgrade it to the latest framework and goodies out there. Hey, XNA is here and writing DirectX goo is a thing of the past.

    The Long And Winding Road

    So with my ambition and fearlessness of the Microsoft release monster, I trudged into the mouth of the beast. I hit up as many people I could find that were still around and pinged them about Terrarium.

    Terrari-who?

    That’s the general response I got for the most part. It’s been 6+ years and most of the original team has moved on. The challenge was to get anyone in Microsoft to find the unreleased source to this project, let alone even remember it.

    image

    I pictured a giant warehouse much like the last scene in Raiders of the Lost Ark. Boxes and boxes with cryptic product codes and license keys on them, all packaged up for someone to unearth someday. That someone was going to be me. Terrarium is my Lost Ark. So I persevered and continued to bug everyone I knew, finally ending up at Scott Guthrie who finally put me in touch with Lisa Supinski, Group Manager with the current Windows SDK team.

    Lisa was instrumental at getting everything going and handling all the details of making this a reality. Without her, it wouldn’t have come to this point. From there the journey was fraught with danger, snakes, legal papers to read, source code to fix, and agreements to sign (did I mention the snakes?) and lots of emails, phone calls, and secret handshakes.

    The fruit of our labour is upon us so now I proudly present…

    Terrarium 2, Electric Boogaloo!

    whidbey_image001

    (okay, we’ll drop the Electric Boogaloo part)

    Here We  Go

    The new Terrarium comes in two forms, the client and the server. The client consists of a few parts including a local Terrarium client executable (which also doubles as a screensaver), and SDK documentation and samples for building your own creations. The local Terrarium client and run your own critters but you’ll need a server to connect to if you want it to interact with other creations.

    The client can run in two modes:

    • Terrarium Mode – 1) The user may run alone, without peers. In this case, the ecosystem presented on the screen represents the whole of the ecosystem. This is good for creature testing purposes. 2) The user may also elect to join with a select group of peers, expanding the ecosystem across all of the participating peer computers. This is simple to do. Each participating user opts into a special, private network by entering an agreed upon character string in the “channel” textbox on the Terrarium console. Upon entering that string, the user’s computer is matched with only those computers which also entered that same string.
    • Ecosystem Mode – This is the standard mode, in which the user’s computer runs just a small slice of an ecosystem which spans all of the participating peer computers, worldwide.

    In both modes, you can develop your own creatures or you can watch as other developers’ creatures battle it out for survival by running Terrarium as a standalone application or as a screensaver.

    The server is two parts. First there’s the web server part which consists of a single web server that provides a user interface for monitoring a Terrarium server (and all the critters uploaded to it) and there are web services that are consumed by the client (for uploading creatures, getting stats, interacting with peers, etc.). The server also includes some SQL scripts and installation instructions for setting up the database. Any flavour of SQL Server will work (2000, 2005, Express). 2008 is untested but should work fine. The scripts are pretty simple (the tables are pretty basic) and there are some stored procedures which could be ported to work with other servers (MySQL, Firebird, etc.) but that’s an exercise I’ll leave to the reader.

    Custom Creatures

    When creating a creature, you have control over everything from genetic traits (eyesight, speed, defensive power, attacking power, etc.) to behaviour (the algorithms for locating prey, moving, attacking, etc.) to reproduction (how often a creature will give birth and what “genetic information,” if any, will be passed on to its offspring). Upon completing the development process, the code is compiled into an assembly (dynamically linked library, or DLL) that can be loaded into the local ecosystem slice, viewable through the Terrarium console. When a creature is initially introduced in Ecosystem Mode, ten instances of it are scattered throughout the local ecosystem. No more instances of that creature may be introduced by that user or any other on the network until the creature has died off completely. By contrast, if running in Terrarium Mode, an infinite number of instances of a given creature may be entered into the environment.

    Once the creature is loaded into Terrarium, it acts on the instructions supplied by its code. Each creature is granted between 2 and 5 milliseconds (depending on the speed of the machine) to act before it is destroyed. This prevents any one creature from hogging the processor and halting the game.

    Within each peer in the network, a blue “teleporter” ball rolls randomly about. If the user is running with active peers logged in (either in Ecosystem Mode or using a private channel in Terrarium Mode), whenever this blue ball rolls over a creature, that creature is transported to a randomly selected peer machine.

    In the SDK zip file there’s a help file and several samples to get you up and running instantly with a local Terrarium. Feel free to modify these or use them as a starter for your own new creations. Code samples are in both VB.NET and C#.

    The Road Ahead

    image

    Putting Terrarium on CodePlex was intentional as it’s meant to be a collaborative piece. Getting the system out there is three fold and having it on CodePlex supports this:

    1. Get the code out there for all to see and dissect
    2. Get people setting up Terrarium servers and creating bugs (virtual ones for the game, not defects)
    3. Extending the game as a learning tool and introducing new features to breathe new life into this puppy

    Like I said, the current build is for 2.0. I didn’t want to delay the release while I upgraded it to 3.5 since I wasn’t going to be adding any value (yet) to the codebase and there might be some challenges with 3.5 and the DirectX code (I haven’t tried an upgrade yet, so it could “just work”). The other challenge is driven by you, being the fact that not everyone is building in Visual Studio 2008 and targeting the 3.5 framework. So I didn’t want to exclude a large number of developers by forcing them to 3.5. I think time will tell (via the CodePlex forums and feedback on this project) when the right time to move to 3.5 will be (and how, for example will we maintain a 2.0 and 3.5 codebase?). I don’t have all the answers but I’m here to listen and juggle the kittens for everyone.

    What’s planned? Here’s my product backlog that will probably make it’s way onto the Issues page on the CodePlex project. These are just seeds for ideas, I’m sure you guys can come up with better ones.

    • 3.5 framework/Visual Studio 2008 upgrade (possibly split off and have dual solutions/project files?)
    • Leverage 2.0 language features. Much of the code was 1.1 so generics and other goodness wasn’t there. The current codebase is compiled and built on Visual Studio 2005/2.0 Framework but not really making use of the features (yet). For example, all WinForms are 1.1 style (i.e. no partial classes). Same with the 3.5 upgrade where more cool stuff could be done all over the codebase.
    • Extend the current system by adding new features. Not sure off the top of my head what those features would be but there’s plenty of room for improvement.
    • Bug hunt. I don’t have a list from Microsoft of bugs that were there but no software is perfect. I’m sure things will crop up. We’ll log them in the Issue tracker, you guys should vote on them, and we’ll fix them up as they’re prioritized by popularity.
    • ClickOnce install of the Terrarium Client from a Terrarium Server. This would be a nice-to-have since ClickOnce is a breeze to keep clients updated. However it would require some reshuffling of the current client as it requires additional files and ClickOnce has limitations on what it can put on a users machine.
    • VSI project template add-ons so people can create new creatures in Visual Studio quickly and easily (this would be a value-added mod and pretty simple to do).
    • XNA upgrade/port. This is pretty major as DirectX isn’t really all that abstracted away in the current system but the hope would be to bring Terrarium to the Xbox 360 (complete with networking support). This is probably a 4.0 release that could be a year or so away (but would kick the llamas’ butt)
    • Documentation isn’t awesome yet. The SDK help file has been updated and is current (built with the latest release of Sandcastle) but some of the documentation files are a little out of date.
    • The server project website is a bit of a mess (read:disaster). It was built in the 1.1 days and never updated. It contains a mixture of code behind files, raw class files, and aspx pages with embedded code. In short, it needs to be rewritten. The web services are okay, although with moving to 3.5 we should probably look at using WCF instead.

    Jumping into the project is not for the casual developer. As this codebase came from Microsoft there are some guidelines and constraints we’re going to follow. The first being team members. Please understand this is neither the Blue Monster talking or me being an uber-control freak, it’s just how it is. So if you’re interested in joining the team and contributing there are a few things that have to happen:

    1. First off, you’ll need to submit a patch to me as a sample of what you’re planning to do or an example of how you’re looking to extend things. This would be something meaningful, but doesn’t have to be an epic contribution (like porting DirectX to XNA). The patch itself won’t go in by me, it’s your golden ticket into the world of the Terrarium team. You will have to modify the codebase with the changes once you gain access (below). I know, it’s rather convoluted and you can beat me up next time  you catch me on the street. I don’t make up the rules, I just make sure everyone in the sandbox is playing by them.
    2. Second, you’ll need to be committed to development. The “submit a patch and run” technique won’t cut it here so we’re looking for some kind of commitment to the project. There’s a signup process involved (requiring you to digitally sign a Microsoft agreement, don’t worry it’s quick, painless, and pretty cool technology to boot) so becoming a team member is a bit more involved than your average open source project.

    Like I said, it’s a little more tasking than a typical CodePlex project and there are constraints we can talk about via email or whatever if you’re really interested in enhancing or extending Terrarium and becoming a member of the team.

    image

    You can grab the various packages now from the release page on CodePlex here. There are packages in various formats:

    • Client – This is the client installer. You can run a local terrarium for testing creations and connecting to remote servers.
    • Server – This is the server installer and consists of a webserver along with some SQL server files (and instructions for installation). This allows you to setup a server for other people to upload their beasties to.
    • SDK – This contains the documentation for building new animals along with some samples (in both VB and C#). You’ll need the client installed first in order to use this package.
    • Source – This is the source code package for the entire system. Unzip this and load it up to do customizations. See the notes above for contributing back to the project.

    Just a couple of final notes.

    Client/Server versions are very sensitive. This is due to security and not allowing clients to “take over” the server or upload malicious code. So if you’ve decided to create your own fork of the code or are running a “custom” server, be aware that only clients that are keyed to your server (based on version) will work. Other clients may have issues connecting or interacting with your server.

    The server setup is not fully automated (and probably could be via a MSBuild script or PowerShell script) so there’s some manual intervention needed. The website installs via an installer but you’ll need to create a database and run the scripts provided then do some manual editing of the web.config file to connect to the db. This is all documented in the server package. If you do spin a server up let us know (via the CodePlex project). Maybe we’ll have a dedicated wiki page with active servers people can connect to or something.

    I’m also thinking of setting up a new domain and website for a creature exchange program. Upload your creatures, put them to battle, and show them off. Sort of a Digg for Terrarium. Let me know if you have ideas on this or want to help out (I always have 10x more ideas than I have time for). In any case, they’ll be more blog posts to come on building critters and the fine art of Terrarium A.I. (the “A” is for Artificial and the “I” is for intelligence. Wait, what’s the “A” for again?).

    I do have a Terrarium 2.0 server up and running at http://terrariumserver.com that you can use for testing (which may or not be fully operational when you read this due to power outages in Vancouver). It’s a playground but can be used for checking out your battle bugs before you unleash them on other unsuspecting victims. This server will always be running the latest version of the server and have the most current (working) features available.

    This is a “1.0” type release since it’s the first release of the source code. A few things (as you’ve read) have been done along the way and it’s by no means perfect or complete. It’s just the first step of the journey.

    Differences from the Previous Version

    For those that remember (or even still have copies of the old version of the program) I wanted to point out a few differences that you (or may not) notice in comparison.

    • Several custom executable are missing from the 2.0 release, namely the custom skin tool and some other utilities. We’re working on finding these and/or rebuilding them.
    • The custom charting component was removed from the server website and is not available. The project is trying to stay true to an out-of-the-box experience so the decision was not to clutter up the core project with 3rd party utilities and libraries. This functionality may return in some form, once there’s a way to do it with the core .NET framework
    • Documentation you find may refer to items or concepts that are non-existent in the 2.0 version (this is mainly prevalent in the Client UI as that has changed quite a bit). The documentation is an on-going effort and will evolve over time.
    • Some “features” in the Client are not working or wired up. For example the “Report a bug” button does nothing. They’ll be various bits and pieces that are like this which, again, will come with time.

    Credit where credit is due

    While this was my labour of love the past couple of months, I really want to thank everyone involved from the Microsoft side in getting this project going. Shout outs especially to Lisa from the Windows SDK team who’s become my best friend over the past couple of months and really got things moving on the MS side. Without her the Ark would still be boxed up somewhere in that warehouse.

    Communities are not created, they’re grown and it takes time. I’m taking a chance on this project (as is Microsoft) in the hopes that it *will* spark some creativity and contribution. The discussion forums on CodePlex are there to talk about it and the Issue Tracker is to suggest features and report bugs. Who knows, given time to grow, we may be talking about this same time next year with a plethora of Terrarium resources out there. At least that would be a nice place to be and it can happen with you.

    So there you go. Have at it. Build some creatures, learn some .NET and game programming, but above all… have fun!

  • You know you've been playing too much LEGO Indiana Jones when...

    It's a great game, but don't let it take over your life 

    • You jump around the house hoping to trigger the door open to that last golden artifact
    • You instinctively target anything that looks like it could produce studs while walking around campus/work
    • You don't go too far away from your spouse in the fear you may reappear somewhere else unexpected
    • You start targeting everything with a hook in it with your bullwhip and try to pull it down
    • You don't worry too much about getting hurt since you'll probably pick up a heart somewhere
    • You create torches and toss them around in the backyard, thinking you'll blow up some hidden latch
    • You hop on the back of your dog, hoping to leap off and onto your roof
    • You push on a wall as you walk down your living room hallway looking for secret entrances
    • You carry a shovel and a book around with you, just in case

  • Microsoft StyleCop, Totalitarian Rules

    I got turned onto a fairly new tool by a friend and was interested in checking it out. It's called Microsoft StyleCop and done in the style of FxCop but rather than analyzing assemblies it looks at code for formatting and style rules.

    The original use was within Microsoft for keeping code across all teams consistent. Imagine having to deal with hundreds of developers moving around an organization like Microsoft where there are dozens of major teams (Windows, Office, Visual Studio, Games, etc.) and millions of lines of code. It helps if the code is consistent in style so people moving between teams don't have to re-learn how the "style" of that new team works. Makes sense and I can see where there's benefit, even in smaller organizations.

    As an example, here's a small User Interface utility class for long(ish) running operations. It's simple but works and is easy to use:

    using System;
    using System.Windows.Forms;
     
    namespace UserInterface.Common
    {
        /// <summary>
        /// Utility class used to display a wait cursor
        /// while a long operation takes place and
        /// guarantee that it will be removed on exit.
        /// </summary>
        /// <example>
        /// using(new WaitCursor())
        /// {
        ///     // long running operation goes here...
        /// }
        /// </example>
        internal class WaitCursor : IDisposable
        {
            private readonly Cursor _cursor;
     
            public WaitCursor()
            {
                _cursor = Cursor.Current;
                Cursor.Current = Cursors.WaitCursor;
            }
     
            public void Dispose()
            {
                Cursor.Current = _cursor;
            }
        }
    }

    One could even argue here that the class documentation header is somewhat excessive, but this is meant to be a framework class that any application could use and maybe deserves the <example/> tag.

    Maybe it's my formatting style but I like using the underscore prefix for class fields. This is for two reasons. First, I don't have to use "this." all over the place (so the compile can tell between a parameter variable, local variable, and class variable. Secondly, I can immediately recognize that "_cursor" is a class wide variable. Sometimes we have a policy of only referencing variables via Properties so for example I could tell if this was a problem if I saw a method other than a getter/setter use this variable. The debate on underscore readability can be fought some other time, but for me it works.

    After running StyleCop on this single file (I wasn't about to deal with all the voilations in the entire solution) it created this list of violations:

    • SA1600: The field must have a documentation header.
    • SA1600: The constructor must have a documentation header.
    • SA1600: The method must have a documentation header.
    • SA1633: The file has no header, the header Xml is invalid, or the header is not located at the top of the file.
    • SA1309: Field names must not start with an underscore.
    • SA1200: All using directives must be placed inside of the namespace.
    • SA1200: All using directives must be placed inside of the namespace.
    • SA1101: The call to _cursor must begin with the "this." prefix to indicate that the item is a member of this class.
    • SA1101: The call to _cursor must begin with the "this." prefix to indicate that the item is a member of this class.

    Hmmm, that's a lot of problems for such a little file. Now grant you, when you run FxCop against any assembly (even Microsoft ones) you get a whack of "violations". They range from actual, real, critical errors that should be fixed, to annoyances like not enough members in a namespace. Any team using FxCop generally has to sift through all the violations and decide, as a team, what makes sense to enforce and what to ignore. StyleCop has similar capabilities through it's SourceAnalysisSettingsEditor program (buried in the Program Files directory where the tool is installed or via right-click on the Project you're performing analysis on). It allows rules to be ignored but it's pretty simplistic.

    I think one of the biggest issues with the tool is the fact that it goes all Chef Ramsey on your ass, even if its code created by Microsoft in the first place. For example create a new WinForms project and run source analysis on it. You'll get 20+ errors (even if you ignore the .Designer generated file). You can exclude designer files and generated files through the settings of the tool, but still its extra work and more friction to use the tool this way. It might be debated that the boilerplate code Visual Studio generates for new files (which you can modify but again, more work) should conform to the StyleCop guidelines. After all Microsoft produced both tools. However this would probably anger the universe as the "new" boilerplate code would look different from the "old".

    There are other niggly bits like the tool insisting on documenting private variables so pretty much every property, method, and variable (public, private, or otherwise) will all have at least an extra 3 lines added to it should you enforce this rule. More work, more noise.

    I'm somewhat torn on the formatting issues here. What it suggests doesn't completely jive with me, but that might be style. After all, the tool is designed to provide consistency of code formatting across multiple disparate sources. However unless you're a company with *no* code and start with this tool, you'll probably be ignoring certain rules (or groups of rules) or doing a lot of work to try to bring your code to match the violations you'll stumble on. It's like writing unit tests after the fact. Unit tests are good, but writing them after the code is done (and even shipped) has a somewhat diminished cost to benefit ratio.

    In getting this simple class up to snuff I had to not have the urge to hit Ctrl+Alt+F in ReSharper (ReSharper's default formatting totally blows the violations) and hold my nose on a few things (like scattering the code with "this." prefixes and seemingly redundant documentation headers). Documentation is a good thing but my spidey-sense has taught me that comments mean something might be wrong with the code (not descriptive enough, should have been refactored into a well-named method, etc.). It only took a few minutes to shuffle things around, but I look at large codebases that you could point this tool at and think of weeks of code reformatting and what a cost that would be.

    In any case, here's the final class with the changes to "conform" to StyleCop's way of life:

    //-----------------------------------------------------------------------
    // <copyright file="WaitCursor.cs" company="MyCompany">
    //     Copyright MyCompany. All rights reserved.
    // </copyright>
    //-----------------------------------------------------------------------
    namespace UserInterface.Common
    {
        using System;
        using System.Windows.Forms;
     
        /// <summary>
        /// Utility class used to display a wait cursor
        /// while a long operation takes place and
        /// guarantee that it will be removed on exit.
        /// </summary>
        /// <example>
        /// using(new WaitCursor())
        /// {
        ///     // long running operation goes here...
        /// }
        /// </example>
        internal class WaitCursor : IDisposable
        {
            /// <summary>
            /// Holds the cursor so it can be set on Dispose
            /// </summary>
            private readonly Cursor cursor;
     
            /// <summary>
            /// Default constructor
            /// </summary>
            public WaitCursor()
            {
                this.cursor = Cursor.Current;
                Cursor.Current = Cursors.WaitCursor;
            }
     
            /// <summary>
            /// Resets the cursor back to it's previous state
            /// </summary>
            public void Dispose()
            {
                Cursor.Current = this.cursor;
            }
        }
    }

    I feel this is a lot of noise. Sure, it could be consistent if all files were like this but readability is a funny thing. You want code to be readable and to me this last version (after StyleCop) is less readable than the first. Documenting default constructors? Pretty useless in any system. What more can you say except "Create an instance of <T>". Documenting private variables? Another nitpick but why should I? In this class you could probably rename it be _previousCursorStyle or something to be more descriptive and then what is documentation going to give me. Have I got anything extra from the tool as a result? I don't think so.

    If it's all about consistency something we've done is to share a ReSharper reformatting file which tells R# how to format code (when you press Ctrl+Alt+F or choose Reformat Code from the ReSharper menu). It has let us do things like not wrap interface implementations in regions (regions are evil) and decide how our code should be formatted like curly braces, spacing, etc. However it completely doesn't match StyleCop in style or form. You could probably tweak ReSharper to match StyleCop "to a certain extent" but I disagree on certain rules that are baked into the tool.

    For example take "this." having to prefix a variable. To me a file full of "this" prefixes is just more noise. ReSharper agrees with me because it flags "this.PropertyName" as redundant. Maybe the debate whether it's a parameter or a field is probably a non-issue. If a method is short, one can immediately identify the local variables and distinguish them from member fields and properties with a glance. If it is long, then there is probably a bigger issue than the code style: the method simply should be refactored. For whatever reason, Microsoft thinks "this." is important and more readable. Go figure.

    Rules can be excluded but it's a binary operation. Currently StyleCop doesn't have any facility on differentiating between "errors" and "warnings" or "suggestions". Maybe it should but then with all the exclusions and errors->warnings you could configure, the value of the tool quickly diminishes. Enough errors being turned into warnings and you would have to argue the value of the tool at all, versus a ReSharper template.

    In any case, feel free to try the tool out yourself. If you're starting with a brand new codebase and are willing to change your style to match a tool then this might work for you. For me, even with public frameworks I'm working on, the tool seems to be more regiment and rules than being fit for purpose. I suppose if you buy into the "All your StyleCop are belong to us" mentality, it'll go far for you.

    For me it's just lots of extra noise that seems to provide little value but YMMV.

  • ALT.NET Canada Open Spaces is LIVE!

    It’s Canada Day, and what better way to celebrate geekdom with a 100% All-Beef Canadian announcement.

    We’re very proud to present the first major Canadian Open Spaces ALT.NET event, hosted right here in my hometown of Calgary August 15-17, 2008. The event follows the same principals and format as the previous ALT.NET Open Spaces hosted in Seattle and Austin.

    image

    We’ll be hosting it at the local University and they’ll be tons’o’fun as with any of the ALT.NET events. Lots of cool local Canadian guys will be there. Vancouver or Bust Greg Young, the Bahama Connection with Kyle Baley, the regular NHibernate Mafia gang headed up by James Kovacs, the Edmonton Contingent with Donald Belcham, Justice Gray will be doing hair product demos, and a host of others will be there.

    Don’t miss out on this once in a lifetime event!

    Registration is open now and space is limited to the first 100 participants. You can visit the site here and get in on the coolest event in Western Canada (besides that Stampede thing).

  • Tree Surgeon 2.0 Released

    We’ve released version 2.0 of Tree Surgeon. This is the first major release since I took the project over from Mike Roberts.

    image

    This release adds the following features:

    • 2005 and 2008 support in addition to the original 2003 support
    • Ability to choose the unit test framework generated (NUnit or MbUnit)
    • Updated tool resources to latest versions
    • NAnt build scripts will use the appropriate .NET versions (1.1, 2.0 and 3.5)
    • Minor bug fixes
    • Improved User Interface

    Please download the latest project files here. Source code, zip file, and installer are all available.

  • Tree Surgeon is Looking for a Logo

    A new release of Tree Surgeon is forthcoming and I’m looking to the community to see if someone with some time and artistic skills on their hands would be interested in putting together a logo to kick things up a notch. Tree Surgeon is a .NET development tree generator. Just give it the name of your project, and it will set up a development tree for you in seconds.

    The UI for Tree Surgeon is pretty simple and it doesn’t need to be extravagant (you run it once to create a new solution tree and you’re done, this generally doesn’t happen dozens of times a day unless you’re someone like me). However it would be nice to have something snappy as a splash screen and give the product a little branding.

    image

    The image will be used in the product itself (probably as a splash or something) and on the website (to replace the icky picture of logs I put there so long ago) so please size it accordingly.

    Get your crayons out and thinking caps on and let’s see what you can come up with. The rewards? My undying gratitude, exposure on the blog (for the 10 readers that I have), and 15 minutes of fame (and I’ll toss in some XBox 360 games or something cool that I can dig up, Microsoft or .NET related of course; no Java swag here).

    Any ideas are welcome and I’ll post the entries here on the blog (please provide your name, email (if desired), and a link to your website (if desired)). Please submit your entries to me via email.

    Thanks!

  • Testing Castle Windsor Mappings Part Deux

    In my original post on testing Windsor Container mappings, I posted a spec to run whenever you are using Castle Windsor in your project. It basically ran through your configuration file and ensured all the mappings worked. This was meant to be a safety net to catch a rename or namespace move in the domain (which wouldn't update the configuration file).

    It worked pretty good and has helped us catch silly errors but we were getting pain with mappings on classes like this:

    public partial class FinderGrid<T> : UserControl, IFinderGrid<T> where T : Entity
    {
    }

    Generics were a funny thing so you get an error like this:

    System.ArgumentException: GenericArguments[0], 'T',
    on 'UserInterface.FinderGrid`1[T]' violates the constraint of type 'T'.
    ---> System.TypeLoadException: GenericArguments[0], 'T',
    on 'UserInterface.FinderGrid`1[T]' violates the constraint of type parameter 'T'.
       at System.RuntimeTypeHandle._Instantiate(RuntimeTypeHandle[] inst)
       at System.RuntimeTypeHandle.Instantiate(RuntimeTypeHandle[] inst)
       at System.RuntimeType.MakeGenericType(Type[] instantiation)
       --- End of inner exception stack trace ---
       at System.RuntimeType.ValidateGenericArguments(MemberInfo definition, Type[] genericArguments, Exception e)
       at System.RuntimeType.MakeGenericType(Type[] instantiation)
       at Castle.MicroKernel.Handlers.DefaultGenericHandler.Resolve(CreationContext context) 

    We put an exception handler around the test, but it was butt ugly. After some posting on the Castle mailing list and discussion with a few people I came up with a way to handle any generic mapping you have. Here's the updated spec that will deal with (hopefully) any mapping:

    [TestFixture]
    public class When_starting_the_application : Spec
    {
        [Test]
        public void Verify_Windsor_Container_mapping_configuration_is_correct()
        {
            IWindsorContainer container = new WindsorContainer("castle.xml");
            foreach (IHandler handler in container.Kernel.GetAssignableHandlers(typeof (object)))
            {
                if (handler is DefaultGenericHandler)
                {
                    Type[] genericArguments = handler
                        .ComponentModel
                        .Service
                        .GetGenericArguments();
     
                    foreach (Type genericArgument in genericArguments)
                    {
                        Type[] genericParameterConstraints =
                            genericArgument.GetGenericParameterConstraints();
                        foreach (Type genericParameterConstraint in genericParameterConstraints)
                        {
                            container.Resolve(
                                handler
                                    .ComponentModel
                                    .Service
                                    .MakeGenericType(genericParameterConstraint));
                        }
                    }
                }
                else
                {
                    container.Resolve(handler.ComponentModel.Service);
                }
            }
        }
    }

    This will handle any mapping with constraints and the name isn't tied to your test (originally I found one that worked but I had to specify the generic type when trying to set the constraint). This is a 2.0 solution and not as pretty as it could be with LINQ and 3.5 but it works.

    Hope this helps!

    P.S. Here's a silly creepy version for those that dig anonymous delegates to the extreme. Lamdbas would just make most of this syntax sugar go away:

    [Test]
    public void Verify_Windsor_Container_mapping_configuration_is_correct()
    {
        IWindsorContainer container = new WindsorContainer("castle.xml");
        foreach (IHandler handler in container.Kernel.GetAssignableHandlers(typeof (object)))
        {
            if (handler is DefaultGenericHandler)
            {
                new List<Type>(handler
                                   .ComponentModel
                                   .Service
                                   .GetGenericArguments())
                    .ForEach(
                    delegate(Type argument)
                        {
                            new List<Type>(argument.GetGenericParameterConstraints())
                                .ForEach(
                                delegate(Type constraint)
                                    {
                                        container
                                            .Resolve(
                                            handler
                                                .ComponentModel
                                                .Service
                                                .MakeGenericType(constraint));
                                    }
                                );
                        }
                    );
            }
            else
            {
                container.Resolve(handler.ComponentModel.Service);
            }
        }
  • ADO.NET Enity Framework Vote of No Confidence

    Over the past year or two, I've been a casual observer into the Entity Framework coming out of Microsoft. Being an ALT.NET guy, the world tends to revolve around NHibernate for me so I've already got an excellent OR/M tool in my toolset. One of the big issues with EF that we've recognized is the general direction Microsoft has taken with it, following a data centric model rather than an object one. One of the first principles I picked up when I started doing OO programming (back in the SmallTalk days in the 80s) was that objects are defined by behavior, not their properties. Yes it's true that objects are pretty thin without data, but data is not my centre of the universe.

    What we see on the horizon is a new breed of VB6 drag-n-drop programmers embracing EF as the next Messiah. We see a new generation of developers focused on mapping their data models and missing the target of architecting and constructing well designed systems. As a result, the community has put together an open letter to Microsoft outlining these concerns. The letter outlines the deficiencies in the EF specifically related to the values we see as solid working practices. It's late to the game and Microsoft probably isn't going to make any sweeping changes so close to the release so don't expect any big short-term changes however as Dave Laribee says, it's good to be explicit and professional about criticisms so this is one of those.

    What's interesting too is that Microsoft has put tgoether what they call the Data Programmability Advisory Council, a team of notable people including Eric Evans, Martin Fowler, and Jimmy Nilsson (all very non-data centric guys in their own right). I'm not quite sure what they will do or how they fit into the entire fray but it might be a step in the right direction (whatever that direction may be).

    You can view the entire letter here where you can sign at the bottom to show your support and you can view the list of signatories here.

  • Creating a Native Win32 Splash Screen

    Splash screens are all the rage. They’re cool, they’re fun, and they can be a pain to program right.

    I though I would share a native Win32 splash solution with you on this rainy night in June (well, it is June here and it is raining from where I am, YMMV). This is slightly different from your typical splash screen as it’s done using the Win32 API calls and it’s fired off before the .NET Forms engine even gets started. As a result it’s quick and snappy and doesn’t intrude on your normal WinForms programming.

    First off, let’s look at how we’re going to invoke it. Here’s the Program class that will call our normal splash screen:

       1: [STAThread]
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   2:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Main()</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   3:</span> {</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   4:</span>     SplashWindow.Current.Image = <span style="color: rgb(0, 0, 255);">new</span> Bitmap(<span style="color: rgb(0, 0, 255);">typeof</span>(Form1), <span style="color: rgb(0, 96, 128);">"splash.jpg"</span>);</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   5:</span>     SplashWindow.Current.ShowShadow = <span style="color: rgb(0, 0, 255);">true</span>;</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   6:</span>     SplashWindow.Current.MinimumDuration = 3000;</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   7:</span>     SplashWindow.Current.Show();</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   8:</span>&nbsp; </pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   9:</span>     Application.EnableVisualStyles();</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">  10:</span>     Application.SetCompatibleTextRenderingDefault(<span style="color: rgb(0, 0, 255);">false</span>);</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">  11:</span>     Application.Run(<span style="color: rgb(0, 0, 255);">new</span> Form1());</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">  12:</span> }</pre>
    

    Note that it’s the first thing called (even before we do Application calls or create the main form). We’re launching it using a JPG image but any embedded or external resource file will do (JPEG, PNG, BMP, etc.). There are a couple of options we turn on here like showing a shadow (if the OS supports it) and setting a duration.

    The duration is the minimum number of milliseconds to display the splash screen for. For example you can set this to 5000 (5 seconds) and no matter how much or how little your app is doing, the splash screen will stay around for at least this long. This is handy to keep it up even though your app may find a burst of speed and be ready before you know it.

    Now that we’ve launched the splash screen, we just go about our normal business and at the right time launch the main window and tell the splash screen to go away. We’ll do this in our Main form class by overriding the OnActivate event:

    protected override void OnActivated(EventArgs e)
    {


        base.OnActivated(e);


        if (_firstActivated)


        {


            _firstActivated = false;


            SplashWindow.Current.Hide(this);


        }


    }

    The call here to SplashWindow.Current.Hide passes in the Form derived class of our window. The SplashWindow will keep a reference to this Form object so later in the splash thread it can invoke Activate on the Form class to pop it up after destroying itself. The “_firstActivated” variable is just a boolean set on the Form class and set to true at creation. This prevents us from hiding the splash screen if the main form is activated more than once (can happen).

    And that’s it for using the SplashWindow. Simple huh? Here’s our splash in action over top of our important business application (another Bil Simser UI Special):

    Splash Window:

    image

    Main Window with Splash in Front:

    image

    Ready to work!

    image

    One of the other options you can do with this class is to provide it a custom event handler. This is called during the WM_PAINT event and will allow you to get a copy of the Graphics object that the SplashWindow owns (the surface holding the bitmap image you provide) and a Rectangle class of the boundaries of the splash window. This is really handy for doing fancy stuff to your splash screen without having to fuss around with the image itself.

    For example here’s the call to our SplashWindow again but using a custom handler:

       1: [STAThread]
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   2:</span> <span style="color: rgb(0, 0, 255);">private</span> <span style="color: rgb(0, 0, 255);">static</span> <span style="color: rgb(0, 0, 255);">void</span> Main()</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   3:</span> {</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   4:</span>     SplashWindow.Current.Image = <span style="color: rgb(0, 0, 255);">new</span> Bitmap(<span style="color: rgb(0, 0, 255);">typeof</span>(Form1), <span style="color: rgb(0, 96, 128);">"splash.jpg"</span>);</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   5:</span>     SplashWindow.Current.ShowShadow = <span style="color: rgb(0, 0, 255);">true</span>;</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   6:</span>     SplashWindow.Current.MinimumDuration = 3000;</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   7:</span>     SplashWindow.Current.SetCustomizer(CustomEventHandler);</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   8:</span>     SplashWindow.Current.Show();</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   9:</span>&nbsp; </pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">  10:</span>     Application.EnableVisualStyles();</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">  11:</span>     Application.SetCompatibleTextRenderingDefault(<span style="color: rgb(0, 0, 255);">false</span>);</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">  12:</span>     Application.Run(<span style="color: rgb(0, 0, 255);">new</span> Form1());</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">  13:</span> }</pre>
    

    And here’s the custom handler. This simply uses the GDI+ function of drawing a string on the Graphics surface. You could use this to display version information from your app, progress messages, etc. without having to build a form and adding labels to it.

       1: private static void CustomEventHandler(SplashScreenSurface surface)
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   2:</span> {</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   3:</span>     Graphics graphics = surface.Graphics;</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   4:</span>     Rectangle bounds = surface.Bounds;</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   5:</span>&nbsp; </pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   6:</span>     graphics.DrawString(<span style="color: rgb(0, 96, 128);">"Welcome to the Application!"</span>,</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   7:</span>                         <span style="color: rgb(0, 0, 255);">new</span> Font(<span style="color: rgb(0, 96, 128);">"Impact"</span>, 32),</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">   8:</span>                         <span style="color: rgb(0, 0, 255);">new</span> SolidBrush(Color.Red),</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: white;"><span style="color: rgb(96, 96, 96);">   9:</span>                         <span style="color: rgb(0, 0, 255);">new</span> PointF(bounds.Left + 20, bounds.Top + 150));</pre>
    
    <pre style="border-style: none; margin: 0em; padding: 0px; overflow: visible; font-size: 8pt; width: 100%; color: black; line-height: 12pt; font-family: consolas,'Courier New',courier,monospace; background-color: rgb(244, 244, 244);"><span style="color: rgb(96, 96, 96);">  10:</span> }</pre>
    

    And here’s the result:

    Splash with custom event handler

    Of course this is pretty simplistic. I would love to see some creative geniuses out there do something cool with this. Since your have the Graphics object (already loaded with the splash screen image) and the GDI+ at your disposal, the sky is the limit. Let me know what you come up with.

    Like I said, this is simple and easy. A few lines of code in your main program to launch it, one line to hide it, and the initialization is just providing it an image to display. All of the code is available for download below in source and binary form. You can just add the SplashLib.dll to your projects and go. Or feel free to enhance it, the code is released under the Creative Commons Attribution-Share Alike 3.0 Unported License. You can share and adapt it (even in commercial work) but please give back to the community.

    One side note, .NET doesn’t provide an interface to winuser.h and other Win32 headers so the structures and constants that are needed by SplashWindow to work are in the class. If you’re a ReSharper junkie you’ll notice that R# complains that the file has a lot of dead code. Don’t for the love of all that is holy remove the unused structure members as the SplashWindow will fall down and go boom.

    Of course there’s room for improvement so feel free to send me your changes or enhancements!

    SplashLib Source Files


    SplashLib Binary Files

    Enjoy!