Friday, April 06, 2007

Backwards Compatibility

At work we are currently developing a suite of applications that are expected to work on Windows XP and, I assume, eventually Windows Vista. The entire development team refreshed their workstations just after Vista went RTM and was available to MSDN subscribers. At the time Visual Studio 2005 wasn't fully supported in Vista and there were too many unknowns so an executive decision was made to stay with XP on the dev machines. I feel it was the right decision at the time.

However, there was one particular reason for staying with XP that I wasn't sure I could agree with. There was a concern that by developing under Vista we might lose touch with XP and find ourselves developing a product that has accidentally used facilities only available in Vista or that differ in Vista. The result, of course, is that we may lose compatibility with XP and discover the problem too late in development to solve it without large time, effort, or cost consequences.

I have decided to use my blog as a place of discussion for reasons why this concern is, or is not, valid. My bias is that the concern is unnecessary but I invite comments on anything I haven't considered.

Acceptance Testing

For each iteration of a product that we produce it goes to our testers to find bugs and usability issues before it can be considering for release. Our testers utilise a clean Windows XP environment inside Virtual PC to perform the suite of tests against the product. Any problems in our software that are specific to XP should be picked up here.

Visual Studio Limitations

Visual Studio 2005 was released well before Windows Vista was close to completion. As a result the IDE itself is not aware of any new features in Vista. In fact, it doesn't even fully support all the features introduced in Windows XP, one aspect that comes to mind is correct rendering of 32-bit icons. Any Vista specific features that are used will have be done so explicitly and presumably with prior consideration.

Framework 3.0

The new .NET Framework 3.0 features are included out of the box in Vista. Updates have been released for Visual Studio 2005 to provide project items and designers for the new WPF, WCF, and WWF components. However, just as we need to ensure that our XP clients need to install .NET Framework 2.0, version 3.0 is supported on XP and Server 2003, and is redistributable via the same methods as 2.0.

Features Lost

One of the primary focuses of Windows Vista has been to improve security. Many popular applications have required (or still require) an update to support Vista due to a change in the operating system's default behaviour. I believe there is a greater risk of utilising a Windows XP feature that will break under Vista because security has been tightened or the feature has been removed altogether (anyone still using WinHelp?).

Practice

With these points in mind I am in the process of building a Vista 64-bit development machine for the home office. With this configuration I intend to experience first hand what issues there are in terms of application compatibility and problems with the development process itself. Anything I find along the way that supports or disproves my beliefs above will help to decide when the development team should migrate to Vista, if at all.

If you have any experiences yourself with this situation I would appreciate your input.

 Friday, March 02, 2007

Self-executing SQL scripts

I am currently preparing our deployment processes for our most recent software product at work. A fair portion of it involves executing SQL scripts to install and update SQL Server 2005 databases. The deployment will ultimately be performed to several sites by staff who are less familiar with SQL Server than the development team.
 
At the moment it involves executing the SQLCMD tool from the command line with appropriate parameters to connect to the server, process the script and output a log. However, I feel that this is just one more error-prone step that should be avoided. Some time ago I read about Polyglots on Wikipedia and I was inspired. I thought I would try to write a batch file that also contained a SQL script. The ultimate goal would be a single-file that could be double-clicked and the script would run and the log would be created.
 
This meant it must be written so the batch command interpreter would ignore the SQL and the SQLCMD tool would ignore the batch commands. The trick was finding the keywords and structures in each language that had similar syntax. After several attempts I settled on GOTO, proving that it isn't totally harmful.
 
Here is a base example of my solution that you can use to create your own self executing SQL scripts. Just put it in a file with a ".cmd" extension and change as appropriate:
 
:setvar NUMBEROFROWS 15
 
GOTO startofpolyglotsqlbatch /*
:startofpolyglotsqlbatch
@echo off
sqlcmd.exe -S MySqlServer -E -e -i "%~f0" -o "%~f0.log"
more "%~f0.log"
goto endofpolyglotsqlbatch
::
*/
startofpolyglotsqlbatch:

USE MyDb;
GO
SELECT TOP $(NUMBEROFROWS) * FROM MyTable;
GO

/*
:endofpolyglotsqlbatch
::
*/
 
I have added some colour to highlight how the code is interpretted. The initial GOTO is parsed by both the batch command processor and SQLCMD but goes to a different destination for each. The green text is only seen and processed by the batch parser and the blue text is only seen and processed by SQLCMD. The grey text can be replaced with content relevant to your script. This is designed to only work with SQL Server 2005 and only on Windows XP, Windows Server 2003, or later.
 Saturday, February 24, 2007

What rolls down stairs, alone or in pairs?

I recently discovered that our databases in SQL Server 2005 using the Bulk Logged recovery model were not getting their logs backed up by the Log Backup maintenance plan. I did some searching to no avail and ending up posting a question to the MSDN forums. I was told this is a known bug in SQL 2005 RTM and SP1 and will be fixed in SP2. SP2 is now available and the problem is fixed... but not very well.
 
The Log Backup maintenance plan allows you to choose "all databases" when asked what to back up. In pre-SP2 it would select all databases on the server, filter out the ones with inappropriate recovery models, then execute a BACKUP LOG statement against the remaining databases. The problem was that instead of only excluding Simple recovery models databases, it excluded Bulk Logged also. I imagined the fix in SP2 would be to correct the filter. Not so.
 
Now, in SP2, the maintenance plan selects all databases on the server and attempts to execute a BACKUP LOG statement against each of them. Those with appropriate recovery models succeed, the others fail. Unfortunately the failures are then treated by SQL Agent as a job error and the maintenance plan reports as failed even though all the right databases were backed up successfully.
 
The benefit in SP2 is that the Bulk Logged databases actually get backed up now because you couldn't back them up at all with a maintenance plan previously even if you explicitly selected the Bulk Logged databases only. The downside is that I have to update my maintence plan everytime a new database is added or the recovery model changes. I appreciate that you should give more time to getting backups right on a production database, but on the development servers this is tedious.
 Tuesday, August 15, 2006

Components need good ISite

Accessing a Form from inside a Component is surprisingly convoluted in the .NET Framework. I created a new class that inherits from Component that would provide extra functionality to any Form I dropped it on. Ideally, it would search it's parent Form for various types of controls and add handlers to certain control events to provide special behaviour. Unfortunately, neither the Component.Site or .Container properties provide access to the parent Form or ContainerControl.

Some of the components included with the Framework are interacting with their parents so I know it's possible. I dropped a ErrorProvider onto a new Form and checked the designer code to see how it was instantiated. I then opened up Reflector, headed directly for the ErrorProvider component and followed this rather bizarre code path:

  1. The designer code creates a private member "components" initialised as a new ComponentModel.Container.  
  2. It then creates the ErrorProvider passing the new Container to its constructor.  
  3. The ErrorProvider constructor simply calls the Container.Add method passing itself.  
  4. The Container.Add method (the trick bit), after extensive validation and array sizing, creates a new ComponentModel.Site and assigns it to the (ErrorProvider) component's Site property.  
  5. The ErrorProvider.Site property stores a reference to the incoming Site then proceeds to request a ComponentModel.Design.IDesignerHost via a call to Site.GetService.  
  6. The ErrorProvider then retrieves the IDesignerHost.RootComponent property, casts it to a ContainerControl and assigns the value to it's own public ContainerControl property.  
  7. The designer then serializes the value of this property to the designer code of the parent Form as "Me.ErrorProvider1.ContainerControl = Me".

The ErrorProvider, and probably many other components included with the Framework, use the behaviour of the designer's code generator to ensure it will have access to it's container at run-time. This feels tightly-coupled yet fragile all at the same time with these odd interdependencies.

Sadly, a Component cannot find trace its roots any other way, so my custom component was forced to borrow this ugly technique. Like the ErrorProvider, my component too must be instantiated differently if created programmatically instead of in the Visual Studio designer.

At least now I, and hopefully you, understand how the Component, Site, and Container classes interact with each other and if you want to access the Form from your own Component, know you can.

 Sunday, August 06, 2006

Adding New

I've spent too much time in Reflector again these past weeks. One of the instigators was the BindingSource AddingNew event. If you happen to handle this event and assign your own object to e.NewObject property, don't expect the Position on the BindingSource to refer to the new item as it normally would.
 
The BindingSource explicitly checks to see if you have set e.NewObject yourself and if you have, it doesn't bother to update the Position to refer to your new item at the end of the list. You will need to set the Position property yourself too.
 Wednesday, May 03, 2006

Cold Cup(Of T)

I often wonder exactly which collection interface I should implement in a new collection class or which I should use as a method parameter. I like to choose the highest level interface that will provide access to the properties and methods I need. Instead of following the links through MSDN Library everytime I quickly created a map in Visio so I can see all the relationships between the standard framework collection interfaces and classes, including the new generic items. It probably isn't complete but I think it is good guide for getting information at a glance.
 
It was interesting to discover the significant differences between the generic and non-generic ICollection interfaces. The original non-generic ICollection provides enumeration support and a Count property. The new generic ICollection(Of T) goes further and includes support for adding and removing items, much more like IList than ICollection. It doesn't even inherit from ICollection which unfortunately means that while most of the standard implementation classes of ICollection(Of T) also implement ICollection, I can't safely pass ICollection(Of T) objects to AddRange methods or common collection constructors.

Deblector arrives

Felice Pollano has just released the first version of the new Deblector addin for debugging within Reflector. It's only alpha at the moment and has some obvious bugs but it is very promising. In the past I have looked at having a Virtual PC with a hacked rebuild of the core framework with debugging enabled. Now I can step into framework code just as easily within the familar Reflector interface. I don't have much experience with IL so I was a little confused at first when multiple lines of IL seemed to execute at once but I quickly realised they all applied to method call setup. I suspect, if possible, we may even be able step through the framework viewed in our chosen language. Keep an eye on this one.
 Monday, May 01, 2006

Role your own

I discovered an annoying limitation in the SQL Server Management Studio today. The GUI does not offer an option to add a Database Role as a member of another Database Role. In my case I wanted to add my "bigAppAdmins" role to the "bigAppUsers" role so all administrators are implicitly users also. Unfortunately I had to resort to the sp_addrolemember stored procedure to achieve this. If I didn't already know that roles could be members of other roles I might have been convinced that SQL Server didn't support it.
 Monday, April 24, 2006

Captain's Log, Stardate NULL

Today I discovered a need for a data-bound DateTimePicker to support the display and input of NULL values. I remembered reading a blog a short while ago about someone else who had already developed a solution.
 
Google helpfully pointed me to Alexander Shirshov's original solution that I had read before. However I also spotted Claudio Grazioli's solution on Code Project which apparently correct some bugs in Alexander's implementation. I downloaded the source, gave it a try and it works very neatly.
 
If anyone would like the source for the NullableDateTimePicker in VB.NET instead of C# just leave a comment.