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

C# Script: The Missing Puzzle Piece

Rate me:
Please Sign up or sign in to vote.
4.88/5 (184 votes)
6 Aug 2014MIT24 min read 1.3M   9.4K   531  
An article on a "scripting engine" for the C# language
using System;
using System.Windows.Forms;
using System.IO;
using Microsoft.Win32;
using System.Xml;
using System.Collections;
using System.Runtime.InteropServices;
using System.Diagnostics;
using CSScriptLibrary;


class Script
{
	static string usage = "Usage: Debug#D.cs [file]|[/i|/u] ...\nLoads C# script file into temporary SharpDevelop project and opens it.\n</i> / </u> - command switch to install/uninstall shell extension";

	static public void Main(string[] args)
	{
		if (args.GetLength(0) == 0 || (args.GetLength(0) == 1 && (args[0] == "?" || args[0] == "/?" || args[0] == "-?" || args[0].ToLower() == "help")))
		{
			Console.WriteLine(usage);
		}
		else if (args[0].Trim().ToLower() == "/i")
		{
			SharpDevelopIDE.InstallShellExtension();
		}
		else if (args[0].Trim().ToLower() == "/u")
		{
			SharpDevelopIDE.UninstallShellExtension();
		}
		else
		{
			try
			{
				FileInfo info = new FileInfo(args[0]);
				string scriptFile = info.FullName;
				string srcProjDir = @"debug\#D"; //relative to CSSCRIPT_DIR
				string scHomeDir = Environment.GetEnvironmentVariable("CSSCRIPT_DIR");
				string tempDir = Path.Combine(Path.Combine(Path.GetTempPath(), "CSSCRIPT"), Environment.TickCount.ToString());
				//string tempDir = @"C:\cs-script\Dev\debug\Test"; //??

				string projFile = Path.Combine(tempDir, "DebugScript.prjx");
				string solutionFile = Path.Combine(tempDir, "DebugScript.cmbx");


				//copy project template
				Directory.CreateDirectory(tempDir);
			
				foreach(string file in Directory.GetFiles(Path.Combine(scHomeDir, srcProjDir)))
					File.Copy(file, Path.Combine(tempDir, Path.GetFileName(file)), true);

				//update project template with script specific data
				SharpDevelopIDE ide = new SharpDevelopIDE();
				csscript.ScriptParser parser = new csscript.ScriptParser(scriptFile);
				csscript.AssemblyResolver asmResolver = new csscript.AssemblyResolver();
				
				ide.InsertFile(scriptFile, projFile);
				
				string[] importerdScripts = parser.SaveImportedScripts();
				foreach (string file in importerdScripts)
					ide.InsertFile(file, projFile);
						
				foreach (string name in parser.ReferencedNamespaces)
				{
					string[] asmFiles = csscript.AssemblyResolver.FindAssembly(name, Path.GetDirectoryName(scriptFile));
					foreach (string file in asmFiles)	
						ide.InsertReference(file, projFile);
				}

				foreach (string asmName in parser.ReferencedAssemblies) //some assemblies were referenced from code
				{
					string file = Path.Combine(Path.GetDirectoryName(scriptFile), asmName);
					ide.InsertReference(file, projFile);
				}

				//open project
				Environment.CurrentDirectory = Path.GetDirectoryName(scriptFile);

				Process myProcess = new Process();
				myProcess.StartInfo.FileName = SharpDevelopIDE.GetIDEFile();
				myProcess.StartInfo.Arguments = "\"" + solutionFile + "\" ";
				myProcess.Start();
				myProcess.WaitForExit();

				//do clean up
				Directory.Delete(tempDir, true);
				foreach (string file in importerdScripts)
				{
					File.SetAttributes(file, FileAttributes.Normal);
					File.Delete(file);
				}
			}
			catch (Exception e) 
			{
				MessageBox.Show("Specified file could not be linked to the temp project:\n" + e.Message);
			}	
		}
	}
	
	class SharpDevelopIDE
	{
		public void InsertFile(string scriptFile, string projFile)
		{
			try
			{
				//<File name="C:\cs-script\Dev\debug\SharpDevelop\tick.cs" subtype="Code" buildaction="Compile" dependson="" data="" />

				XmlDocument doc = new XmlDocument();
				doc.Load (projFile);
		
				//Create a new node.
				XmlElement elem = doc.CreateElement("File");
				XmlAttribute newAttr; 
		
				newAttr = doc.CreateAttribute("name");
				newAttr.Value = scriptFile;
				elem.Attributes.Append(newAttr);

				newAttr = doc.CreateAttribute("subtype");
				newAttr.Value = "Code";
				elem.Attributes.Append(newAttr);
				
				newAttr = doc.CreateAttribute("buildaction");
				newAttr.Value = "Compile";
				elem.Attributes.Append(newAttr);

				newAttr = doc.CreateAttribute("dependson");
				newAttr.Value = "";
				elem.Attributes.Append(newAttr);

				newAttr = doc.CreateAttribute("data");
				newAttr.Value = "";
				elem.Attributes.Append(newAttr);
		
				newAttr = doc.CreateAttribute("SubType");
				newAttr.Value = "Form";
				elem.Attributes.Append(newAttr);
		
				XmlNode contentsNode = doc.FirstChild.FirstChild;
				contentsNode.AppendChild(elem);
			
				doc.Save (projFile);
			}
			catch (Exception e)
			{
				MessageBox.Show("Specified file could not be inserted to the temp project:\n" + e.Message);
			}
		}
		public void InsertReference(string refFile, string projFile)
		{
			try
			{
				//<Reference type="Assembly" refto="C:\cs-script\Dev\debug\SharpDevelop\CSScriptLibrary.dll" localcopy="True" />

				XmlDocument doc = new XmlDocument();
				doc.Load (projFile);
		
				//Create a new node.
				XmlElement elem = doc.CreateElement("Reference");
				XmlAttribute newAttr; 
		
				newAttr = doc.CreateAttribute("type");
				newAttr.Value = "Assembly";
				elem.Attributes.Append(newAttr);
				
				newAttr = doc.CreateAttribute("refto");
				newAttr.Value = refFile;
				elem.Attributes.Append(newAttr);
				
				newAttr = doc.CreateAttribute("localcopy");
				newAttr.Value = "True";
				elem.Attributes.Append(newAttr);

				XmlNode ReferencesNode = doc.FirstChild.ChildNodes[1];
				ReferencesNode.AppendChild(elem);
			
				doc.Save (projFile);
			}
			catch (Exception e)
			{
				MessageBox.Show("Specified reference could not be inserted into the temp project:\n" + e.Message);
			}
		}
		static public string GetIDEFile()
		{
			string retval = "<not defined>";
			string fileTypeName = null;
			RegistryKey csFile = Registry.ClassesRoot.OpenSubKey(".cmbx");

			if (csFile != null)
			{
			    fileTypeName = (string)csFile.GetValue("");

			    RegistryKey csIDE = Registry.ClassesRoot.OpenSubKey(fileTypeName + "\\shell\\open\\command");
			    if (csFile != null)
			    {
			        retval = csIDE.GetValue("").ToString().TrimStart("\"".ToCharArray()).Split("\"".ToCharArray())[0];
			    }
			}
			return retval;
		}

		static public void InstallShellExtension()
		{
			string fileTypeName = null;
			RegistryKey csFile = Registry.ClassesRoot.OpenSubKey(".cs");

			if (csFile != null)
			{
				fileTypeName = (string)csFile.GetValue("");
			}
			if (fileTypeName != null)
			{
				//Shell extensions
				Console.WriteLine("Create 'Open as script (#D)' shell extension...");
				RegistryKey shell = Registry.ClassesRoot.CreateSubKey(fileTypeName + "\\shell\\Open as script(#D)\\command");
				string scHomeDir = Environment.GetEnvironmentVariable("CSSCRIPT_DIR");
				string regValue = "\"" + Path.Combine(scHomeDir, "cswscript.exe") + "\"" +
					" /c " +
					"\"" + Path.Combine(scHomeDir, "lib\\Debug#D.cs") + "\" " +
					"\"%1\"";

				shell.SetValue("", regValue);
				shell.Close();
			}
		}
		static public void UninstallShellExtension()
		{
			string fileTypeName = null;
			RegistryKey csFile = Registry.ClassesRoot.OpenSubKey(".cs");

			if (csFile != null)
			{
				fileTypeName = (string)csFile.GetValue("");
			}
			if (fileTypeName != null)
			{
				try
				{
					if (Registry.ClassesRoot.OpenSubKey(fileTypeName + "\\shell\\Open as script(#D)") != null)
					{
						Console.WriteLine("Remove 'Open as script (#D)' shell extension...");
						Registry.ClassesRoot.DeleteSubKeyTree(fileTypeName + "\\shell\\Open as script(#D)");
					}
				}
				catch { }
			}
		}
	}
}

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 MIT License


Written By
Program Manager
Australia Australia
I was born in Ukraine. After completing the university degree worked there as a Research Chemist. Last 23 years I live in Australia where I've got my second qualification as a Software Engineer.

"I am the lucky one: I do enjoy what I am doing!"

Comments and Discussions