Wednesday, May 03, 2006

This is the beginning of a new series of blogs that I plan on writing. Its called ‘MSBuild Fun’, the idea is that I’ll discuss some examples of how you might use MSBuild, outside of building applications. MSBuild is a tool that certainly is geared toward building applications, but is not limited to that. Knowledge of MSBuild can help you with some small things that come up quite often.

In this example we will consider a relatively simple task, copying a set of files from one location to another. Let’s say that you would like to locate all image files contained in a particular location and copy those files to another. There are a few options; you can use the Windows Explorer to search for all of the image files, and copy-paste them to the other location. There are many problems associated with this approach:

  • If there are files with the same name in a different folder then you will only be able to get 1 copy of it
  • If there is an error during the course of copying the files it will stop all together
  • This doesn’t preserve directory hierarchy
  • You can only include files to be copied, not exclude them

Another option is to use the xcopy command from the command prompt. This is a good method to employ to solve the problems associated wit the previous approach. Using this approach we can continue on error,  and preserve the directory hierarchy.  We can also exclude files from being copied. If you are to perform this task many times that you can simply insert the call into a .bat file to preserve the command.
The approach we will use here is to use MSBuild
Copy task to copy the files from the source to the destination. It solves all the problems associated with the first approach, and throws in a few bonuses. Those are:

  • Syntax for excluding files is very powerful, much better than that for xcopy
  • You can transform the name of the file as you copy it
  • You can skip files that already exist, and haven’t changed, in the destination location
  • In one MSBuild file you could house various different copies. With the batch file approach you are basically limited to one pre file.

From a performance perspective the xcopy and MSBuild approach are pretty much equivalent, so that is not a factor. Now lets have a look at this in action.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="CopyFiles">

    <ItemGroup>

      <FilesToCopy Include="**\*.doc;**\*.txt"

                   Exclude="**\*trash*"/>

    </ItemGroup>

 

    <PropertyGroup>

      <Dest>Dest2</Dest>

    </PropertyGroup>

 

    <Target Name="CopyFiles">

      <Copy SourceFiles="@(FilesToCopy)"

            DestinationFiles="@(FilesToCopy->'$(Dest)\%(RecursiveDir)\%(Filename)%(Extension)')"

            ContinueOnError="true"/>

    </Target>

</Project>

This simple MSBuild project file will copy all Word Documents and text files that don’t contain trash in the filename to another location maintaining the directory hierarchy. As you can see here, in the FilesToCopy item declaration, I’m using the include attribute to include a list of files to be copied, and the exclude attribute to exclude a list of files from being copied. You can place complex wildcard expressions in these attributes to select only the files you are truly interested in.

 

 

Sayed Ibrahim Hashimi

Wednesday, May 03, 2006 6:02:18 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Friday, April 21, 2006

In the June 06 issue of the MSDN magazine you'll find an article that I wrote titled "Inside MSBuild: Compile Apps Your Way With Custom Tasks For The Microsoft Build Engine". As far as I know this will be the first article in print for the release version of MSBuild. Before I wrote this article I noticed a need, that was there was no one good resource for people to go to to learn all the key things they need to really get going with MSBuild. I think this article really does meet that need decently well. The only large topic that wasn't covered in the article is writing custom loggers. There are a few reasons for this; limited number of words, most users won't be interested in writing custom loggers and there is a lot of material about writing custom loggers available. If you are interested in writing a custom logger, I've got examples on this blog and here are a few other places you can visit:
http://msdn2.microsoft.com/en-us/library/ms171471.aspx
http://blogs.msdn.com/msbuild/archive/2005/10/10/479223.aspx

Along with these in my book I present a custom XML logger. If you read the article I welcom your feedback.

Sayed Ibrahim Hashimi

Friday, April 21, 2006 3:13:06 PM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Wednesday, April 05, 2006
If you are using Team Foundation Server as your SCM tool, I hope you're taking advantage of using the Team Build tool to create re-producable public builds for your projects. Very cool, and very useful, especially for those Enterprise applications. As you use Team Build you'll need to make changes to how your build process is executed. You can make the customizations in the TFSBuild.proj file. This is the file that will drive your team build. In this file there are many properties declared that are generated by the New Build Type Creation Wizard. These properties are contained in the first PropertyGroup element in that file. Some of these properties include; Description, DropLocation,BuildDirectoryPath,... which are used internally by Team Build to setup the build. Of course Team Build uses MSBuild to actually execute the build, but some things need to happen before/after MSBuild gets involved. For instance creating the Build report, which require those values. In the ideal world you'd expect for those values to be gathered using the MSBuild Object Model, but this is not the case. Team Build is extracting those values as they are declared.
There has been a few posts about this particular problem on the MSBuild MSDN Forum. Those posts are at:
Post: Property Evaluation Order (beta 3)
Properties in properties
In the post Property Evaluation Order (beta 3) I provide a workaround for most situations, but its not always perfect. Here it is for you to see:

It seems like Team build is not using the msbuild object model to get those evaluated properties, but instead are simply extracting the text value from those property declarations.

I tried to overwirte it in different places in the project file as well, with no luck. It always took the first declaration. I'm guessing that the property is not able to be overwritten because it is passed in as a command line parameter to msbuild.exe by team build. But there is a workaround that solves some of the issues. In your TFSBuild.proj file, modify the DropLocation to one that doesn't use any properties and insert the following towards the bottom:

  <PropertyGroup>

    <RootProjectFolder>ProjectX</RootProjectFolder>

 

    <DropBuildDependsOn>

      FixDropLocation;

      $(DropBuildDependsOn);

    </DropBuildDependsOn>

  </PropertyGroup>

 

  <Target Name="FixDropLocation">

    <CreateProperty Value="$(DropLocation)\$(RootProjectFolder)">

      <Output TaskParameter="Value" PropertyName="DropLocation"/>

    </CreateProperty>

    <Message Text="Drop loc: $(DropLocation)" Importance="high"/>

  </Target>

This prepends the FixDropLocation to the DropBuildDependsOn list of targets, so it will be executed before the DropBuild target. This cause your project drop files to be dropped in the location tat you want. This is able to overwrite the DropLocation property becuase we are using the CreateProperty task to overwrite this instead of the normal property declaration.

This is not however a perfect solution, because your build log will always be located in the DropLocation that was originally declared (the one w/o the property embedded within it). And in the Team build type history the drop location will also have this location as well. But it does place the files where you want them :)

Unfortunately it looks like the DropLocation that is given to TFS is happening outside the scope of MSBuild so I'm not sure you have a lot of options. You can't even pass this as a command line parameter to the tfsbuild.exe utility either. Let me know if this  is not clear.


Sayed Ibrahim Hashimi


Wednesday, April 05, 2006 8:09:52 AM (GMT Daylight Time, UTC+01:00)  #    Comments [2]  | 
Friday, March 31, 2006
In case you haven't already heard a service pack will be released for both VS 2003 & VS 2005 this year! SP1 for VS 2003 is scheduled to ship during the second quarter, and SP1 for VS 2005 in the third. You can read more about this at: http://msdn.microsoft.com/vstudio/support/servicing/. I think its kind of interesting that VS2003 didn't have a service pack for 3 years, yet 2005 is having one not even 1 year later. Perhaps because of all the new features that were shipped with this version, however VS 2003 shipped with many new features as well. Since MSBuild is technically a part of the .NET Redistributable, I'm not sure if the service packs will impact anything related to MSBuild. If I find out more I'll be sure to post more.

Sayed Ibrahim Hashimi

Friday, March 31, 2006 7:07:45 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Thursday, March 30, 2006

Previoiusly I wrote about the Microsoft SDC Tasks library, there is another great resource for MSBuild tasks. This is the MSBuild Tigris Tasks project. This is an open source project, so you can submit your tasks to this library as well. Tigris.org is known for their Source Control Management (SCM) tool, Subversion. I've used Subversion previously and was pleased with it, but my favorite is Team Foundation Server :) If you're using Subversion as your source control you'll be glad to find many task for accessing your repository. From the project's site here is a list of the MSBuild tasks that are either completed or currently under development.

Task

Description

AppPoolController*

Allows control for an app pool on a local or remote machine with IIS installed.

AppPoolCreate*

Creates a new application pool on a local or remote machine.

AppPoolDelete*

Deletes an existing application pool on a local or remote machine.

AssemblyInfo

Generates an AssemblyInfo file using the attributes given.

Attrib*

Changes the attributes of files and/or directories

FileUpdate*

Replace text in file(s) using a Regular Expression.

FtpUpload

Uploads a file using File Transfer Protocol (FTP).

FxCop*

Uses FxCop to analyze managed code.

Mail

Sends an email message.

Math.Add

Add numbers.

Math.Divide

Divide numbers.

Math.Multiple

Multiple numbers.

Math.Subtract

Subtract numbers.

Move*

Moves files on the filesystem to a new location.

NDoc

Runs NDoc to create documentation.

NUnit

Runs tests using the NUnit.

RegistryRead

Reads a value from the Registry.

RegistryWrite

Writes a value to the Registry.

Script*

Executes code contained within the task.

ServiceController*

Task that can control a Windows service.

ServiceQuery*

Task that can determine the status of a service.

Sleep*

A task for sleeping for a specified period of time.

SqlExecute*

Executes a SQL command

SvnCheckout

Checkout files from Subversion

SvnClient

Subversion Client

SvnCommit

Commit files to Subversion

SvnExport

Export files from Subversion

SvnInfo*

Get Subversion information for a file or directory.

SvnUpdate

Update files from Subversion

SvnVersion

Get Subversion revision number of a local copy

TaskSchema*

Generates a XSD schema of the MSBuild tasks in an assembly.

Time*

Gets the current date and time.

Unzip

Unzip a file to a target directory.

Version

Increments a four-part version number stored in a text file

VssAdd*

Adds files to a Visual SourceSafe database.

VssCheckin*

Checks in files to a Visual SourceSafe database.

VssCheckout*

Checks out files from a Visual SourceSafe database.

VssClean*

Removes VSS binding information and status files from a solution tree.

VssDiff*

Generates a diff between two versions of an item in a Visual SourceSafe database.

VssGet*

Gets the latest version of a file or project from a Visual SourceSafe database.

VssHistory*

Generates an XML file containing the history of an item in a VSS database.

VssLabel*

Labels an item in a Visual SourceSafe database.

VssUndoCheckout*

Cancels a checkout of an item from a Visual SourceSafe database.

WebDirectoryCreate*

Creates a new web directory on a local or remote machine.

WebDirectoryDelete*

Deletes a web directory on a local or remote machine

WebDownload*

Downloads a resource with the specified URI to a local file.

XmlRead

Reads a value from a XML document using a XPath.

XmlWrite

Updates a XML document using a XPath.

Xslt*

Merge and transform a set of xml files.

Zip

Create a zip file with the files specified.

 * Items not complete or have not been released.

Sayed Ibrahim Hashimi

Thursday, March 30, 2006 4:21:48 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Tuesday, March 28, 2006

I'm working on an application during my spare time, its called Dreamcatcher. The purpose of this dream is to maintain a digital dream journal, or any journal for that matter. A major goal of the Dreamcatcher is to facilitate finding specific dreams easily, this is going to be accomplished by search mechanisms, and a "tagging" dreams with specific information. For instance you'll categorize the dream, you can place keywords (or labels in gmail terms) onto a dream, and other similar things. These will allow the user to find the desired dream in a set of different ways. Currently all of the data will be stored on the uesrs local machine, but I was also thinking of having a database available for users to keep their entries. This will be determined by user feedback, at a later stage. Here is what the main screen looks like:

http://www.sedodream.com/images/Dreamcatcher/main.jpg

If you are interested in using this app please send me an email (sayed.hashimi [AT] gmail.com )and I'll keep you posted on its progress. I'm expecting to have a useable release in the next couple months.

Sayed Ibrahim Hashimi

Tuesday, March 28, 2006 7:50:21 AM (GMT Daylight Time, UTC+01:00)  #    Comments [0]  | 
Tuesday, March 21, 2006
A co-worker of mine is playing the role of Jesus in a play at his local church. He had to have fake hair implanted inorder to fulfill the role properly. So this week he is coming to work looking a little different. I thought I'd take a picture so everyone could see this. The information for the play is available at http://www.northfloridapassionplay.com/default.htm



Sayed Ibrahim Hashimi
Tuesday, March 21, 2006 11:48:14 PM (GMT Standard Time, UTC+00:00)  #    Comments [4]  | 
Saturday, March 18, 2006

One of the Microsoft teams based in the UK has created a library of MSBuild tasks that is available for you to download at: http://www.codeplex.com/sdctasks You can download binary versions as well as all the source code for these tasks. There is almost 170 tasks that they have made available! Below is a list of them all if you are interested in what they are.

 

ActiveDirectory.Group.AddUser SourceDepot.ReverseIntegrate
ActiveDirectory.Group.Create SourceDepot.Sync
ActiveDirectory.User.Create SourceSafe.Get
ActiveDirectory.User.GrantPrivilege SourceSafe.LabelGet
AssignCulture SourceSafe.LabelLatest
BizTalk2002.Configure SourceSafe.Changes
Cab.AddFile Sql.DisconnectUsers
Cab.Create Sql.Execute
Cab.ExtractFile Sql.Access.Revoke
Certificates.AddCertificate Sql.Role.AddUser
CheckComponentInstalled Sql.Access.Grant
CheckProductInstalled ShortenPath"/>
CodeCoverage.AddAssembly StringToItemList"/>
CodeCoverage.Create StringComparison"/>
CodeCoverage.MergeReports StringReplace"/>
CodeCoverage.Start Summary.AddToReport
CodeCoverage.Stop Time.Get
CompileTestSummary Time.Diff
ComponentServices.Application.AddComponent Time.Report
ComponentServices.Application.Delete Tools.DevEnv
ComponentServices.Application.RemoveComponent Tools.FxCop
ComponentServices.Application.Shutdown Tools.Installshield
ComponentServices.Application.Update Tools.MsTest"/>
ComponentServices.Component.Update Tools.Ndoc
ConsoleReadLine Tools.Nunit
CreateGuid Tools.PreSharp
Email Tools.PsExec
EventSource.Create Tools.StrongName.AddSkipVerification
EventSource.Log Tools.StrongName.ReSign
File.Delete Tools.StyleCop
File.GetFiles TrimJavascript
File.RegEx VersionNumber.CreateSourceFiles
Folder.Copy VersionNumber.Load
Folder.GetInfo VersionNumber.SplitBuildNumber
Folder.Share.Connect VersionNumber.Update
Folder.Share.Create VersionNumber.VSSUpdate
Folder.Share.Delete VirtualServer.VirtualMachine.OS.CheckHeartBeat
Folder.Share.Disconnect VirtualServer.VirtualMachine.OS.Shutdown
Folder.Share.Exists VirtualServer.VirtualMachine.Start
GetInstalledComponents VirtualServer.VirtualMachine.Stop
GetInstalledProducts Web.AppPool.Create
GetMetadataValueFromList Web.AppPool.Delete
GlobalAssemblyCache.AddAssembly Web.FtpSite.Create
GlobalAssemblyCache.RemoveAssembly Web.FtpSite.CreateVirtualDirectory
Help.Compile Web.FtpSite.Delete
Help.CreateProject Web.FtpSite.DeleteVirtualDirectory
Help.Decompile Web.FtpSite.Start
Help.DocumentExceptions Web.FtpSite.Stop
Help.InsertAfter Web.ServiceExtension.AddFile
Help.InsertBefore Web.ServiceExtension.DeleteFile
Help.InsertParent Web.WebSite.AddBinding
LogicalComparison Web.WebSite.AddFilter
MessageQueue.Create Web.WebSite.AddHttpCustomHeader
MessageQueue.Delete Web.WebSite.AddMimeType
MessageQueue.SetPermissions Web.WebSite.Continue
Msi.EmbedInstallProperties Web.WebSite.Create
Msi.EmbedUninstallProperties Web.WebSite.CreateVirtualDirectory
Msi.GetProperty Web.WebSite.Delete
Msi.Install Web.WebSite.Modify
Msi.Repair Web.WebSite.DeleteFilter
Msi.Uninstall Web.WebSite.DeleteVirtualDirectory
PerformanceCounters.Add Web.WebSite.FilterExists
PerformanceCounters.Remove Web.WebSite.Pause
Registry.CreateKey Web.WebSite.Start
Registry.DeleteKey Web.WebSite.Stop
Registry.DeleteKeyTree Web.WebSite.UnloadVirtualDirectory
Registry.Get Web.WebSite.UpdateHttpErrorSetting
Registry.Set Web.WebSite.UpdateLogSettings
Security.AddAcl Web.WebSite.UpdateServerCertificate
Security.RemoveAcl Web.Smtp.Create
ServiceProcess.Exists Web.Smtp.Start
ServiceProcess.Start Web.Smtp.Stop
ServiceProcess.Stop Wix.CompileMsi
ServiceProcess.UpdateIdentity Wix.LinkMsi
Sleep Wix.Fragment
SourceDepot.Changes Xml.CanonicalizeFile
SourceDepot.ChangesInInterval Xml.ModifyFile
SourceDepot.CreateBranch Xml.GetValue  
SourceDepot.CreateClientFromTemplate Xml.XslTransform
SourceDepot.DeleteBranch Zip.AddFile
SourceDepot.GetChangelistFromDateTime Zip.Create
SourceDepot.GetChangelistFromLabel Zip.ExtractFile
SourceDepot.GetUsersForChangelists MergeByOrder
SourceDepot.Integrate MergeByRef
SourceDepot.LabelSync  

 

I’m sure that some of these tasks you’ll find completely useless. For example I presume that most of you will not be needing the SourceDepot.* tasks. But there are several very cool tasks that are made available here. Tasks for code coverage, tasks for invoking common tools and other things. I think its great that they have made this available and hope to see some of these tasks integrated into the next realease of MSBuild.

Sayed Ibrahim Hashimi


(Edit: Updated SDC tasks link)

Saturday, March 18, 2006 7:23:16 AM (GMT Standard Time, UTC+00:00)  #    Comments [1]  | 
Monday, March 06, 2006
A friend of mine was installing SQL Server 2005 & Visual Studio 2005 on a new machine he received. After installing SQL Server 2005, he tried to install VS 2005 and received an error stating that he couldn't install VS 2005 becase beta versions were present on his machine. I had this problem earlier when I needed to upgrade my machine from RC to RTM. The problem was that he accidently installed SQL Server 2005 CTP. I told him to run the him to download and run the Visual Studio Beta Removal tool. When I had this problem it solved it right up for me. Unfortunately, I think Windows got confused with all the installing/un-installing that was going on. He got his machine to the point where SQL Server wouldn't show up in the add/remove programs list, he couldn't run the un-installer for it because it wasn't present, and he couldn't re-install the same CTP version to uninstall it correctly. And of course he couldn't install VS 2005. It seemed like he was in a real tough spot, we searched around for more information about how to get around this situation. I found a tool, the Windows Installer Clean Up tool, that can be used to removal applications and installer files from failed apps that don't show up in the add/remove programs list. When he ran this tool he was able to see and remove the SQL related components. Following this he was able to install the correct versions of SQL Server 2005 & Visual Studio 2005.

Sayed Ibrahim Hashimi

Monday, March 06, 2006 4:57:24 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 
Tuesday, February 28, 2006

When using MSBuild you can import external declarations into your project by using the Import element. This is very useful for distributing your shared targets across your organization, and is a way to segregate where things are located. When MSBuild encounters this tag, a few things happen. First the current directory is changed to that of the file that is being imported. This is done so assembly locations specified by the Using Task and other imports are resolved correctly. What you may be surprised to find out is that if the importing project file declares any items, those item declarations are always relative to the top project file location. To clarify this if you have the following directory structure:

C:.

├───one

   └───Two

           YourProject.proj

├───Shared

      CurrentDirectory.dll

      SharedTargets.targets

  

   └───Another

           SharedTargets_2.targets

└───utils

        CommandLine.txt

In this scenario YourProject.proj is the top project file, it imports both SharedTargets.targets and SharedTargets_2.targets files. If the SharedTargets.targets had an item declaration of

<ItemGroup>
    <Test Include="test.txt"/>
</ItemGroup>

When imported by YourProject.proj this item declaration would actually resolve to C:\one\two\test.txt instead of the expected C:\Shared\test.txt value. In 95% of the time this is not an issue at all. But for that other 5% how can we accomplish this?

Well, there is no magic reserved MSBuild property for this. So we're gonna have to do some work here. To accomplish this we'll have to create a custom MSBuild task. If you've never created an MSBuild task you might be surprised how easy it is!

I created a new project named DirectoryTask which will house this task. Following this I added a reference to Microsoft.Build.Framework and Microsoft.Build.Utilities assemblies. Following this I wrote the task. It is shown below

using System;

using System.Collections.Generic;

using System.Text;

using Microsoft.Build.Framework;

using Microsoft.Build.Utilities;

namespace CurrentDirectory

{

    /// <summary>

    /// Task that will return the folder that contains the current project.

    /// Inheriting from AppDomainIsolatedTask causes this task to execute in its own

    /// App domain. Not necessary here, only for demonstration.

    ///

    /// Sayed Ibrahim Hashimi

    /// www.sedodream.com

    /// </summary>

    public class CurrentDir : AppDomainIsolatedTask

    {

        private ITaskItem currentDir;

        [Output]

        public ITaskItem CurrentDirectory

        {

            get

            {

                return this.currentDir;

            }

        }

        public override bool Execute()

        {

            System.IO.FileInfo projFile = new System.IO.FileInfo(base.BuildEngine.ProjectFileOfTaskNode);

            this.currentDir = new TaskItem(projFile.Directory.FullName);

           

            return true;

        }

    }

}

As you can see this is a pretty simple task. When Execute is called the directory is gathered from the project file that contains the task invocation. The name of the assembly that I built this into is CurrentDirectory.dll.

Now to see this in action I will use the same directory structure shown above. The contents of the SharedTargets.targets file is:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

 

  <UsingTask AssemblyFile="CurrentDirectory.dll" TaskName="CurrentDir"/>

 

  <Target Name="SharedTarget">

    <CurrentDir>

      <Output ItemName="CurrentDir" TaskParameter="CurrentDirectory" />

    </CurrentDir>

 

 

    <Message Text="Inside the SharedTargets.targets" Importance="high"/>

    <Message Text="Location: @(CurrentDir->'%(Fullpath)')"/>

  </Target>

 

</Project>

This uses the CurrentDirectory task to determine what the current directory is. The SharedTargets_2.targets file is very similar and is:

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">

 

  <Target Name="SharedTarget2">

 

    <CurrentDir>

      <Output ItemName="CurrentDir2" TaskParameter="CurrentDirectory" />

    </CurrentDir>

 

 

    <Message Text="Inside the SharedTargets_2.targets" Importance="high"/>

    <Message Text="Location: @(CurrentDir2->'%(Fullpath)')"/>

  </Target>

 

</Project>

 

Now let’s take a look at the very simple YourProject.Proj file.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" DefaultTargets="Print">

  <Import Project="..\..\Shared\SharedTargets.targets"/>

  <Import Project="..\..\Shared\Another\SharedTargets_2.targets"/>

 

  <PropertyGroup>

    <PrintDependsOn>

      SharedTarget;

      SharedTarget2

    </PrintDependsOn>

  </PropertyGroup>

 

  <Target Name="Print" DependsOnTargets="$(PrintDependsOn)">

  </Target>

</Project>

 

This file simply imports the two other files and defines the print target. Now we want to invoke the Print target on this project file. To do this open the Visual Studio2005 command prompt and go the directory containing the YourProjec.proj file. Then execute the following:

>msbuild.exe YourProject.proj /t:Print

 

The results of this invocation are:

__________________________________________________

Project "C:\Data\Community\msbuild\MSBuildDirectoryExample\one\Two\YourProject.proj" (default targets):

 

Target SharedTarget:

    Inside the SharedTargets.targets

    Location: C:\Data\Community\msbuild\MSBuildDirectoryExample\Shared

Target SharedTarget2:

    Inside the SharedTargets_2.targets

    Location: C:\Data\Community\msbuild\MSBuildDirectoryExample\Shared\Another

 As you can see the correct location was resolved for both of these items. Previously if you had command line utilities in source control and .targets files that would manage invoking those tools, it was error prone. This is because the .targets file wouldn’t be able to resolve the location of the command line util, even if in the same directory. The solution to this problem it to rely on the developer to set a property (or environment variable) which states where this tool can be located; or some other similar means. With this task we no longer have to rely on such a solution. The .targets file is able to resolve the location of the command line utility. 

I have bundled all related files into a zip file which you can download below.

MSBuildDirectoryExample.zip (you may have to right-click->Save As)

 http://www.sedodream.com/content/binary/MSBuildDirectoryExample.zip

Sayed Ibrahim Hashimi

Tuesday, February 28, 2006 6:23:33 AM (GMT Standard Time, UTC+00:00)  #    Comments [0]  | 

Theme design by Jelle Druyts