I was experimenting with dynamic class creation at runtime but I get the following error when i run my program at the last line. Does anyone know how to solve this? I tried searching similar problems online but none of the solutions have helped me. Thanks in advance for any help
Could not load file or assembly 'file:///C:\Users\xxxx\AppData\Local\Temp\jelsfwqz.dll' or one of its dependencies. The system cannot find the file specified.
string code2 = "using System;" +
"using System.Collections.Generic;" +
"using System.Linq;" +
"using System.Text;" +
"" +
" public sealed class CustomClass" +
" {" +
" }"
;
// Compiler and CompilerParameters
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters compParameters = new CompilerParameters();
CodeDomProvider compiler = CSharpCodeProvider.CreateProvider("CSharp");
// Compile the code
CompilerResults res = codeProvider.CompileAssemblyFromSource(compParameters, code2);
// Create a new instance of the class 'CustomClass'
object myClass = res.CompiledAssembly.CreateInstance("CustomClass");
Fixed code:
string code2 =
" public sealed class CustomClass" +
" {" +
" }"
;
// Compiler and CompilerParameters
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters compParameters = new CompilerParameters();
CodeDomProvider compiler = CSharpCodeProvider.CreateProvider("CSharp");
**compParameters.ReferencedAssemblies.Add("System.dll");**
// Compile the code
CompilerResults res = codeProvider.CompileAssemblyFromSource(compParameters, code2);
// Create a new instance of the class 'CustomClass'
object myClass = res.CompiledAssembly.CreateInstance("CustomClass");
Related
I have created a tool that open a c# Winform application, the question is after I made some modification to the files I want to recompile those files programmatically using c#.
You can do it by using CSharpCodeProvider. You can find more information about this class in documentation.
after searching i have use this solution :
String[] csFiles = CopyAllSourceFilesToCLASSESFolder().ToArray();
String[] referenceAssemblies = { "System.dll", "System.Drawing.dll", "System.Windows.Forms.dll", "ICSharpCode.TextEditor.dll", "System.Xml.dll", "System.IO.dll", "System.ComponentModel.dll" , "System.Data.dll" , "System.linq.dll" };
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
string Output = "Out.exe";
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters(referenceAssemblies);
//Make sure we generate an EXE, not a DLL
parameters.GenerateExecutable = true;
parameters.OutputAssembly = Output;
CompilerResults results = icc.CompileAssemblyFromFileBatch(parameters, csFiles);
if (results.Errors.Count > 0)
{
foreach (CompilerError CompErr in results.Errors)
{
ErrorTextBox.Text = ErrorTextBox.Text +
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine + Environment.NewLine;
}
}
else
{
//Successful Compile
ErrorTextBox.ForeColor = Color.Blue;
ErrorTextBox.Text = "Success!";
//If we clicked run then launch our EXE
}
Process.Start(Output);
I am trying to do a Visual Studio kind of program, which allows you to type code into a RichTextBox. After pressing F5(Compile), it would compile the code. How would the user compile said code? I know how to use the ConsoleApplication Compiler, but not compiling Windows Forms :(
Could someone help? A code-example is preferable, but at this point, I'll accept ANYTHING!
My current code for Console Apps is this:
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
string Output = "MCCACOut.exe";
Button ButtonObject = (Button)sender;
richTextBox201.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, richTextBox301.Text);
if (results.Errors.Count > 0)
{
richTextBox201.ForeColor = Color.Red;
foreach (CompilerError CompErr in results.Errors)
{
richTextBox201.Text = richTextBox201.Text +
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine + Environment.NewLine;
}
}
else
{
//Successful Compile
richTextBox201.ForeColor = Color.Blue;
richTextBox201.Text = "Success!";
//If we clicked run then launch our EXE
Process.Start(Output);
}
Could anyone convert this to compile WinForms instead of ConsoleApp? :)
I think you have to save your file with .cs extension and invoke a process to compile it using c# compiler csc.exe.
After saving the file, you can compile the code using,
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe [options] filename.cs
Take a look at this for options
You can invoke a process to do this from your IDE.
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe filename.cs";
process.StartInfo = startInfo;
process.Start();
Hope this helps.
Finally, after many, many times of struggling, I got it to work :) With the help of Nishan Chathuranga
string compiledOutput = "Generated.exe";
//COMPILATION WORK
String[] referenceAssemblies = { "System.dll", "System.Drawing.dll", "System.Windows.Forms.dll" };
CodeDomProvider _CodeCompiler = CodeDomProvider.CreateProvider("CSharp");
System.CodeDom.Compiler.CompilerParameters _CompilerParameters =
new System.CodeDom.Compiler.CompilerParameters(referenceAssemblies, "");
_CompilerParameters.OutputAssembly = compiledOutput;
_CompilerParameters.GenerateExecutable = true;
_CompilerParameters.GenerateInMemory = false;
_CompilerParameters.WarningLevel = 3;
_CompilerParameters.TreatWarningsAsErrors = true;
_CompilerParameters.CompilerOptions = "/optimize /target:winexe";//!! HERE IS THE SOLUTION !!
string _Errors = null;
try
{
// Invoke compilation
CompilerResults _CompilerResults = null;
_CompilerResults = _CodeCompiler.CompileAssemblyFromSource(_CompilerParameters, richTextBox1.Text);
if (_CompilerResults.Errors.Count > 0)
{
// Return compilation errors
_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";
}
}
}
catch (Exception _Exception)
{
// Error occurred when trying to compile the code
_Errors = _Exception.Message;
}
//AFTER WORK
if (_Errors == null)
{
// lets run the program
MessageBox.Show(compiledOutput + " Compiled !");
System.Diagnostics.Process.Start(compiledOutput);
}
else
{
MessageBox.Show("Error occurred during compilation : \r\n" + _Errors);
}
This works like a charm!
I has a question, does CodeDom Compiler can compile c# code with custom configuration such as x64 bit or x86 bit.By default it compiles c# code to .exe with "Any CPU" configuration.
Compiling c# code:
public static string BCS(string[] sources,string[] libs,string outPath,bool exef)
{
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters(libs);
parameters.GenerateExecutable = exef;
parameters.OutputAssembly = outPath;
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, sources);
if (results.Errors.Count > 0)
{
string errsText = "";
foreach (CompilerError CompErr in results.Errors)
{
errsText = "("+CompErr.ErrorNumber +
")Line " + CompErr.Line +
",Column "+CompErr.Column +
":"+CompErr.ErrorText + "" +
Environment.NewLine;
}
return errsText;
}
else
{
return "Success";
}
}
I think,youre understand my question,if not, leave a comment,i will give details.
Try to set CompilerOptions this way
parameters.CompilerOptions = "-platform:anycpu32bitpreferred";
using params from this link
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/platform-compiler-option
P.S. CSharpCodeProvider uses csc.exe
https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/compiler-options/command-line-building-with-csc-exe
Let's say a create an (executable) assembly in memory by
compiling a code string. Then I want to serialize this assembly
object into a byte array and then store it in a database. Then later
on I want to retrieve the byte array from the database and deserialize
the byte array back into an assembly object, then invoke the entry
point of the assembly.
At first I just tried to do this serialization like I would any other simple object in .net, however apparently that won't work with an assembly object. The assembly object contains a method called GetObjectData which gets serialization data necessary to reinstantiate the assembly. So I'm somewhat confused as to how I piece all this together for my scenario.
The answer only needs to show how to take an assembly object, convert it into a byte array, convert that back into an assembly, then execute the entry method on the deserialized assembly.
A dirty trick to get the assembly bytes using reflection:
MethodInfo methodGetRawBytes = assembly.GetType().GetMethod("GetRawBytes", BindingFlags.Instance | BindingFlags.NonPublic);
object o = methodGetRawBytes.Invoke(assembly, null);
byte[] assemblyBytes = (byte[])o;
Explanation: at least in my sample (assembly was loaded from byte array) the assembly instance was of type "System.Reflection.RuntimeAssembly". This is an internal class, so it can be accessed only using reflection. "RuntimeAssembly" has a method "GetRawBytes", which return the assembly bytes.
An assembly is more conveniently represented simply as a binary dll file. If you think of it like that, the rest of the problems evaporate. In particlar, look at Assembly.Load(byte[]) for loading an Assembly from binary. To write it as binary, use CompileAssemblyFromSource and look at the result's PathToAssembly - then File.ReadAllBytes(path) to obtain the binary from the file.
System.Reflection.Assembly is ISerializable and can simply be serialized like so:
Assembly asm = Assembly.GetExecutingAssembly();
BinaryFormatter formatter = new BinaryFormatter();
MemoryStream stream = new MemoryStream();
formatter.Serialize(stream, asm);
and deserialization is just as simple but call BinaryFormatter.Deserialize instead.
Here is my example:
public static byte[] SerializeAssembly()
{
var compilerOptions = new Dictionary<string, string> { { "CompilerVersion", "v4.0" } };
CSharpCodeProvider provider = new CSharpCodeProvider(compilerOptions);
CompilerParameters parameters = new CompilerParameters()
{
GenerateExecutable = false,
GenerateInMemory = false,
OutputAssembly = "Examples.dll",
IncludeDebugInformation = false,
};
parameters.ReferencedAssemblies.Add("System.dll");
ICodeCompiler compiler = provider.CreateCompiler();
CompilerResults results = compiler.CompileAssemblyFromSource(parameters, StringClassFile());
return File.ReadAllBytes(results.CompiledAssembly.Location);
}
private static Assembly DeserializeAssembyl(object fromDataReader)
{
byte[] arr = (byte[])fromDataReader;
return Assembly.Load(arr);
}
private string StringClassFile()
{
return "using System;" +
"using System.IO;" +
"using System.Threading;" +
"namespace Examples" +
"{" +
" public class FileCreator" +
" {" +
" private string FolderPath { get; set; }" +
" public FileCreator(string folderPath)" +
" {" +
" this.FolderPath = folderPath;" +
" }" +
" public void CreateFile(Guid name)" +
" {" +
" string fileName = string.Format(\"{0}.txt\", name.ToString());" +
" string path = Path.Combine(this.FolderPath, fileName);" +
" if (!File.Exists(path))" +
" {" +
" using (StreamWriter sw = File.CreateText(path))" +
" {" +
" sw.WriteLine(\"file: {0}\", fileName);" +
" sw.WriteLine(\"Created from thread id: {0}\", Thread.CurrentThread.ManagedThreadId);" +
" }" +
" }" +
" else" +
" {" +
" throw new Exception(string.Format(\"duplicated file found {0}\", fileName));" +
" }" +
" }" +
" }" +
"}";
}
I build a CodeCompileUnit and the following code outputs a C# source code file, a .dll and I can get an instance from the assembly:
TextWriter tw = new IndentedTextWriter(new StreamWriter(filePath + ".cs", false), " ");
provider.GenerateCodeFromCompileUnit(compileUnit, tw, new CodeGeneratorOptions());
tw.Close();
CompilerParameters cp = new CompilerParameters { GenerateInMemory = true, GenerateExecutable = false};
cp.ReferencedAssemblies.Add("MyProgram.exe");
cp.OutputAssembly = filePath + ".dll";
CompilerResults cr = provider.CompileAssemblyFromFile(cp, filePath + ".cs");
MyType instance = (MyType)Activator.CreateInstance(cr.CompiledAssembly.GetTypes()[0]);
So far so good. Now I would like to avoid generating those files:
CompilerParameters cp = new CompilerParameters { GenerateInMemory = true, GenerateExecutable = false};
cp.ReferencedAssemblies.Add("MyProgram.exe");
//cp.OutputAssembly = filePath + ".dll";
CompileResults cr = provider.CompileAssemblyFromDom(cp, compileUnit);
This throws a FileNotFoundException. It looks for a x32savit.dll (or similar) in my \temp folder but it is not there. If I uncomment the OutputAssembly it fails the same but on that path.
It turned out to be an error with namespaces. There is a good example here.
Adding the following code was very helpful while debugging.
string errorText = String.Empty;
foreach (CompilerError compilerError in compilerResults.Errors)
errorText += compilerError + "\n";