Tuesday, 26 April 2011

Assuming culture

I've just had an interesting bug report for Aussie Toilets. The stack trace starts with this:

System.Reflection.TargetInvocationException: TargetInvocationException ---> System.FormatException: FormatException
à System.Decimal.Parse(String s, NumberStyles style, IFormatProvider provider)
à Gardiner.PublicToilets.Services.DataService.<LoadManifest>b__3(XElement x)

There's a small clue there, but the other big hint was the user's regional setting:

Culture: fr-FR

It turns out in a number of places I'd been assuming the default number format, particularly instances of Decimal.Parse(), Convert.ToDouble(), and the popular String.Format().

So if you're in France, you'd be used to seeing "123.49" written as "123,49". The bug in the application was that the data being read was originally formatted in the former, but with the user's regional settings set to 'French (France)' the parsing methods were assuming it would be formatted as the latter.

I've resolved the problem in this instance by explicitly specifying the InvariantCulture, as the data isn't displayed to the user. If it were intended for user display, then allowing the user's regional settings to influence the display would be quite appropriate.

FxCop (aka Visual Studio Code Analysis) will warn you about these kinds of issues, specifically CA1305 – Specify IFormatProvider. I've changed this warning (and a few others) to an error to ensure I don't get caught by it again.

Visual Studio Code Analysis Settings - changing warnings to errors

Expect Aussie Toilets v1.4 soon!


When I first started working on Aussie Toilets, I was doing it from the perspective of a parent who has had first-hand experience trying to find a public toilet for a young child. I hadn't really considered another market for the app might be the overseas visitor. Maybe I should consider providing translations for some of the labels for these users too.

Thursday, 21 April 2011

Aussie Toilets app v1.2

'Aussie Toilets' version 1.2 is now available in the Windows Phone marketplace. This is my Windows Phone 7 app that shows the nearest public toilets to your current location.
The latest release includes the April 2011 dataset, and significant performance improvements. Specifically, toilet locations should load almost instantly. So now if you're in a hurry to find the nearest public toilet, you'll be relieved (ha ha) to know you won't be kept waiting any longer than necessary.
I'm quite chuffed that 'Aussie Toilets' is currently sitting at no. 3 in the top selling apps of the 'Navigation' category in Zune. Not sure if this is just for Australia or global. So far I've had over 1,200 downloads, which isn't too bad at all.
PS. I have received a bug report from an Austrian user of Aussie Toilets – turns out I hadn't tested the app outside Australia! This may explain an issue I had with getting 1.2 passing the Marketplace requirements (as I assume the testing would be taking place in North America). So expect v1.3 very soon!

Update 24th April, 3.30pm
Version 1.3 is now available in the marketplace

Monday, 18 April 2011

The big Four Zero

Today I am 40 years old!

I know this because as you can see the in the photo below, I'm wearing a badge (made by my daughter) that says "40 years old" Smile

Photo of David wearing a '40 years old' badge

Yesterday I celebrated the occasion with family and friends at a picnic lunch in Belair National Park. The weather couldn't have been better and I think everyone really enjoyed themselves (I know I did).

Extra special thanks to my lovely wife Narelle who worked very hard to make it a fantastic day, Narelle's Mum & Dad for decorations, barbecue knowledge and other help, my Mum and Dad for having me in the first place Smile, my sister Fiona for putting together a wonderful birthday scrapbook, and my kids for helping with the games.

Saturday, 9 April 2011

Renaming date-named folders using PowerShell

Since I've been using the Windows 7 Import Pictures and Videos wizard to upload photos from our digital camera, we've used the directory naming scheme of YYYY-MM-DD. Prior to this, I'd written my own custom photo importer in C++ as I didn't like the naming schemes that Windows XP offered. Unfortunately I'd chosen YYYYMMDD instead.

I'm now consolidating all our digital photos onto our Windows Home Server. This makes them easier to browse on the big screen using Windows Media Center, and has the added benefit that they also get backed up to the cloud via a subscription to CrashPlan.

I discovered the downside to having the different naming schemes when you go to view the photos in Media Center – it displays the folders out of order because they don't all follow the same format.

PowerShell to the rescue:

cd \\homeserver\photos
dir | Where-Object {$_.Name -match "^\d{8}$" } | Rename-Item -NewName { $_.Name -replace "^(\d{4})(\d{2})(\d{2})(.*)", "`$1-`$2-`$3`$4" }

This finds directories matching the old naming scheme and renames them to conform to the new one.

My C++ importer imported all photos into a single folder, so to avoid overwriting the same folder if you imported twice on the same day, I would add a .0 (or .1 etc) to the end of the folder to ensure it was unique. There weren't too many of these though, so I dealt with them manually.

Friday, 8 April 2011

Free licenses for WP7 EQATEC Profiler

If you're a Windows Phone 7 developer, you may have come across Eqatec's Profiler. As far as I know, it's currently the only performance profiler that supports WP7 applications (Red Gate have indicated that they will support WP7 in 2011 Q4).

I've made use of Eqatec Profiler already, as there is a free version available, but with some restrictions (such as only profiling a single assembly).

Now in exchange for trialling their analytics product, they're offering upgrades to give you free licenses to the less-restricted versions.

As well as WP7, the product also support profiling regular .NET, Silverlight, Services, ASP.NET and even .NET CF.

I participated in the analytics evaluation and got 21 points which entitled me to a 'Professional' profiler license (normally $US399).

So what did I think of the analytics product? Well it seems quite solid, and didn't have any noticeable impact on my test apps. If you were selling software commercially then it might be of interest, but the price is prohibitive for those of us who have only released free software so far.

Monday, 4 April 2011

Windows 7 Boot to VHD

For my own reference, some useful resources about boot to VHD:

Following instructions from http://technet.microsoft.com/en-us/library/dd979534%28WS.10%29.aspx


create vdisk file=C:\VHD\test.vhd maximum=25000 type=expandable      select vdisk file=C:\VHD\test.vhd      attach vdisk      create partition primary      assign letter=v      format quick FS=NTFS label=VHD



PS C:\VHDs> .\Install-WindowsImage.ps1 -WIM D:\sources\install.wim

Index   Image Name
[1]     Windows 7 Home Basic
[2]     Windows 7 Home Premium
[3]     Windows 7 Professional
[4]     Windows 7 Ultimate


PS C:\VHDs> .\Install-WindowsImage.ps1 -WIM D:\sources\install.wim -Apply -Index 4 -Destination v:
Applying "Windows 7 Ultimate" to v:...
WARNING: This may take up to 15 minutes...

V:\Windows\System32\bcdboot V:\Windows
bcdedit -v
bcdedit /set {GUID} description=”Windows 7 VHD”

Useful utility BCDEdit - http://neosmart.net/downloads/software/EasyBCD/EasyBCD%202.0.2.exe

Saturday, 2 April 2011

Including generated files as input for a project

Sometimes you may have a project in your solution who's sole purpose is to generate files that need to be referenced by a second project. If the files are fixed, then it's just a matter of adding a link to them in the second project, but what about when you don't know at build time how many files will be generated?

It turns out that MSBuild can handle this situation. For example, given the following solution:


Note that we've added a reference for the Generate project to the IncludeProjectOutputs project. We've also set 'Copy Local' to false as the only reason for the reference is to enforce building the projects in the right order (we don't actually refer to the Generate assembly within the IncludeProjectOutputs code).

So that the executable output from the generator project is run, add the following to the generator project's project file:

  <Target Name="AfterBuild">
    <Message Text="After build execute $(TargetPath)" Importance="high" />
    <Exec Command="$(TargetPath)" />

In the project that should be including the generated files, add the following:

    <Target Name="IncludeGenerated" BeforeTargets="ResolveAssemblyReferences">
            <Content Include="$(ProjectDir)..\Generate\*.txt" >

In this instance, we're including all .txt files from the ..\Generate folder. Because we define the <Content /> item, they're added as content (equivalent to the 'Content' build action). I haven't tested it, but conceivably you could also add to <Compile/> or <References/> too.

The ability to add ItemGroup elements within a Target element was added in .NET 3.5. The advantage of this is that the filenames matching the pattern of the Include attribute are evaluated in the execution phase. This contrasts with normal ItemGroup elements, which are assigned values during the evaluation phase of the build. See MSBuild Items for more details.

Building this project gives the following result:

Microsoft (R) Build Engine Version 4.0.30319.1
[Microsoft .NET Framework, Version 4.0.30319.431]
Copyright (C) Microsoft Corporation 2007. All rights reserved.

Build started 2/04/2011 8:49:43 AM.
Project "C:\dev\Sandbox\IncludeProjectOutputs\IncludeProjectOutputs.sln" on node 1 (default targets).
  Building solution configuration "Debug|Mixed Platforms".
Project "C:\dev\Sandbox\IncludeProjectOutputs\IncludeProjectOutputs.sln" (1) is building "C:\dev\Sandbox\IncludeProjectOutputs\IncludeProjectOutputs\IncludeProjectOutputs.csproj" (2) on node 1 (default targets).
Project "C:\dev\Sandbox\IncludeProjectOutputs\IncludeProjectOutputs\IncludeProjectOutputs.csproj" (2) is building "C:\dev\Sandbox\IncludeProjectOutputs\Generate\Generate.csproj" (3) on node 1 (default targets).
  A TargetFramework profile exclusion list will be generated.
Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.
Skipping target "_CopyOutOfDateSourceItemsToOutputDirectory" because all output files are up-to-date with respect to the input files.
  Generate -> C:\dev\Sandbox\IncludeProjectOutputs\Generate\bin\Debug\Generate.exe
  After build execute C:\dev\Sandbox\IncludeProjectOutputs\Generate\bin\Debug\Generate.exe
  Generated file
Done Building Project "C:\dev\Sandbox\IncludeProjectOutputs\Generate\Generate.csproj" (default targets).
  A TargetFramework profile exclusion list will be generated.
Skipping target "GenerateTargetFrameworkMonikerAttribute" because all output files are up-to-date with respect to the input files.
Skipping target "CoreCompile" because all output files are up-to-date with respect to the input files.
  Copying file from "C:\dev\Sandbox\IncludeProjectOutputs\Generate\stuff.txt" to "bin\Debug\stuff.txt".
  IncludeProjectOutputs -> C:\dev\Sandbox\IncludeProjectOutputs\IncludeProjectOutputs\bin\Debug\IncludeProjectOutputs.exe
Done Building Project "C:\dev\Sandbox\IncludeProjectOutputs\IncludeProjectOutputs\IncludeProjectOutputs.csproj" (default targets).
Done Building Project "C:\dev\Sandbox\IncludeProjectOutputs\IncludeProjectOutputs.sln" (default targets).

Build succeeded.
    0 Warning(s)
    0 Error(s)

Time Elapsed 00:00:00.20