string code = System.IO.File.ReadAllText(path);
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters options = new CompilerParameters();
options.GenerateExecutable = false;
options.GenerateInMemory = true;
options.ReferencedAssemblies.Add(Assembly.GetExecutingAssembly().Location);
CompilerResults result;
result = codeProvider.CompileAssemblyFromSource(options, code);
LastErrors = result.Errors;
if (result.Errors.HasErrors)
{
throw new Exception("Compiling the code has returned exceptions!\r\nCheck LastErrors for details.");
}
return result.CompiledAssembly;
is my code for compiling C# code into an assembly.
But instead, I would like to somehow compile all the files in a directory into that assembly.
Can you not just use CompileAssemblyFromFile instead? That allows you to specify multiple filenames.
Related
My application generates and compiles code runtime:
CompilerParameters m_cp = new CompilerParameters();
m_cp.ReferencedAssemblies.Add("system.dll");
m_cp.GenerateExecutable = false;
m_cp.GenerateInMemory = true;
m_cp.CompilerOptions = "/optimize";
...
CompilerResults cr = new CSharpCodeProvider().CompileAssemblyFromSource(m_cp, code.ToString());
if (cr.Errors.HasErrors)
{
//getting here with error:
//"Compiling Expression: cannot open c:\Users\*" for reading
//'c:\Users\* is not a valid Win32 resource file
// Example of file c:\Users\[User]\AppData\Local\Temp\1\faw31esr\CSC23CEA88A205E4588B799FD8B4456176B.TMP
}
Issue is happening only for some users but their access is OK (access is the same as for trouble-free users). E.g. problematic users can get to shown directory and remove files.
One of vulnerability management products blocked file access and caused error.
so what I am creating dll type files, running them and then I want to delete them.
However when I try to delete them I get an exception as it claims they are still in use by another process.
I assuming that the code used to create the files does not dispose of resources correctly to allow the deleting of the file after, here is my code to create the file.
if (!Directory.Exists(PathToRobots + Generation))
{
Directory.CreateDirectory(PathToRobots + Generation);
}
File.WriteAllText(Path.Combine(PathToRobots + Generation, NameSpace + GetRobotName() + robotNumber + ".cs"), code);
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters()
{
GenerateInMemory = false,
GenerateExecutable = false, // True = EXE, False = DLL
IncludeDebugInformation = true,
OutputAssembly = Path.Combine(FileName + ".dll") // Compilation name
};
parameters.ReferencedAssemblies.Add(#"robocode.dll");
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
if (results.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
Assembly assembly = results.CompiledAssembly;
provider.Dispose();
The code to delete the file is quite simple and is as follows,
var files = Directory.GetFiles(DirectoryPath);
foreach (var file in files)
{
File.Delete(file);
}
Any idea as to why I can't delete the files?
See the notes at CompilerResults.CompiledAssembly Property
The get accessor for the CompiledAssembly property calls the Load method to load the compiled assembly into the current application domain. After calling the get accessor, the compiled assembly cannot be deleted until the current AppDomain is unloaded.
So when you do this:
Assembly assembly = results.CompiledAssembly;
You have loaded the compiled assembly into the current app domain and thus have locked the file. To be able to delete the generated file, you would need to load it into a separate app domain (this answer may help with specifics for doing that).
I have a solution in VS2013, the solution has 2 projects, projA and projB.
In projA, the startup project, I wrote some code to compile C# text files at runtime, and my code actually works well when linking it to namespaces inside of the projA running it.
But when I try to link it to namespaces inside of projB, for example doing something like using namespaceInProjB, it says that they dont exist. I thought they would also be found in the current domains assemblies?
Does anyone know how to include them as well? Here is my code:
CodeDomProvider provider = new CSharpCodeProvider();
CompilerParameters compilerParams = new CompilerParameters();
compilerParams.CompilerOptions = "/target:library";
compilerParams.GenerateExecutable = false;
compilerParams.GenerateInMemory = true;
compilerParams.IncludeDebugInformation = false;
compilerParams.ReferencedAssemblies.Add("mscorlib.dll");
var assemblies = AppDomain.CurrentDomain
.GetAssemblies()
.Where(a => !a.IsDynamic)
.Select(a => a.Location);
foreach (string str in assemblies.ToArray<string>())
compilerParams.ReferencedAssemblies.Add(str);
CompilerResults result = provider.CompileAssemblyFromSource(compilerParams, scriptCode);
// Write out all the errors
if (result.Errors.Count > 0)
{
errors = result.Errors;
return null;
}
return result.CompiledAssembly;
Make sure classes you use in projB are public, because by default classes are internal and you can't use them in another project in projA in your case.
Is there a way to have a less-strict compilation with a CodeDomProvider? I am trying to compile and load dll files into my already running program by using:
public static String Compile(string commandName, string source = "")
{
private static CodeDomProvider compiler = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
private static CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.MainClass = commandName;
parameters.OutputAssembly = dll;
parameters.ReferencedAssemblies.Add("MCLight_.dll");
parameters.CompilerOptions = "/optimize";
parameters.WarningLevel = 4;
parameters.TreatWarningsAsErrors = false;
StreamReader sr = new StreamReader(sourcepath + "cmd" + commandName + ".cs");
results = compiler.CompileAssemblyFromSource(parameters, sr.ReadToEnd());
.....
}
The problem is that errors such as:
Error #CS0122
Message: 'MCLight.Independent' is inaccessible due to its protection level
Line: 1178
and
Error #CS1501
Message: No overload for method 'Find' takes '1' arguments
Line: 617
are being thrown.
Now I know for a fact this class compiles fine when I compile it as part of my solution in VS. But when compiled separately it's throwing these errors. Is there a way to have the compiler ignore these errors since I know it will hook into the application just fine?
You could try setting the warning level lower:
parameters.WarningLevel = 1;
But it is hard to say for sure without seeing the source of code you are compiling.
I have an application which loads up c# source files dynamically and runs them as plugins. When I am running the main application in debug mode, is it possible to debug into the dynamic assembly? Obviously setting breakpoints is problematic, since the source is not part of the original project, but should I be able to step into, or break on exceptions for the code?
Is there a way to get codedom to generate PDBs for this or something?
Here is the code I am using for dynamic compliation.
CSharpCodeProvider codeProvider = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v3.5" } });
//codeProvider.
ICodeCompiler icc = codeProvider.CreateCompiler();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
parameters.CompilerOptions = string.Format("/lib:\"{0}\"", Application.StartupPath);
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Core.dll");
CompilerResults results = icc.CompileAssemblyFromSource(parameters, Source);
DLL.CreateInstance(t.FullName, false, BindingFlags.Default, null, new object[] { engine }, null, null);
Try the following options:
parameters.GenerateInMemory = false; //default
parameters.TempFiles = new TempFileCollection(Environment.GetEnvironmentVariable("TEMP"), true);
parameters.IncludeDebugInformation = true;
I am not sure if this works OK in your case, but if it does, you can surround this parameters with conditional compilation directive, so that it dumps the generated assembly only in debug mode.
The answer by #bbmud is correct, though it misses one bug fix. The CSharpCodeGenerator (the class in .NET the compiles C# code to IL) is set to remove pdb files immediately after they are created, UNLESS you add /debug:pdbonly to the CompilerOptions string. However, if you do that, the IncludeDebugInformation flag is ignored and the compiler generates optimised code which is hard to debug. To avoid this you must explicitly tell the Code Generator to keep all files.
Here is the complete recipe:
parameters.GenerateInMemory = false; //default
parameters.TempFiles = new TempFileCollection(Environment.GetEnvironmentVariable("TEMP"), true);
parameters.IncludeDebugInformation = true;
parameters.TempFiles.KeepFiles = true
Here is the culprit part of the code of CSharpCodeGenerator:
string fileExtension = "pdb";
if ((options.CompilerOptions != null) && (CultureInfo.InvariantCulture.CompareInfo.IndexOf(options.CompilerOptions, "/debug:pdbonly", CompareOptions.IgnoreCase) != -1))
{
results.TempFiles.AddExtension(fileExtension, true);
}
else
{
results.TempFiles.AddExtension(fileExtension);
}
The TempFiles.AddExtension(fileExtension, true) tells the compile to keep the pdb files. The else option of results.TempFiles.AddExtension(fileExtension); tells it to treat pdb as all temporary files which by default means delete them.