Sunday, 28 October 2007

Building Rhino Tools from the trunk

I read about the release of Binsor 2.0, and thought that might be really handy for a current project. The problem is that you need to compile it yourself.

This was causing me a few headaches and one late night after a countless false starts I gave up and posted to the Rhino Tools Dev group.

Prerequisites

You will need the command-line SVN tools (even if you already have TortoiseSVN).

Directory layout

I've used the following directory layout (with SVN repository paths):

I then saved RhinoTools-Trunk\BuildFromTrunk-Config.build.sample to BuildFromTrunk-Config.build and edited it like this:

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Update-All;Build-All;Copy-To-Artifact-Dir" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <!-- Configuration -->
 <PropertyGroup>
 <Configuration>debug</Configuration>
 <Enable-Tests>false</Enable-Tests>
 
 <!-- User Settings -->
 <Dest-Dir></Dest-Dir>
 <Dest-Lib-Dir>$(Dest-Dir)\lib\$(Configuration)</Dest-Lib-Dir>
 <Dest-Tool-Dir>$(Dest-Dir)\tools</Dest-Tool-Dir>
 
 <Tools-Dir>$(MSBuildProjectDirectory)\SharedLibs\Tools</Tools-Dir>
 <NH-Dir>$(MSBuildProjectDirectory)\..\NHibernate-Trunk\nhibernate</NH-Dir>
 <Castle-Dir>$(MSBuildProjectDirectory)\..\Castle-Trunk</Castle-Dir>
 <Rhino-Dir>$(MSBuildProjectDirectory)</Rhino-Dir>
 <Artifact-Dir>$(MSBuildProjectDirectory)\Trunk-Artifacts</Artifact-Dir>
 
 <MSBuildCommunityTasksPath>$(Tools-Dir)</MSBuildCommunityTasksPath>
 <Svn-Dir>$(Tools-Dir)\Subversion</Svn-Dir>
 </PropertyGroup>
</Project>

The final thing that caused me grief was some missing edits to RhinoTools-Trunk\rhino-commons\Rhino.Commons\Rhino.Commons.csproj. Hopefully this will be patched soon, but I had to make the following hand-edits to the csproj file:

Index: Rhino.Commons.csproj =================================================================== --- Rhino.Commons.csproj (revision 908) +++ Rhino.Commons.csproj (working copy) @@ -158,7 +158,9 @@ <Compile Include="Binsor\Extensions\StartableExtension.cs" /> <Compile Include="Binsor\Macros\AbstractBinsorMacro.cs" /> <Compile Include="Binsor\Macros\BaseBinsorExtensionMacro.cs" /> - <Compile Include="Binsor\Macros\BaseNamedBinsorMacro.cs" /> + <Compile Include="Binsor\Macros\BaseBinsorToplevelMacro.cs" /> + <Compile Include="Binsor\Macros\BaseConfigurationMacro.cs" /> + <Compile Include="Binsor\Macros\ParametersMacro.cs" /> <Compile Include="Binsor\Macros\ComponentMacro.cs" /> <Compile Include="Binsor\Macros\ComponentMethodVisitor.cs" /> <Compile Include="Binsor\Macros\ConfigurationMacro.cs" />

I then opened a Visual Studio 2005 Command Prompt ("Run as Administrator" on Vista), and entered:

msbuild BuildFromTrunk.build /t:Build-All

3 minutes and 44 odd seconds later, Rhino.Commons.dll appeared.

One thing to note, this is built of the trunks of NHibernate and Castle Project code, so those bits may or may not be as stable as the most recent public releases.

Friday, 19 October 2007

G3 on the way

It is with great excitement that I can now announce that we're expecting our third child, due in May next year.

Not specifically "one for the country", but at least with our extension almost finished we should have enough room for everyone!

Strongly-typed primary key identifiers

Often the primary keys for tables are integer types. One problem can occur when you accidentally use the OrderID when you really meant to use CustomerID. This bug can happen inside the database and it can also arise in your code data layer.

One solution for this at the code level is to create custom types (eg. OrderIdentifier and CustomerIdentifier) so that the compiler will throw an error if you try and assign or compare different types.

The down-side to this is that because Integers are value types, you can't just inherit from the Integer class. Instead you need to store the actual integer value inside the class and expose it through a property.

eg.

Public Class OrderIdentifier
 
 Private _value As Integer
 Public Property Value() As Integer
 Get
 Return _value
 End Get
 Set(ByVal Value As Integer)
 _value = Value
 End Set
 End Property
 
 Public Sub New()
 End Sub
 
 Public Sub New(ByVal value As Integer)
 Me.Value = value
 End Sub
 
End Class

I've also noticed that NHibernate doesn't like having custom types for primary keys, as it tries to use the System.Type.IsAssignableFrom method to see if it can convert an Integer to the OrderIdentifier object (which fails).

I'm not sure that there's a workaround for that, as I think it would require a class to inherit from the Int32 structure, which isn't possible.

Wednesday, 17 October 2007

ActiveWriter for NHibernate

Like NHibernateAddin, ActiveWriter is an add-in for Visual Studio 2005.

It leverages the DSL functionality to allow you to model classes and relationships and it generates the NHibernate mapping and class files (in VB or C#).

I think this has the potential to meet all my requirements for doing the hard work of class and mapping generation.

Gökhan (the main developer) has done a great job, though his focus is more on C#, so I've submitted some bugs (and worked on some patches) to improve the VB side of things.

One thing that is missing at the moment, is that if you drop tables onto the design surface one at a time, they don't automatically add relations with existing classes. I did discover yesterday that if you drop multiple tables at the same time, it does figure out the relations and add them in.

One of my patches adds support to clean up the class property names. If your database naming strategy means that your column names have some kind of common prefix, you probably don't want that in the property name.

For example, given the following database table:

CREATE TABLE [dbo].[TEST_CONTENT]
( 
 [TC_ID] [int] IDENTITY(1,1) NOT NULL, 
 [TC_TEST] [int] NOT NULL, 
 [TC_CONTENT] [int] NOT NULL
) 
If you set the model's "Property Name Filter Expression" property to the regular expression ^\w+?_ it will then remove the text up to the first underscore for each property name, so that you end up with a class like this:

TestContent Class Diagram

Future improvements

  • Add relations when dropping additional tables
  • Support for custom types for properties
  • Auto-arrange model layout

Wednesday, 3 October 2007

bit columns

I was looking at some T-SQL that RJ had written and noticed he was using 'True' and 'False' when dealing with bit data types.

I've always used 1 and 0, but I think 'True' and 'False' is more obvious, and I think I'll start using it from now on. 

Sure enough, the SQL 2005 Books Online entry for bit (Transact-SQL) mentions this:

The string values TRUE and FALSE can be converted to bit values: TRUE is converted to 1 and FALSE is converted to 0.

Tuesday, 2 October 2007

Monday, 1 October 2007

Mounting ISO files from the command-line

With some recent birthdays, we've acquired some computer games for the kids to play.

The titles include:

  • Arthur's Wilderness Rescue
  • Arthur's Sand Castle Content
  • Arthur's Pet Chase
  • Discovering Dinosaurs
  • Phonics 1 for beginners

Even though these games are quite engaging and the kids really seem to like them, it's amazing at how clumsy some of these applications are to get installed in a 'safe' way.

I install them myself, and then set up shortcuts so that the kids can log in using their username. I am an admin on our home pc, but the other accounts are just regular users.

The games expect to run as Administrator (eg. the "Arthur" titles try and write the saved games back to the Program File installed directory (instead of in the user's profile). As a consequence, I had to fire up cacls.exe to grant Everyone permission to write to this folder.

They also seem to assume you have a VGA monitor - when they try and change the resolution it doesn't always look that good on a LCD display.

They also often require the CD to be in the CD-ROM drive. I find this particularly annoying. The installation should allow me to install everything from the drive onto the hard disk so you don't need to be swapping CD's.

I'm trying to work around this by generating an ISO image of the CD using ISO Recorder, and then mounting and unmounting the image when you want to run the game.

I found FileDisk - a Windows driver and command-line tool to mount and unmount ISO files. I then created a small batch file that I thought should do the job:

@echo off

REM mount cd
"C:\bin\filedisk.exe" /mount 1 "c:\Install\ISO\ArthurWildernessRescue.iso" /cd e:

cd "C:\Program Files\The Learning Company\Arthur's Wilderness Rescue\Launcher"

REM run
"C:\Program Files\The Learning Company\Arthur's Wilderness Rescue\Launcher\TLCLauncher.exe"

REM unmount
"C:\bin\filedisk.exe" /umount e:

I then tried this out with one of the non-admin logins, but sadly it fails with an "access denied" error. It appears that filedisk is using one of the Win32 API calls assuming the current user is an Administrator too.

Filedisk does include source code, so it might be possible to fix this, but I'm guessing it might take a bit of time to figure it out.

Taking "Arthur's Wilderness Rescue" as an example, I looked closer at what files it had left on the CD, and it didn't appear to be many at all!

I located a file "salstartup.xml" and noticed that it was pointing to a file on the CD, so I copied this file onto the hard disk and updated the XML file and it appears that it all works now without the CD being in the drive.