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.
Related
Is this possible if not could some one please explain how i could implement this to work?
So i have a C# Application and a folder with it called modules, so files:
Application.exe
modules/
Application.Handler.ModuleName.dll
So inside the DLL it has the namespace Application.Handle containing the type ModuleName and ModuleName extends Handler that is implemented in Application.exe so to compile requires Application.exe as a reference.
Inside my host application i have:
string[] dirs = Directory.GetFiles(#"modules/", "Application.Handler.*.dll");
foreach(string filePath in dirs)
{
Assembly.LoadFile(new FileInfo(filePath).FullName);
string fileName = filePath.Split('/').Last();
string typeAssemblyName = fileName.Replace(".dll", "");
string typeName = typeAssemblyName.Split('.').Last();
}
But i'm unsure if i can implement the types from the strings i thought i could with Activator.CreateInstance but i'm not sure if I'm doing it correctly or if the way I'm trying to implement it works?
UPDATE
I might not have been clear but effectively what i need to do is
Application.Handler handler = new Application.Handler.ModuleName() Where Application.Handler.ModuleName in php it's done like below i thought there would be a system that returns an object of the type given in the string. if it's not there throw an exception
$className = "\Application\Handler\ModuleName";
$instance = new $className();
I have also tried using the Unwrap system that #rene suggested
Assembly asm = Assembly.LoadFile(new FileInfo(filePath).FullName);
string fileName = filePath.Split('/').Last();
string typeAssemblyName = fileName.Replace(".dll", "");
string typeName = typeAssemblyName.Split('.').Last();
FrameHandler fh;
fh = (FrameHandler)Activator.CreateInstance(asm.FullName, typeAssemblyName).Unwrap();
fh.RegisterHandlers();
using this method where i give it the Assembly name it gives me a FileNotFoundException and without the Assembly name i get TypeLoadException but it must be loading the manifest of the assembly as Application.Handler.ModuleName, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null
You just need a handle to the type, so you'll need the assembly path and the type's full name.
var assy = Assembly.LoadFile("...");
var type = assy.GetType("...");
var obj = Activator.CreateInstance(type);
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.
We try to compile source code at runtime and then add the resulting assembly to an AppDomain. But in the moment even loading the assembly fails:
string sourceCode = "using System;\r\n" +
"public class Program1{\r\n" +
" public static void Main1(){\r\n" +
" int i = 100;\r\n" +
" }\r\n" +
"}";
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
Assembly[] assembliesOfCurrentDomain = AppDomain.CurrentDomain.GetAssemblies();
for (int runAssembliesInCurrDomain = 0; runAssembliesInCurrDomain < assembliesOfCurrentDomain.Length; runAssembliesInCurrDomain++)
{
try
{
parameters.ReferencedAssemblies.Add(assembliesOfCurrentDomain[runAssembliesInCurrDomain].Location);
}
catch
{
}
}
// True - memory generation, false - external file generation
parameters.GenerateInMemory = false;
parameters.OutputAssembly = "D:\\temp\\123.dll";
parameters.IncludeDebugInformation = true;
parameters.ReferencedAssemblies.Add(Assembly.GetEntryAssembly().Location);
// True - exe file generation, false - dll file generation
parameters.GenerateExecutable = false;
CompilerResults results = provider.CompileAssemblyFromSource(parameters, sourceCode);
Assembly a = Assembly.Load("D:\\temp\\123.dll");
The last line throws an exception "An unhandled exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll". We have no idea what's going wrong there. We tried compiling this code with .Net Framework 2.0 and 4.5, with AnyCPU, x64, and x86. Always the same problem. Any ideas why this exception is be thrown?
You have to use the Assembly.LoadFrom method to load from a path. It will throw an exception that it is not recommended to do so but this exception is caught internally and programm succeeds.
From the MSDN article you should be passing in the long name of the assembly to Assembly.Load. For example:
string longName = "123, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
Assembly assem = Assembly.Load(longName);
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 ?
So I dont know how to do that...
I have a program "Prg.cs" and a dll "Test.dll".
I have try:
Assembly asm=Assembly.Load(#"C:\Users\Me\documents\visual studio 2013\Projects\Prg\Prg\bin\Debug\Test.dll");
Type runApp = asm.GetType();
dynamic thisApp = Activator.CreateInstance(runApp, this);
But gives me error:
An unhandled exception of type 'System.IO.FileLoadException' occurred in mscorlib.dll
Additional information: Could not load file or assembly 'C:\\Users\\Me\\documents\\visual studio 2013\\Projects\\Prg\\Prg\\bin\\Debug\\Test.dll' or one of its dependencies. The given assembly name or codebase was invalid. (Exception from HRESULT: 0x80131047)
Thanks!
You can do something like this:
class Program
{
static void Main(string[] args)
{
var dll = Assembly.LoadFile(#"C:\Test.dll");//The path of your dll
var theType = dll.GetType("dll.Test");
var c = Activator.CreateInstance(theType);
var method = theType.GetMethod("Output");//Your method in the class
method.Invoke(c, new object[]{#"Hello world"});
Console.ReadLine();
}
}
this link can help youstackoverflow.com/a/18362515/3383479