I've got a C# program this is attempting to dynamically compile some VB.Net code.
var vbc = new Microsoft.VisualBasic.VBCodeProvider(new Dictionary<string, string>
{ { "CompilerVersion", "v4.0" } });
var parameters = new CompilerParameters(new[] {"mscorlib.dll", "System.Core.dll",
"System.Data.dll", "System.dll", "System.Xml.dll", "Microsoft.VisualBasic.dll"},
#"MyFile.exe", false)
{
GenerateInMemory = false,
GenerateExecutable = true
};
CompilerResults results = vbc.CompileAssemblyFromFile(parameters, "file1.vb", "file2.vb",
"file3.vb", "file4.vb");
It's working, but with errors. The problem is, in a real Visual Basic project, by default, the following namespaces are automatically imported:
System
System.Collections
System.Collections.Generic
System.Data
System.Diagnostics
System.Linq
System.Xml.Linq
System.Threading.Tasks
Microsoft.VisualBasic
You can verify this yourself by going to create a new Visual Basic project, then looking at the properties of the project and clicking References. You will see that the above listed namespaces are automatically imported.
My question is, how do I globally auto import these namespaces and pass it into VBCodeProvider so it will automatically import these when it tries to compile?
I found a similar question to mine here, however, no answers have been provided except by the OP, who is doing something "hacky", which I prefer not to do.
Related
I'm currently trying to generate and execute some C# code directly from a Xamarin.iOS code editor application I'm working on. I use Roslyn for all the compilation steps, but unfortunately, Mono doesn't allow you to load Assemblies at Runtime on iOS.
So, this code would typically throw a Attempting to JIT compile method while running with --aot-onlyexception.
var tree = CSharpSyntaxTree.ParseText(#"public Foo
{
public void Bar() { Console.WriteLine(""""foo"""");
}");
var compilation = CSharpCompilation.Create(
"Generated." + Guid.NewGuid(),
syntaxTrees: new[] { tree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
var result = compilation.Emit(ms);
var assembly = Assembly.Load(ms); // <- Thrown here
}
I know that Frank A. Krueger did a custom interpreter for IL for his awesome Continuous application.
I imagine having a similar approach but directly from the SemanticModel and SyntaxTrees outputted by Roslyn because I only want to support C#.
Regarding the pretty huge codebase of Roslyn, are there some bits I can pickup to base my interpreter on ?
Another question, without the possibility to generate Types dynamically, how could I represent those dynamic declared Types at Runtime ?
Thanks!
The ecosystem on iOS does not allow dynamically generated code. It's also part of legal restrictions for iOS platform.
I am aware of a class called AssemblyBuilder, and I would have thought I could use it to pass a folder containing C# source files, or pass a single C# source file to it in order to compile the source into an assembly (.dll) which can then be referenced in a config file.
I'm aware of csc.exe which can compile C#, and I'm effectively looking for a way to replicate this dynamically.
I couldn't figure out how to use AssemblyBuilder, or whether this is the wrong class to be using, or whether I should be doing something similar to the following:
http://support.microsoft.com/kb/304655
Can you point me in the right direction please.
You might want to look into CodeDomProvider
Example snippet:
CompilerParameters parms = new CompilerParameters
{
GenerateExecutable = false,
GenerateInMemory = true,
IncludeDebugInformation = false
};
parms.ReferencedAssemblies.Add("System.dll");
parms.ReferencedAssemblies.Add("System.Data.dll");
CodeDomProvider compiler = CSharpCodeProvider.CreateProvider("CSharp");
return compiler.CompileAssemblyFromSource(parms, source);
Warning: assemblies built dynamically in this fashion won't be handled by the garbage collector.
Suppose Project Main has a reference to Project Ref. In Main, I have defined a CSharpCodeProvider and use it to compile code at runtime.
var provider = new CSharpCodeProvider(new Dictionary<string, string> { { "CompilerVersion", "v4.0" } });
var parameters = new CompilerParameters();
parameters.ReferencedAssemblies.Add("System.dll");
// Rest of the referenced assemblies.
The code which is compiled at runtime, might require a newer version of Project Ref to run correctly. So I tried to add the new Ref.Dll in a relative subfolder (plugins):
parameters.ReferencedAssemblies.Add(#"d:\project-output-path\plugins\Ref.dll");
I have also added the following:
AppDomain.CurrentDomain.AppendPrivatePath("plugins");
Problem is when I try to compile the script dynamically, the Ref.dll in the main folder is being used and causes error.
So, What would be the best way to reference the new Ref project only for my script?
P.S. I really prefer not having to create another AppDomain since the dynamically executing code is coupled with the code loaded in current AppDomain and cannot be separated.
I'm attempting to include an embedded resource into a dll that I am compiling using Roslyn. I've found something that helped put me on the right track here.
However, when I create the dll using the following code:
const string resourcePath = #"C:\Projects\...\Properties\Resources.resources";
var resourceDescription = new ResourceDescription(
"Resources.resources",
() => File.OpenRead(resourcePath),
true);
var result = mutantCompilation.Emit(file, manifestResources: new [] {resourceDescription});
I find that it will pass all of the unit tests that I have created for the project except for those that rely on the Resources file.
The error I'm getting looks like the following:
System.Resources.MissingManifestResourceException ... Make sure "[Project].Properties.Resources.resources" was correctly embedded or linked into
assembly "[Project]" at compile time, or that all the satellite assemblies required are loadable and fully signed.
The dll is supposed to be signed, and when it is emitted by roslyn it comes out with the correct public key. Also, the Resource.resx is included in my project directly in the Properties folder.
I would appreciate any help anyone could provide.
Ok, so while I was looking for answers, I came across this web page where it was commented that the resource stream was null until the he added the namespace.
So after adding the namespace I got somehting like this
const string resourcePath = #"C:\Projects\...\Properties\Resources.resources";
var resourceDescription = new ResourceDescription(
"[namespace].Resources.resources",
() => File.OpenRead(resourcePath),
true);
var result = mutantCompilation.Emit(file, manifestResources: new [] {resourceDescription});
which runs exactly like you'd expect.
I need shell32 in my program to create a shortcut.
This is my code:
var compiler = new CSharpCodeProvider();
var Params = new System.CodeDom.Compiler.CompilerParameters
{
GenerateExecutable = true,
OutputAssembly = outputName,
ReferencedAssemblies = {
"System.dll",
"System.Core.dll",
"System.Windows.Forms.dll",
"System.Drawing.dll",
#"C:\Windows\System32\Shell32.dll"
}
};
Doing this, I get an error:
Metadata file C:\Windows\System32\Shell32.dll could not be opened. An attempt was made to load a program with incorrect format.
Found nothing while searching.. I wasn't even sure what to search for :/
How would I go about doing this?
Shell32.dll (Windows file systems don't care about case, so "s" or "S" shouldn't matter) is not a .NET assembly and thus can't be treated as such.
If you want to call functions exported from non-.NET libraries, you should use the DllImportAttribute.
I had the same problem and just solved it.
Add the following to your referenced Assemblies list:
ReferencedAssemblies.Add("Interop.Shell32.dll");