How to include using declaratives with CodeDomProvider in c#? - c#

I want to compile several .cs-files to an executable program.
My CodeDomProvider doesn't find the using declaratives that I wrote into the .cs-files. Especially the followings error Messages are created:
-The type- or namespace 'CodeDom' in the namespace 'System' is not available.
-The type- or namespace 'Windows' in the namespace 'System' is not available.
-The type- or namespace 'Stack' could not be found.
From this function, I'm calling the CodeDomProvider:
private CompileParserSolution()
{
List<string> cSharpFiles = new List<string>();
DirectoryInfo dir = new DirectoryInfo(Path.Combine(_inData.ProjectDir, #"NCParser\NCParser"));
foreach (FileInfo f in dir.GetFiles("*.cs"))
{
cSharpFiles.Add(Path.Combine(dir.FullName, f.Name));
}
CodeDomProvider provider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters cp = new CompilerParameters();
cp.GenerateExecutable = true;
cp.OutputAssembly = "Parser_TEST.exe";
cp.GenerateInMemory = true;
cp.TreatWarningsAsErrors = false;
cp.ReferencedAssemblies.Add("System.Linq.dll");
cp.ReferencedAssemblies.Add("System.Text.RegularExpressions.dll");
cp.ReferencedAssemblies.Add(Path.Combine(_inData.ProjectDir, #"NCParser\NCParser", #"QUT.ShiftReduceParser.dll"));
CompilerResults cr = provider.CompileAssemblyFromFile(cp, cSharpFiles.ToArray());
}
My question is, how can I include the System.CodeDom, System.Windows and the System.Collections.Stack librarys into the project to compile.
With the command:
cs.ReferencedAssemblies.Add("System.CodeDom.dll");
...
it doesn't work!

Assemblies and namespaces don't correspond to each other 1:1. To find in which assembly a certain type is, look at its MSDN documentation.
There is no System.CodeDom.dll, a lot of the CodeDOM types are in the System.dll, which you didn't reference.
Stack<T> is likewise in System.dll.
WPF is spread over several assemblies, the basic types are in PresentationFramework.dll.
Referencing these assemblies will likely fix your issue.

Related

Is it possible to generate Satellite Assemblies from within code?

I'm about to elaborate a solution for simplifying a translator tool. Therefore I currently try to automatically compile a Satellite Assembly from within my code.
So what I want to achive is to replace a manual run of the following command:
AL.exe /culture:de /out:de\TestResource.resources.dll /embed:TestResource.de.resources
So far I've tested generating a .dll file, which worked. But embedding/linking an ressource like shown below doesn't has any effect, but expanding the dll's size. So obviously it's there but not usable as if the resulting dll was a Satellite Assembly.
static void Main(string[] args)
{
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.OutputAssembly = "./output/satellite_test.dll";
parameters.EmbeddedResources.Add(#"./TestResource.en.resources");
parameters.LinkedResources.Add(#"./TestResource.de.resources");
CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, "");
}
Is there any way to generate a dll programmatically which contains just the localized resources for one language, so that it's usable as a Satellite Assembly?
Finally I've managed to generate Satellite Assemblies from Code.
Following code generates an appropriate resourcefile:
// Already the resourcefilename has to match the
// exact namespacepath of the original resourcename.
var resourcefileName = #"TranslationTest.Resources.TestResource.de.resources";
// File has to be a .resource file. (ResourceWriter instead of ResXResourceWriter)
// .resx not working and has to be converted into .resource file.
using (var resourceWriter = new ResourceWriter(resourcefileName))
{
resourceWriter.AddResource("testtext", "Language is german!!");
}
Using this resourcefile there are some compileroptions which are necessary:
CompilerParameters parameters = new CompilerParameters();
// Newly created assembly has to be a dll.
parameters.GenerateExecutable = false;
// Filename has to be like the original resourcename. Renaming afterwards does not work.
parameters.OutputAssembly = "./de/TranslationTest.resources.dll";
// Resourcefile has to be embedded in the new assembly.
parameters.EmbeddedResources.Add(resourcefileName);
Finally compiling the assembly there is some required code which has to be compiled into:
// Culture information has to be part of the newly created assembly.
var assemblyAttributesAsCode = #"
using System.Reflection;
[assembly: AssemblyCulture(""de"")]";
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
CompilerResults results = codeProvider.CompileAssemblyFromSource(
parameters,
assemblyAttributesAsCode
);

Pass objects to Dynamic Assembly

I have some types whose objects i need to pass to a dynamic assembly. But my types are not recognised and i am getting compile errors
Here is my code to compile
using System.Linq;
using System.Text;
using System.Collections.Generic;
using SkillBuilder.AutoGens.Libs;
namespace TempNs
{
public class MyClass
{
public MyClass()
{}
public Autozen ag;
//do stuff
}
}
The above code throws error saying that type Autozen could not be found. Are you missing an Assembly reference?. The type is in SkillBuilder.AutoGens.Libs.
This is how i compile it.
public static Assembly Compile(string sourceCode)
{
var provider_options = new Dictionary<string, string>
{
{"CompilerVersion","v4.0"}
};
CodeDomProvider cpd = new CSharpCodeProvider(provider_options);
var cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Core.Dll");
// True - memory generation, false - external file generation
cp.GenerateInMemory = true;
cp.GenerateExecutable = false;
CompilerResults cr = cpd.CompileAssemblyFromSource(cp, sourceCode);
if (cr.Errors.HasErrors)
{
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in cr.Errors)
{
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
return cr.CompiledAssembly;
}
I want to be able to assign the value of "ag" by the calling application.
How do i make Autozen available during compile time ? Is there any other way?
EDIT :
The code is generated and compiled by an EXE. The compiled output is again going to be used by the same EXE.
thanks for your help.
EDIT :
After adding Assembly.GetExecutingAssembly().Location to the referenced assembly collection now i get System.Core.dll missing referece error. Since i have included CompilerVersion, it should pickup the assembly from the GAC. Then why am i still getting this error ?

CodeDOM compilation no errors but fails to launch console

I have created my project and now want to compile using a CodeDOM compiler.
I have a folder full of the .CS files that should be compiled to an EXE. The application is supposed to be a console application although it fails to launch any console. There are no building errors. The following is my compile method:
public static void Build(string AssemblyName, string OutputDirectory, string[] SourceFiles)
{
CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = true;
parameters.GenerateInMemory = false;
parameters.ReferencedAssemblies.Add("System.dll");
parameters.ReferencedAssemblies.Add("System.Data.dll");
parameters.ReferencedAssemblies.Add("System.Xml.dll");
parameters.OutputAssembly = OutputDirectory + #"\" + AssemblyName + ".exe";
parameters.CompilerOptions = "/unsafe /target:winexe /platform:x86";
if (codeProvider.Supports(GeneratorSupport.EntryPointMethod))
{
parameters.MainClass = "MyApp.Program";
}
CompilerResults results = codeProvider.CompileAssemblyFromFile(parameters, SourceFiles);
if (results.Errors.Count > 0)
{
foreach (CompilerError error in results.Errors)
Console.WriteLine(error.ErrorText);
}
}
string[] SourceFiles correctly provides all .CS files (classes, structs and enums) located in the folder like follows:
"D:\\Development\\MyAppCodeDom\\Program.cs"
"D:\\Development\\MyAppCodeDom\\IniParser.cs"
And 26 more of those. I do not use any external DLL files as reference whatsoever. It fails, however, to launch the console window.
Any idea? Perhaps a console application requires certain options?
EDIT:
Using ILSpy, the assembly seems to contain ALL the classes etc it should have.
Thank you in advance.
I removed /target:winexe from the CompilerOptions and now it works.

System.ArgumentException Invalid file name in Assembly.LoadModule(string,byte[])

During my studies of reflection, I have encountered the .net module.
I understand that means I can compile a single class as .net module (correct me if I wrong) then load this compiled .net module using Assembly.LoadModule(string,byte[]).
I wrote a class that look like this:
using System;
using System.Text;
public class Mycs {
public static string GiveString(){
return "Hello World !";
}
}
and compiled it using the switch "/target:module" using this code:
CodeDomProvider CDP = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters CP = new CompilerParameters();
CP.GenerateExecutable = false;
CP.CompilerOptions = "/target:module";
CP.OutputAssembly = FilePathText.Text.Replace(Strings.Right(FilePathText.Text, 3), ".netmodule");
string source = File.ReadAllText(FilePathText.Text);
CompilerResults RS = CDP.CompileAssemblyFromSource(CP, source);
I then retrieved the resulted file bytes:
byte[] b = File.ReadAllBytes(FilePathText.Text);
And finally I tried to load the module to the current executed assembly:
Module[] Modules = Assembly.GetExecutingAssembly().GetModules();
Module[] moduless = Assembly.GetExecutingAssembly().GetLoadedModules();
Module A = Assembly.GetExecutingAssembly().LoadModule(Modules[0].Name, b);
Whether I passed the Modules[0].Name or moduless[0].Name both cause this exception:
An unhandled exception of type 'System.ArgumentException' occurred in mscorlib.dll
Additional information: Invalid file name
Why do I get this invalid file name error?
You cannot load dynamically created module to an existing assembly, assemblies once compiled are immutable.
My best guess is that you need to use AssemblyBuilder.DefineDynamicModule() to create your classes in it. In this case you the type you created will be loaded automatically. or compile your classes as assemblies, not the modules, and load those assemblies dynamically using Assembly.LoadFile method.

.Net - Merging In-memory Assemblies

I have a project where I am dynamically compiling code from a string as such:
public static Assembly BuildItem(Document doc)
{
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.GenerateInMemory = true;
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults results = provider.CompileAssemblyFromSource(parameters, doc.GetCompileString());
return results.CompiledAssembly;
}
What I'd like to be able to do is take these resulting assembly files and combine them into a single assembly without writing them to disk. I know about ILMerge, and that is currently a fallback plan if I need to do that. Any help is appreciated. Thanks in advance.
When compiling you can pass an array of source files, then they're all in one assembly. e.g
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerResults results = provider.CompileAssemblyFromSource(parameters, new string [] { source1, source2... })
Alternatively if you really have to call CompileAssemblyFromSource seperately for each source. You could add all the generated assemblies as embedded resources to another assembly using
CSharpCodeProvider provider = new CSharpCodeProvider();
foreach(string assemblyPath in generatedAssemblies)
provider.EmbeddedResources.Add(assemblyPath);
Then...
CompilerResults results = provider.CompileAssemblyFromSource(parameters, source);
...where source is from the following blog which describes how to load assemblies from embedded resources...
http://blogs.msdn.com/b/microsoft_press/archive/2010/02/03/jeffrey-richter-excerpt-2-from-clr-via-c-third-edition.aspx

Categories