4

I am trying to embed C# as a scripting langague to my C++ library. I was aware that this might be not a trivial task so I went for a minimal test project to see if this is even possible first.

I have managed to create a C# assembly containing code for managing simple scripts and compiling them @ run-time using CSharpCodeProvider. The assembly was tested using C# console app as a test project (given C# source files are compiled in memory and executed when necessary).

So the next step was to bridge this with a C++ application.

I have somehow managed to do that using COM. I exported my C# dll, the classes and interfaces, as COM objects and generated the tlb file using Regasm.

I am able to create instances of these classes in C++ project and call their methods and everything seemed to work fine (for example displaying Windows.Forms message box) until the actual logic needed to be executed. It just throws exceptions that should not be thrown as It already worked with a C# console app as a host of the library.

As I don't know if I can debug COM components (well stepping into the code of this C# dll is not possible AFAIK) so I added plethora of message boxes and try-catch blocks.

It seems that it breaks when I try to retrieve any type from compiled assembly. It throws: Reflection.ReflectionTypeLoadException

The compiling on the other hand does not fail nor generate any error messages.

Using C# to trigger these methods works 100%, only while executing from C++ it does break somehow.

What might be the cause of this? Or possibly is there another way of doing what I am trying to do? I do find COM somehow right to be used in such scenario but are there aspects that I am not aware of that cause such code to break?

EDIT: This is the managed C# assembly exported as COM: http://nopaste.info/9da70dbcbd.html

So these objects are accessed from C++ app like so: http://nopaste.info/50c4c9726a.html

And the script is as simple as class deriving from IScript and implementing Execute method which displays message box.

Edit 2:

The details regarding the exception thrown is the following: "Could not load file or assembly 'lame2.scripting, Version=1.0.0.0, Culture=neutral, PublicKeyToken=84d0df983ded76a1' or one of its dependencies. Nie można odnaleźć określonego pliku."

The last sentence means that the File could not be found.

But it is strange since when compiling I have the following line: compilerparams.ReferencedAssemblies.Add("D:\Interop\lame2.scripting\lame2.scripting\bin\Debug" + "\lame2.scripting.dll");

This is the "script" contents:

using System;
using System.Linq;
using System.Windows.Forms;
using System.Reflection;
using lame2.scripting;

namespace Olaboga
{
  public class TestScript : IScript
  {
    public TestScript() { }

    public void Execute(Event ev)
    {
      MessageBox.Show("Script that has been compiled from a source file has been invoked.   TestScript.Execute");
    }
  }
}

Edit 3:

Finally after switch from compilation in memory to compilation to temporary file it suddenly started to work properly. So the last question can someone knows why it failed to work while being compiled in memory and if is it possible to do so.

8
  • Have you seen Roslyn. Commented Oct 1, 2012 at 10:58
  • Thanks for the link but as it seems as this is not production-code ready and I cannot see this more suitable solution for my needs then using CSharpCodeProvider and reflection from within the dll library to be honest. Commented Oct 1, 2012 at 11:05
  • I agree, but this is something that be be released into production environment so it is good to be aware of it. Good luck :] Commented Oct 1, 2012 at 11:14
  • At which line exactly is exception thrown? Can you show the full stack trace of the exception? What is the location of your lame2.scripting assembly relative to your c++ console and your main .NET assembly? Is it obj = (IScript)Activator.CreateInstance(script_type); or script_assembly.GetTypes()? Commented Oct 1, 2012 at 14:15
  • GetTypes() throws an exception. I am using absolute path to the assembly which is D:\Interop\lame2.scripting\lame2.scripting\bin\Debug\lame2.scripting.dll" (of course I use double slashes) Commented Oct 1, 2012 at 14:22

1 Answer 1

4

If you can expose your application functionality as a COM object model, then it should be possible to do it. You should take care to model interfaces in a way which can be handled properly by .NET interop layer.

If I understood correctly, you have problems debugging the .NET assembly generated from your C# script, right? In this case you can use the following compiler settings when compiling the assembly:

CompilerParameters cp = new CompilerParameters();

// Generate debug information.
cp.IncludeDebugInformation = true;

// Save the assembly as a physical file.
cp.GenerateInMemory = false;

// Set a temporary files collection. 
// The TempFileCollection stores the temporary files 
// generated during a build in the current directory, 
// and does not delete them after compilation.
cp.TempFiles = new TempFileCollection(".", true);

This will enable debugging of the generated code, as you would have source code, debug symbols and the assembly. However, you mention 'COM components' a few times, but I don't see any - there is a C++ app and .NET assembly - the stuff in between is not a real COM component but 'interop magic' which, more or less, just marshals the stuff between these two parties.

If you have issues debugging the original .NET assembly which contains your implementation, then make sure that Debug settings are correct:

  • if you start debugging normally (F5) with native app, go to Project Settings -> Debugging -> Debugger Type and set it to Mixed
  • if you attach the debugger to the running process, in the Attach to Process form click Select... button near 'Attach to` textbox and choose those you need (Managed and Native)

This assumes that you do have source code and .pdb file for your assembly.

Sign up to request clarification or add additional context in comments.

4 Comments

Actually I have difficulties in debugging the managed dll itself (that uses run-time compiler). I will post an example source code what I have done so far.
I have added some info about possible reasons for that.
Thank You for the info about debbuging. It works like a charm! Still having the issue with exceptions though, but it will make figuring it out much easier.
I have decided to accept this answer as combining it with compilation to temporary assembly have worked but look for the last edit to the question.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.