I have some code to create an exe from c# source on-the-fly using the CSharpCodeProvider, here it is:
public static void BuildAssembly(string code)
{
Microsoft.CSharp.CSharpCodeProvider provider =
new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
CompilerParameters compilerparams = new CompilerParameters();
compilerparams.ReferencedAssemblies.Add("System.dll");
compilerparams.GenerateExecutable = true;
compilerparams.GenerateInMemory = false;
compilerparams.OutputAssembly = #"C:\Users\me\AppData\Roaming\test.exe";
CompilerResults results =
compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in results.Errors)
{
errors.AppendFormat("Line {0},{1}\t: {2}\n",
error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
}
}
all works fine, it compiles my console application c# code. But when I'm writing a console app and i requires that the console not be visible I simply go to the application properties and change output type from console to Windows Application. So how would I do this via the function I pasted above? I've looked through all the options but .. no idea :(
thanks.
Try this:
compilerparams.CompilerOptions = "/target:winexe";
Related
So I have this simple generator just for test purposes:
var provider = new CSharpCodeProvider();
var options = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true
};
string code = "using System;namespace Expression{public static class Expression{public static void Test() {var foo = 2}}}";
var result = provider.CompileAssemblyFromSource(options, code);
But Whenever I run it gives me System.PlatformNotSupportedException: Operation is not supported on this platform.
Note I am targeting net5.0-windows (do not know if this is relevant to the error)
I'm trying to use CodeDomProvider to make a C# compiler.
I managed to get the errors but i can't get the output.
This is what i have so far:
public List<string> Errors(CompilerResults compilerResults)
{
List<string> messages = new List<string>();
foreach (CompilerError error in compilerResults.Errors)
{
messages.Add(String.Format("Line {0} Error No:{1} - {2}", error.Line, error.ErrorNumber, error.ErrorText));
}
return messages;
}
public CompilerResults ProcessCompilation(string programText)
{
CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
StringCollection assemblies = new StringCollection();
return codeDomProvider.CompileAssemblyFromSource(parameters, programText);
}
CSharpCompiler is the class that contains the functions from above
public JsonResult Compiler(string code)
{
CSharpCompiler compiler = new CSharpCompiler();
CompilerResults compilerResults = compiler.ProcessCompilation(code);
Debug.WriteLine("OUTPUT----------------------------------------------");
foreach (var o in compilerResults.Output)
{
Debug.WriteLine(o);
}
List<string> compilerErrors = compiler.Errors(compilerResults);
if (compilerErrors.Count != 0)
return Json(new { success = false, errors = compilerErrors});
return Json(true);
}
compilerResults.Output is always empty.
If i run this piece of code:
using System;
public class HelloWorld
{
public static void Main()
{
Console.WriteLine("Hello world!");
}
}
What can i do to display the message "Hello world!"?
CompileAssemblyFromSource creates, as its name implies, an assembly. To get access to the compiled code, you can use the CompilerResults.CompiledAssembly property and then use reflection to find and invoke the Main method:
compilerResults.CompiledAssembly.GetType("HelloWorld").GetMethod("Main").Invoke(null, null);
Though if you set parameters.GenerateExecutable to true, you can simplify this to:
compilerResults.CompiledAssembly.EntryPoint.Invoke(null, null);
I have had success using this tutorial: http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime to set up a framework for runtime compilation and execution of C# code. Below is the code I currently have:
public static class CodeCompiler {
public static object InterpretString(string executable) {
string compilation_string =
#"
static class RuntimeCompilationCode {
public static void Main() {}
public static object Custom() {
/* CODE HERE */
}
}";
compilation_string = compilation_string.Replace("/* CODE HERE */", executable);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters compiler_parameters = new CompilerParameters();
// True - memory generation, false - external file generation
compiler_parameters.GenerateInMemory = true;
// True - exe file generation, false - dll file generation
compiler_parameters.GenerateExecutable = true;
// Compile
CompilerResults results = provider.CompileAssemblyFromSource(compiler_parameters, compilation_string);
// Check errors
if (results.Errors.HasErrors) {
StringBuilder builder = new StringBuilder();
foreach (CompilerError error in results.Errors) {
builder.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(builder.ToString());
}
// Execute
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("RuntimeCompilationCode");
MethodInfo execute = program.GetMethod("Custom");
return execute.Invoke(null, null);
}
}
I can pass a statement in the form of a string (ex. "return 2;") to InterpretString() and it will be compiled and executed as part of the Custom() function. However I am wondering if it is possible to use the same approach to execute a method that is in my original file. For instance, suppose the CodeCompiler class had another method returnsTwo() which returns the integer 2. Is there a way to call such a method by passing "CodeCompiler.returnsTwo();" or a similar string to InterpretString()?
Provided that the function is a static function this should not be a problem, as long as you add the appropriate reference to the compilation. I've done this short of thing on several projects.
If the CodeCompiler is in your current executable you have to include the references in this fashion:
string exePath = Assembly.GetExecutingAssembly().Location;
string exeDir = Path.GetDirectoryName(exePath);
AssemblyName[] assemRefs = Assembly.GetExecutingAssembly().GetReferencedAssemblies();
List<string> references = new List<string>();
foreach (AssemblyName assemblyName in assemRefs)
references.Add(assemblyName.Name + ".dll");
for (int i = 0; i < references.Count; i++)
{
string localName = Path.Combine(exeDir, references[i]);
if (File.Exists(localName))
references[i] = localName;
}
references.Add(exePath);
CompilerParameters compiler_parameters = new CompilerParameters(references.ToArray())
I have a Windows Forms application, which I use to generate resource files. I'm trying to add such functionality to this application, that would allow me to compile another Windows Forms application into an executable, that would have these resources included. However, I'm stuck on that compile another Windows Forms project part.
I tried to follow this article, my code so far looks like this:
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = true;
parameters.IncludeDebugInformation = true;
parameters.GenerateInMemory = false;
//parameters.TreatWarningsAsErrors = true;
parameters.WarningLevel = 3;
parameters.CompilerOptions = "/optimize";
parameters.OutputAssembly = "Program.exe";
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, new string[] { "Program.cs" });
I'm not exactly sure, if I'm doing this correctly (if I should compile Program.cs file). Program.cs file looks like this:
using System;
using System.Windows.Forms;
namespace example
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}
}
}
And when I try to compile it with the code above, I get this error:
Line number 16, Error Number: CS0246, 'The type or namespace name 'Form1' could not be found (are you missing a using directive or an assembly reference?)
I'd really appreciate if you guys could help me out, I've never compiled anything from another project.
Assuming the other project you want to compile is project.csproj, reference Microsoft.Build.Framework and use this code:
var globalProperty = new Dictionary<string, string> { { "Configuration", "Debug"}, { "Platform", "Any CPU" } };
var buildParameters = new BuildParameters(new ProjectCollection()) { Loggers = new List<ILogger> { new ConsoleLogger() } };
var buildRequest = new BuildRequestData(#"C:\example\project.csproj", globalProperty, "4.0", new[] {"Build" }, null);
BuildResult buildResult = BuildManager.DefaultBuildManager.Build(buildParameters, buildRequest);
Or you could just wrap the MsBuild.exe
var p = new Process();
p.StartInfo = new ProcessStartInfo(#"C:\Windows\Microsoft.NET\Framework\v4.0.30319\msbuild.exe");
p.StartInfo.Arguments = #"C:\example\project.csproj";
p.Start();
I'm trying to compile some unsafe code from an application using Codedom, but everytime I get an error saying I must use "/unsafe." I've googled the issue and added:
Parameters.CompilerOptions = "/unsafe";
To my codedom code. Are there any simple solutions for this?
Edit: if it wasn't already clear, my solution didn't work.
Edit: Here is the class.
public static bool Compile(string EXE_Name, string Source)
{
var Compiler = new CSharpCodeProvider();
var Parameters = new CompilerParameters
{
CompilerOptions = "/unsafe"
};
CompilerResults cResults = default(CompilerResults);
Parameters.GenerateExecutable = true;
Parameters.OutputAssembly = EXE_Name;
Parameters.ReferencedAssemblies.Add(typeof(System.Xml.Linq.Extensions).Assembly.Location);
Parameters.ReferencedAssemblies.Add("System.dll");
Parameters.ReferencedAssemblies.Add("System.Core.dll");
Parameters.ReferencedAssemblies.Add("System.Data.dll");
Parameters.ReferencedAssemblies.Add("System.Data.DataSetExtensions.dll");
Parameters.ReferencedAssemblies.Add("System.Deployment.dll");
Parameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
Parameters.ReferencedAssemblies.Add("System.Drawing.dll");
Parameters.ReferencedAssemblies.Add("System.Xml.dll");
Parameters.CompilerOptions = " /target:winexe";
Parameters.TreatWarningsAsErrors = false;
cResults = Compiler.CompileAssemblyFromSource(Parameters, Source);
if (cResults.Errors.Count > 0)
{
foreach (CompilerError CompilerError_loopVariable in cResults.Errors)
{
CompilerError error = CompilerError_loopVariable;
MessageBox.Show("Error: " + error.ErrorText, "", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
return false;
}
else if (cResults.Errors.Count == 0)
{
return true;
}
return true;
}
It works for me - perhaps you weren't setting the parameters correctly?
using System.CodeDom.Compiler;
using Microsoft.CSharp;
class Test
{
public static void Main(string[] args)
{
var compiler = new CSharpCodeProvider();
var parameters = new CompilerParameters {
CompilerOptions = "/unsafe"
};
var source = "unsafe struct Foo {}";
var result = compiler.CompileAssemblyFromSource(parameters, source);
// No errors are shown with the above options set
foreach (var error in result.Errors)
{
Console.WriteLine(error);
}
}
}
var Parameters = new CompilerParameters
{
CompilerOptions = "/unsafe"
};
and later:
Parameters.CompilerOptions = " /target:winexe";
You just replace "/unsafe" with " /target:winexe". Use:
Parameters.CompilerOptions += " /target:winexe";