Add additional References when compliling code at runtime - c#

I found this program ( http://support.microsoft.com/kb/304655 ) where i compile the code during runtime, It works for code that uses the reference,
using System;
Following is the the code for the program that compiles code during runtime,
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
string Output = "Out.exe";
Button ButtonObject = (Button)sender;
textBox2.Text = "";
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
//Make sure we generate an EXE, not a DLL
parameters.GenerateExecutable = true;
parameters.OutputAssembly = Output;
CompilerResults results = icc.CompileAssemblyFromSource(parameters, textBox1.Text);
if (results.Errors.Count > 0)
{
textBox2.ForeColor = Color.Red;
foreach (CompilerError CompErr in results.Errors)
{
textBox2.Text = textBox2.Text +
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine + Environment.NewLine;
}
}
else
{
//Successful Compile
textBox2.ForeColor = Color.Blue;
textBox2.Text = "Success!";
//If we clicked run then launch our EXE
if (ButtonObject.Text == "Run") Process.Start(Output);
}
And Following is the code i need to compile at runtime,
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;
using Newtonsoft.Json.Linq;
namespace Tsubame
{
class Program
{
static void Main(string[] args)
{
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(#"url");
// Create Client
WebClient client = new WebClient();
// Assign Credentials
client.Credentials = new NetworkCredential("user", "pass");
//Grab Data
var data = client.DownloadString(#"url");
JObject o = JObject.Parse(data);
string getFristRow = Convert.ToString(o["Body"][0]["RowId"]);
string encaplulateStart = "\\\"";
string encaplulateEnd = "\\\":";
List<string> _matches = new List<string>();
_matches = Regex.Matches(getFristRow, #"(?<=" + encaplulateStart + ").*(?=" + encaplulateEnd + ")")
.Cast<Match>()
.Select(m => m.Value)
.ToList();
foreach (string head in _matches)
{
Console.WriteLine(head);
}
Console.ReadLine();
}
}
}
But when I input this gives the error code,
Error Number: CS0234
For the references other than System. May I please know how to add additional references during runtime so that it can compile sucessfully :) Thank you very much :)

You need to add the references in CompilerParameters using CompilerParameters.ReferencedAssemblies:
var parameters = CompilerParameters
{
GenerateExecutable = true,
OutputAssembly = Output,
ReferencedAssemblies = {
"System.dll",
"System.Core.dll",
// etc
}
};
(Of course you don't have to use object initializer syntax to set this up, but it makes it neater IMO.)

Related

C# not recognizing my variable

I'm trying to load code from an exe file then create it into a new .exe file. But it's not recognizing my variable "SourceCode". It says the name "SourceCode" does not exist in the current context
private void button1_Click(object sender, EventArgs e)
{
using (FileStream SourceCode = new FileStream("thecode.exe", FileMode.Open, FileAccess.ReadWrite, FileShare.None));
string Output = textBox3.Text;
String[] Assembly = { "System.dll", "System.Drawing.dll", "System.Windows.Forms.dll" };
CodeDomProvider CodeCompiler = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters Parameters = new CompilerParameters(Assembly, "");
Parameters.OutputAssembly = Output;
Parameters.GenerateExecutable = true;
Parameters.GenerateInMemory = false;
Parameters.WarningLevel = 3;
Parameters.TreatWarningsAsErrors = true;
Parameters.CompilerOptions = "/optimize+ /target:winexe";
string Errors = null;
try
{
CompilerResults Results = null;
Results = CodeCompiler.CompileAssemblyFromSource(Parameters, SourceCode); //This here is giving me an error
if (Results.Errors.Count > 0)
{
Errors = "";
foreach (System.CodeDom.Compiler.CompilerError CompileError in Results.Errors)
{
Errors += "Line number " + CompileError.Line + ", Error Number: " + CompileError.ErrorNumber + ", '" + CompileError.ErrorText + ";\r\n\r\n";
}
The following line is ending with a semicolon ';'
using (FileStream SourceCode = new FileStream("thecode.exe", FileMode.Open, FileAccess.ReadWrite, FileShare.None));
In C# the semicolon is a statement terminator rather than a line terminator.
You should declare your using statements like this
using(var Bar = new Foo())
{
}
Thus making your code:
using (FileStream SourceCode = new FileStream("thecode.exe", FileMode.Open, FileAccess.ReadWrite, FileShare.None))
{
}
Your using statement at the top has a ; at the end. A using block is used to ensure a Disposable resource is disposed at the end of the block. In this case, without { }, your using statement is kind of useless. Either your expand the block of code using { }, or you just declare the variable without the using statement. Hope this helps!

Stop CodeDom generated executables being detected as a virus

So when i generate a C# program using CodeDom and scan it online it comes up as being a virus. How do I stop this?
This is the code i am using to generate it:
string Output = "Out.exe";
string[] fileArray = { "source.cs", "AssemblyInfo.cs" };
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = true;
parameters.OutputAssembly = Output;
parameters.ReferencedAssemblies.Add("System.dll");
CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, fileArray);
if (results.Errors.Count > 0)
{
foreach (CompilerError CompErr in results.Errors)
{
MessageBox.Show(
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine + Environment.NewLine);
}
}
else
{
MessageBox.Show("Success!");
}
This is the code i'm using for the generated exe
using System;
using System.Text;
namespace Out
{
class Program
{
static void Main(string[] args)
{
System.Text.StringBuilder sbMessage = new System.Text.StringBuilder();
Console.WriteLine(sbMessage.Append("the result of adding (1+2) is " + (1 + 2).ToString()));
System.Console.ReadLine();
}
}
}
So when I scan the generated file, its getting detected as a virus as showen in the VirusTotal link https://www.virustotal.com/en/file/d19cb8ad9c9de9da50a29acab91b53d10327b3023aa1a32c367d17c0c50fd28c/analysis/1434772258/

Hiding Command Prompt with CodeDomProvider

I've just got my own little custom c# compiler made, using the article from MSDN.
But, when I create a new Windows Forms application using my sample compiler, the MSDOS window also appears, and if I close the DOS window, my WinForms app closes too. How can I tell the Compiler? not to show the MSDOS window at all?
Thank you :)
Here's my code:
using System;
namespace JTS
{
public class CSCompiler
{
protected string ot,
rt,
ss, es;
protected bool rg, cg;
public string Compile(String se, String fe, String[] rdas, String[] fs, Boolean rn)
{
System.CodeDom.Compiler.CodeDomProvider CODEPROV = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("CSharp");
ot =
fe;
System.CodeDom.Compiler.CompilerParameters PARAMS = new System.CodeDom.Compiler.CompilerParameters();
// Ensure the compiler generates an EXE file, not a DLL.
PARAMS.GenerateExecutable = true;
PARAMS.OutputAssembly = ot;
PARAMS.CompilerOptions = "/target:winexe"; PARAMS.ReferencedAssemblies.Add(typeof(System.Xml.Linq.Extensions).Assembly.Location);
PARAMS.LinkedResources.Add("this.ico");
foreach (String ay in rdas)
{
if (ay.Contains(".dll"))
PARAMS.ReferencedAssemblies.Add(ay);
else
{
string refd = ay;
refd = refd + ".dll";
PARAMS.ReferencedAssemblies.Add(refd);
}
}
System.CodeDom.Compiler.CompilerResults rs = CODEPROV.CompileAssemblyFromFile(PARAMS, fs);
if (rs.Errors.Count > 0)
{
foreach (System.CodeDom.Compiler.CompilerError COMERR in rs.Errors)
{
es = es +
"Line number: " + COMERR.Line +
", Error number: " + COMERR.ErrorNumber +
", '" + COMERR.ErrorText + ";" +
Environment.NewLine + Environment.NewLine;
}
}
else
{
// Compilation succeeded.
es = "Compilation Succeeded.";
if (rn) System.Diagnostics.Process.Start(ot);
}
return es;
}
}
}
In C# compiler Console window is shown when /target switch is exe. When /target=winexe, Console window is not shown.
http://msdn.microsoft.com/en-us/library/6h25dztx.aspx
Try this:
System.CodeDom.Compiler.CompilerParameters PARAMS = new System.CodeDom.Compiler.CompilerParameters();
PARAMS->CompilerOptions = "/target:winexe";
See:
http://msdn.microsoft.com/en-us/library/system.codedom.compiler.compilerparameters.compileroptions.aspx
I don't know which MSDN Article you are referring to, but if you use the AssemblyBuilder then the "magic" is in the call to SetEntryPoint.
If you have a Windows Forms application, you need to specify PEFileKinds.WindowApplication:
var asm = AppDomain.CurrentDomain.DefineDynamicAssembly(
new AssemblyName(assemblyName), AssemblyBuilderAccess.Save);
var mod = asm.DefineDynamicModule(assemblyName, fileName);
var type = mod.DefineType("Program",
TypeAttributes.Class | TypeAttributes.Sealed | TypeAttributes.Public);
var mainMethod = type.DefineMethod("Main",
MethodAttributes.Public | MethodAttributes.Static);
// ... Code for Main method and the rest ...
type.CreateType();
asm.SetEntryPoint(mainMethod,PEFileKinds.WindowApplication);
asm.Save(fileName);
Other PEFileKinds are ConsoleApplication and Dll, although I think the AssemblyBuilder automatically assumes it's a Dll if you don't specify an EntryPoint.

CodeDom.compiler memory

I am generating assembly on runtime . Problem is that i cant get rid-of it after i am done with it. I need to destroy this assambly what i have created
string _Errors = "";
object[] parms = null;
CodeDomProvider _CodeCompiler = CodeDomProvider.CreateProvider("CSharp"); //new Microsoft.CSharp.CSharpCodeProvider().CreateCompiler();
CompilerParameters _CompilerParameters = new CompilerParameters();
_CompilerParameters.GenerateExecutable = false;
_CompilerParameters.GenerateInMemory = true;
_CompilerParameters.ReferencedAssemblies.Add("System.Windows.Forms.dll");
_CompilerParameters.TreatWarningsAsErrors = false;
_CompilerParameters.CompilerOptions = "/optimize";
try
{
System.CodeDom.Compiler.CompilerResults _CompilerResults = null;
_CompilerResults = _CodeCompiler.CompileAssemblyFromSource(_CompilerParameters, _SourceCode);
if (_CompilerResults.Errors.Count > 0)
{
_Errors = "";
foreach (System.CodeDom.Compiler.CompilerError CompErr in _CompilerResults.Errors)
{
_Errors += "Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";\r\n\r\n";
}
return false;
}
else
{
_Errors = null;
} _CompilerResults.CompiledAssembly = null;
_CompilerResults = null;
_CompilerParameters = null;
_CodeCompiler.Dispose();
GC.Collect();}catch{}
I suppose by "get rid of it" you mean "unload". Unfortunatelly (or not so) once loaded into an AppDomain, assemblies cannot be unloaded. To circumvent this, you can generate (or load, for that matter) assembly in a separate AppDomain and then destroy it as needed.

Constant error in compiler using C#'s provided objects

I have used the built in C# methods to write a compiler, like the following:
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
string Output = "Out.exe";
Button ButtonObject = (Button)sender;
this.RadTextBox1.Text = string.Empty;
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
//Make sure we generate an EXE, not a DLL
parameters.GenerateExecutable = true;
parameters.OutputAssembly = Output;
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, RadTextBox1.Text);
if (results.Errors.Count > 0)
{
RadTextBox2.ForeColor = Color.Red;
foreach (CompilerError CompErr in results.Errors)
{
RadTextBox2.Text = RadTextBox2.Text +
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine + Environment.NewLine;
}
}
else
{
//Successful Compile
RadTextBox2.ForeColor = Color.Blue;
Guid guid = Guid.NewGuid();
string PathToExe = Server.MapPath(Path.Combine(#"\Compiled" , Output));
FileStream fs = System.IO.File.Create(PathToExe);
using (StreamWriter sw = new StreamWriter(fs))
{
sw.Write(RadTextBox1.Text);
}
Response.WriteFile(PathToExe);
When I run this code and write a Main method (such as the code sample in http://msdn.microsoft.com/en-us/library/ms228506(VS.80).aspx, I get this error:
Line number 0, Error Number: CS5001, 'Program 'c:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\Out.exe' does not contain a static 'Main' method suitable for an entry point;
The code above is used as the basis of a compiler on my site (not yet live). So you type in code and generate an .exe assembly. But when I enter code into the textbox for code writing (Radtextbox1), even with a main method, I get the error.
What gives?
Thanks
The entry point function is special: you can't just add a method called "main" to the assembly. Instead you must add an instance of the CodeEntryPointMethod type to one of your classes.
See http://blogs.msdn.com/bclteam/archive/2005/10/01/475768.aspx for more information on some of the limitations of using the CodeEntryPointMethod.

Categories