This could get a little tricky, depending on how fully integrated you
want this. I think the trick is essentially creating a custom MSBuild
task. You would put a call to that task in your .csproj file and when
you build the project it would pass in the paths to the various xml
files, then you could do whatever you wanted after that. In your case
build an assembly based on the xml files.
If you look in a .csproj file you'll see a chunk of xml for importing
"$(MSBuildBinPath)\Microsoft.CSharp.targets", which will probably
point to "C:\WINDOWS\Microsoft.NET\Framework
\v2.0.50727\Microsoft.CSharp.targets". If you pop that file open
you'll see a target with the name "CoreCompile" which takes in a
variety of paramters then calls "Csc". What you need to do is create
your own targets file that looks pretty much exactly the same except
instead of calling "Csc" it'll call "MyXmlGenerator" task which you'll
need to create yourself. Put the targets file in the correct place and
then change the .csproj file to import your custom targets file
instead of the "Microsoft.CSharp.targets". A good place to put all of
this is "C:\Program Files\MSBuild\MyXmlGenerator\". Put the targets
and all of your assemblies in there.
I have done something similar to this only more extensively with a
full on language service and project type (which hopefully you won't
have to do for now) and here is a link to an example (http://
www.codeplex.com/nbusiness) :
[The targets file]
http://www.codeplex.com/NBusiness/SourceControl/FileView.aspx?itemId=291876&chan
geSetId=22187
[The custom Task]
http://www.codeplex.com/NBusiness/SourceControl/FileView.aspx?itemId=291875&chan
geSetId=22187
[The custom .csproj]
http://www.codeplex.com/NBusiness/SourceControl/FileView.aspx?itemId=272443&chan
geSetId=22187
In my case it's "esproj" but you should be ok with just using csproj
files and changing the build target. This is the important line there:
<Import Project="$(MSBuildExtensionsPath)\NBusiness\ESharp
\2.0\ESharp.targets" />
Ok, good luck!
P.S. What are you generating with your XML files? I'd be interested in
knowing. Thanks!
Hi,
as far as I understand, you have yet a console app tool doing exactly what
you want and all you want to do is to do it automatically during a build.
Write an Add-in which handles the OnBuildProjConfigDone event or one of the
other events fired during the build process:
// Let BuildEventHandler be the class which actually handle the events
buildEventHandler = new BuildEventHandler(applicationObject);
Events events = applicationObject.Events;
BuildEvents buildEvents = events.BuildEvents;
buildEvents.OnBuildBegin += new
_dispBuildEvents_OnBuildBeginEventHandler(buildEventHandler.OnBuildBegin);
buildEvents.OnBuildDone += new
_dispBuildEvents_OnBuildDoneEventHandler(buildEventHandler.OnBuildDone);
buildEvents.OnBuildProjConfigBegin += new
_dispBuildEvents_OnBuildProjConfigBeginEventHandler(buildEventHandler.OnBuildProjConfigBegin);
buildEvents.OnBuildProjConfigDone += new
_dispBuildEvents_OnBuildProjConfigDoneEventHandler(buildEventHandler.OnBuildProjConfigDone);
Now you can use the Process class to launch the external program. See the
example below. Note, that if your launched process generates a certain
amount of output, you need to use a worker thread to read the stdout and
stderr, otherwise it
will block. This is demonstrated in the sample below. Derive you own class
from the
ConsoleProcess class for each program you want to launch.
Hope that helps.
Regards,
Mirko
www.netdataobjects.com
using System;
using System.Text;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Diagnostics;
namespace ...
{
public class ConsoleProcess
{
StreamReader outReader;
StreamReader errReader;
string stdout = string.Empty;
bool verboseMode;
public string Stdout
{
get { return stdout; }
}
string stderr = string.Empty;
public string Stderr
{
get { return stderr; }
}
public ConsoleProcess(bool verboseMode)
{
this.verboseMode = verboseMode;
}
public int Execute(string exeFileName, string parameters)
{
return Execute(exeFileName, parameters, null);
}
public int Execute(string exeFileName, string parameters, string
workingDirectory)
{
if (this.verboseMode)
Console.WriteLine("Execute: " + "\"" + exeFileName + "\" " +
parameters);
ProcessStartInfo psi = new ProcessStartInfo(exeFileName, parameters);
psi.CreateNoWindow = true;
psi.UseShellExecute = false;
if (workingDirectory != null)
psi.WorkingDirectory = workingDirectory;
psi.RedirectStandardOutput = true;
psi.RedirectStandardError = true;
psi.StandardErrorEncoding =
Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage);
psi.StandardOutputEncoding =
Encoding.GetEncoding(CultureInfo.CurrentCulture.TextInfo.OEMCodePage);
System.Diagnostics.Process proc = System.Diagnostics.Process.Start( psi );
this.errReader = proc.StandardError;
this.outReader = proc.StandardOutput;
Thread threadOut = new Thread(new ThreadStart(ReadStdOut));
Thread threadErr = new Thread(new ThreadStart(ReadStdErr));
threadOut.Start();
threadErr.Start();
proc.WaitForExit();
while (threadOut.ThreadState != System.Threading.ThreadState.Stopped
|| threadErr.ThreadState != System.Threading.ThreadState.Stopped)
Thread.Sleep(1);
return proc.ExitCode;
}
void ReadStdOut()
{
stdout = outReader.ReadToEnd();
}
void ReadStdErr()
{
stderr = errReader.ReadToEnd();
}
}
}
> Hi,
>
[quoted text clipped - 16 lines]
>
> Please suggest directions/code/ideas, appreciated.
Vin - 15 May 2007 19:18 GMT
Thanks you guys that helps a lot.
justncase80, I am most likely going to build my custom target file and
use it. Thanks for your suggestion, I almost forgot I could do this
way.
I am generating C# classes out of Xml and then producing a
classlibrary that has set of classes and properties which then
developers use to create applications playing with them with their own
logic. Sounds interesting. Isn't it?
Mirko thanks for your step-by-step instructions with code. Appreciate
it.