Click here to Skip to main content
15,885,031 members
Articles / Programming Languages / C#

Coco Custom Tool for Visual Studio.NET

Rate me:
Please Sign up or sign in to vote.
4.64/5 (34 votes)
29 Oct 2005CPOL4 min read 130.7K   698   53  
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.

License

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


Written By
Software Developer (Senior)
France France
I am a French programmer.
These days I spend most of my time with the .NET framework, JavaScript and html.

Comments and Discussions