Wednesday, 31 October 2007

Problems with the formatting

I'm using windows live writer to do the postings to this blog but I'm finding that the Insert Code plugin is not formatting correctly on the finished blog. I need to get to the bottom of this as my postings are looking rubbish. Bear with me as I try to find out what's going on.


Signing a third party assembly

The other day I had to add a library to our third party tools folder (nmock2 actually) but in order to use it in our code I had to ensure that it had a strong name. Now one way I could have done this is to have downloaded the source code for the assembly and then recompiled adding a strong name. However I found a simpler solution on Adrian Hara's blog that showed how I could use the ILMerge tool from MS Research to achieve the same effect but without the hassle (and there would have been) of recompiling the unsigned module.

Essentially what you do is sign your own assembly and merge in the unsigned assembly, creating a single signed assembly package. This does requires some code compilation but not the original code from the unsigned third party assembly, just some of your own. Being a lazy so an so (:-) I decided to automated the process:

  1. Create temporary assembly (ILMerge.dummy.dll) with a correct strong name. This is my favourite bit as the code I'm using to create this assembly doesn't exist (e.g. echo.>tmp.cs) .
  2. Run ILMerge on this assembly together with the third party one, also specifying the strong name.
  3. Delete the temporary assembly

with a command file and that's it.

Here's a batch file snippet that I used to do all of this:

 1: @echo off 

 2: setlocal

 3: echo.>tmp.cs

 4: set thekeyfile="MyStrongNameKeyFile.snk"

 5: csc /out:"ilmerge.dummy.dll" /target:library /keyfile:%thekeyfile% tmp.cs 

 6: if exist "%%~nf.XXXXX%%~xf" del "%%~nf.XXXXX%%~xf"

 7: for %%f in (%1) do "ILMerge.exe" "ilmerge.dummy.%%~nf%%~xf" %%f /ndebug /keyfile:%thekeyfile% /out:%%~nf.XXXXX%%~xf

 8: if exist "ilmerge.dummy.dll" del "ilmerge.dummy.dll"

 9: del tmp.cs

 10: endlocal

By the way the XXXXX is an identifier I've used to distinguish the output from the original assembly (e.g. preet.dll becomes a signed preet.XXXXX.dll). To use it just save the code snippet above use like this:


 2: C:\temp\thirdparty>dir /b

 3: MyStrongNameKeyFile.snk

 4: NMock2.dll

 5: signasm.cmd


 7: C:\temp\thirdparty>signasm.cmd NMoc*

 8: Microsoft (R) Visual C# 2005 Compiler version 8.00.50727.42

 9: for Microsoft (R) Windows (R) 2005 Framework version 2.0.50727

 10: Copyright (C) Microsoft Corporation 2001-2005. All rights reserved.



 13: C:\temp\thirdparty>dir /b

 14: MyStrongNameKeyFile.snk

 15: NMock2.dll

 16: NMock2.XXXXX.dll

 17: signasm.cmd


 19: C:\temp\thirdparty>

Wednesday, 10 October 2007

SDC TeamBuild Task Clash

Just ran into this and put a Codeplex discussion posting on the Microsoft Codeplex site for Microsoft SDC Tasks for MsBuild, indicating this fault we got with the latest version.

Essentially the team build has Get Source Code target and this calls the Get task in Team Foundation, unless you use SDC in which case the Get task used is from SDC - and boom!

C:\Program Files\MSBuild\Microsoft\VisualStudio\v8.0\TeamBuild\Microsoft.TeamFoundation.Build.targets(331,11): error MSB4064: The "Workspace" parameter is not supported by the "Get" task. Verify the parameter exists on the task, and it is a settable public instance property.

 C:\Program Files\MSBuild\Microsoft\VisualStudio\v8.0\TeamBuild\Microsoft.TeamFoundation.Build.targets(329,5): error MSB4063: The "Get" task could not be initialized with its input parameters.

Heres the changed lines in Microsoft.Sdc.Common.tasks file:

 1: <!-- Not needed so excluded -->

 2: <!-- <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.Changes" />

 3:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.ChangesInInterval" />

 4:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.CreateBranch" />

 5:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.CreateClientFromTemplate" />

 6:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.CreateChangelist" />

 7:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.DeleteBranch" />

 8:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.GetChangelistFromDateTime" />

 9:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.GetChangelistFromLabel" />

 10:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.GetUsersForChangelists" />

 11:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.Integrate" />

 12:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.LabelSync" />

 13:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.ReverseIntegrate" />

 14:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceDepot.Sync" />

 15:  -->

 16:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.Changes" />

 17:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.Checkin" />

 18:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.Checkout" />

 19:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.CreateBranch" />

 20:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.CreateClientFromTemplate" />

 21:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.DeleteBranch" />

 22:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.GetChangelistFromDateTime" />

 23:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.GetChangelistFromLabel" />

 24:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.GetUsersForChangelists" />

 25:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.Integrate" />

 26:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.LabelSync" />

 27:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceTfs.Sync" />

 28: <!-- Not needed so excluded -->

 29: <!-- <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceSafe.Get" />

 30:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceSafe.LabelGet" />

 31:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceSafe.LabelLatest" />

 32:  <UsingTask AssemblyFile="$(TasksPath)Microsoft.Sdc.Tasks.dll" TaskName="Microsoft.Sdc.Tasks.SourceSafe.Changes" />

 33: -->

Tuesday, 9 October 2007

Silly little MsBuild gotcha

I've inherited some custom MsBuild tasks that just worked - until I moved their deployment location from C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 to another directory (e.g. under program files\msbuild).

Once moved they started giving out the message

MSB4062: The "Blah.BlahTask" task could not be loaded from the assembly C:\Program Files\MSBuild\Blah\Blah.BlahTasks.dll or one of its dependencies. The system cannot find the file specified. Confirm that the <UsingTask> declaration is correct, and that the assembly and all its dependencies are available.

Thinking I'd missed a hidden assembly I searched until I was blue in the face. Moving the assembly back made it work again when I got message MSB4036 saying that the task assembly could be found, but that now my new tasks (in another new assembly) were not implementing ITask, or not public.

This was really interesting as I'd written the new tasks from the ref docs and they were indeed public and implemented ITask. So I pulled up the source to the legacy tasks and low and behold they were private classes derived from Task and not explicitly labeled as implemented ITask. Quick recompile sorted not only this problem but also (I figured) the location issue and yep it did.

So the question is why did my new task give a message about other tasks? Maybe it was a glitch as I only saw it once.

Wednesday, 3 October 2007

TFS Cloaking as a way of avoiding the "get all the stuff I don't need for my build"

The source tree has things that you don’t always want. So use the TFS command line program tf  with the workfold command to cloak the stuff you don’t want.  This way a “get specific” or “get latest” will ignore those directories


  • to ignore one directory
tf workfold /server:tfs-server /workspace:"my workspace name" /cloak $/Project1/Prototypes/Directory1

  • to ignore the directories in the in the prototypes directory:

for /f %f in ('dir C:\Development\Project1\Prototypes /ad/b') do tf workfold /server:tfs-server /workspace:"my workspace name" /cloak $/Project1/Prototypes/%f


  • You can only seem to cloak a directory not individual file

  • You cannot decloak a directory that has an ancestor cloaked. So you have to use. 

  • if you’re an UI guy then you use the TFS Manage Workspaces to achieve the same effect. However it does take longer as you have navigate the entire TFS project hierarchy for each cloak.  Which is mucho boring after the second time!manage workspace - cloak