From ed0031b621c6cf8824a9a3e588426907244aeb7e Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Tue, 18 Apr 2006 01:38:08 +0000 Subject: implemented class-based method management very fast native-to-managed transition most of the logic transferred to the CLR side svn path=/trunk/externals/clr/; revision=4931 --- PureData/Atom.cs | 55 ++-- PureData/DynamicMethod.cs | 101 +++++++ PureData/PureData.cs | 666 +++++++++++++++++++++++++++++++++++++--------- PureData/PureData.csproj | 213 +++++++-------- 4 files changed, 793 insertions(+), 242 deletions(-) create mode 100644 PureData/DynamicMethod.cs (limited to 'PureData') diff --git a/PureData/Atom.cs b/PureData/Atom.cs index 6bad0b6..4e78eef 100755 --- a/PureData/Atom.cs +++ b/PureData/Atom.cs @@ -8,38 +8,57 @@ using System.Collections.Generic; namespace PureData { [StructLayout (LayoutKind.Sequential)] - public unsafe struct Symbol + public struct Symbol { // this should NOT be public (or at least read only) - private readonly void *sym; + private readonly IntPtr sym; public Symbol(string s) { - sym = Internal.SymGen(s); + this = Internal.SymGen(s); } public override string ToString() { - return Internal.SymEval(sym); + return Internal.SymEval(this); + } + + public static bool operator ==(Symbol s1,Symbol s2) + { + return s1.sym == s2.sym; + } + + public static bool operator !=(Symbol s1, Symbol s2) + { + return s1.sym != s2.sym; + } + + public override bool Equals(object o) + { + try { return this == (Symbol)o; } + catch {} + return false; + } + + public override int GetHashCode() + { + return (int)sym; } } [StructLayout (LayoutKind.Sequential)] - public unsafe struct Pointer + public struct Pointer { - private readonly void *ptr; + private readonly IntPtr ptr; public override string ToString() { - if(sizeof(void *) == 4) - return ((int)ptr).ToString(); - else - return ((long)ptr).ToString(); + return ptr.ToString(); } } [StructLayout (LayoutKind.Sequential)] - public unsafe struct Atom + public struct Atom { private enum AtomType {Null = 0, Float = 1, Symbol = 2, Pointer = 3}; @@ -146,7 +165,7 @@ namespace PureData } } - public class AtomListEnum + internal class AtomListEnum : IEnumerator { public AtomList list; @@ -192,8 +211,8 @@ namespace PureData // with l also being an AtomList... the two private members of the struct will get copied, although atoms is only a temporary reference [StructLayout (LayoutKind.Sequential)] - unsafe public struct AtomList -#if NET_2_0 + internal unsafe struct AtomList +#if xNET_2_0 : ICollection #else : ICollection @@ -203,7 +222,7 @@ namespace PureData private readonly Atom *atoms; public int Count { get { return len; } } -#if NET_2_0 +#if xNET_2_0 public bool IsReadOnly { get { return false; } } // member of generic.ICollection (C# 2.0) #endif public bool IsSynchronized { get { return false; } } @@ -212,7 +231,7 @@ namespace PureData // protect this from being used private AtomList(AtomList a) { len = 0; atoms = null; } -#if NET_2_0 +#if xNET_2_0 public void CopyTo(Atom[] array,int start) #else public void CopyTo(Array array,int start) @@ -246,7 +265,7 @@ namespace PureData } } -#if !NET_2_0 +//#if 1 // !NET_2_0 public static explicit operator Atom[](AtomList l) { Atom[] ret = new Atom[l.Count]; @@ -254,7 +273,7 @@ namespace PureData for(i = 0; i < l.Count; ++i) ret[i] = l.atoms[i]; return ret; } -#endif +//#endif override public string ToString() { diff --git a/PureData/DynamicMethod.cs b/PureData/DynamicMethod.cs new file mode 100644 index 0000000..749bb1a --- /dev/null +++ b/PureData/DynamicMethod.cs @@ -0,0 +1,101 @@ +using System; +using System.Reflection; +using System.Reflection.Emit; + +namespace PureData +{ + public delegate void DynamicMethodBang(External target); + public delegate void DynamicMethodFloat(External target,float f); + public delegate void DynamicMethodSymbol(External target,Symbol s); + public delegate void DynamicMethodPointer(External target,Pointer p); + public delegate void DynamicMethodList(External target,Atom[] l); + public delegate void DynamicMethodAnything(External target,int i,Symbol s,Atom[] l); + public delegate void DynamicMethodObject(External target,int i,object o); + + class DynamicMethods + { + private static Delegate CreateIntern(Delegate del, Type dyntype) + { + MethodInfo dynmethod = dyntype.GetMethod("Invoke"); + ParameterInfo[] dynparms = dynmethod.GetParameters(); + MethodInfo method = del.Method; + +#if DEBUG + if (dynmethod.ReturnType != typeof(void)) throw new ArgumentException("Return type must be void"); + + ParameterInfo[] parms = method.GetParameters(); + int numparms = parms.Length; + + if (dynparms.Length != numparms + 1) throw new ArgumentException("Number of parameters don't match"); + + for (int i = 0; i < numparms; ++i) + if (dynparms[i + 1].ParameterType != parms[i].ParameterType) throw new ArgumentException("Parameter types don't match"); +#endif + + Type[] argtypes = new Type[dynparms.Length]; + for (int i = 0; i < dynparms.Length; ++i) + argtypes[i] = dynparms[i].ParameterType; + + // Create dynamic method and obtain its IL generator to inject code. + DynamicMethod dynam = new DynamicMethod("dummy", typeof(void), argtypes, typeof(DynamicMethods)); + ILGenerator il = dynam.GetILGenerator(); + + #region IL Code generation + // If method isn't static push target instance on top of stack. + if (!method.IsStatic) + // Argument 0 of dynamic method is target instance. + il.Emit(OpCodes.Ldarg_0); + + // Push parameters onto the stack + for (int i = 0; i < dynparms.Length - 1; ++i) + il.Emit(OpCodes.Ldarg, i + 1); + + // Perform actual call. + // If method is not final a callvirt is required otherwise a normal call will be emitted. + il.Emit(method.IsFinal ? OpCodes.Call : OpCodes.Callvirt, method); + + // Emit return opcode. + il.Emit(OpCodes.Ret); + #endregion + + return dynam.CreateDelegate(dyntype); + } + + #region Specialized DynamicMethod makers + public static DynamicMethodBang Create(Public.MethodBang method) + { + return (DynamicMethodBang)CreateIntern(method, typeof(DynamicMethodBang)); + } + + public static DynamicMethodFloat Create(Public.MethodFloat method) + { + return (DynamicMethodFloat)CreateIntern(method,typeof(DynamicMethodFloat)); + } + + public static DynamicMethodSymbol Create(Public.MethodSymbol method) + { + return (DynamicMethodSymbol)CreateIntern(method,typeof(DynamicMethodSymbol)); + } + + public static DynamicMethodPointer Create(Public.MethodPointer method) + { + return (DynamicMethodPointer)CreateIntern(method,typeof(DynamicMethodPointer)); + } + + public static DynamicMethodList Create(Public.MethodList method) + { + return (DynamicMethodList)CreateIntern(method,typeof(DynamicMethodList)); + } + + public static DynamicMethodAnything Create(Public.MethodAnything method) + { + return (DynamicMethodAnything)CreateIntern(method,typeof(DynamicMethodAnything)); + } + + public static DynamicMethodObject Create(Public.MethodObject method) + { + return (DynamicMethodObject)CreateIntern(method, typeof(DynamicMethodObject)); + } + #endregion + } +} diff --git a/PureData/PureData.cs b/PureData/PureData.cs index 4df716e..0174317 100644 --- a/PureData/PureData.cs +++ b/PureData/PureData.cs @@ -1,203 +1,637 @@ using System; using System.Runtime.CompilerServices; // for extern import using System.Runtime.InteropServices; // for structures +using System.Reflection; +using System.Collections; namespace PureData { + [StructLayout(LayoutKind.Sequential)] + internal struct ClassPtr + { + private IntPtr ptr; + + public void Clear() { ptr = IntPtr.Zero; } + public bool Valid() { return ptr != IntPtr.Zero; } + + public override string ToString() { return ptr.ToString(); } + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ExternalPtr + { + private IntPtr ptr; + + public void Clear() { ptr = IntPtr.Zero; } + public bool Valid() { return ptr != IntPtr.Zero; } + + public override string ToString() { return ptr.ToString(); } + } + + // data passed from/to native side + [StructLayout(LayoutKind.Sequential)] + internal class PassedData + { + public Class klass; + public External ext; + public object obj; + } + // PD core functions - public unsafe class Internal + public class Internal { - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void *SymGen(string sym); + // the ExternalPtr when initializing an External instance + internal static ExternalPtr extptr; - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static string SymEval(void *sym); + internal static PassedData pass; // -------------------------------------------------------------------------- + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static Symbol SymGen(string sym); + [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj,Symbol sel,Symbol to_sel); + internal extern static string SymEval(Symbol sym); + + // -------------------------------------------------------------------------- + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj, Symbol sel, Symbol to_sel); // map to data member - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj,ref float f); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj, ref float f); // map to data member - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj,ref Symbol s); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj, ref Symbol s); // map to data member -// [MethodImplAttribute (MethodImplOptions.InternalCall)] -// internal extern static void AddInlet(void *obj,ref Pointer f); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj,ref Pointer f); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj,Symbol type); // create proxy inlet (typed) + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj, Symbol type); // create proxy inlet (typed) - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddInlet(void *obj); // create proxy inlet (anything) + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddInlet(ExternalPtr obj); // create proxy inlet (anything) // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void AddOutlet(void *obj,Symbol type); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void AddOutlet(ExternalPtr obj, Symbol type); // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n); - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,float f); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal extern static void Outlet(ExternalPtr obj, int n); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Symbol s); + internal extern static void Outlet(ExternalPtr obj, int n, float f); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Pointer p); + internal extern static void Outlet(ExternalPtr obj, int n, Symbol s); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Atom a); + internal extern static void Outlet(ExternalPtr obj, int n, Pointer p); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Symbol s,AtomList l); + internal extern static void Outlet(ExternalPtr obj, int n, Atom a); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Outlet(void *obj,int n,Symbol s,Atom[] l); + internal extern static void Outlet(ExternalPtr obj, int n, Symbol s, Atom[] l); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void OutletEx(void *obj,int n,object o); + internal extern static void OutletEx(ExternalPtr obj, int n, object o); // -------------------------------------------------------------------------- [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Bind(void *obj,Symbol dst); + internal extern static void Bind(ExternalPtr obj, Symbol dst); [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void Unbind(void *obj,Symbol dst); + internal extern static void Unbind(ExternalPtr obj, Symbol dst); } - - // This is the base class for a PD/CLR external - public unsafe abstract class External - { - // PD object pointer - private readonly void *ptr; + + public abstract class Public + : Internal + { // to be returned by Setup function - protected enum ClassType { Default = 0,PD = 1,GObj = 2,Patchable = 3,NoInlet = 8 } + protected enum ClassType { Default = 0, PD = 1, GObj = 2, Patchable = 3, NoInlet = 8 } // -------------------------------------------------------------------------- - protected readonly static Symbol _ = new Symbol(""); - protected readonly static Symbol _bang = new Symbol("bang"); - protected readonly static Symbol _float = new Symbol("float"); - protected readonly static Symbol _symbol = new Symbol("symbol"); - protected readonly static Symbol _pointer = new Symbol("pointer"); - protected readonly static Symbol _list = new Symbol("list"); - protected readonly static Symbol _anything = new Symbol("anything"); + public delegate void MethodBang(); + public delegate void MethodFloat(float f); + public delegate void MethodSymbol(Symbol s); + public delegate void MethodPointer(Pointer p); + public delegate void MethodList(Atom[] lst); + public delegate void MethodAnything(int inlet, Symbol tag, Atom[] lst); + public delegate void MethodObject(int inlet, object o); // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void Post(string message); - - protected static void Post(string format,object arg0) { Post(String.Format(format,arg0)); } - protected static void Post(string format,object arg0,object arg1) { Post(String.Format(format,arg0,arg1)); } - protected static void Post(string format,object arg0,object arg1,object arg2) { Post(String.Format(format,arg0,arg1,arg2)); } - protected static void Post(string format,params object[] args) { Post(String.Format(format,args)); } - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void PostError(string message); - - protected static void PostError(string format,object arg0) { PostError(String.Format(format,arg0)); } - protected static void PostError(string format,object arg0,object arg1) { PostError(String.Format(format,arg0,arg1)); } - protected static void PostError(string format,object arg0,object arg1,object arg2) { PostError(String.Format(format,arg0,arg1,arg2)); } - protected static void PostError(string format,params object[] args) { PostError(String.Format(format,args)); } - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void PostVerbose(int lvl,string message); - - protected static void PostVerbose(int lvl,string format,object arg0) { PostVerbose(lvl,String.Format(format,arg0)); } - protected static void PostVerbose(int lvl,string format,object arg0,object arg1) { PostVerbose(lvl,String.Format(format,arg0,arg1)); } - protected static void PostVerbose(int lvl,string format,object arg0,object arg1,object arg2) { PostVerbose(lvl,String.Format(format,arg0,arg1,arg2)); } - protected static void PostVerbose(int lvl,string format,params object[] args) { PostVerbose(lvl,String.Format(format,args)); } + public readonly static Symbol _ = new Symbol(""); + public readonly static Symbol _bang = new Symbol("bang"); + public readonly static Symbol _float = new Symbol("float"); + public readonly static Symbol _symbol = new Symbol("symbol"); + public readonly static Symbol _pointer = new Symbol("pointer"); + public readonly static Symbol _list = new Symbol("list"); // -------------------------------------------------------------------------- - protected delegate void Method(); - protected delegate void MethodFloat(float f); - protected delegate void MethodSymbol(Symbol s); - protected delegate void MethodPointer(Pointer p); - protected delegate void MethodList(AtomList lst); - protected delegate void MethodAnything(int inlet,Symbol tag,AtomList lst); - protected delegate void MethodObject(int inlet,object o); + [MethodImplAttribute (MethodImplOptions.InternalCall)] + public extern static void Post(string message); - // -------------------------------------------------------------------------- + public static void Post(string format, object arg0) { Post(String.Format(format, arg0)); } + public static void Post(string format, object arg0, object arg1) { Post(String.Format(format, arg0, arg1)); } + public static void Post(string format, object arg0, object arg1, object arg2) { Post(String.Format(format, arg0, arg1, arg2)); } + public static void Post(string format, params object[] args) { Post(String.Format(format, args)); } [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Method m); + public extern static void PostError(string message); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodFloat m); + public static void PostError(string format, object arg0) { PostError(String.Format(format, arg0)); } + public static void PostError(string format, object arg0, object arg1) { PostError(String.Format(format, arg0, arg1)); } + public static void PostError(string format, object arg0, object arg1, object arg2) { PostError(String.Format(format, arg0, arg1, arg2)); } + public static void PostError(string format, params object[] args) { PostError(String.Format(format, args)); } [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodSymbol m); + public extern static void PostVerbose(int lvl, string message); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodPointer m); + public static void PostVerbose(int lvl, string format, object arg0) { PostVerbose(lvl, String.Format(format, arg0)); } + public static void PostVerbose(int lvl, string format, object arg0, object arg1) { PostVerbose(lvl, String.Format(format, arg0, arg1)); } + public static void PostVerbose(int lvl, string format, object arg0, object arg1, object arg2) { PostVerbose(lvl, String.Format(format, arg0, arg1, arg2)); } + public static void PostVerbose(int lvl, string format, params object[] args) { PostVerbose(lvl, String.Format(format, args)); } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodList m); + // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodAnything m); + [MethodImplAttribute(MethodImplOptions.InternalCall)] + public extern static string SearchPath(string file); + } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,Method m); - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodFloat m); + public sealed class Class + : Public + { + // PD class pointer + private readonly ClassPtr ptr; + + // class type + private Type extclass; + + // -------------------------------------------------------------------------- + + // simple methods for inlet 0 + private DynamicMethodBang m_bang = null; + private DynamicMethodFloat m_float = null; + private DynamicMethodSymbol m_symbol = null; + private DynamicMethodPointer m_pointer = null; + private DynamicMethodList m_list = null; + private DynamicMethodAnything m_anything = null; + private DynamicMethodObject m_object = null; + + // -------------------------------------------------------------------------- + + private static void ResizeArray(ref Hashtable[] oldArray, int newSize) + { + int oldSize = oldArray.Length; + System.Type elementType = oldArray.GetType().GetElementType(); + Hashtable[] newArray = (Hashtable[])System.Array.CreateInstance(elementType, newSize); + int preserveLength = System.Math.Min(oldSize, newSize); + if (preserveLength > 0) + System.Array.Copy(oldArray, newArray, preserveLength); + oldArray = newArray; + } + + private struct MapValue + { + public MapValue(Kind k,Delegate d) { this.k = k; this.d = d; } + + public Kind k; + public Delegate d; + } + + private Hashtable[] m_map = new Hashtable[0]; + + // -------------------------------------------------------------------------- + + public override string ToString() + { + return extclass.Name; + } + + // -------------------------------------------------------------------------- + + private enum Kind { k_bang, k_float, k_symbol, k_pointer, k_list, k_anything, k_object } + + private enum MethodFlags { f_none = 0,f_bang = 0x01, f_float = 0x02, f_symbol = 0x04, f_pointer = 0x08, f_list = 0x10, f_anything = 0x20 } + + private static MethodFlags methodflags; + + + // -------------------------------------------------------------------------- + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private extern static bool RegisterClass(ClassPtr ptr, Symbol sym, ClassType cflags, MethodFlags mflags); + + private void AddMethodIntern(int inlet, Symbol sel, Kind k, Delegate d) + { + // add to map + if (m_map.Length <= inlet) ResizeArray(ref m_map, inlet + 1); + Hashtable h = m_map[inlet]; + if(h == null) m_map[inlet] = h = new Hashtable(); + h[sel] = new MapValue(k, d); + + methodflags |= MethodFlags.f_anything; + } + + public void AddMethod(int inlet, Symbol sel, MethodBang d) + { + DynamicMethodBang dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _bang) + { + m_bang = dyn; + methodflags |= MethodFlags.f_bang; + } + else + AddMethodIntern(inlet, sel, Kind.k_bang, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodFloat d) + { + DynamicMethodFloat dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _float) + { + m_float = dyn; + methodflags |= MethodFlags.f_float; + } + else + AddMethodIntern(inlet, sel, Kind.k_float, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodSymbol d) + { + DynamicMethodSymbol dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _symbol) + { + m_symbol = dyn; + methodflags |= MethodFlags.f_symbol; + } + else + AddMethodIntern(inlet, sel, Kind.k_symbol, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodPointer d) + { + DynamicMethodPointer dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _pointer) + { + m_pointer = dyn; + methodflags |= MethodFlags.f_pointer; + } + else + AddMethodIntern(inlet, sel, Kind.k_pointer, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodList d) + { + DynamicMethodList dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _list) + { + m_list = dyn; + methodflags |= MethodFlags.f_list; + } + else + AddMethodIntern(inlet, sel, Kind.k_list, dyn); + } + + public void AddMethod(int inlet, Symbol sel, MethodAnything d) + { + DynamicMethodAnything dyn = DynamicMethods.Create(d); + if (inlet == 0 && sel == _) + { + m_anything = dyn; + methodflags |= MethodFlags.f_anything; + } + else + AddMethodIntern(inlet, sel, Kind.k_anything, dyn); + } + + public void AddMethod(int inlet, MethodObject d) + { + DynamicMethodObject dyn = DynamicMethods.Create(d); + m_object = dyn; + methodflags |= MethodFlags.f_anything; + } + + // -------------------------------------------------------------------------- + + private Class(ClassPtr p,Type c) + { + ptr = p; + extclass = c; + } + + private delegate void DelegateClass(ClassPtr ptr, Symbol sym); + private static void NewClass(ClassPtr ptr, Symbol sym) + { + Internal.pass.klass = null; + + try + { + string name = sym.ToString(); + + // load assembly according to name + string file = SearchPath(name + ".dll"); + if (file.Length == 0) return; // throw new ArgumentException("Assembly file " + name + " not found"); + Assembly assembly = Assembly.LoadFile(file); + if (assembly == null) return; // throw new ArgumentException("Assembly " + name + " could not be loaded"); + Type exttp = assembly.GetType(name); + if (exttp == null) throw new ArgumentException("Class " + name + " could not be found"); + + Class klass = new Class(ptr, exttp); + + // create dummy external + ConstructorInfo ctor = exttp.GetConstructor(System.Type.EmptyTypes); + if (ctor == null) throw new MissingMethodException("External class must have a default constructor"); + + Internal.pass.klass = klass; + Internal.extptr.Clear(); + + External dummy = (External)ctor.Invoke(null); + + // reset flags + methodflags = MethodFlags.f_none; + + // call Setup method + MethodInfo setup = exttp.GetMethod("Setup",BindingFlags.NonPublic|BindingFlags.Static,null, new Type[1] { exttp },null); + if (setup == null) throw new MissingMethodException("External class must have a Setup function"); + + object ret = setup.Invoke(exttp, new object[1] { dummy }); + ClassType classflags; + try { classflags = (ClassType)ret; } + catch { classflags = ClassType.Default; } + + // set callbacks + RegisterClass(ptr, sym, classflags, methodflags); + } + catch (Exception exc) + { + Internal.pass.klass = null; + PostError(exc.ToString()); + } + } + + private delegate void DelegateNew(ExternalPtr ptr,AtomList args); + private static void NewInstance(ExternalPtr ptr,AtomList args) + { + External instance; + + Class cl = Internal.pass.klass; // set by native side + Internal.extptr = ptr; + +// Post("CLASS-NEW {0}",cl); + try + { + // TODO: create dynamic delegate for that.... + System.Reflection.ConstructorInfo m = cl.extclass.GetConstructor(new Type[1] { typeof(Atom[]) }); + if (m != null) + instance = (External)m.Invoke(new object[1] { (Atom[])args }); + else + { + // search for the argument-less constructor... it must exist, we searched before + m = cl.extclass.GetConstructor(System.Type.EmptyTypes); + instance = (External)m.Invoke(null); + } + } + catch (Exception exc) + { + instance = null; + PostError(exc.ToString()); + } + +#if DEBUG + Internal.extptr.Clear(); +#endif + + Internal.pass.ext = instance; // back to native + } + + private delegate void DelegateBang(); + private static void CallBang() + { + External e = Internal.pass.ext; + try { e.klass.m_bang(e); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateFloat(float f); + private static void CallFloat(float f) + { + External e = Internal.pass.ext; + try { e.klass.m_float(e, f); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateSymbol(Symbol s); + private static void CallSymbol(Symbol s) + { + External e = Internal.pass.ext; + try { e.klass.m_symbol(e, s); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegatePointer(Pointer p); + private static void CallPointer(Pointer p) + { + External e = Internal.pass.ext; + try { e.klass.m_pointer(e, p); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateList(AtomList l); + private static void CallList(AtomList l) + { + External e = Internal.pass.ext; + try { e.klass.m_list(e, (Atom[])l); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateAnything(int inlet, Symbol s, AtomList l); + private static void CallAnything(int inlet, Symbol s, AtomList l) + { +// Post("CLASS-ANYTHING {0}->{1}:{2}", inlet,s,l); + + try { + External e = Internal.pass.ext; + Class c = e.klass; + + Hashtable h; + try { h = (Hashtable)c.m_map[inlet]; } + catch (IndexOutOfRangeException) { h = null; } + + if(h != null) + { + object fnd = h[s]; + if (fnd != null) + { + MapValue mv = (MapValue)fnd; + switch(mv.k) + { + case Kind.k_bang: + { + ((DynamicMethodBang)mv.d)(e); + return; + } + case Kind.k_float: + { + float f = l.Count > 0 ? (float)l[0] : 0; + ((DynamicMethodFloat)mv.d)(e, f); + return; + } + case Kind.k_symbol: + { + Symbol sym = l.Count > 0 ? (Symbol)l[0] : _; + ((DynamicMethodSymbol)mv.d)(e, sym); + return; + } + case Kind.k_pointer: + { + Pointer p = l.Count > 0 ? (Pointer)l[0] : new Pointer(); + ((DynamicMethodPointer)mv.d)(e, p); + return; + } + case Kind.k_list: + ((DynamicMethodList)mv.d)(e,(Atom[])l); + return; + case Kind.k_anything: + ((DynamicMethodAnything)mv.d)(e,inlet,s,(Atom[])l); + return; + default: + throw new NotImplementedException("Selector " + s.ToString() + " not handled"); + } + } + } + + // no explicit method found... + c.m_anything(e, inlet, s, (Atom[])l); + } + catch (Exception exc) { PostError(exc.ToString()); } + } + + private delegate void DelegateObject(int inlet); + private static void CallObject(int inlet) + { +// Post("CLASS-OBJECT {0}", inlet); + + External e = Internal.pass.ext; + try { e.klass.m_object(e, inlet, Internal.pass.obj); } + catch (Exception exc) { PostError(exc.ToString()); } + } + + // -------------------------------------------------------------------------- + + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private extern static void Register(DelegateClass d_class, DelegateNew d_new, DelegateBang d_bang, DelegateFloat d_float, DelegateSymbol d_symbol, DelegatePointer d_pointer, DelegateList d_list, DelegateAnything d_anything, DelegateObject d_object); + + private static void Setup() + { + try + { + Internal.pass = new PassedData(); + + Register( + new DelegateClass(NewClass), + new DelegateNew(NewInstance), + new DelegateBang(CallBang), + new DelegateFloat(CallFloat), + new DelegateSymbol(CallSymbol), + new DelegatePointer(CallPointer), + new DelegateList(CallList), + new DelegateAnything(CallAnything), + new DelegateObject(CallObject) + ); + } + catch (Exception exc) { PostError(exc.ToString()); } + } + } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodSymbol m); + + // This is the base class for a PD/CLR external + public abstract class External + : Public + { + // PD object pointer + internal readonly ExternalPtr ptr; + // Class + internal readonly Class klass; - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodPointer m); + // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodList m); + protected External() + { + ptr = Internal.extptr; + klass = Internal.pass.klass; + } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,Symbol sel,MethodAnything m); + public override string ToString() + { + return ptr.Valid()?klass.ToString():"???"; + } - protected static void AddMethod(int inlet,string sel,Method m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodFloat m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodSymbol m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodPointer m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodList m) { AddMethod(inlet,new Symbol(sel),m); } - protected static void AddMethod(int inlet,string sel,MethodAnything m) { AddMethod(inlet,new Symbol(sel),m); } + // -------------------------------------------------------------------------- - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void AddMethod(int inlet,MethodObject m); + protected static void AddMethod(int inlet, Symbol sel, MethodBang m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodFloat m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodSymbol m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodPointer m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodList m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, Symbol sel, MethodAnything m) { ((External)m.Target).klass.AddMethod(inlet, sel, m); } + protected static void AddMethod(int inlet, MethodObject m) { ((External)m.Target).klass.AddMethod(inlet, m); } + + protected static void AddMethod(int inlet, MethodBang m) { AddMethod(inlet, _bang, m); } + protected static void AddMethod(int inlet, MethodFloat m) { AddMethod(inlet, _float, m); } + protected static void AddMethod(int inlet, MethodSymbol m) { AddMethod(inlet, _symbol, m); } + protected static void AddMethod(int inlet, MethodPointer m) { AddMethod(inlet, _pointer, m); } + protected static void AddMethod(int inlet, MethodList m) { AddMethod(inlet, _list, m); } + protected static void AddMethod(int inlet, MethodAnything m) { AddMethod(inlet, _, m); } + + protected static void AddMethod(MethodBang m) { AddMethod(0, m); } + protected static void AddMethod(MethodFloat m) { AddMethod(0, m); } + protected static void AddMethod(MethodSymbol m) { AddMethod(0, m); } + protected static void AddMethod(MethodPointer m) { AddMethod(0, m); } + protected static void AddMethod(MethodList m) { AddMethod(0, m); } + protected static void AddMethod(MethodAnything m) { AddMethod(0, m); } + protected static void AddMethod(MethodObject m) { AddMethod(0, m); } + + protected static void AddMethod(int inlet, string sel, MethodBang m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodFloat m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodSymbol m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodPointer m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodList m) { AddMethod(inlet, new Symbol(sel), m); } + protected static void AddMethod(int inlet, string sel, MethodAnything m) { AddMethod(inlet, new Symbol(sel), m); } // -------------------------------------------------------------------------- - protected void AddInlet(ref float f) { Internal.AddInlet(ptr,ref f); } // map to data member - protected void AddInlet(ref Symbol s) { Internal.AddInlet(ptr,ref s); } // map to data member -// protected void AddInlet(ref Pointer p) { Internal.AddInlet(ptr,ref p); } // map to data member + protected void AddInlet(ref float f) { Internal.AddInlet(ptr, ref f); } // map to data member + protected void AddInlet(ref Symbol s) { Internal.AddInlet(ptr, ref s); } // map to data member + protected void AddInlet(ref Pointer p) { Internal.AddInlet(ptr,ref p); } // map to data member // protected void AddInlet(Symbol type) { Internal.AddInlet(ptr,type); } // create typed inlet protected void AddInlet() { Internal.AddInlet(ptr); } // create inlet responding to any message - protected void AddInlet(Symbol sel,Symbol to_sel) { Internal.AddInlet(ptr,sel,to_sel); } // redirect messages to defined selector + protected void AddInlet(Symbol sel, Symbol to_sel) { Internal.AddInlet(ptr, sel, to_sel); } // redirect messages to defined selector // -------------------------------------------------------------------------- - protected void AddOutlet(Symbol type) { Internal.AddOutlet(ptr,type); } + protected void AddOutlet(Symbol type) { Internal.AddOutlet(ptr, type); } protected void AddOutletBang() { AddOutlet(_bang); } protected void AddOutletFloat() { AddOutlet(_float); } protected void AddOutletSymbol() { AddOutlet(_symbol); } protected void AddOutletPointer() { AddOutlet(_pointer); } protected void AddOutletList() { AddOutlet(_list); } - protected void AddOutletAnything() { AddOutlet(_anything); } + protected void AddOutletAnything() { AddOutlet(_); } // -------------------------------------------------------------------------- @@ -206,9 +640,7 @@ namespace PureData protected void Outlet(int n,Symbol s) { Internal.Outlet(ptr,n,s); } protected void Outlet(int n,Pointer p) { Internal.Outlet(ptr,n,p); } protected void Outlet(int n,Atom a) { Internal.Outlet(ptr,n,a); } - protected void Outlet(int n,AtomList l) { Internal.Outlet(ptr,n,_list,l); } protected void Outlet(int n,Atom[] l) { Internal.Outlet(ptr,n,_list,l); } - protected void Outlet(int n,Symbol s,AtomList l) { Internal.Outlet(ptr,n,s,l); } protected void Outlet(int n,Symbol s,Atom[] l) { Internal.Outlet(ptr,n,s,l); } protected void OutletEx(int n,object o) { Internal.OutletEx(ptr,n,o); } @@ -223,16 +655,12 @@ namespace PureData [MethodImplAttribute (MethodImplOptions.InternalCall)] protected extern static void Send(Symbol sym,Atom a); - protected static void Send(Symbol sym) { Send(sym,_bang,null); } + protected static void Send(Symbol sym) { Send(sym,_bang,new Atom[0]); } protected static void Send(Symbol sym,float f) { Send(sym,new Atom(f)); } protected static void Send(Symbol sym,Symbol s) { Send(sym,new Atom(s)); } protected static void Send(Symbol sym,Pointer p) { Send(sym,new Atom(p)); } - protected static void Send(Symbol sym,AtomList l) { Send(sym,_list,l); } protected static void Send(Symbol sym,Atom[] l) { Send(sym,_list,l); } - [MethodImplAttribute (MethodImplOptions.InternalCall)] - protected extern static void Send(Symbol sym,Symbol s,AtomList l); - [MethodImplAttribute (MethodImplOptions.InternalCall)] protected extern static void Send(Symbol sym,Symbol s,Atom[] l); diff --git a/PureData/PureData.csproj b/PureData/PureData.csproj index f1b3d08..2d65f14 100644 --- a/PureData/PureData.csproj +++ b/PureData/PureData.csproj @@ -1,105 +1,108 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + Local + 8.0.50727 + 2.0 + {0015D5E7-B0FB-4F06-B334-225447D1F992} + Debug + AnyCPU + + + + + PureData + + + JScript + Grid + IE50 + false + Library + PureData + OnBuildSuccess + + + + + + + + + bin\Debug\ + true + 285212672 + false + + + TRACE;DEBUG;NET_2_0 + + + true + 4096 + false + + + false + false + false + false + 4 + full + prompt + + + bin\Debug\ + true + 285212672 + false + + + TRACE;DEBUG;NET_2_0 + + + false + 4096 + false + + + false + false + false + false + 4 + none + prompt + + + + System + + + System.Data + + + System.XML + + + + + Code + + + Code + + + Code + + + Code + + + + + + + + + + \ No newline at end of file -- cgit v1.2.1