Friday, October 17, 2008

Weekly digest of interesting stuff

  • News that the D language that is part of the up-coming Oslo release has been renamed to M.  Wonder what that stands for?
  • Silverlight 2 goes RTM.  Various useful links: 
  • Changing extensions in IIS 7 - the post is about removing the .svc extension, but the method used works for pretty much any type of URL renaming that you want to perform
  • A Channel9 video discussing the provider model in LINQ.  I've not watched it yet, but Erik Meyer is a smart guy and normally worth watching.  Beware of his shirts though, they are normally pretty shocking!
  • Apple released updates to their MacBook & MacBook Pro lines.  These are nice looking machines, and with bootcamp they will run Vista just fine.  They aren't the cheapest laptops around, but they do compare reasonably well on price with other manufacturers for similar specs / designs.

Visual Studio Tests and "The location of the file or directory xxx is not trusted"

If you've ever downloaded stuff from the internet (from XP SP2 onwards), you'll know that the OS marks the file as un-trusted and that to use it you need to right-click, go to properties and click "Unblock".  If you download a zip and extract it's contents without having unblocked the zip, then you probably also know that every extracted file will also be marked as un-trusted. 

Referencing a file from an un-trusted source within Visual Studio (for example, adding a reference to the latest library that you've just downloaded) will work just fine, but when you try to run your unit tests they will barf with a "location of the file or directory is not trusted" error.

The top tip is to remember to unblock the zip file before doing the extract; that way, all the files that you extract will also be unblocked and the world will be a happy place (assuming that none of them have viruses, trojans etc!)

If you forget, and if you've now got files scattered all over your project such that deleting them and re-extracting is a pain, then here's another option - ZoneStripper is a handy command-line tool that can run recursively over a directory and get rid of the blocks.  Works like a treat.

Tuesday, October 14, 2008

Running 32 bit .Net applications on a 64 bit machine

Just been having a problem trying to get a .Net application running on my 64bit Vista machine.  The app was compiled using the "Any CPU" flag, which means that it can target both 32 or 64 bit machines.  With this flag set, the .Net bootstrap process loads up the appropriate CLR based upon your machine architecture - if you're running a 32 bit OS, then the 32 bit CLR is loaded and the JIT compiler generates 32 bit code.  If you're running a 64 bit OS, then you can guess what happens - 64 bit CLR and 64 bit code.

For most apps, this is probably exactly the behaviour that you want (although do remember that you need to test on both environments).  If there is a reason why you need to target a specific architecture, then you can change the build settings to force either 32 or 64 bit.  Why would you want to force things?  A good reason would be if you are loading up 32 bit native DLLs for some reason (perhaps your database vendor only ships 32 bit client DLLs, for example).  In this case, quite clearly you need to make sure that your app is also running 32 bit - if not, then when launched on a 64 bit OS, it'll throw a BadImageFormatException at the point that it tries to load the native DLL. 

That's all fine, but what if you've been given an app that needs to run in 32 bit mode, but was compiled with the "Any CPU" flag?  If you've got the code then you could recompile, but what if that's not an option?  Turns out that there's a handy tool called corflags.exe which comes with the SDK.  Using this, you can flip the 32 bit flag in the application without requiring access to the source.  For example:

corflags /32BIT+ /Force TheApplication.exe

the /Force flag is needed if the application is strong name signed - if you omit that flag, then it will fail when run against such assemblies.  Obviously, once the bit has been flipped the strong name is no longer valid.  If you've got access to the private key then you can re-sign.  If you don't have the private key and you need to keep the strong name then I'm afraid you're out of luck.

Friday, October 10, 2008

Weekly digest of interesting stuff

I read quite a few blogs and web sites over the course of each week, and thought it might be useful to do a weekly blog on the things that I've found interesting.  If nothing else, it gives me a way of keeping track of things - but hopefully some of you will find it useful as well...

 

    • The Austrian's now have the first computer network protected by quantum encryption. This stuff has been in the labs for a while, but this is the first (reported) implementation "in the wild".
    • A largely speculative post, but it's one of the first to discuss the new name from Microsoft: Windows Strata.
    • Eager loading in the Entity Framework, and how it differs from LINQ to SQL.
    • New MSBuild extensions library released.
    • "Library Oriented Programming" - is this what we're all doing now?
    • A list of links that details the new stuff, and the broken stuff, in .Net 3.5 SP1. I know it's been out a while, but it's nice to have one place to refer to :)
    • A list of the talks that Don Box wants to see at PDC.  And if Don's interested, then you probably should be too.
    • Some VSTS 2010 features.  It's a while until we'll see this, so it's nice to see what's coming our way.
    • For anyone into encryption,I think you'll find the Silverlight Enigma Machine kind of cute.
    • I've not watched it myself yet, but any video of Anders talking about language design is likely to be worth watching.  If you're into that sort of thing, of course!
    • A really good article on what makes a good software architect.  If you think you are, or think you'd like to be, or work in a team with one, or have the misfortune to be married to one (or, worse, to be married to someone who thinks they are!), then it's worth a read.

Friday, October 03, 2008

WPF Localization, part II

Following on from the previous blog, I'll briefly look here at how to localise strings that you build within your application as opposed to resources that are within the XAML.  There are a variety of options here, but this approach seems pretty simple and plays nicely with the locabaml / csv approach described earlier.

Step 1:

Add a new item to your project, of type Resource Dictionary.  By default, VS will name it Dictionary1.xaml.

Step 2:

Edit the App.xaml file to reference the new resource dictionary.  The markup you'll need is:

<Application.Resources>
   <ResourceDictionary x:Uid="ResourceDictionary_1">
      <ResourceDictionary.MergedDictionaries>
         <ResourceDictionary x:Uid="ResourceDictionary_2" Source="Dictionary1.xaml" />
      </ResourceDictionary.MergedDictionaries>
   </ResourceDictionary>
</Application.Resources>

Step 3:

Let's now add some code and content.  Assuming that you are using the "app" we built in the previous blog, double click on the button in the designer to add a Click event and the corresponding method in the code behind file.  Within the method, add the following code:

MessageBox.Show((string)Application.Current.FindResource("buttonMessage"));

"buttonMessage" is the name of the resource that we want to display - edit the Dictionary1.xaml file to include it:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:system="clr-namespace:System;assembly=mscorlib">

   <system:String x:Key="buttonMessage">Hello World!</system:String>
</ResourceDictionary>

If you are running in the default locale ("en-GB" in our previous example), the app should run and you should get a message box with the text "Hello World" when you click the button.

Step 4:

Back to our friends from before.  Do the following:

  • run "msbuild /t:updateuid" from your project directory
  • build the project
  • run "locbaml /parse" from your bin\debug directory
  • translate the corresponding csv file
  • run "locbaml /generate" to build the new resource dll

(I've not put in the full command lines here, since they are exactly as in the previous blog).

Once you've done this, if you switch culture to your new culture, you should find that the message box now displays the translated text. 

As before, this isn't too invasive on the project - for each string that you handle in code, add a resource to the resource dictionary and use the FindResource() method to retrieve the string.  That's pretty much it.

WPF Localization

There are a good number of articles out there on how to localize WPF resources, including the main one on MSDN.  However, they are all quite long-winded and having now gone through all the necessary steps I thought I'd just document exactly what you have to do.  Hopefully this will be of some help to others.

The support for localization within WPF is actually pretty good, but unfortunately it is not quite as integrated with the IDE as one might like, and does involve some work on the command line.  For all you "point'n'click" warriors, I think the best I can do is to send you here.

Step 1:

Download and compile locbaml.  You can find it here.  Once you've downloaded and "installed" it, head to the directory you chose and go into the "csharp" folder.  In there, you'll see a csproj file.  Either open that in Visual Studio and build, or run msbuild from the command prompt.  Either way, you'll end up with a nice new locbaml.exe just a couple of seconds later.

Step 2:

Create yourself a new WPF project within Visual Studio, and the close the IDE straight away.  Open up the new .csproj file in your favorite text editor, and add the following property to the first PropertyGroup section:

<UICulture>en-GB</UICulture>

where "en-GB" is the culture that you are developing in.  For a full list of culture codes, head here.

Open up the project again, and open the AssemblyInfo.cs file.  Add the following line to the bottom:

[assembly: NeutralResourcesLanguage("en-GB", UltimateResourceFallbackLocation.Satellite)]

If you build & run now, your app should work just fine.  If you take a peek in the bin\debug directory, you'll notice that VS has created an en-BG directory and popped a new dll in there.  This dll is a satellite assembly containing just the resources for that culture. 

Step 3:

Before localizing, let's add some content to our application. Open up Window1.xaml, and add the following as a child of the Grid element:

<Button>Hello</Button>

You can look at all of Fran's blogs for details on how to make it prettier :)

Step 4:

Here's where we drop down to the command line.  Spin up a VS Command Prompt, and cd to the directory that contains your project.  Run the following:

msbuild /t:updateuid

This will walk all the XAML in your project and add Uid attributes to pretty much everything.   It does mess the XAML up a smidge, but that's just how it goes.

Step 5:

Copy the locbaml.exe that you created in step 1 to the bin/debug directory.  Then run:

LocBaml.exe /parse en-GB\WpfLocalization.resources.dll

If all goes well, you should now have a .CSV file containing all the resource information which locbaml has extracted from the default resources dll.  Mine looks something like this:

WpfLocalization1.g.en-GB.resources:window1.baml,Window_1:WpfLocalization.Window1.$Content,None,True,True,,#Grid_1;
WpfLocalization1.g.en-GB.resources:window1.baml,Window_1:System.Windows.Window.Title,Title,True,True,,Window1
WpfLocalization1.g.en-GB.resources:window1.baml,Window_1:System.Windows.FrameworkElement.Height,None,False,True,,300
WpfLocalization1.g.en-GB.resources:window1.baml,Window_1:System.Windows.FrameworkElement.Width,None,False,True,,300
WpfLocalization1.g.en-GB.resources:window1.baml,Button_1:System.Windows.Controls.Button.$Content,Button,True,True,,Hello

The columns in this file are:

  • Baml Name - the name of the compiled XAML stream that is held in the resource dll
  • Resource Key - maps back to the Uid attributes that we created in Step 4.  Actually, it's even better than that, since it doesn't just have the content of the element, it also allows for the modification of some of the other properties.  So in the example above, on the element with the Uid of Window_1, I can change the $Content, Title, Height and Width properties.
  • Localization Category - A value from the LocalizationCategory enumeration
  • Readable: Is the value visible for translation
  • Modifiable: Is the value modifiable during the translation
  • Comments: Any comments - more on this later
  • Value: The value of the property.  This is the chap that needs translating

Step 6:

Translate the file.  Can't help you there :)

Step 7:

So you've now got a new version of the CSV file in the new culture (let's say it's es-ES).  From this, we need to build a new satellite assembly.  Drop the file into the bin\debug directory alongside the original, and then run this:

locbaml /generate en-GB\WpfLocalization.resources.dll /trans:WpfLocalization.resources.CSV /out:es-ES /cul:es-ES

It should be pretty obvious what's happening here - from the information present in the original resource dll, and with the updated values in the CSV, generate a new resource dll in the es-ES directory, for the culture es-ES.  Note that you need to create the output directory first.

Step 8:

Test it.  Either change your locale in the control panel, or add some code to the constructor of your App class (in App.xaml.cs):

public App()
{
   CultureInfo ci = new CultureInfo("es-ES");
   Thread.CurrentThread.CurrentCulture = ci;
   Thread.CurrentThread.CurrentUICulture = ci;
}

Note that you do need to do this pretty early on in the application lifecycle; once resource start being read, then you are fixed in whatever locale you were at the time.  You can't use this approach to switch languages dynamically once the app is loaded - if that's a requirement, then I'm afraid you need to head back to google.

Conclusion

That's it.  It's a bit of an effort first time round, but once you get used to things it's pretty simple.  To summarise:

  • You can pretty much develop your WPF app as normal. (just add the UICulture to the .csproj and the NeutralResourceLanguage attribute to AssemblyInfo.cs)
  • At suitable points, run "msbuild /t:updateuids" to refresh your Uids, and run "locbaml /parse" to get your latest CSV
  • Once translated, run "locbaml /generate" to build a new resource DLL.

What I like is that it doesn't really impact day-to-day development, and it doesn't require a recompile of the main application to add additional languages.

I'll do another blog shortly that extends this to include the localization of strings that are used within code (e.g., exception messages etc.)

Wednesday, October 01, 2008

Apple drop iPhone NDA

It appears that Cupertino does listen to what's going on in the wild...

http://www.appleinsider.com/articles/08/10/01/apple_drops_iphone_nda_for_released_software.html

It's only for for released software, but considerably better than the previous position.

There's a new Process Monitor

It's even had a major version number change - you can get Process Monitor V2.0 here.