Click here to Skip to main content
Click here to Skip to main content
Articles » Languages » C# » General » Downloads
Add your own
alternative version
Go to top

Coco Custom Tool for Visual Studio.NET

, 29 Oct 2005
Use the award winning Coco compiler's compiler directly from within Visual Studio
namespace CustomToolGenerator {

	using System;
	using System.Diagnostics;
	using System.IO;
	using System.Runtime.InteropServices;

	/// <summary>
	/// A managed wrapper for VS's concept of an IVsSingleFileGenerator which is
	/// a custom tool invoked during the build which can take any file as an input
	/// and provide a compilable code file as output.
	/// </summary>
	public abstract class BaseCodeGenerator : IVsSingleFileGenerator {

		private IVsGeneratorProgress	codeGeneratorProgress;
		private string					codeFileNameSpace	= String.Empty;
		private string					codeFilePath		= String.Empty;

		/// <summary>
		/// namespace for the file.
		/// </summary>
		protected string FileNameSpace {
			get {
				return codeFileNameSpace;

		/// <summary>
		/// file-path for the input file.
		/// </summary>
		protected string InputFilePath {
			get {
				return codeFilePath;

		/// <summary>
		/// interface to the VS shell object we use to tell our
		/// progress while we are generating.
		/// </summary>
		internal IVsGeneratorProgress CodeGeneratorProgress {
			get {
				return codeGeneratorProgress;

		/// <summary>
		/// gets the default extension for this generator
		/// </summary>
		/// <returns>string with the default extension for this generator</returns>
		public abstract string GetDefaultExtension();

		/// <summary>
		/// the method that does the actual work of generating code given the input
		/// file.
		/// </summary>
		/// <param name="inputFileName">input file name</param>
		/// <param name="inputFileContent">file contents as a string</param>
		/// <returns>the generated code file as a byte-array</returns>
		protected abstract byte[] GenerateCode(string inputFileName, string inputFileContent);

		/// <summary>
		/// method that will communicate an error via the shell callback mechanism.
		/// </summary>
		/// <param name="warning">true if this is a warning</param>
		/// <param name="level">level or severity</param>
		/// <param name="message">text displayed to the user</param>
		/// <param name="line">line number of error/warning</param>
		/// <param name="column">column number of error/warning</param>
		protected virtual void GeneratorErrorCallback(bool warning, int level, string message, int line, int column) {
			IVsGeneratorProgress progress = CodeGeneratorProgress;
			if (progress != null) {
				progress.GeneratorError(warning, level, message, line, column);

        /// <summary>
        /// main method that the VS shell calls to do the generation
        /// </summary>
        /// <param name="wszInputFilePath">path to the input file</param>
        /// <param name="bstrInputFileContents">contents of the input file as a string (shell handles UTF-8 to Unicode & those types of conversions)</param>
        /// <param name="wszDefaultNamespace">default namespace for the generated code file</param>
        /// <param name="rgbOutputFileContents">byte-array of output file contents</param>
        /// <param name="pcbOutput">count of bytes in the output byte-array</param>
        /// <param name="pGenerateProgress">interface to send progress updates to the shell</param>
		public void Generate(string wszInputFilePath, 
                             string bstrInputFileContents, 
                             string wszDefaultNamespace, 
			                 out IntPtr rgbOutputFileContents, 
                             out int pcbOutput, 
                             IVsGeneratorProgress pGenerateProgress) {

			if (bstrInputFileContents == null) {
				throw new ArgumentNullException(bstrInputFileContents);

			codeFilePath = wszInputFilePath;
			codeFileNameSpace = wszDefaultNamespace;
			codeGeneratorProgress = pGenerateProgress;

			byte[] bytes = GenerateCode(wszInputFilePath, bstrInputFileContents);

			if (bytes == null) {
				rgbOutputFileContents = IntPtr.Zero;
				pcbOutput = 0;
			else {
				pcbOutput = bytes.Length;
				rgbOutputFileContents = Marshal.AllocCoTaskMem(pcbOutput);
				Marshal.Copy(bytes, 0, rgbOutputFileContents, pcbOutput);                

        /// <summary>
        /// method to return a byte-array given a Stream
        /// </summary>
        /// <param name="stream">stream to convert to a byte-array</param>
        /// <returns>the stream's contents as a byte-array</returns>
        protected byte[] StreamToBytes(Stream stream) {

            if (stream.Length == 0) {
                return new byte[] { };

            long position = stream.Position;
            stream.Position = 0;
            byte[] bytes = new byte[(int)stream.Length];
            stream.Read(bytes, 0, bytes.Length);
            stream.Position = position;

            return bytes;

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Pascal Ganaye
Software Developer (Senior)
United Kingdom United Kingdom
I am a French programmer.
These days I spend most of my time with the .NET framework, JavaScript and html.

| Advertise | Privacy | Mobile
Web04 | 2.8.140921.1 | Last Updated 29 Oct 2005
Article Copyright 2005 by Pascal Ganaye
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid