Thanks @nathanletwory,
I’ll take a look at c# events, more how they are created.
I can compile ironpython into dll but I’ve no idea how could I reference the resulting mess of a dll.
Thanks @nathanletwory,
I’ll take a look at c# events, more how they are created.
I can compile ironpython into dll but I’ve no idea how could I reference the resulting mess of a dll.
Look up this forum for clr.AddReference
no, I know that.
but have you looked a compiled IronPython with ILspy?
Nope, I haven’t used IronPython outside of Rhino.
This is decompiled empty winform with title “hello world” compiled to dll:
using IronPython.Compiler;
using IronPython.Runtime;
using IronPython.Runtime.Operations;
using Microsoft.Scripting;
using Microsoft.Scripting.Actions;
using Microsoft.Scripting.Runtime;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
public class DLRCachedCode
{
[CachedOptimizedCode(new string[]
{
"__name__",
"__file__",
"__doc__",
"__path__",
"__builtins__",
"__package__",
"clr",
"Application",
"Form",
"HelloWorldForm",
"form"
})]
public static object helloworld$1(CodeContext $globalContext, FunctionCode $functionCode)
{
object[] expr_06 = new object[1];
StrongBox<object[]> strongBox = expr_06[0] = new StrongBox<object[]>();
object[] locals = expr_06;
object[] value = new object[10];
strongBox.Value = value;
strongBox.Value[9] = CallSite<Func<CallSite, object, string, object>>.Create(PythonOps.MakeSetAction($globalContext, "Name"));
strongBox.Value[8] = CallSite<Func<CallSite, object, string, object>>.Create(PythonOps.MakeSetAction($globalContext, "Text"));
strongBox.Value[7] = PythonOps.MakeFunctionCode($globalContext, "__init__", null, new string[]
{
"self"
}, 0, 152, 245, "helloworld", new Func<PythonFunction, object, object>(new Closure(null, locals).__init__$1), null, null, null, new string[]
{
"self"
}, 1);
strongBox.Value[6] = new string[]
{
"__module__",
"__init__"
};
strongBox.Value[5] = CallSite<Func<CallSite, object, CodeContext, object>>.Create(PythonOps.MakeGetAction($globalContext, "Run", false));
strongBox.Value[4] = CallSite<Func<CallSite, CodeContext, object, object, object>>.Create(PythonOps.MakeInvokeAction($globalContext, new CallSignature(1)));
strongBox.Value[3] = CallSite<Func<CallSite, CodeContext, object, object>>.Create(PythonOps.MakeInvokeAction($globalContext, new CallSignature(0)));
strongBox.Value[2] = PythonOps.MakeFunctionCode($globalContext, "HelloWorldForm", null, new string[0], 0, 115, 251, "helloworld", new Func<CodeContext, CodeContext>(new Closure(null, locals).HelloWorldForm$2), null, null, null, new string[]
{
"__module__",
"__init__"
}, 2);
strongBox.Value[1] = CallSite<Func<CallSite, object, CodeContext, object>>.Create(PythonOps.MakeGetAction($globalContext, "AddReference", false));
strongBox.Value[0] = CallSite<Func<CallSite, CodeContext, object, string, object>>.Create(PythonOps.MakeInvokeAction($globalContext, new CallSignature(1)));
PythonGlobal[] globalArrayFromContext = PythonOps.GetGlobalArrayFromContext($globalContext);
try
{
object obj = PythonOps.PublishModule($globalContext, "helloworld");
try
{
globalArrayFromContext[1].set_CurrentValue((object)"helloworld");
globalArrayFromContext[0].set_CurrentValue((object)"helloworld");
PythonOps.ModuleStarted($globalContext, 8);
globalArrayFromContext[2].set_CurrentValue(null);
int num = 1;
globalArrayFromContext[6].set_CurrentValue(LightExceptions.CheckAndThrow(PythonOps.ImportTop($globalContext, "clr", -1)));
num = 3;
CallSite<Func<CallSite, CodeContext, object, string, object>> arg;
CallSite<Func<CallSite, object, CodeContext, object>> arg2;
(arg = (CallSite<Func<CallSite, CodeContext, object, string, object>>)strongBox.Value[0]).Target(arg, $globalContext, (arg2 = (CallSite<Func<CallSite, object, CodeContext, object>>)strongBox.Value[1]).Target(arg2, globalArrayFromContext[6].get_CurrentValue(), $globalContext), "System.Windows.Forms");
num = 7;
object obj2 = LightExceptions.CheckAndThrow(PythonOps.ImportWithNames($globalContext, "System.Windows.Forms", new string[]
{
"Application",
"Form"
}, -1));
globalArrayFromContext[7].set_CurrentValue(PythonOps.ImportFrom($globalContext, obj2, "Application"));
globalArrayFromContext[8].set_CurrentValue(PythonOps.ImportFrom($globalContext, obj2, "Form"));
num = 11;
globalArrayFromContext[9].set_CurrentValue(PythonOps.MakeClass((FunctionCode)strongBox.Value[2], null, $globalContext, "HelloWorldForm", new object[]
{
globalArrayFromContext[8].get_CurrentValue()
}, "Text,Name"));
num = 23;
CallSite<Func<CallSite, CodeContext, object, object>> arg3;
globalArrayFromContext[10].set_CurrentValue((arg3 = (CallSite<Func<CallSite, CodeContext, object, object>>)strongBox.Value[3]).Target(arg3, $globalContext, globalArrayFromContext[9].get_CurrentValue()));
num = 25;
CallSite<Func<CallSite, CodeContext, object, object, object>> arg4;
CallSite<Func<CallSite, object, CodeContext, object>> arg5;
(arg4 = (CallSite<Func<CallSite, CodeContext, object, object, object>>)strongBox.Value[4]).Target(arg4, $globalContext, (arg5 = (CallSite<Func<CallSite, object, CodeContext, object>>)strongBox.Value[5]).Target(arg5, globalArrayFromContext[7].get_CurrentValue(), $globalContext), globalArrayFromContext[10].get_CurrentValue());
}
catch (Exception ex)
{
int num;
PythonOps.UpdateStackTrace(ex, $globalContext, $functionCode, num);
throw;
}
}
catch (Exception)
{
object obj;
PythonOps.RemoveModule($globalContext, "helloworld", obj);
throw;
}
return null;
}
private static object __init__$1(Closure closure, PythonFunction $function, object self)
{
object[] locals = closure.Locals;
StrongBox<object[]> strongBox = (StrongBox<object[]>)locals[0];
CodeContext globalContext = PythonOps.GetGlobalContext(PythonOps.GetParentContextFromFunction($function));
PythonGlobal[] globalArrayFromContext = PythonOps.GetGlobalArrayFromContext(globalContext);
try
{
try
{
List<FunctionStack> list = PythonOps.PushFrame(globalContext, $function.get___code__());
int num = 17;
CallSite<Func<CallSite, object, string, object>> arg;
(arg = (CallSite<Func<CallSite, object, string, object>>)strongBox.Value[8]).Target(arg, self, "Hello World!");
num = 19;
CallSite<Func<CallSite, object, string, object>> arg2;
(arg2 = (CallSite<Func<CallSite, object, string, object>>)strongBox.Value[9]).Target(arg2, self, "Hello World!");
}
finally
{
List<FunctionStack> list;
list.RemoveAt(list.Count + -1);
}
}
catch (Exception ex)
{
int num;
PythonOps.UpdateStackTrace(ex, globalContext, (FunctionCode)strongBox.Value[7], num);
throw;
}
return null;
}
private static CodeContext HelloWorldForm$2(Closure closure, CodeContext $parentContext)
{
object[] locals = closure.Locals;
CodeContext globalContext = PythonOps.GetGlobalContext($parentContext);
PythonGlobal[] globalArrayFromContext = PythonOps.GetGlobalArrayFromContext(globalContext);
ClosureCell closureCell = PythonOps.MakeClosureCell();
ClosureCell closureCell2 = PythonOps.MakeClosureCell();
CodeContext codeContext = PythonOps.CreateLocalContext($parentContext, new MutableTuple<ClosureCell, ClosureCell>(closureCell, closureCell2), (string[])((StrongBox<object[]>)locals[0]).Value[6]);
closureCell.Value = globalArrayFromContext[0].get_CurrentValue();
closureCell2.Value = PythonOps.MakeFunction(codeContext, (FunctionCode)((StrongBox<object[]>)locals[0]).Value[7], globalArrayFromContext[0].get_RawValue(), null);
return codeContext;
}
[CachedOptimizedCode(new string[]
{
"__name__",
"__file__",
"__doc__",
"__path__",
"__builtins__",
"__package__",
"clr",
"Application",
"Form",
"HelloWorldForm",
"form"
})]
public static object __main__$2(CodeContext $globalContext, FunctionCode $functionCode)
{
object[] expr_06 = new object[1];
StrongBox<object[]> strongBox = expr_06[0] = new StrongBox<object[]>();
object[] locals = expr_06;
object[] value = new object[10];
strongBox.Value = value;
strongBox.Value[9] = CallSite<Func<CallSite, object, string, object>>.Create(PythonOps.MakeSetAction($globalContext, "Name"));
strongBox.Value[8] = CallSite<Func<CallSite, object, string, object>>.Create(PythonOps.MakeSetAction($globalContext, "Text"));
strongBox.Value[7] = PythonOps.MakeFunctionCode($globalContext, "__init__", null, new string[]
{
"self"
}, 0, 152, 245, "helloworld.py", new Func<PythonFunction, object, object>(new Closure(null, locals).__init__$2), null, null, null, new string[]
{
"self"
}, 1);
strongBox.Value[6] = new string[]
{
"__module__",
"__init__"
};
strongBox.Value[5] = CallSite<Func<CallSite, object, CodeContext, object>>.Create(PythonOps.MakeGetAction($globalContext, "Run", false));
strongBox.Value[4] = CallSite<Func<CallSite, CodeContext, object, object, object>>.Create(PythonOps.MakeInvokeAction($globalContext, new CallSignature(1)));
strongBox.Value[3] = CallSite<Func<CallSite, CodeContext, object, object>>.Create(PythonOps.MakeInvokeAction($globalContext, new CallSignature(0)));
strongBox.Value[2] = PythonOps.MakeFunctionCode($globalContext, "HelloWorldForm", null, new string[0], 0, 115, 251, "helloworld.py", new Func<CodeContext, CodeContext>(new Closure(null, locals).HelloWorldForm$3), null, null, null, new string[]
{
"__module__",
"__init__"
}, 2);
strongBox.Value[1] = CallSite<Func<CallSite, object, CodeContext, object>>.Create(PythonOps.MakeGetAction($globalContext, "AddReference", false));
strongBox.Value[0] = CallSite<Func<CallSite, CodeContext, object, string, object>>.Create(PythonOps.MakeInvokeAction($globalContext, new CallSignature(1)));
PythonGlobal[] globalArrayFromContext = PythonOps.GetGlobalArrayFromContext($globalContext);
try
{
object obj = PythonOps.PublishModule($globalContext, "__main__");
try
{
globalArrayFromContext[1].set_CurrentValue((object)"helloworld.py");
globalArrayFromContext[0].set_CurrentValue((object)"__main__");
PythonOps.ModuleStarted($globalContext, 8);
globalArrayFromContext[2].set_CurrentValue(null);
int num = 1;
globalArrayFromContext[6].set_CurrentValue(LightExceptions.CheckAndThrow(PythonOps.ImportTop($globalContext, "clr", -1)));
num = 3;
CallSite<Func<CallSite, CodeContext, object, string, object>> arg;
CallSite<Func<CallSite, object, CodeContext, object>> arg2;
(arg = (CallSite<Func<CallSite, CodeContext, object, string, object>>)strongBox.Value[0]).Target(arg, $globalContext, (arg2 = (CallSite<Func<CallSite, object, CodeContext, object>>)strongBox.Value[1]).Target(arg2, globalArrayFromContext[6].get_CurrentValue(), $globalContext), "System.Windows.Forms");
num = 7;
object obj2 = LightExceptions.CheckAndThrow(PythonOps.ImportWithNames($globalContext, "System.Windows.Forms", new string[]
{
"Application",
"Form"
}, -1));
globalArrayFromContext[7].set_CurrentValue(PythonOps.ImportFrom($globalContext, obj2, "Application"));
globalArrayFromContext[8].set_CurrentValue(PythonOps.ImportFrom($globalContext, obj2, "Form"));
num = 11;
globalArrayFromContext[9].set_CurrentValue(PythonOps.MakeClass((FunctionCode)strongBox.Value[2], null, $globalContext, "HelloWorldForm", new object[]
{
globalArrayFromContext[8].get_CurrentValue()
}, "Text,Name"));
num = 23;
CallSite<Func<CallSite, CodeContext, object, object>> arg3;
globalArrayFromContext[10].set_CurrentValue((arg3 = (CallSite<Func<CallSite, CodeContext, object, object>>)strongBox.Value[3]).Target(arg3, $globalContext, globalArrayFromContext[9].get_CurrentValue()));
num = 25;
CallSite<Func<CallSite, CodeContext, object, object, object>> arg4;
CallSite<Func<CallSite, object, CodeContext, object>> arg5;
(arg4 = (CallSite<Func<CallSite, CodeContext, object, object, object>>)strongBox.Value[4]).Target(arg4, $globalContext, (arg5 = (CallSite<Func<CallSite, object, CodeContext, object>>)strongBox.Value[5]).Target(arg5, globalArrayFromContext[7].get_CurrentValue(), $globalContext), globalArrayFromContext[10].get_CurrentValue());
}
catch (Exception ex)
{
int num;
PythonOps.UpdateStackTrace(ex, $globalContext, $functionCode, num);
throw;
}
}
catch (Exception)
{
object obj;
PythonOps.RemoveModule($globalContext, "__main__", obj);
throw;
}
return null;
}
private static object __init__$2(Closure closure, PythonFunction $function, object self)
{
object[] locals = closure.Locals;
StrongBox<object[]> strongBox = (StrongBox<object[]>)locals[0];
CodeContext globalContext = PythonOps.GetGlobalContext(PythonOps.GetParentContextFromFunction($function));
PythonGlobal[] globalArrayFromContext = PythonOps.GetGlobalArrayFromContext(globalContext);
try
{
try
{
List<FunctionStack> list = PythonOps.PushFrame(globalContext, $function.get___code__());
int num = 17;
CallSite<Func<CallSite, object, string, object>> arg;
(arg = (CallSite<Func<CallSite, object, string, object>>)strongBox.Value[8]).Target(arg, self, "Hello World!");
num = 19;
CallSite<Func<CallSite, object, string, object>> arg2;
(arg2 = (CallSite<Func<CallSite, object, string, object>>)strongBox.Value[9]).Target(arg2, self, "Hello World!");
}
finally
{
List<FunctionStack> list;
list.RemoveAt(list.Count + -1);
}
}
catch (Exception ex)
{
int num;
PythonOps.UpdateStackTrace(ex, globalContext, (FunctionCode)strongBox.Value[7], num);
throw;
}
return null;
}
private static CodeContext HelloWorldForm$3(Closure closure, CodeContext $parentContext)
{
object[] locals = closure.Locals;
CodeContext globalContext = PythonOps.GetGlobalContext($parentContext);
PythonGlobal[] globalArrayFromContext = PythonOps.GetGlobalArrayFromContext(globalContext);
ClosureCell closureCell = PythonOps.MakeClosureCell();
ClosureCell closureCell2 = PythonOps.MakeClosureCell();
CodeContext codeContext = PythonOps.CreateLocalContext($parentContext, new MutableTuple<ClosureCell, ClosureCell>(closureCell, closureCell2), (string[])((StrongBox<object[]>)locals[0]).Value[6]);
closureCell.Value = globalArrayFromContext[0].get_CurrentValue();
closureCell2.Value = PythonOps.MakeFunction(codeContext, (FunctionCode)((StrongBox<object[]>)locals[0]).Value[7], globalArrayFromContext[0].get_RawValue(), null);
return codeContext;
}
[DlrCachedCode]
public static MutableTuple<Type[], Delegate[][], string[][], string[][]> GetScriptCodeInfo()
{
return new MutableTuple<Type[], Delegate[][], string[][], string[][]>(new Type[]
{
typeof(PythonContext)
}, new Delegate[][]
{
new Delegate[]
{
new LookupCompilationDelegate(DLRCachedCode.helloworld$1),
new LookupCompilationDelegate(DLRCachedCode.__main__$2)
}
}, new string[][]
{
new string[]
{
"helloworld",
"helloworld.py"
}
}, new string[][]
{
new string[]
{
"helloworld",
"__main__"
}
});
}
}
I had some free time and I was interested in this anyway, so here is an extremely hacky and dangerous (no error checking) but seemingly working example of a custom event firing from one script to another, based on the above example problem of point containment by a brep.
Summary:
I used the event watcher sample and added a custom event (and caller) with pyevent, to the class.
In the init, the class asks the user to select a point of interest and a brep to test with.
I used the ReplaceObject doc event to check if the replaced object matches the point of interest. If so, then use the new RhinoObject from the event args as the point for the containment test. If true then call the custom event caller with a dictionary for e, the event args.
Once that is running (from the sticky), I run a another script that gets the reference to the event watcher from the sticky, subscribes a function to the custom event made previously, then runs a function to allow the user to move the point of interest. If the point moves inside the brep then subscribed function fires.
Here is the event watcher sample with mods:
################################################################################
# SampleEventHandler.py
# Copyright (c) 2018 Robert McNeel & Associates.
# See License.md in the root of this repository for details.
################################################################################
################################################################################
# Modified for custom event example on discourse
################################################################################
import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs
import pyevent
################################################################################
# SampleEventHandler class
################################################################################
class SampleEventHandler():
# Initializer
def __init__(self):
# Enable the event handlers
Rhino.RhinoDoc.AddRhinoObject += self.OnAddRhinoObject
Rhino.RhinoDoc.ReplaceRhinoObject += self.OnReplaceRhinoObject
Rhino.RhinoDoc.DeleteRhinoObject += self.OnDeleteRhinoObject
Rhino.RhinoDoc.UndeleteRhinoObject += self.OnUndeleteRhinoObject
# make the event and caller with pyevent
self.brep_contains_point_event, self.brep_contains_point_caller = pyevent.make_event()
self.Enabled = True
# get the guid for the point of interest (the one you will move later)
self.point_guid_of_interest = rs.GetObject('select point of interest')
# get the guid for the brep to test inclusion with
self.brep_guid = rs.GetObject('select brep')
# Disables the event handlers
def Disable(self):
Rhino.RhinoDoc.AddRhinoObject -= self.OnAddRhinoObject
Rhino.RhinoDoc.ReplaceRhinoObject -= self.OnReplaceRhinoObject
Rhino.RhinoDoc.DeleteRhinoObject -= self.OnDeleteRhinoObject
Rhino.RhinoDoc.UndeleteRhinoObject -= self.OnUndeleteRhinoObject
self.Enabled = False
# Returns the enabled state
def IsEnabled(self):
return self.Enabled
# AddRhinoObject event handler
def OnAddRhinoObject(self, sender, e):
# print '> SampleEventHandler.OnAddRhinoObject'
pass
# ReplaceRhinoObject event handler
def OnReplaceRhinoObject(self, sender, e):
print '> SampleEventHandler.OnReplaceRhinoObject'
try:
# print(e.OldRhinoObject.Id, e.NewRhinoObject.Id, e.ObjectId)
if e.ObjectId == self.point_guid_of_interest:
print('point moved')
# we need the new location, not the old, or the one associated with the Id
# as it also seems to be the old location
point3d = e.NewRhinoObject.Geometry.Location
# get the brep geometry for inclusion test
brep = rs.coercebrep(self.brep_guid)
if brep.IsPointInside(point3d, sc.doc.ModelAbsoluteTolerance, True):
print('point inside brep, emitting event')
# event args can be anything, so I would use a dictionary
# and populate with items. For example just an empty is OK.
event_args = {}
# here you call the caller of the event (made in __init__)
# you pass in the sender (self) and the event args
self.brep_contains_point_caller(self, event_args)
except Exception as exp:
print(exp)
# DeleteRhinoObject event handler
def OnDeleteRhinoObject(self, sender, e):
# print '> SampleEventHandler.OnDeleteRhinoObject'
pass
# UndeleteRhinoObject event handler
def OnUndeleteRhinoObject(self, sender, e):
# print '> SampleEventHandler.OnUndeleteRhinoObject'
pass
################################################################################
# TestSampleEventHandler function
################################################################################
def TestSampleEventHandler():
# See if we already have a handler
if sc.sticky.has_key('sample_event_handler'):
# Delete the handler
handler = sc.sticky.pop('sample_event_handler', None)
if handler:
handler.Disable()
handler = None
print ' SampleEventHandler disabled'
else:
# Create handler
handler = SampleEventHandler()
# Add the handler to the sticky dictionary so it
# survives when the main function ends.
sc.sticky['sample_event_handler'] = handler
print ' SampleEventHandler enabled'
################################################################################
# Check to see if this file is being executed as the 'main' python
# script instead of being used as a module by some other python script
# This allows us to use the module which ever way we want.
################################################################################
if __name__ == '__main__':
TestSampleEventHandler()
Here is the second script to test the custom event:
import Rhino
import scriptcontext as sc
import rhinoscriptsyntax as rs
emitter = sc.sticky.get('sample_event_handler', None)
class EventListener:
def __init__(self):
if emitter:
# subscribe a function to the event
emitter.brep_contains_point_event += self.react_to_event
# call the function to move a point
self.move_point()
def move_point(self):
point_guid = rs.GetObject('select point to move')
if point_guid:
dest = rs.GetPoint('select destination')
if dest:
vect = dest - rs.coerce3dpoint(point_guid)
rs.MoveObject(point_guid, vect)
again = rs.GetString('Again?', strings=['yes', 'no'])
if again == 'yes':
self.move_point()
# disconnect event before quitting, otherwise they linger
print('disconnecting event')
emitter.brep_contains_point_event -= self.react_to_event
def react_to_event(self, sender, e):
print('reacting to event')
print(sender, e)
if __name__ == '__main__':
el = EventListener()
For testing I put a brep cube and a point in the doc, ran the event listener selecting said point and brep when prompted, then ran the second script and selected the same point to move around. The subscribed ‘react_to_event’ function ran when the point was moved into the brep volume, so I think it is working, at least here.
@ivelin.peychev : Don’t know if this is exactly what you want but perhaps it may help or provide an interim solution. Perhaps there are ways to make custom Rhino.DocObjects that are capable of emitting events but themselves but I don’t know about it.
Thanks for sharing this @nathancoatney,
Very interesting indeed.
I’ll try to understand it and see if I can apply it.
Meanwhile I started looking into csharp again, after @nathanletwory mentioned that perhaps this is the proper way to go. I’ve forgotten a lot of stuff about C# and everything is happening so slow.
hi ivelin peychev,
had you figure out delegating event?
I also need to implement a event system.
I end at this:
with this tutorial:
http://opensimulator.org/git/opensim-libs-save/IronPython/IronPython-1.1.1/Tutorial/Tutorial.htm#T2.1.3
Yep that’s what I found as well.