I'm starting to dive into the world of C# Dynamics and Metaprogramming, and having some trouble.
I managed to create a CodeDom tree, and generate the following code:
namespace Mimsy {
using System;
using System.Text;
using System.Collections;
internal class JubJub {
private int _wabeCount;
private ArrayList _updates;
public JubJub(int wabeCount) {
this._updates = new ArrayList();
this.WabeCount = wabeCount;
}
public int WabeCount {
get {
return this._wabeCount;
}
set {
if((value < 0))
this._wabeCount = 0;
else
this._wabeCount = value;
this._updates.Add(this._wabeCount);
}
}
public string GetWabeCountHistory() {
StringBuilder result = new StringBuilder();
int ndx;
for(ndx = 0; (ndx < this._updates.Count); ndx = ndx + 1) {
if((ndx == 0))
result.AppendFormat("{0}", this._updates[ndx]);
else
result.AppendFormat(", {0}", this._updates[ndx]);
}
}
}
}
I am then compiling dynamically this namespace to an assembly named "dummy".
I can succesfully get an instance of this Type:
string typeName = "Mimsy.JubJub";
Type type = dummyAssembly.GetType(typeName);
dynamic obj = Activator.CreateInstance(type, new object[] { 8 });
//obj is a valid instance type
If I debug this code, I can see in the debugger that obj actually has the property WabeCount:
However, when trying to access this property, the compiler shouts that the dynamic property does not exist.
There are one or perhaps two problems with your code:
You are using an internal class, and trying to access it with dynamic. The two things don't play well together. See https://stackoverflow.com/a/18806787/613130. Use public clasas
You need to cast the value before assigning it to wabeCount, like:
obj.WabeCount = (int)wabes[ndx]
Note that technically, if your "main" assembly is strong named, you could add the InternalsVisibleToAttribute to the "dynamic" assembly to make its internal "things" visible to the main assembly... I do think it would be wasted work.
Related
I am working with convergent facet bodies in NX and using C# in NXOpen. In the process, I am using UFSession.Facet.AskAdjacentFacet function to get the adjacent facets of each facet. But on using this particular command, the NXOpen throws error stating "NXOpen.NXException: The facet object is not supported for this operation". I went through the example given in NXOpen documentation (https://docs.plm.automation.siemens.com/data_services/resources/nx/10/nx_api/en_US/custom/ugopen_doc/uf_facet/uf_facet_eg2.c) and used similar approach, but this error shows up any way. Below is the script that I tried.
'''
public static void Main(string[] args)
{
NXOpen.UF.UFFacet myFacet = UFSession.Facet;
int facetID;
int edgeID;
int adjFacID;
int edgeIDinAdjFac;
int null_facet_ID = UFConstants.UF_FACET_NULL_FACET_ID;
facetID = null_facet_ID;
foreach (NXOpen.Facet.FacetedBody facetBody in workPart.FacetedBodies)
{
myFacet.CycleFacets(facetBody.Tag, ref facetID); // initialise for cycling
while (facetID != null_facet_ID)
{
List<int> Adj_fac_list = new List<int>();
for (edgeID = 0; edgeID < 3; edgeID++)
{
myFacet.AskAdjacentFacet(facetBody.Tag, facetID, edgeID, out adjFacID, out edgeIDinAdjFac);
if (adjFacID != UFConstants.UF_FACET_NULL_FACET_ID)
{
Adj_fac_list.Add(adjFacID);
}
}
}
}
}
Note: I could use the same model tag and facet id in the function UFSession.FACET.AskNumVertsInFacet and the script works fine. But I do not know why AskAdjacentFacet is not working. Can anyone help me on why there is an error and how to get this working?
On first glimpse, the problem I see is that you have not initialized the variable myFacet and it's null. And since it's null, you cannot call its members.
So change a single line of the code from
NXOpen.UF.UFFacet myFacet = UFSession.Facet;
To
NXOpen.UF.UFFacet myFacet = UFSession.GetUFSession().Facet;
Since P/Invoke does not support returning dynamic sized arrays (you must statically specify the size of the array at compile time), I decided to write a C++/CLI wrapper for some functions I need in a .net application that is otherwise written in C#.
Take the GetTcpTable2 function from IpHlpApi.dll...
I made C# classes to match the types in that function as follows:
public class MibTcpTable2
{
public int NumEntries;
public MibTcpRow2[] Table;
}
public class MibTcpRow2
{
public int State;
public int LocalAddr;
public int LocalPort;
public int RemoteAddr;
public int RemotePort;
public int OwningPid;
public int OffloadState;
}
In my C++/CLI program, I call GetTcpTable2 as shown in the MSDN example, and then iterate through the resulting array and assign its output to a new instance of the TcpTable2 class I made in C#.
See code:
PMIB_TCPTABLE2 pTcpTable;
ULONG ulSize = 0;
DWORD dwRetVal = 0;
pTcpTable = (MIB_TCPTABLE2 *)MALLOC(sizeof(MIB_TCPTABLE2));
if (pTcpTable == NULL) {
return nullptr;
}
ulSize = sizeof(MIB_TCPTABLE);
if ((dwRetVal = ::GetTcpTable2(pTcpTable, &ulSize, TRUE)) == ERROR_INSUFFICIENT_BUFFER)
{
FREE(pTcpTable);
pTcpTable = (MIB_TCPTABLE2 *)MALLOC(ulSize);
if (pTcpTable == NULL) {
return nullptr;
}
}
NetClasses::MibTcpTable2^ managedTable = gcnew NetClasses::MibTcpTable2();
managedTable->Table = gcnew cli::array<NetClasses::MibTcpRow2^>(pTcpTable->dwNumEntries);
if ((dwRetVal = ::GetTcpTable2(pTcpTable, &ulSize, TRUE)) == NO_ERROR)
{
for (int i = 0; i < pTcpTable->dwNumEntries; i++)
{
managedTable->Table[i].LocalAddr = pTcpTable->table[i].dwLocalAddr;
managedTable->Table[i].LocalPort = pTcpTable->table[i].dwLocalPort;
managedTable->Table[i].OffloadState = pTcpTable->table[i].dwOffloadState;
managedTable->Table[i].OwningPid = pTcpTable->table[i].dwOwningPid;
managedTable->Table[i].RemoteAddr = pTcpTable->table[i].dwRemoteAddr;
managedTable->Table[i].RemotePort = pTcpTable->table[i].dwRemotePort;
managedTable->Table[i].State = pTcpTable->table[i].dwState;
}
}
However, Visual Studio 2015 hates the accesses to managedTable inside the for loop. It complains that "expression must have a class type." Ok, so that usually means you're using the wrong data accessor operator, so I tried a dot instead. No dice.
How the heck do I access the Table member of managedTable? The access to it before the for loop was valid. Why isn't it valid inside the for loop?
Your array access is giving you a handle to a managed object, so shouldn't your field access also be -> rather than . ?
Array[i]->Field
I have a piece of code that gets a specific portion of the namespace from the calling assembly. Now I want to unit test this code.
Is there a way to fake the name of the calling namespace using NUnit without implementing the NUnit testcase in that particular namespace?
Here is the method I want to test:
public static string FindCallingNameSpace()
{
var stackTrace = new StackTrace();
var stackFrames = stackTrace.GetFrames();
if (stackFrames != null)
{
int nrFrames = stackFrames.Length;
for (int i = 0; i < nrFrames; i++)
{
var methodBase = stackTrace.GetFrame(i).GetMethod();
var Class = methodBase.ReflectedType;
if (Class != null && Class.Namespace != null && Class.Namespace != "Foo.Common.WebService")
{
var Namespace = Class.Namespace.Split('.');
return Namespace[1];
}
}
}
throw new Exception("Can't determine calling namespace! Need this to determine correct api url to call!");
}
An example would be:
Bar.ExampleNs.SomeMethod() calls Foo.Common.WebService.CallApi() which itself calls the method above to retrieve the namespace from SomeMethod(). The result then would be "ExampleNs".
Now is it possible to create an NUnit UnitTest that is coded in the namespace MyUnitTests.ApiTest.TestNameSpace() but inside Foo.Common.WebService the call appears to come from Bar.ExampleNs.SomeMethod() so I can test for "ExampleNs"?
I think by far the simplest way of achieving what you're after is to just create a call forwarder and call the FindCallingNamespace method via the forwarder. So, assuming that the FindCallingNamespace method is in a class CallerStuff you create this:
namespace SomeNameSpace.ToTest {
static class RemoteCaller {
static public string Run() {
return CallerStuff.FindCallingNameSpace();
}
}
}
Then in your test you call RemoteCaller.Run, rather than CallerStuff.FindCallingNamespace.
However, you mentioned having Parameterized Tests, so presumably you might end up with a few different namespaces you want to test from which would mean more remote callers in different namespaces, which got me thinking that there might be a more generic approach.
The code below, essentially creates these wrapper classes for you by compiling them on the fly and then invoking them.
class CodeMaker {
static string _codesectionOne = #"
using Foo.Common.WebService;
namespace ";
static string _codesectionTwo = #" {
class RemoteCaller {
static public string Run() {
return CallerStuff.FindCallingNameSpace();
}
}
}";
public static string CompileAndCall(string targetNamespace,
string referenceAssembly) {
CompilerParameters CompilerParams = new CompilerParameters();
string outputDirectory = Directory.GetCurrentDirectory();
CompilerParams.GenerateInMemory = true;
CompilerParams.TreatWarningsAsErrors = false;
CompilerParams.GenerateExecutable = false;
CompilerParams.CompilerOptions = "/optimize";
string[] references = { "System.dll", referenceAssembly};
CompilerParams.ReferencedAssemblies.AddRange(references);
CSharpCodeProvider provider = new CSharpCodeProvider();
var codeToCompile = _codesectionOne + targetNamespace + _codesectionTwo;
CompilerResults compile = provider.CompileAssemblyFromSource(CompilerParams,
codeToCompile);
if (compile.Errors.HasErrors) {
string text = "Compile error: ";
foreach (CompilerError ce in compile.Errors) {
text += "rn" + ce.ToString();
}
throw new Exception(text);
}
Module module = compile.CompiledAssembly.GetModules()[0];
Type mt = null;
MethodInfo methInfo = null;
if (module != null) {
mt = module.GetType(targetNamespace + ".RemoteCaller");
}
if (mt != null) {
methInfo = mt.GetMethod("Run");
}
if (methInfo != null) {
return (string)methInfo.Invoke(null, null);
}
throw new InvalidOperationException("It's all gone wrong!");
}
}
You would then invoke the method from your test:
Assert.AreEqual("Fiddle", CodeMaker.CompileAndCall("Wibble.Fiddle.Con", "SO.dll"));
Assert.AreEqual("Fuddle", CodeMaker.CompileAndCall("Wibble.Fuddle.Con", "SO.dll"));
Note, "SO.dll" in the example above is the name of the assembly containing the CallerStuff.FindCallingNamespace
Using the compiler to generate the caller classes is probably overkill for what you're after and you might have to tweak the error handling in the code if you do decide to use it. If you're invoking the generated classes multiple times from different tests, then it may also be worth caching them, possibly through a dictionary keyed off namespace rather than compiling them every time. Compile + Call code is based on this blog post by Simeon Pilgrim.
I have a public class, "CodeCompiler", which allows me to compile and run C# code at run-time. Just like IDEs work.
When I click the "button1" it creates code at run-time, compiles and executes.
My main Form1 contains a TextBox control called "textbox1". In order to make changes on that "textbox1" by runtime I made this button1_Click event.
But when I click it, it shows me a run-time error...
Compiler Errors :
Line 14,34 : An object reference is required for the non-static field, method, or property 'Compiling_CSharp_Code_at_Runtime.Form1.textBox1'
It showed me when I was editing the text data on that "textbox1". But if I will try to make changes about other property like "Size", "Location" then imagine what will happen!
using System;
using System.Text;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using System.Reflection;
namespace Compiling_CSharp_Code_at_Runtime
{
public class CodeCompiler
{
public CodeCompiler()
{
}
public object ExecuteCode(string code, string namespacename, string classname,
string functionname, bool isstatic,
string[] References1, params object[] args)
{
object returnval = null;
CompilerParameters compilerparams = new CompilerParameters();
for (int i = 0; i <= References1.GetUpperBound(0); i++)
{
compilerparams.ReferencedAssemblies.Add(References1[i]);
}
Assembly asm = BuildAssembly(code, compilerparams);
object instance = null;
Type type = null;
if (isstatic)
{
type = asm.GetType(namespacename + "." + classname);
}
else
{
instance = asm.CreateInstance(namespacename + "." + classname);
type = instance.GetType();
}
MethodInfo method = type.GetMethod(functionname);
returnval = method.Invoke(instance, args);
return returnval;
}
private Assembly BuildAssembly(string code, CompilerParameters compilerparams)
{
Microsoft.CSharp.CSharpCodeProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
compilerparams.GenerateExecutable = false;
compilerparams.GenerateInMemory = true;
CompilerResults results = compiler.CompileAssemblyFromSource(compilerparams, code);
if (results.Errors.HasErrors)
{
StringBuilder errors = new StringBuilder("Compiler Errors :\r\n");
foreach (CompilerError error in results.Errors )
{
errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText);
}
throw new Exception(errors.ToString());
}
else
{
return results.CompiledAssembly;
}
}
}
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
CodeCompiler cc = new CodeCompiler();
string SourceCode1 = #"
using Compiling_CSharp_Code_at_Runtime;
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
namespace N1
{
public class C1
{
public static void F1(string st1, string st2)
{
Compiling_CSharp_Code_at_Runtime.Form1.textBox1.Text += ""This is a DEMO "" st1 + st2.ToUpper();
}
}
}";
string namespace1 = "N1", class1 = "C1", function1 = "F1";
bool IsStatic = true;
object o = cc.ExecuteCode(SourceCode1, namespace1, class1, function1, IsStatic, new string[] { "Compiling CSharp Code at Runtime.exe", "System.Windows.Forms.dll", "System.Drawing.dll", "System.ComponentModel.dll", "System.dll" }, "arg1", "arg2");
}
}
}
I found many problems related to this problem on this site where a suggestion was:
"It looks like I am calling a non static property from a static method.
I should either make the property static, or create an instance of Form1."
But even creation an instance of Form1 was difficult at runtime!
The problem appears to be that you're not passing reference to the Form1 on which you want code to be executed to CodeCompiler at all. The fact that you're calling it within your Form1 doesn't change anything - objects don't automatically learn anything about the object using them. (If they did, things would be a lot more complicated.)
The way you're accessing Form1 is also incorrect - you're using the typename (by the way, as a fully-qualified path which is pointless, because while the class C1 is not in the same namespace as Form1, you include Form1's namespace in the compiled code via using) to refer to a non-static member of the type. The instance member textBox1 of the type Form1 can be accessed only from some instance, but there's no logical way to access the Form1 object. What if you'd instantiated 10 of them? How would the decision be made which of those 10 to return to your call?
What you should do, if you want to continue down this path (and I'm not really sure why you're trying to mimic eval() in C# - you're throwing away a lot of the safety that makes C# nice and easy to work with), is pass a reference to the Form1 instance you want altered either in the constructor of CodeCompiler or in the ExecuteCode method. I think the latter would probably make more sense.
You should change your SourceCode1 so that it looks like this (this also fixes a typo in the original code, restoring a missing + character):
string SourceCode1 = #"
using Compiling_CSharp_Code_at_Runtime;
using System;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
namespace N1
{
public class C1
{
public static void F1(string st1, string st2, Form1 formToExecuteOn)
{
formToExecuteOn.textBox1.Text +=
""This is a DEMO "" + st1 + st2.ToUpper();
}
}
}";
Then call the ExecuteCode() method like this:
object o = cc.ExecuteCode(SourceCode1, namespace1, class1, function1, IsStatic,
new string[] { "Compiling CSharp Code at Runtime.exe",
"System.Windows.Forms.dll", "System.Drawing.dll",
"System.ComponentModel.dll", "System.dll" },
"arg1", "arg2", this);
This will compile the code such that the Form1 instance to be used can be passed to the method when it's invoked. And the reference to that Form1 instance is provided in the argument list that is actually passed for the method invocation (i.e. the last argument, this)..
Granted, even if that works, it'll only allow you to execute code on Form1 objects. The greater point of this is that if you're going to go down this path, you need to be passing reference to anything you want altered to CodeCompiler somehow. I'm not sure whether object objectToChange would work instead of formToChange, and how much information the compiler is going to need about the object you're passing in order to execute code on it.
And once more, for feeling: you need a very, very unique use case to make any of this even remotely a good use of time or sanity. (You have to pass seven precisely-constructed objects, mostly strings, to ExecuteCode() every single time you want to run anything!)
In my "LuaTest" namespace I have a class called "Planet". The C# code reads like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace LuaTest
{
public class Planet
{
public Planet(string name)
{
this.Name = name;
}
public Planet() : this("NoName") { }
public string Name
{
get;
private set;
}
public void printName()
{
Console.WriteLine("This planet's name is {0}", Name);
}
}
}
Then I built LuaTest.dll and copied this file to the same folder where my Lua script is saved. In the Lua script I wrote:
--define Path for required dlls
package.cpath = package.cpath .. ";" .. "/?.dll"
package.path = package.path .. ";" .. "/?.dll/"
require 'luanet'
luanet.load_assembly("LuaTest")
local Planet = luanet.import_type("LuaTest.Planet")
local planet = Planet("Earth")
planet.printName()
However, this piece of code does not work. Lua interpreter throws this error:
lua: dllTest.lua:7: attempt to call local 'Planet' (a nil value)
I suspect that my LuaTest assembly is not loaded at all. Could anyone point out where I did wrong? I would very much appreciate it, since I've been stuck by this problem for days.
Also it might be helpful to add that my LuaInterface.dll is the rebuilt version in .NET4.0 environment.
So I spent a LOT of time similarly. What really drove me bonkers was trying to get Enums working. Eventually I ditched my project for a very simplified console application, very similar (ironically also named 'LuaTest').
Edit: I've noted that the initial "luanet.load_assembly("LuaTest")" appears superfluous. Works with it, or surprisingly without it.
Another Edit: As in my badly edited comment below, when I removed:
print(luanet.LuaTest.Pointless)
It all stopped working (LuaTest.Pointless became nil). But adding the luanet.load_assembly("LuaTest") then makes it work. It may be that there is some sort of odd implicit load in the print or in just expressing they type. Very Strange(tm).
In any case, it seems to work for me (note: after a lot of experimentation). I don't know why yours is failing, I don't note any real difference, but here's all my code in case someone else can spot the critical difference:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LuaInterface;
namespace LuaTest
{
public class Program
{
static void Main(string[] args)
{
Lua lua = new Lua();
lua.DoFile("test.lua");
}
public int some_member = 3;
}
public class Pointless
{
public enum AnEnum
{
One,
Two,
Three
};
public static string aStaticInt = "This is static.";
public double i;
public string n = "Nice";
public AnEnum oneEnumVal = AnEnum.One;
private AnEnum twoEnumVal = AnEnum.Two;
private string very;
public Pointless(string HowPointLess)
{
i = 3.13;
very = HowPointLess;
}
public class MoreInnerClass
{
public string message = "More, please!";
}
public void Compare(AnEnum inputEnum)
{
if (inputEnum == AnEnum.Three)
Console.WriteLine("Match.");
else
Console.WriteLine("Fail match.");
}
}
}
and test.lua:
luanet.load_assembly("LuaTest")
--Pointless is a class in LuaTest assembly
local Pointless = luanet.import_type("LuaTest.Pointless")
print(Pointless)
--Gives 'ProxyType(LuaTest.Pointless): 46104728
print(Pointless.aStaticInt)
--'This is static.'
--Fails if not static, as we expect
--Instantiate a 'Pointless'.
local p = Pointless("Very")
print(p)
--Gives 'LuaTest.Pointless: 12289376'
--Now we can get at the items inside the Pointless
--class (well, this instance, anyway).
local e = p.AnEnum;
print(e)
--ProxyType(LuaTest.Pointless+AnEnum): 23452342
--I guess the + must designate that it is a type?
print(p.i)
--3.14
print(p.oneEnumVal)
--Gives 'One: 0'
print(p.twoEnumVal)
--Gives 'twoEnumVal'... private
--behaves very differently.
print(e.Two:ToString())
--Gives 'Two'
local more = p.MoreInnerClass()
print(more.message)
--'More, Please!'
--create an enum value here in the script,
--pass it back for a comparison to
--the enum.
local anotherEnumVal = p.AnEnum.Three
p:Compare(anotherEnumVal)
--outputs 'Match'
Having spent the last several days working on a project that required this exact functionality from LuaInterface, I stumbled across a piece of Lua code that turned out to be the perfect solution (see Reference 1). Whilst searching for this solution, I noticed this question and figured I'd drop my two cents in.
To apply this solution, I merely run the CLRPackage code while initializing my LuaInterface Lua object. However, the require statement works just as well.
The code provided in reference 1 allows the use of import statements, similar to C# using statements. Once an assembly is imported, its members are accessible in the global namespace. The import statement eliminates the need to use load_assembly or import_type (except in situations in which you need to use members of the same name from different assemblies. In this scenario, import_type would be used similar to C# using NewTypeName = Assembly.OldTypeName).
import "LuaTest"
planet = Planet("Earth")
planet:printName()
This package also works great with enums!
Further information regarding the use of this package may be found at Reference 2.
Hope this helps!
Reference 1: https://github.com/stevedonovan/MonoLuaInterface/blob/master/bin/lua/CLRPackage.lua
Reference 2: http://penlight.luaforge.net/project-pages/penlight/packages/LuaInterface/
I spent some time in binding C# dll to lua. Your posts were helpful but something was missing. The following solution should work:
(Make sure to change your compiler to .NET Framework 3.5 or lower!)
Planet.dll:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Planets
{
public class Planet
{
private string name;
public string Name
{
get { return name; }
set { this.name = value; }
}
private float diameter;
public float Diameter
{
get { return diameter; }
set { this.diameter = value; }
}
private int cntContinents;
public int CntContinents
{
get { return cntContinents; }
set { this.cntContinents = value; }
}
public Planet()
{
Console.WriteLine("Constructor 1");
this.name = "nameless";
this.diameter = 0;
this.cntContinents = 0;
}
public Planet(string n, float d, int k)
{
Console.WriteLine("Constructor 2");
this.name = n;
this.diameter = d;
this.cntContinents = k;
}
public void testMethod()
{
Console.WriteLine("This is a Test!");
}
}
}
Use the code above, paste it into your class library project and compile it with .NET smaller or equal 3.5.
The location of the generated DLL needs to be known by the lua enviroment. Paste it e.g at "clibs"-folder or another well known lua system path. Then try to use the following lua example. It should work.
Test1.lua: (Option 1 with "import" from CLRPackage)
require "luanet"
require "CLRPackage"
import "Planet"
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print( "Planet " ..
PlanetObject2.Name ..
" is my home planet. Its diameter is round about " ..
PlanetObject2.Diameter .. "km." ..
" Our neighour is " ..
PlanetObject1.Name)
Test2.lua: (Option 2 with "load_assembly")
require "luanet"
require "CLRPackage"
luanet.load_assembly("Planet")
local PlanetClass = luanet.import_type("Planets.Planet")
print(PlanetClass)
local PlanetObject1 = PlanetClass()
print(PlanetObject1)
local PlanetObject2 = PlanetClass("Earth",6371.00*2,7)
print(PlanetObject1.Name)
PlanetObject1.Name = 'Mars'
print(PlanetObject1.Name)
print( "Planet " ..
PlanetObject2.Name ..
" is my home planet. Its diameter is round about " ..
PlanetObject2.Diameter .. "km." ..
" Our neighour is " ..
PlanetObject1.Name)
In both cases the console output will look like this:
ProxyType(Planets.Planet): 18643596
Constructor 1
Planets.Planet: 33574638
Constructor 2
nameless
Mars
Planet Earth is my home planet. Its diameter is round about 12742km. Our neighbour is Mars
I hope its helps some of you.
Edit 1:
by the way, a method call from lua looks like this:
PlanetObject1:testMethod()
PlanetObject2:testMethod()
Edit 2:
I found different dll's whitch needed to be handled differently. One needed the "import"-function and another needed the "load_assembly"-function. Keep that maybe in mind!