Wednesday, 24 August 2011

Nice LINQ Path.Combine trick

It’s a simple thing – but it’s a nice thing, instead of multiple explicit calls to Path.Combine:

using System;
using System.Linq;

namespace PathAggregation
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine(
		AggregatePath("some", "interesting", "path")
            );
            
	    Console.ReadKey();
        }

        static string AggregatePath(params string[] pathParts)
        {
            return pathParts.Aggregate(System.IO.Path.Combine);
        }
    }
}

Wednesday, 17 August 2011

System.BadImageFormatException with NUnit on 64bit Windows

This wasted a couple of hours until inspiration struck. In this case it was very useful to have a standalone app that ran the code through its paces without running unit tests.

I’d been developing tests for an x86-targeted library. The tests were fine on our 32bit workstations, but broke when we ran on our 64 bit build machine.

System.BadImageFormatException : Could not load file or assembly ‘XXX, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. An attempt was made to load a program with an incorrect format. 

Tests run on dev workstations went fine.

peverify for the assembly indicated that it was fine.

A simple app that just called LoadLibrary for the assembly indicated it was fine.

A sophisticated proprietary test app that ran the code through its paces behaved as expected.

Build machine was 64 bit OS, compared to 32 bit workstations. I assumed – because of the above – that the library was fine, so I couldn’t figure out why the test was failing. I couldn’t hit the right search on Google for it until it struck me that of course – it was just the nunit tests that were failing. Searching for:

nunit badimageformatexception 64 bit

immediately brought up a wealth of information. On 64 bit machines you need to run the specific x86-targeted nunit apps to test x86-targeted assemblies.

http://stackoverflow.com/questions/208985/nunit-exe-cannot-work-on-vista-64bits-if-x86-build

Tuesday, 16 August 2011

Today’s subtle waste of time

I hit a wrinkle with a TeamCity build today – the build was just hanging, unexplained.

TC was actually quite useful, showing that the build agent was running a script which had then spun up (basically)

rundll.exe shell32,openas_rundll some_file.ico

and it took me a little while rooting around to work out that something was opening the “Open as … “ dialog for the file some_file.ico. No wonder the build was hanging – there was no-one to acknowledge the dialog box.

I could not figure out why it was being spun up in the first place. The build was running a dos script that was simply zipping up a set of files, some_file.ico being one of them.

7za.exe <some args>^
second_file.dll^
third_file.dll^ 
some_file.ico^
some_other_file.dll^
...

That all seemed fine – and yet it’s almost as if some_file.ico was being opened, not appended to the zip that 7za was creating.

The trick lies in the line before. See it?

The build script running it had ‘^ ‘ at the end of a line instead of ‘^’.

(Frustratingly 7za actually thinks it has finished at that point and writes out “Everything is Ok”.)

Tuesday, 9 August 2011

Tools for diagnosing library load problems

Today I had one of those days where you engage in an extended exercise of hide and seek trying to work out why it works on our machines but not on yours, Yes, I was hunting dependencies for a software deployment.

As is often the case, today the dependencies were hidden underneath some third party code and that third party code was using LoadLibrary to load dependencies at runtime.

Furthermore we wipe out and reset the path – to include certain third party libraries – with a cmd we use to open our VS solution. If you happen to forget that for a moment then tracking down dependencies becomes that little bit harder.

Now, in general it’s hard to give a one-size-fits-all process for tracking down library dependencies (Yes, Tess had the right idea with sets of debugging tutorials). On the other hand, a couple of tools didn’t quite spring to mind as quick as they should have, and some were unknown to members of the team I’m on, so I thought I might write myself a list of tools useful in diagnosing these problems.

Visual Studio In debug, use the Immediate Window to run

System.Environment.GetEnvironmentVariable(“PATH”)

to work out whether your path is being managed unexepectedly, and

System.IO.Directory.GetCurrentDirectory()

to work out where you are.

You can drag a module/dll onto VS and open up the manifest as well.
Fuslogvw Helps you monitor managed assembly binding – and tells you where the runtime is trying to load assemblies from.
Depends Dependency walker determines the (native) dependency tree of a module, and tells you if anything’s missing. If there’s an hourglass next to a dependency it means it’s late loaded – and may not be a problem.
Windbg If you run an executable in windbg (Open Executable, ‘g’ to go) it’ll tell you which modules it loads, and where from.

To debug LoadLibrary fails:

x MyModule!*LoadLib*

locates symbols in MyModule that reference LoadLib.

bu kernel32!LoadLibraryExW ".echo LoadLibraryExW for ->; du dwo(@esp+4); g"

sets a breakpoint for LoadLibrary calls and displays the name of the library that’s meant to be loaded.

These examples are drawn from this page of common windbg commands, which is a good one to have bookmarked.
Process Explorer Can show you which modules have been loaded by a still-running process, and from where it loaded them.

Frequently Depends.exe says that ieshims.dll and wer.dll are missing – if I recall correctly this is associated with an upgrade to Internet Explorer 8, and can basically be discounted in most situations (google search for ieshims and wer.dll should clarify this).

If Depends.exe shows up missing MSVC*{80,90,100}.dll then you’re missing a Visual C++ runtime redistributable. If you’re missing one titled DebugCRT then you’ll probably need to rebuild, as these versions are only available on machines with VS installed. Remember that you shouldn;t assume that these redistributables are installed on machines in a cluster – you might need to package them up alongside your app code to make sure they get out there at deployment time.

Thursday, 4 August 2011

Getting to github

Remember – if you have a git branch you’ve been committing to locally then all you have to do to get it to github – assuming you’ve already registered with github etc – is:

1. Log on to github on the web and create a suitable repository – like Alembic.Tools.

2. Add a remote, and push:

git remote add origin git@github.com:timbarrass/Alembic.Tools.git
git push origin master