How to dynamically compile code with resources references using properties? - c#

I have a problem with compiling code dynamically using below code:
CSharpCodeProvider provider = new CSharpCodeProvider();
// Build the parameters for source compilation.
CompilerParameters cp = new CompilerParameters();
// Add an assembly reference.
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Management.dll");
// Generate an executable instead of
// a class library.
cp.GenerateExecutable = true;
// Set the assembly file name to generate.
cp.OutputAssembly = "test.exe";
// Save the assembly as a physical file.
cp.GenerateInMemory = false;
// Invoke compilation.
CompilerResults cr = provider.CompileAssemblyFromFile(cp, "data.txt");
if (cr.Errors.Count > 0)
{
// Display compilation errors.
MessageBox.Show("Errors building {0} into {1}","data,txt");
foreach (CompilerError ce in cr.Errors)
{
MessageBox.Show(ce.ToString());
}
}
else
{
MessageBox.Show("Source {0} built into {1} successfully.","data.txt");
}
The code in data.txt file has line:
Properties.Resources.something
Now when I compile code dynamically it shows error:
Name "Properites" does not exist in current context.
I don't know how to fix it. There is no DLL named Properties.dll so I cannot refernce it.
I tried System.References.dll but It does not solve the problem.
Edit sample:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApp1
{
public static void Main()
{
byte[] resource = Properties.Resources.someresource;
}
}

Based on my search, I find that your source file is wrong. As usual, the source file should end with .cs instead of .txt.
I make a successful code example and you could have a look.
Code:
class Program
{
[STAThread]
static void Main(string[] args)
{
if (args.Length > 0)
{
// First parameter is the source file name.
if (File.Exists(args[0]))
{
CompileExecutable(args[0]);// Here args[0] is 'D:\\test.cs'
}
else
{
Console.WriteLine("Input source file not found - {0}",
args[0]);
}
}
else
{
Console.WriteLine("Input source file not specified on command line!");
}
Console.WriteLine("success");
Console.ReadKey();
}
public static bool CompileExecutable(String sourceName)
{
FileInfo sourceFile = new FileInfo(sourceName);
CodeDomProvider provider = null;
bool compileOk = false;
// Select the code provider based on the input file extension.
if (sourceFile.Extension.ToUpper(CultureInfo.InvariantCulture) == ".CS")
{
provider = CodeDomProvider.CreateProvider("CSharp");
}
else if (sourceFile.Extension.ToUpper(CultureInfo.InvariantCulture) == ".VB")
{
provider = CodeDomProvider.CreateProvider("VisualBasic");
}
else
{
Console.WriteLine("Source file must have a .cs or .vb extension");
}
if (provider != null)
{
// Format the executable file name.
// Build the output assembly path using the current directory
// and <source>_cs.exe or <source>_vb.exe.
String exeName = String.Format(#"{0}\{1}.exe",
System.Environment.CurrentDirectory,
sourceFile.Name.Replace(".", "_"));
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Console.dll");
cp.ReferencedAssemblies.Add("System.Resources.ResourceManager.dll");
cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");// I have changed here.
cp.GenerateExecutable = true;
// Specify the assembly file name to generate.
cp.OutputAssembly = exeName;
// Save the assembly as a physical file.
cp.GenerateInMemory = false;
// Set whether to treat all warnings as errors.
cp.TreatWarningsAsErrors = false;
// Invoke compilation of the source file.
CompilerResults cr = provider.CompileAssemblyFromFile(cp,
sourceName);
if (cr.Errors.Count > 0)
{
// Display compilation errors.
Console.WriteLine("Errors building {0} into {1}",
sourceName, cr.PathToAssembly);
foreach (CompilerError ce in cr.Errors)
{
Console.WriteLine(" {0}", ce.ToString());
Console.WriteLine();
}
}
else
{
// Display a successful compilation message.
Console.WriteLine("Source {0} built into {1} successfully.",
sourceName, cr.PathToAssembly);
}
// Return the results of the compilation.
if (cr.Errors.Count > 0)
{
compileOk = false;
}
else
{
compileOk = true;
}
}
return compileOk;
}
}
.cs file
using System;
using System.Collections;
using System.Collections.Generic;
using System.Resources;
namespace ConsoleApp1
{
public class Student
{
public static void Main()
{
using (ResXResourceWriter resx = new ResXResourceWriter(#".\CarResources.resx"))
{
resx.AddResource("Title", "Classic American Cars");
resx.AddResource("Name", "test1");
resx.AddResource("Age", "22");
}
Dictionary<string, string> pairs = new Dictionary<string, string>();
using (ResXResourceReader resxReader = new ResXResourceReader(#".\CarResources.resx"))
{
foreach (DictionaryEntry entry in resxReader)
{
pairs.Add(entry.Key.ToString(), entry.Value.ToString());
Console.WriteLine(entry.Value);
}
}
Console.WriteLine("success");
Console.ReadKey();
}
}
}
Result:
When you click the .exe file, you will get the following:

Related

The specified executable is not a valid application for this OS platform mediatoolkit

I have this function to get the duration of an mp3 file using mediaToolKit.
but when execute engine.GetMetadata(inputFile); I have an exception that is :
System.ComponentModel.Win32Exception: 'The specified executable is not a valid application for this OS platform.'
private string getDuration()
{
string orginalFilePath = LocalMediaPath;
if (File.Exists(orginalFilePath))
{
var inputFile = new MediaFile { Filename = orginalFilePath };
using (var engine = new Engine())
{
engine.GetMetadata(inputFile);
return inputFile.Metadata.Duration.TotalSeconds.ToString();
}
}
else
return "-1";
}
I found the source code.
It works well!
Snippet:
using MediaToolkit;
using MediaToolkit.Model;
using System;
namespace ConsoleApp2
{
class Program
{
static void Main(string[] args)
{
var inputFile = new MediaFile { Filename = #"C:\Users\Admin\source\repos\ConsoleApp2\ConsoleApp2\music\123.mp3" };
using (var engine = new Engine())
{
engine.GetMetadata(inputFile);
}
Console.WriteLine(inputFile.Metadata.Duration);
System.Console.ReadLine();
}
}
}
Change your file, it is likely that your file is not supported.

How to use project methods with Roslyn?

I am using Roslyn to run C# code from text.
It works, but I can't figure out how can I use my project class methods, didn't find a way to reference my project methods. I can't use a dll as there too many classes and forms I need to use.
For exmaple, using the Number set method, or the DoMultiAction() method inside the roslyn ExecuteUserCodeTest() text code. How to do that they will be referenced?
Is it even possible? Any explanation or example will be appreciated.
My Code:
namespace bot1
{
class Testing
{
private int number;
public int Number
{
get { return number; }
set { this.number = value; }
}
public int DoMultiAction(int num1, int num2)
{
return num1 * num2 * Number;
}
public void ExecuteUserCodeTest()
{
String text = #"
using System;
using System.Drawing;
using System.Windows.Forms;
namespace RoslynCompileSample
{
public class Writer
{
public void Write(String text)
{
MessageBox.Show(text);
}
}
}";
// define source code, then parse it (to the type used for compilation)
SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(text);
// define other necessary objects for compilation
string assemblyName = Path.GetRandomFileName();
MetadataReference[] references = new MetadataReference[]
{
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.Drawing.Point).Assembly.Location),
MetadataReference.CreateFromFile(typeof(System.Windows.Forms.MessageBox).Assembly.Location),
MetadataReference.CreateFromFile(typeof (ScriptManagerHandler.ScriptHandler).Assembly.Location)
};
// analyse and generate IL code from syntax tree
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { syntaxTree },
references: references,
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
using (var ms = new MemoryStream())
{
// write IL code into memory
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
// handle exceptions
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
String error = "";
foreach (Diagnostic diagnostic in failures)
{
error += "" + diagnostic.Id + ", " + diagnostic.GetMessage() + "\n";
}
if (error != "")
MessageBox.Show(error);
}
else
{
// load this 'virtual' DLL so that we can use
ms.Seek(0, SeekOrigin.Begin);
Assembly assembly = Assembly.Load(ms.ToArray());
// create instance of the desired class and call the desired function
Type type = assembly.GetType("RoslynCompileSample.Writer");
object obj = Activator.CreateInstance(type);
type.InvokeMember("Write",
BindingFlags.Default | BindingFlags.InvokeMethod,
null,
obj,
new object[] { "Hello World" });
}
}
}
}
}

Calling a static method in C#

I implemented a plugin (using pGina software) to allow the user to authenticate the username/password in their computer by scanning a NFC tag.
I used a program I found called CSharp PC/SC Wrapper for .NET to read the tag ID. Every time a tag is scanned the program writes the ID to a text file and checks that the ID is the the same as the one set on the string.
if (userInfo.Username.Contains("hello") && userInfo.Password.Contains("pGina")
&& text.Equals("UID = 0x04 82 EC BA 7A 48 80"))
The plugin is set to find the .exe file that reads the ID (PC/SC Wrapper). Everything works fine. However, I don't one the reader program to be in a different file. I want everything to be in the plugin file.
I created a method and copied the code from the wrapper that performs the reading of the tag ID (runme()), but I'm not sure how to replace the line that calls the .exe file with the method I created
ProcessStartInfo ps = new ProcessStartInfo(#"C:\Users\Student\Desktop\CSharpPCSC\CSharpPCSC\ExamplePCSCReader\bin\Release\ExamplePCSCReader.exe");
Any suggestions? I'm new to C#
Below is my code for the plugin with the method containing the code that reads the ID
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using pGina.Shared.Types;
using log4net;
using System.IO;
using System.Diagnostics;
using GS.PCSC;
using GS.Apdu;
using GS.SCard;
using GS.Util.Hex;
using System.Threading;
namespace HelloPlugin
{
public class PluginImpl : pGina.Shared.Interfaces.IPluginAuthentication
{
private ILog m_logger;
private static readonly Guid m_uuid = new Guid("CED8D126-9121-4CD2-86DE-3D84E4A2625E");
public PluginImpl()
{
m_logger = LogManager.GetLogger("pGina.Plugin.HelloPlugin");
}
public string Name
{
get { return "Hello"; }
}
public string Description
{
get { return "Authenticates users with 'hello' in the username and 'pGina' in the password"; }
}
public Guid Uuid
{
get { return m_uuid; }
}
public string Version
{
get
{
return System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
}
public void Starting()
{
}
public void Stopping() { }
public BooleanResult AuthenticateUser(SessionProperties properties)
{
UserInformation userInfo = properties.GetTrackedSingle<UserInformation>();
ProcessStartInfo ps = new ProcessStartInfo(#"C:\Users\Student\Desktop\CSharpPCSC\CSharpPCSC\ExamplePCSCReader\bin\Release\ExamplePCSCReader.exe");
Process.Start(ps);
Thread.Sleep(2000);
string text = File.ReadAllText(#"C:\Users\Student\Desktop\text.txt", Encoding.UTF8);
text = text.Trim();
if (userInfo.Username.Contains("hello") && userInfo.Password.Contains("pGina") && text.Equals("UID = 0x04 82 EC BA 7A 48 80"))
{
// Successful authentication
m_logger.InfoFormat("Successfully authenticated {0}", userInfo.Username);
return new BooleanResult() { Success = true };
}
// Authentication failure
m_logger.ErrorFormat("Authentication failed for {0}", userInfo.Username);
return new BooleanResult() { Success = false, Message = "Incorrect username or password." };
}
static void runme()
{
ConsoleTraceListener consoleTraceListener = new ConsoleTraceListener();
Trace.Listeners.Add(consoleTraceListener);
PCSCReader reader = new PCSCReader();
string cardid = "";
try
{
reader.Connect();
reader.ActivateCard();
RespApdu respApdu = reader.Exchange("FF CA 00 00 00"); // Get NFC Card UID ...
if (respApdu.SW1SW2 == 0x9000)
{
Console.WriteLine("UID = 0x" + HexFormatting.ToHexString(respApdu.Data, true));
cardid = "UID = 0x" + HexFormatting.ToHexString(respApdu.Data, true);
cardid = cardid.Trim();
}
}
catch (WinSCardException ex)
{
Console.WriteLine(ex.WinSCardFunctionName + " Error 0x" +
ex.Status.ToString("X08") + ": " + ex.Message);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
string path = #"C:\Users\Student\Desktop\text.txt";
string text2write = cardid;
System.IO.StreamWriter writer = new System.IO.StreamWriter(path);
writer.Write(text2write);
writer.Close();
reader.Disconnect();
Environment.Exit(0);
Console.WriteLine("Please press any key...");
Console.ReadLine();
}
}
}
}
You've created a class called PluginImpl and in that class declared the method runme. To call that method from anywhere, you need to write PluginImpl.runme().
Since you've put your class in the namespace HelloPlugin - if the calling *.cs file is in a different namespace, you'll need a using HelloPlugin directive at the top.
That's all!
It's possible I have misunderstood your question, if so please re-word your question and send me a comment.
If you want to replace the line
ProcessStartInfo ps = new ProcessStartInfo(
#"C:\Users\Student\Desktop\CSharpPCSC\CSharpPCSC\"
+"ExamplePCSCReader\bin\Release\ExamplePCSCReader.exe");
with a method call instead, you want something like this
ProcessStartInfo ps = runme();
Since you are calling your static method from within the class, you don't need a PluginImpl. prefix.
Okay, so now it will complain that runme doesn't return ProcessStartInfo. You're going to need to change runme so that it does. Any subclass of ProcessStartInfo will do.
static ProcessStartInfo runme()
{
// ... Some code
ProcessStartInfo toReturn = new ProcessStartInfo( //...
);
// ... More code
return toReturn;
}

Console.WriteLine text from CodeDomProvider

I'm trying to use CodeDomProvider to make a C# compiler.
I managed to get the errors but i can't get the output.
This is what i have so far:
public List<string> Errors(CompilerResults compilerResults)
{
List<string> messages = new List<string>();
foreach (CompilerError error in compilerResults.Errors)
{
messages.Add(String.Format("Line {0} Error No:{1} - {2}", error.Line, error.ErrorNumber, error.ErrorText));
}
return messages;
}
public CompilerResults ProcessCompilation(string programText)
{
CodeDomProvider codeDomProvider = CodeDomProvider.CreateProvider("CSharp");
CompilerParameters parameters = new CompilerParameters();
parameters.GenerateExecutable = false;
StringCollection assemblies = new StringCollection();
return codeDomProvider.CompileAssemblyFromSource(parameters, programText);
}
CSharpCompiler is the class that contains the functions from above
public JsonResult Compiler(string code)
{
CSharpCompiler compiler = new CSharpCompiler();
CompilerResults compilerResults = compiler.ProcessCompilation(code);
Debug.WriteLine("OUTPUT----------------------------------------------");
foreach (var o in compilerResults.Output)
{
Debug.WriteLine(o);
}
List<string> compilerErrors = compiler.Errors(compilerResults);
if (compilerErrors.Count != 0)
return Json(new { success = false, errors = compilerErrors});
return Json(true);
}
compilerResults.Output is always empty.
If i run this piece of code:
using System;
public class HelloWorld
{
public static void Main()
{
Console.WriteLine("Hello world!");
}
}
What can i do to display the message "Hello world!"?
CompileAssemblyFromSource creates, as its name implies, an assembly. To get access to the compiled code, you can use the CompilerResults.CompiledAssembly property and then use reflection to find and invoke the Main method:
compilerResults.CompiledAssembly.GetType("HelloWorld").GetMethod("Main").Invoke(null, null);
Though if you set parameters.GenerateExecutable to true, you can simplify this to:
compilerResults.CompiledAssembly.EntryPoint.Invoke(null, null);

using in memory assembly generated from ICode Compiler to build another source code

I have an interface and a class that implements it. I am trying to create a unit test that will compile both the interface and the class and see that if there are any errors(if theres none then that would mean the class does implement the interface). I am able to build the interface with no errors but when I try to build the class that implements it it says that the class does not implement the interface. I made sure already that the class does implement the interface so i know that there is something wrong with the way I am trying to compile it on my unit test. I generate the inMemoryAssembly.dll and then try to add it to the parameters when trying to compile the implementation, but that is not working.Any suggestion?
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Text;
using System.IO;
namespace UnitTestProject2
{
[TestClass]
public class UnitTest1
{
[TestMethod]
[TestCategory("NumberOfFiles")]
public void TestMethod1()
{
var serviceReferancepath = System.IO.Path.GetFullPath(#"..\..\Service References\");
compileIterface(serviceReferancepath);
compileImplementation(serviceReferancepath);
}
static void compileIterface(string path)
{
CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
ICodeCompiler compiler = codeProvider.CreateCompiler();
CompilerParameters parametersForInterface = new CompilerParameters();
parametersForInterface.GenerateInMemory = true;
parametersForInterface.ReferencedAssemblies.Add("System.dll");
parametersForInterface.ReferencedAssemblies.Add("System.Data.Services.Client.dll");
parametersForInterface.ReferencedAssemblies.Add("System.ComponentModel.dll");
parametersForInterface.OutputAssembly = "inMemoryAssembly.dll";
StringBuilder interfaceSC = new StringBuilder();
using (StreamReader sr = new StreamReader(path + #"alarm\IActiveEventSource.cs"))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
interfaceSC.AppendLine(line);
}
}
CompilerResults results = compiler.CompileAssemblyFromSource(parametersForInterface, interfaceSC.ToString());
StringWriter sw = new StringWriter();
foreach (CompilerError ce in results.Errors)
{
if (ce.IsWarning) continue;
sw.WriteLine("{0}({1},{2}: error {3}: {4}", ce.FileName, ce.Line, ce.Column, ce.ErrorNumber, ce.ErrorText);
}
// If there were errors, raise an exception...
string errorText = sw.ToString();
}
static void compileImplementation(string path)
{
Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
ICodeCompiler compiler = codeProvider.CreateCompiler();
CompilerParameters Parameters = new CompilerParameters();
Parameters.ReferencedAssemblies.Add("inMemoryAssembly.dll");
Parameters.GenerateExecutable = false;
Parameters.GenerateInMemory = true;
StringBuilder implementationSC = new StringBuilder();
using (StreamReader sr = new StreamReader(path + #"alarm\implementation\TheActiveEventSource.cs"))
{
string line;
// Read and display lines from the file until the end of
// the file is reached.
while ((line = sr.ReadLine()) != null)
{
implementationSC.AppendLine(line);
}
}
CompilerResults results = compiler.CompileAssemblyFromSource(Parameters, implementationSC.ToString());
StringWriter sw = new StringWriter();
foreach (CompilerError ce in results.Errors)
{
if (ce.IsWarning) continue;
sw.WriteLine("{0}({1},{2}: error {3}: {4}", ce.FileName, ce.Line, ce.Column, ce.ErrorNumber, ce.ErrorText);
}
// If there were errors, raise an exception...
string errorText = sw.ToString();
}
}
}
The compileImplementation method, when I run it with a breakpoint I get the following error for the results
UnitTestProject2.alarm.ActiveEventSource' does not implement interface member 'UnitTestProject2.alarm.IActiveEventSource.EventSource
This the implementation code
namespace UnitTestProject2.alarm
{
partial class ActiveEventSource: IActiveEventSource
{
}
}
edit:
I was looking at the warnings but not the actual error that the compiling of the implementation was saying. the string errortext for the compileImplementatation method says that the inMemoryAssembly.dll could not be found

Categories