I want to create a program that produces an executable slideshow.
So I need it to output an EXE with some required code and certain embedded resources (pictures) in it.
Does .NET provide such capability?
You can use CSharpCodeProvider class to compile code at runtime and add embedded resources. Have a look at this article where I explain how to do it: SlideShow Builder
This is easy to accomplish.
You can add pictures as embedded resources and then use the technique of Reflection to discover and retrieve the embedded pictures.
So the program you write is independent of the list of pictures, which are just embedded resources. You can embed pictures as resources using Visual Studio, or create a custom program to do it.
You can find some examples at http://msdn.microsoft.com/en-us/library/aa287676(v=VS.71).aspx and http://www.java2s.com/Code/CSharp/Development-Class/Saveandloadimagefromresourcefile.htm.
Good luck!
Like what SK-Logic said there is
http://msdn.microsoft.com/en-us/library/system.reflection.emit.aspx
here is example of that
http://olondono.blogspot.com/2008/02/creating-code-at-runtime.html
You could also create a the project file and create the code files and use the Process class to call the compiler if you want help doing this I can give an example
this will generate a process for you with the specified name (you'll still need to add code for the pictures):
public static Process GenerateRuntimeProcess(string processName, int aliveDuration, bool throwOnException = true)
{
Process result = null;
try
{
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName() { Name = processName }, AssemblyBuilderAccess.Save);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(processName, processName + ".EXE");
TypeBuilder typeBuilder = moduleBuilder.DefineType("Program", TypeAttributes.Public);
MethodBuilder methodBuilder = typeBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, null, null);
ILGenerator il = methodBuilder.GetILGenerator();
il.UsingNamespace("System.Threading");
il.EmitWriteLine("Hello World");
il.Emit(OpCodes.Ldc_I4, aliveDuration);
il.Emit(OpCodes.Call, typeof(Thread).GetMethod("Sleep", new Type[] { typeof(int) }));
il.Emit(OpCodes.Ret);
typeBuilder.CreateType();
assemblyBuilder.SetEntryPoint(methodBuilder.GetBaseDefinition(), PEFileKinds.ConsoleApplication);
assemblyBuilder.Save(processName + ".EXE", PortableExecutableKinds.Required32Bit, ImageFileMachine.I386);
result = Process.Start(new ProcessStartInfo(processName + ".EXE")
{
WindowStyle = ProcessWindowStyle.Hidden
});
}
catch
{
if (throwOnException)
{
throw;
}
result = null;
}
return result;
}
you can findmore info on System.Reflection.Emit on MSDN here or a tutorial here or here.
if I were you I'd also look into just using powerpoint and/or the viewer app and some command line options as detailed here. maybe you don't need to "make an app that makes another app that is a slideshow" at all..
Related
Tools like dotnet-script and CSI allow users to write, compile, and run C# like "scripts" rather than including their code in a complete pre-compiled project. These tools work great for command-line usage, but don't offer much in terms of integrating dynamic C# "scripts" into a larger C# application.
If I have an existing C# application which wishes to load additional classes into its existing namespaces via .csx "scripts", how do I do that? Is it possible?
I guess you need to compile and execute your C# script.
In my experience, I used C# scripts by referencing Microsoft.CodeAnalysis.CSharp.Scripting (version 3.*) directly.
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Scripting" Version="3.*" />
Compilation
I suggest to use default compilation options:
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Scripting;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Scripting;
// ...
ScriptOptions options = ScriptOptions.Default;
Maybe in the future, you'll need to add referenced assemblies to your script compilation.
So you need to compile your script (contained in a string variable in the code below):
byte[] assemblyBinaryContent;
var roslynScript = CSharpScript.Create(script, options);
var compilation = roslynScript.GetCompilation();
compilation = compilation.WithOptions(compilation.Options
.WithOptimizationLevel(OptimizationLevel.Release)
.WithOutputKind(OutputKind.DynamicallyLinkedLibrary));
using (var assemblyStream = new MemoryStream())
{
var result = compilation.Emit(assemblyStream);
if (!result.Success)
{
var errors = string.Join(Environment.NewLine, result.Diagnostics.Select(x => x));
throw new Exception("Compilation errors: " + Environment.NewLine + errors);
}
assemblyBinaryContent = assemblyStream.ToArray();
}
GC.Collect(); // it allows to force clear compilation stuff.
Assembly assembly = Assembly.Load(assemblyBinaryContent);
var ret = Run(assembly); // see next paragraph
Execution
Obviously you need an entry point to execute your script.
I found out this trickly solution. It works.
private object Run(Assembly assembly)
{
//Execute the script
var type = assembly.GetType("Submission#0");
var method = type.GetMethod("<Factory>", BindingFlags.Static | BindingFlags.Public);
var retTask = method.Invoke(null, new object[] { new object[2] }) as Task<object>;
return retTask.GetAwaiter().GetResult();
}
I hope it can help.
I have a project where I compile a lot of files in memory using Microsoft.CodeDom.Providers.DotNetCompilerPlatform.CSharpCodeProvider
My problem happened when I started to try to use wpf windows.
I am able to get the in-memory assembly to compile, but when I go to bring up the window I get:
System.Exception: The component 'Dynamic.DragonListForm' does not have
a resource identified by the URI
'/ScriptCode;component/wpf_ui/dragonlistform.xaml'.
at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
NOTE: I compile by adding a list of all the .cs files in a particular folder
objCompileResults = objCodeCompiler.CompileAssemblyFromFile( objCompilerParameters, files.ToArray() );
I also add dll references needed to make it work.
NOTE: Thanks to Reed, I was able to get it working well enough for my needs by doing:
List<string> bamlFiles = Directory.GetFiles( directoryPath, "*.baml", SearchOption.AllDirectories ).ToList();
bamlFiles.ForEach( x => objCompilerParameters.EmbeddedResources.Add( x ) );
In my project this is good enough. I have a .NET app that I use for executing voice commands. In general, I have it so I can recompile assembly changes in memory as I change voice commands. I imagine some of this won't work with WPF but I am now able to use WPF windows in my in-memory assembly.
The problem is that WPF files aren't just C#, they're also the XAML, which then gets compiled in a separate MSBuild task into BAML resources and included as embedded resources.
If you wanted to support some version of this, you'd need to include all of the referenced xaml as resources. See this post for details on how to do that using CodeDom.
Once that was done, you'd have to also make sure that you're using a compatible mechanism for loading the types. The "normal" way C# compiles xaml/xaml.cs files won't work in your situation, as it requires the resources to be precompiled to baml. You'd have to effectively "rewrite" the code behind for the C# types to use a different mechanism of loading the XAML - typically this would be done by using XamlObjectReader and XamlObjectWriter to read the xaml contents and "write them" into the object during the InitializeComponent pass.
Another very helpful piece of information is given at: The component does not have a resource identified by the uri
From that I created an extension method that can be called like this:
// https://stackoverflow.com/questions/7646331/the-component-does-not-have-a-resource-identified-by-the-uri
this.LoadViewFromUri( #"/ScriptCode;component/wpf_ui/spywindowviewer.xaml" );
// InitializeComponent();
NOTE: I just use the uri that shows up in the error message, for example:
The component 'Dynamic.DragonListForm' does not have a resource identified by the URI '/ScriptCode;component/wpf_ui/dragonlistform.xaml'. at
The extension method:
using System;
using System.IO.Packaging;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Markup;
using System.Windows.Navigation;
namespace Extensions
{
public static class WpfWindowExtensions
{
// https://stackoverflow.com/questions/7646331/the-component-does-not-have-a-resource-identified-by-the-uri
public static void LoadViewFromUri( this Window window, string baseUri )
{
try
{
var resourceLocater = new Uri( baseUri, UriKind.Relative );
// log.Info( "Resource locator is: ")
var exprCa = ( PackagePart )typeof( Application ).GetMethod( "GetResourceOrContentPart", BindingFlags.NonPublic | BindingFlags.Static ).Invoke( null, new object[] { resourceLocater } );
var stream = exprCa.GetStream();
var uri = new Uri( ( Uri )typeof( BaseUriHelper ).GetProperty( "PackAppBaseUri", BindingFlags.Static | BindingFlags.NonPublic ).GetValue( null, null ), resourceLocater );
var parserContext = new ParserContext
{
BaseUri = uri
};
typeof( XamlReader ).GetMethod( "LoadBaml", BindingFlags.NonPublic | BindingFlags.Static ).Invoke( null, new object[] { stream, parserContext, window, true } );
}
catch( Exception )
{
//log
}
}
}
}
I found the following code at Dr Dobbs (slightly rewritten):
namespace TestEXEApp
{
public class Program
{
static void Main(string[] args)
{
AssemblyName an = new AssemblyName();
an.Name = "TestEXEApp";
AppDomain ad = AppDomain.CurrentDomain;
AssemblyBuilder ab = ad.DefineDynamicAssembly(an,
AssemblyBuilderAccess.Save);
ModuleBuilder mb = ab.DefineDynamicModule(an.Name, "Hello.exe");
TypeBuilder tb = mb.DefineType("TestEXEApp.Program",
TypeAttributes.Public | TypeAttributes.Class);
MethodBuilder fb = tb.DefineMethod("Main",
MethodAttributes.Public |
MethodAttributes.Static,
typeof(int), new Type[] { typeof(string[]) });
ILGenerator ilg = fb.GetILGenerator();
ilg.Emit(OpCodes.Ldstr, "Hello, World!");
ilg.Emit(OpCodes.Call, typeof(TestClasses.Class1).GetMethod("Test",
new Type[] { typeof(string) }));
ilg.Emit(OpCodes.Ldc_I4_0);
ilg.Emit(OpCodes.Ret);
// Seal the lid on this type
Type t = tb.CreateType();
// Set the entrypoint (thereby declaring it an EXE)
ab.SetEntryPoint(fb, PEFileKinds.ConsoleApplication);
// Save it
ab.Save("Hello.exe");
Console.WriteLine("Press enter...");
Console.ReadLine();
}
}
}
Also, I have the following class in a separate project called TestClasses:
namespace TestClasses
{
public class Class1
{
public static void Test(String t)
{
Console.WriteLine("Test: " + t);
}
}
}
Now, when I compile this, I get (obviously) the two files "TestEXEApp.exe" and "TestClasses.dll". If I run it, I get a new file, "Hello.exe", and if I run this new file, it prints "Test: Hello, World!". So far, so good. Now, the problem is, this new file obviously depends on TestClasses.dll. So if I emit it into another directory, or move it for some reason, it can no longer execute.
Is there some way for Reflection.Emit to in some way include the TestClasses.Class1 code into the Hello.exe executable, so that it becomes 100% self-contained (apart from the dependence on the .NET framework, obviously)? Or, if that can't be done, how can I get the program to output a copy of TestClasses.dll, so that I always have the dll-file written in the same directory as Hello.exe?
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I'm writing a program that would have the possibility to learn for itself.
Example:
a word 'day' was typed
look for interface named 'day'
does it exists?
No => create class based on that interface (and implement the interface) and save it for next use then create instance of that class
Yes => create instance of that class
Google gave me this: How to dynamically create a class in C#?
This solution is the closest I can think of for my scenario, but it assumes you already know how many properties you will need and doesn't implement an interface at all.
I have no experience at all with system.reflection but I'm eager to learn!
Anyone know an example for my case?
Any help is appriciated.
Thank You!
EDIT: MY SOLUTION
(Because nobody gave me a straight answer I figured it out myself)
public void createObject(string name)
{
//Namespace where the interfaces are located
string strnamespace = "Intelligence.Omnia.Categories";
//Get interfacecollection
List<Type> interfaceCollection = Assembly.GetExecutingAssembly().GetTypes().Where(t => t.IsInterface && t.Namespace == strnamespace).ToList();
foreach (Type myinterface in interfaceCollection)
{
//interface names
List<string> interfaceNames = new List<string>();
if (myinterface.Name == name)
{
//Add interface name
interfaceNames.Add(myinterface.Name);
//Add current interfaceproperties
List<PropertyInfo> myProps = myinterface.GetProperties().ToList();
//Does the current interface inhiretes from other interfaces?
foreach (Type inhiretences in myinterface.GetInterfaces())
{
//Add interface name
interfaceNames.Add(inhiretences.Name);
//Add those properties aswell!
foreach (PropertyInfo pi in inhiretences.GetProperties())
{
myProps.Add(pi);
}
}
createType(name, myProps, interfaceNames);
}
}
}
static void createType(string name, List<PropertyInfo> props, List<string> interfacesnames)
{
//create instance of CSharpCodeProvider
CSharpCodeProvider csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
//DLL
string pathDLL = AppDomain.CurrentDomain.BaseDirectory + "Objects.dll";
CompilerParameters parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.dll", "System.Linq.dll", "System.Threading.Tasks.dll", "Intelligence.dll" });
parameters.OutputAssembly = pathDLL;
parameters.GenerateExecutable = false;
ICodeCompiler icc = csc.CreateCompiler();
//>>>>Generated CODE
//Add namespaces
CodeCompileUnit compileUnit = new CodeCompileUnit();
CodeNamespace ns = new CodeNamespace("Objects");
compileUnit.Namespaces.Add(ns);
ns.Imports.Add(new CodeNamespaceImport("System"));
ns.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
ns.Imports.Add(new CodeNamespaceImport("System.Linq"));
ns.Imports.Add(new CodeNamespaceImport("System.Text"));
ns.Imports.Add(new CodeNamespaceImport("System.Threading.Tasks"));
ns.Imports.Add(new CodeNamespaceImport("Intelligence"));
ns.Imports.Add(new CodeNamespaceImport("Intelligence.Omnia"));
ns.Imports.Add(new CodeNamespaceImport("Intelligence.Omnia.Categories"));
//Define your class
CodeTypeDeclaration classType = new CodeTypeDeclaration("Object"+name);
classType.Attributes = MemberAttributes.Public; //make it public
foreach(string interfaceName in interfacesnames) //let it inherit from the interfaces
{
classType.BaseTypes.Add(interfaceName);
}
ns.Types.Add(classType);
//Add constructor
CodeConstructor constr = new CodeConstructor();
constr.Attributes = MemberAttributes.Public;
classType.Members.Add(constr);
//Add all the properties
foreach (var prop in props)
{
//If you want private fields
//CodeMemberField field = new CodeMemberField(prop.PropertyType, prop.Name);
//classType.Members.Add(field);
CodeMemberProperty property = new CodeMemberProperty();
property.Attributes = MemberAttributes.Public | MemberAttributes.Final;
property.Type = new CodeTypeReference(prop.PropertyType);
property.Name = prop.Name;
property.GetStatements.Add(new CodeMethodReturnStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), prop.Name)));
property.SetStatements.Add(new CodeAssignStatement(new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), prop.Name), new CodePropertySetValueReferenceExpression()));
classType.Members.Add(property);
}
//Write the file for later use
TextWriter tw = new StreamWriter(new FileStream(AppDomain.CurrentDomain.BaseDirectory + "Objects\\" + name + ".cs", FileMode.Create));
csc.GenerateCodeFromCompileUnit(compileUnit, tw, null);
tw.Close();
//Compile the class
CompilerResults results = icc.CompileAssemblyFromFile(parameters, AppDomain.CurrentDomain.BaseDirectory + "Objects\\" + name + ".cs");
results.Errors.Cast<CompilerError>().ToList().ForEach(error => System.Windows.Forms.MessageBox.Show(error.ErrorText));
}
As #Stefan says you can dynamically create type using the DLR built into .net 4.0+ but you can also use the older reflection based mechanism in CodeDom. My suggestion is to look at IronPython as this can do what you want really easily. However if you want C#, then you need to understand that C# is compiled and you need to use the compilation in System.CodeDom.Compiler.
Nothing can infer knowledge from word Day to what the interface Day is - you have to supply this is some way. However if you know the rules by which the interface will exist, you can create it dynamically. You can also go further and create additional types based on the interface. Again no code can be written magically - you need to supply the code semantics and syntax.
However if you have this you could separate the code into multiple assemblies (CompileAssemblyFromSource). Then dynamically load the assemblies to load the types (step 2). You can create types and assemblies at runtime (see OS: Generating DLL assembly dynamically at run time).
This code is from the above linked SO answer, and shows you how to an assembly from some string of code.
using System.CodeDom.Compiler;
using System.Diagnostics;
using Microsoft.CSharp;
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
parameters.OutputAssembly = "My_Assembly_Day.dll";
CompilerResults results = icc.CompileAssemblyFromSource(parameters, ".... some C# code ....");
This SO answer shows you how to load assemblies to discover types:
https://stackoverflow.com/a/14184863/30225
edit: To answer comments.
You can name your assembly anything you like - my suggestion is to name it with interface/class combination. The above is just an example of how you can name it
You can either load the existing (pre created assemblies) at load time (first step in the program), or you can dynamically load the assemblies at runtime when needed.
Once you've loaded the assemblies the types are available to you (Activator.CreateInstance) for example.
If you get to your step and for instance type IDay is not available, you can dynamically create it using type text. Of course to get the CodeDom compiler to work, you'll need to ensure that all the things that this code references is supplied to the compilation unit. And compile that into an assembly on the disk. You can create the interface & the class that same time or in two steps.
Once step 4 is done you can load that assembly like in step 3 & 4.
at the end of the day the answer boils down to:
Find the existing type from existing types set
If existing type is not available create it in an assembly dynamically.
Load that type
Instantiate that type.
The concern comes when using that type. You can either create more code using CodeDom (in effect this gives you the ability to recreate classes that may already exist BTW) or you can use types dynamically in your code. The first has the compilation overhead, while the second has the complexity in writing code that doesn't have hard coded types - a job made very simple btw using the C# dynamic keyword. Either way this is a very run of the mill .net coding technique when using types dynamically, and many existing applications use techniques like this for managing plugins.
Caveat:
Please remember that the smallest unloadable unit in .net is the AppDomain. When you load assemblies you load them into an AppDomain. If you want unload assemblies (and thus types) to replace them fo instance, you need to unlaod the AppDomain. This means that you need to ensure that any dynamically loaded assemblies are loaded into new AppDomains which in turn can be unloaded when needed.
I'm trying a sort of experiment in C# .NET. I'd like to create a program that clones itself (eventually as a mutated clone). Finally, I want it to produce a "son" that also needs to have the ability to clone himself and so on!
I want to make something like this:
static void Main(string[] args)
{
string Son_Name = "son";
string Full_Son_Name = Son_Name + ".exe";
AssemblyName aName = new AssemblyName(Son_Name);
AssemblyBuilder aBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Save);
ModuleBuilder mBuilder = aBuilder.DefineDynamicModule("Module", Full_Son_Name, false);
TypeBuilder tBuilder = mBuilder.DefineType("Program", TypeAttributes.Public);
MethodBuilder methodBuilder = tBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static);
ILGenerator ilGenerator = methodBuilder.GetILGenerator();
MethodInfo m_ReadLine = typeof(System.Console).GetMethod("ReadLine", BindingFlags.Public | BindingFlags.Static);
Clone_My_Main_method(methodbuilder);//I need something to do THAT
aBuilder.SetEntryPoint(methodBuilder);
tBuilder.CreateType();
aBuilder.Save(Full_Son_Name);
So, with this code I succeded in making a dynamic assembly at runtime, and save it as "son.exe" or execute it. Now I need to "build" that assembly, reading my main and copying it into the son assembly.
I started using ilgenerator.emit, but I'm going into an infinite "programming" loop. I thought to make the parent.exe, disassemble it with ildasm, translate all the CIL code in ilgenerator.emit opcodes and emit all of that with ilgenerator.emit. Simply, I think this is a tedious work and cannot...work.
In fact, I'd like to READ at runtime my own main method, and then put it onto the dynamic assembly with some trick.
Anyone has any idea?
Thanks :)
You should use Mono Cecil, which can read and modify .Net assemblies.