From 88ae96ff82ddc836a822a55aef17ea66ca06ac65 Mon Sep 17 00:00:00 2001 From: Thomas Grill Date: Tue, 7 Mar 2006 13:18:32 +0000 Subject: restructured project (MSVC can't cope well with folder/classname mismatch) search for CLR DLLs in PD path first steps to efficient method handling svn path=/trunk/externals/clr/; revision=4656 --- Counter/AssemblyInfo.cs | 58 ++++++++++ Counter/Counter.cs | 61 +++++++++++ Counter/Counter.csproj | 105 ++++++++++++++++++ Counter/README.txt | 3 + PureData/AssemblyInfo.cs | 58 ++++++++++ PureData/Atom.cs | 270 +++++++++++++++++++++++++++++++++++++++++++++++ PureData/PureData.cs | 64 +++++++++++ PureData/PureData.csproj | 105 ++++++++++++++++++ PureData/README.txt | 3 + clr.cpp | 210 ++++++++++++++++++++++++------------ external/AssemblyInfo.cs | 58 ---------- external/Counter.cs | 72 ------------- external/README.txt | 3 - external/external.csproj | 106 ------------------- external/external.sln | 21 ---- pd/AssemblyInfo.cs | 58 ---------- pd/Atom.cs | 270 ----------------------------------------------- pd/PureData.cs | 48 --------- pd/README.txt | 3 - pd/pd.csproj | 105 ------------------ pd/pd.sln | 21 ---- 21 files changed, 867 insertions(+), 835 deletions(-) create mode 100755 Counter/AssemblyInfo.cs create mode 100755 Counter/Counter.cs create mode 100644 Counter/Counter.csproj create mode 100755 Counter/README.txt create mode 100755 PureData/AssemblyInfo.cs create mode 100755 PureData/Atom.cs create mode 100644 PureData/PureData.cs create mode 100644 PureData/PureData.csproj create mode 100755 PureData/README.txt delete mode 100755 external/AssemblyInfo.cs delete mode 100755 external/Counter.cs delete mode 100755 external/README.txt delete mode 100755 external/external.csproj delete mode 100755 external/external.sln delete mode 100755 pd/AssemblyInfo.cs delete mode 100755 pd/Atom.cs delete mode 100644 pd/PureData.cs delete mode 100755 pd/README.txt delete mode 100755 pd/pd.csproj delete mode 100755 pd/pd.sln diff --git a/Counter/AssemblyInfo.cs b/Counter/AssemblyInfo.cs new file mode 100755 index 0000000..f341568 --- /dev/null +++ b/Counter/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// Le informazioni generali relative a un assembly sono controllate dal seguente +// insieme di attributi. Per modificare le informazioni associate a un assembly +// occorre quindi modificare i valori di questi attributi. +// +[assembly: AssemblyTitle("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: +// +// Numero di versione principale +// Numero di versione secondario +// Numero revisione +// Numero build +// +// È possibile specificare tutti i valori o impostare come predefiniti i valori Numero revisione e Numero build +// utilizzando l'asterisco (*) come illustrato di seguito: + +[assembly: AssemblyVersion("1.0.*")] + +// +// Per firmare l'assembly è necessario specificare una chiave da utilizzare. +// Fare riferimento alla documentazione di Microsoft .NET Framework per ulteriori informazioni sulla firma degli assembly. +// +// Utilizzare gli attributi elencati di seguito per verificare la chiave utilizzata per la firma. +// +// Note: +// (*) Se non è specificata alcuna chiave, non sarà possibile firmare l'assembly. +// (*) KeyName fa riferimento a una chiave installata nel provider di servizi di +// crittografia (CSP) sul computer in uso. KeyFile fa riferimento a un file che contiene +// una chiave. +// (*) Se entrambi i valori KeyFile e KeyName sono specificati, si +// verificherà il seguente processo: +// (1) Se KeyName è presente in CSP, verrà utilizzata tale chiave. +// (2) Se KeyName non esiste e KeyFile esiste, la chiave +// di KeyFile verrà installata nel CSP e utilizzata. +// (*) Per creare un KeyFile, è possibile utilizzare l'utilità sn.exe (Strong Name). +// Quando si specifica il KeyFile, il percorso dovrà essere +// relativo alla directory di output del progetto, ovvero +// %Project Directory%\obj\. Se ad esempio il KeyFile si +// trova nella directory del progetto, occorre specificare l'attributo AssemblyKeyFile +// come [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) La firma ritardata è un'opzione avanzata. Vedere la documentazione di Microsoft +// .NET Framework per ulteriori informazioni. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/Counter/Counter.cs b/Counter/Counter.cs new file mode 100755 index 0000000..bf1a9d1 --- /dev/null +++ b/Counter/Counter.cs @@ -0,0 +1,61 @@ +using System; + +/// +/// Descrizione di riepilogo per Counter. +/// +public class Counter: + PureData.External +{ + public Counter(PureData.AtomList args) + { + Post("Count.ctor "+args.ToString()); + +// pd.AddInlet(x, "init", ParametersType.Float); +// pd.AddOutlet(x, ParametersType.Float); + } + + // this function MUST exist + private static void Setup(Counter obj) + { + Add(new MethodBang(obj.MyBang)); + Add(new MethodFloat(obj.MyFloat)); + Add(new MethodSymbol(obj.MySymbol)); + Add(new MethodList(obj.MyList)); + + Post("Count.Main"); + } + + protected virtual void MyBang() + { + Post("Count-BANG"); + } + + protected virtual void MyFloat(float f) + { + Post("Count-FLOAT "+f.ToString()); + } + + protected virtual void MySymbol(PureData.Symbol s) + { + Post("Count-SYMBOL "+s.ToString()); + } + + protected virtual void MyList(PureData.AtomList l) + { + Post("Count-LIST "+l.ToString()); + } + +/* + public void SendOut() + { + pd.SendToOutlet(x, 0, new Atom(curr)); + } + + public void Sum(float f) + { + curr += (int) f; + pd.SendToOutlet(x, 0, new Atom(curr)); + } + +*/ +} diff --git a/Counter/Counter.csproj b/Counter/Counter.csproj new file mode 100644 index 0000000..4502d55 --- /dev/null +++ b/Counter/Counter.csproj @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Counter/README.txt b/Counter/README.txt new file mode 100755 index 0000000..dd2d745 --- /dev/null +++ b/Counter/README.txt @@ -0,0 +1,3 @@ +to compile External.dll put PureData.dll in this folder then execute this command: + +mcs External.cs Counter.cs -out:External.dll -target:library -r:PureData.dll \ No newline at end of file diff --git a/PureData/AssemblyInfo.cs b/PureData/AssemblyInfo.cs new file mode 100755 index 0000000..93484d8 --- /dev/null +++ b/PureData/AssemblyInfo.cs @@ -0,0 +1,58 @@ +using System.Reflection; +using System.Runtime.CompilerServices; + +// +// Le informazioni generali relative a un assembly sono controllate dal seguente +// insieme di attributi. Per modificare le informazioni associate a un assembly +// occorre quindi modificare i valori di questi attributi. +// +[assembly: AssemblyTitle("PureData")] +[assembly: AssemblyDescription("bridge between C sharp externals and pd")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("")] +[assembly: AssemblyCopyright("Davide Morelli, Thomas Grill")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// +// Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: +// +// Numero di versione principale +// Numero di versione secondario +// Numero revisione +// Numero build +// +// È possibile specificare tutti i valori o impostare come predefiniti i valori Numero revisione e Numero build +// utilizzando l'asterisco (*) come illustrato di seguito: + +[assembly: AssemblyVersion("1.0.*")] + +// +// Per firmare l'assembly è necessario specificare una chiave da utilizzare. +// Fare riferimento alla documentazione di Microsoft .NET Framework per ulteriori informazioni sulla firma degli assembly. +// +// Utilizzare gli attributi elencati di seguito per verificare la chiave utilizzata per la firma. +// +// Note: +// (*) Se non è specificata alcuna chiave, non sarà possibile firmare l'assembly. +// (*) KeyName fa riferimento a una chiave installata nel provider di servizi di +// crittografia (CSP) sul computer in uso. KeyFile fa riferimento a un file che contiene +// una chiave. +// (*) Se entrambi i valori KeyFile e KeyName sono specificati, si +// verificherà il seguente processo: +// (1) Se KeyName è presente in CSP, verrà utilizzata tale chiave. +// (2) Se KeyName non esiste e KeyFile esiste, la chiave +// di KeyFile verrà installata nel CSP e utilizzata. +// (*) Per creare un KeyFile, è possibile utilizzare l'utilità sn.exe (Strong Name). +// Quando si specifica il KeyFile, il percorso dovrà essere +// relativo alla directory di output del progetto, ovvero +// %Project Directory%\obj\. Se ad esempio il KeyFile si +// trova nella directory del progetto, occorre specificare l'attributo AssemblyKeyFile +// come [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] +// (*) La firma ritardata è un'opzione avanzata. Vedere la documentazione di Microsoft +// .NET Framework per ulteriori informazioni. +// +[assembly: AssemblyDelaySign(false)] +[assembly: AssemblyKeyFile("")] +[assembly: AssemblyKeyName("")] diff --git a/PureData/Atom.cs b/PureData/Atom.cs new file mode 100755 index 0000000..6a29483 --- /dev/null +++ b/PureData/Atom.cs @@ -0,0 +1,270 @@ +using System; +using System.Runtime.InteropServices; // for structures +using System.Collections; +#if NET_2_0 +using System.Collections.Generic; +#endif + +namespace PureData +{ + [StructLayout (LayoutKind.Sequential)] + public unsafe struct Symbol + { + // this should NOT be public (or at least read only) + private readonly void *sym; + + public Symbol(string s) + { + sym = Internal.SymGen(s); + } + + public override string ToString() + { + return Internal.SymEval(sym); + } + } + + [StructLayout (LayoutKind.Sequential)] + public unsafe struct Pointer + { + private readonly void *ptr; + + public override string ToString() + { + if(sizeof(void *) == 4) + return ((int)ptr).ToString(); + else + return ((long)ptr).ToString(); + } + } + + [StructLayout (LayoutKind.Sequential)] + public unsafe struct Atom + { + private enum AtomType {Null = 0, Float = 1, Symbol = 2, Pointer = 3}; + + [StructLayout (LayoutKind.Explicit)] + private struct Word + { + [FieldOffset(0)] public float w_float; + [FieldOffset(0)] public Symbol w_sym; + [FieldOffset(0)] public Pointer w_ptr; + } + + private AtomType type; + private Word word; + + public Atom(float f) + { + type = AtomType.Float; + word = new Word(); + word.w_float = f; + } + + public Atom(int i) + { + type = AtomType.Float; + word = new Word(); + word.w_float = (float)i; + } + + public Atom(Symbol s) + { + type = AtomType.Symbol; + word = new Word(); + word.w_sym = s; + } + + public Atom(string s) + { + type = AtomType.Symbol; + word = new Word(); + word.w_sym = new Symbol(s); + } + + public Atom(Pointer p) + { + type = AtomType.Pointer; + word = new Word(); + word.w_ptr = p; + } + + public bool IsFloat { get { return type == AtomType.Float; } } + public bool IsSymbol { get { return type == AtomType.Symbol; } } + public bool IsPointer { get { return type == AtomType.Pointer; } } + + public float ToFloat() + { + if(IsFloat) + return word.w_float; + else + throw new System.InvalidCastException("Can't be cast to float."); + } + + public Symbol ToSymbol() + { + if(IsSymbol) + return word.w_sym; + else + throw new System.InvalidCastException("Can't be cast to Symbol."); + } + + public Pointer ToPointer() + { + if(IsPointer) + return word.w_ptr; + else + throw new System.InvalidCastException("Can't be cast to Pointer."); + } + + override public string ToString() + { + if(IsFloat) + return word.w_float.ToString(); + else if(IsSymbol) + return word.w_sym.ToString(); + else if(IsPointer) + return word.w_ptr.ToString(); + else + // should never happen + throw new System.InvalidProgramException("Internal error."); + } + + public static explicit operator float(Atom a) + { + return a.ToFloat(); + } + + public static explicit operator Symbol(Atom a) + { + return a.ToSymbol(); + } + + public static explicit operator Pointer(Atom a) + { + return a.ToPointer(); + } + } + + public class AtomListEnum + : IEnumerator + { + public AtomList list; + + // Enumerators are positioned before the first element + // until the first MoveNext() call. + int position = -1; + + public AtomListEnum(AtomList l) + { + list = l; + } + + public bool MoveNext() + { + return ++position < list.Count; + } + + public void Reset() + { + position = -1; + } + + public object Current + { + get + { + try + { + return list[position]; + } + catch (IndexOutOfRangeException) + { + throw new InvalidOperationException(); + } + } + } + } + + + // attention: this is dangerous, because we could do the following + // AtomList l2 = l; + // with l also being an AtomList... the two private memebers will get copied, although atoms is only a temporary reference + + [StructLayout (LayoutKind.Sequential)] + unsafe public struct AtomList +#if NET_2_0 + : ICollection +#else + : ICollection +#endif + { + private readonly int len; + private readonly Atom *atoms; + + public int Count { get { return len; } } +#if NET_2_0 + public bool IsReadOnly { get { return false; } } // member of generic.ICollection (C# 2.0) +#endif + public bool IsSynchronized { get { return false; } } + public Object SyncRoot { get { return null; } } + + // protect this from being used + private AtomList(AtomList a) { len = 0; atoms = null; } + +#if NET_2_0 + public void CopyTo(Atom[] array,int start) +#else + public void CopyTo(Array array,int start) +#endif + { + if(len > array.GetUpperBound(0)+1-start) + throw new System.ArgumentException("Destination array is not long enough."); + int i; + for(i = 0; i < len-start; ++i) + array.SetValue(atoms[start+i],i); + } + + public IEnumerator GetEnumerator() + { + return new AtomListEnum(this); + } + + public Atom this[int i] + { + get + { + if(i < 0 || i >= len) + throw new System.IndexOutOfRangeException("Index outside array bounds."); + return atoms[i]; + } + set + { + if(i < 0 || i >= len) + throw new System.IndexOutOfRangeException("Index outside array bounds."); + atoms[i] = value; + } + } + +#if !NET_2_0 + public static explicit operator Atom[](AtomList l) + { + Atom[] ret = new Atom[l.Count]; + int i; + for(i = 0; i < l.Count; ++i) ret[i] = l.atoms[i]; + return ret; + } +#endif + + override public string ToString() + { + string n = "{"; + if(len > 0) { + int i; + for(i = 0; i < len-1; ++i) n += atoms[i].ToString()+","; + n += atoms[i].ToString(); + } + return n+"}"; + } + } +} diff --git a/PureData/PureData.cs b/PureData/PureData.cs new file mode 100644 index 0000000..c9ac143 --- /dev/null +++ b/PureData/PureData.cs @@ -0,0 +1,64 @@ +using System; +using System.Runtime.CompilerServices; // for extern import +using System.Runtime.InteropServices; // for structures + +namespace PureData +{ + // PD core functions + public unsafe class Internal + { + [MethodImplAttribute (MethodImplOptions.InternalCall)] + internal extern static void *SymGen(string sym); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + internal extern static string SymEval(void *sym); + } + + // This is the base class for a PD/CLR external + public unsafe class External + { + // PD object pointer + private readonly void *ptr; + + // -------------------------------------------------------------------------- + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void Post(string message); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void PostError(string message); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void PostBug(string message); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void PostVerbose(string message); + + // -------------------------------------------------------------------------- + + protected delegate void MethodBang(); + 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(Symbol tag,AtomList lst); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void Add(MethodBang m); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void Add(MethodFloat m); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void Add(MethodSymbol m); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void Add(MethodPointer m); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void Add(MethodList m); + + [MethodImplAttribute (MethodImplOptions.InternalCall)] + protected extern static void Add(MethodAnything m); + } +} diff --git a/PureData/PureData.csproj b/PureData/PureData.csproj new file mode 100644 index 0000000..f1b3d08 --- /dev/null +++ b/PureData/PureData.csproj @@ -0,0 +1,105 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/PureData/README.txt b/PureData/README.txt new file mode 100755 index 0000000..323f00c --- /dev/null +++ b/PureData/README.txt @@ -0,0 +1,3 @@ +to compile PureData.dll execute this command: + +mcs Atom.cs pd.cs -out:PureData.dll -target:library \ No newline at end of file diff --git a/clr.cpp b/clr.cpp index 62f7c2d..59e0d47 100755 --- a/clr.cpp +++ b/clr.cpp @@ -27,10 +27,12 @@ extern "C" { #include +#define CORELIB "PureData" +#define DLLEXT "dll" static MonoDomain *monodomain; static MonoClass *clr_symbol,*clr_pointer,*clr_atom,*clr_atomlist,*clr_external; -static MonoMethodDesc *clr_desc_main,*clr_desc_ctor; +static MonoMethodDesc *clr_desc_tostring,*clr_desc_ctor; static MonoMethodDesc *clr_desc_bang,*clr_desc_float,*clr_desc_symbol,*clr_desc_pointer,*clr_desc_list,*clr_desc_anything; static MonoMethod *ext_method_bang,*ext_method_float,*ext_method_symbol,*ext_method_list,*ext_method_pointer,*ext_method_anything; @@ -45,6 +47,7 @@ typedef struct MonoClass *mono_class; MonoClassField *mono_obj_field; MonoMethod *mono_ctor; + t_symbol *name; // ClrMethodMap *methods; } t_clr_class; @@ -65,6 +68,21 @@ typedef struct +// Print error message given by exception +static void error_exc(char *txt,char *cname,MonoObject *exc) +{ + MonoMethod *m = mono_method_desc_search_in_class(clr_desc_tostring,mono_get_exception_class()); + assert(m); + m = mono_object_get_virtual_method(exc,m); + assert(m); + MonoString *str = (MonoString *)mono_runtime_invoke(m,exc,NULL,NULL); + assert(str); + error("CLR class %s: %s",txt,cname); + error(mono_string_to_utf8(str)); +} + + + static void clr_method_bang(t_clr *x) { assert(x && x->clr_clss); @@ -72,9 +90,7 @@ static void clr_method_bang(t_clr *x) assert(m); MonoObject *exc; mono_runtime_invoke(m,x->mono_obj,NULL,&exc); - if(exc) { - error("Exception raised"); - } + if(exc) error_exc("Exception raised",x->clr_clss->name->s_name,exc); } static void clr_method_float(t_clr *x,t_float f) @@ -85,9 +101,7 @@ static void clr_method_float(t_clr *x,t_float f) gpointer args = &f; MonoObject *exc; mono_runtime_invoke(m,x->mono_obj,&args,&exc); - if(exc) { - error("Exception raised"); - } + if(exc) error_exc("Exception raised",x->clr_clss->name->s_name,exc); } static void clr_method_symbol(t_clr *x,t_symbol *s) @@ -104,9 +118,24 @@ static void clr_method_symbol(t_clr *x,t_symbol *s) #endif MonoObject *exc; mono_runtime_invoke(m,x->mono_obj,&args,&exc); - if(exc) { - error("Exception raised"); - } + if(exc) error_exc("Exception raised",x->clr_clss->name->s_name,exc); +} + +static void clr_method_pointer(t_clr *x,t_gpointer *p) +{ + assert(x && x->clr_clss); + MonoMethod *m = mono_object_get_virtual_method(x->mono_obj,ext_method_pointer); + assert(m); +#if 0 + MonoObject *ptrobj = mono_value_box(monodomain,clr_pointer,&p); + MonoObject *o = (MonoObject *)mono_object_unbox(ptrobj); + gpointer args = o; +#else + gpointer args = &p; +#endif + MonoObject *exc; + mono_runtime_invoke(m,x->mono_obj,&args,&exc); + if(exc) error_exc("Exception raised",x->clr_clss->name->s_name,exc); } struct AtomList @@ -151,28 +180,7 @@ static void clr_method_list(t_clr *x,t_symbol *l, int argc, t_atom *argv) #endif MonoObject *exc; mono_runtime_invoke(m,x->mono_obj,&args,&exc); - if(exc) { - error("Exception raised"); - } -} - -static void clr_method_pointer(t_clr *x,t_gpointer *p) -{ - assert(x && x->clr_clss); - MonoMethod *m = mono_object_get_virtual_method(x->mono_obj,ext_method_pointer); - assert(m); -#if 0 - MonoObject *ptrobj = mono_value_box(monodomain,clr_pointer,&p); - MonoObject *o = (MonoObject *)mono_object_unbox(ptrobj); - gpointer args = o; -#else - gpointer args = &p; -#endif - MonoObject *exc; - mono_runtime_invoke(m,x->mono_obj,&args,&exc); - if(exc) { - error("Exception raised"); - } + if(exc) error_exc("Exception raised",x->clr_clss->name->s_name,exc); } static void clr_method_anything(t_clr *x,t_symbol *sl, int argc, t_atom *argv) @@ -197,7 +205,6 @@ static void clr_method_anything(t_clr *x,t_symbol *sl, int argc, t_atom *argv) #endif } - // this function is called by mono when it wants post messages to pd static void PD_Post(MonoString *str) { @@ -235,6 +242,35 @@ static MonoString *PD_SymEval(t_symbol *sym) return mono_string_new(monodomain,sym->s_name); } +static void PD_AddBang(MonoObject *method) +{ + post("Add bang method"); +} + +static void PD_AddFloat(MonoObject *method) +{ + post("Add float method"); +} + +static void PD_AddSymbol(MonoObject *method) +{ + post("Add symbol method"); +} + +static void PD_AddPointer(MonoObject *method) +{ + post("Add pointer method"); +} + +static void PD_AddList(MonoObject *method) +{ + post("Add list method"); +} + +static void PD_AddAnything(MonoObject *method) +{ + post("Add anything method"); +} #if 0 // this function is called by mono when it wants post messages to pd @@ -316,6 +352,7 @@ void *clr_new(t_symbol *classname, int argc, t_atom *argv) // store class pointer x->clr_clss = clss; + x->clr_clss->name = classname; // store our object pointer in External::ptr member mono_field_set_value(x->mono_obj,clss->mono_obj_field,&x); @@ -329,18 +366,13 @@ void *clr_new(t_symbol *classname, int argc, t_atom *argv) MonoObject *lstobj = new_AtomList(argc,argv); gpointer args = lstobj; #endif + // call constructor MonoObject *exc; - - // call static constructor - MonoObject *ret = mono_runtime_invoke(clss->mono_ctor,x->mono_obj,&args,&exc); - if(ret) { - post("Warning: returned value from %s::.ctor ignored",classname->s_name); - // ??? do we have to mark ret as free? - } + mono_runtime_invoke(clss->mono_ctor,x->mono_obj,&args,&exc); if(exc) { pd_free((t_pd *)x); - error("CLR class %s - exception raised in constructor",classname->s_name); + error_exc("exception raised in constructor",classname->s_name,exc); return NULL; } } @@ -365,7 +397,7 @@ static int classloader(char *dirname, char *classname) char dirbuf[MAXPDSTRING],*nameptr; // search for classname.dll in the PD path int fd; - if ((fd = open_via_path(dirname, classname, ".dll", dirbuf, &nameptr, MAXPDSTRING, 1)) < 0) + if ((fd = open_via_path(dirname, classname, "." DLLEXT, dirbuf, &nameptr, MAXPDSTRING, 1)) < 0) // not found goto bailout; @@ -377,16 +409,13 @@ static int classloader(char *dirname, char *classname) // clr_class->methods = NULL; // try to load assembly - char path[MAXPDSTRING]; - strcpy(path,dirname); - strcat(path,"/"); -// strcat(path,dirbuf); -// strcat(path,"/"); - strcat(path,nameptr); - - assembly = mono_domain_assembly_open(monodomain,path); + strcat(dirbuf,"/"); + strcat(dirbuf,classname); + strcat(dirbuf,"." DLLEXT); + + assembly = mono_domain_assembly_open(monodomain,dirbuf); if(!assembly) { - error("clr: file %s couldn't be loaded!",path); + error("clr: file %s couldn't be loaded!",dirbuf); goto bailout; } @@ -414,24 +443,46 @@ static int classloader(char *dirname, char *classname) // find static Main method + MonoMethodDesc *clr_desc_main = mono_method_desc_new(":Setup",FALSE); + assert(clr_desc_main); + method = mono_method_desc_search_in_class(clr_desc_main,clr_class->mono_class); if(method) { + MonoObject *obj = mono_object_new(monodomain,clr_class->mono_class); + if(!obj) { + error("CLR class %s could not be instantiated",classname); + goto bailout; + } + + // store NULL in External::ptr member + void *x = NULL; + mono_field_set_value(obj,clr_class->mono_obj_field,&x); + // set current class clr_setup_class = clr_class; // call static Main method - MonoObject *ret = mono_runtime_invoke(method,NULL,NULL,NULL); + gpointer args = obj; + MonoObject *exc; + MonoObject *ret = mono_runtime_invoke(method,NULL,&args,&exc); // unset current class clr_setup_class = NULL; if(ret) { - post("CLR - Warning: returned value from %s.Main ignored",classname); + post("CLR - Warning: returned value from %s.Setup ignored",classname); // ??? do we have to mark ret as free? } + + if(exc) { + MonoObject *ret = mono_runtime_invoke(method,NULL,&args,&exc); + + error_exc("CLR - Exception raised by Setup",classname,exc); + goto bailout; + } } else - post("CLR - Warning: no %s.Main method found",classname); + post("CLR - Warning: no %s.Setup method found",classname); // find and save constructor clr_class->mono_ctor = mono_method_desc_search_in_class(clr_desc_ctor,clr_class->mono_class); @@ -502,32 +553,51 @@ void clr_setup(void) #endif try { - monodomain = mono_jit_init("PureData"); + monodomain = mono_jit_init(CORELIB); } catch(...) { monodomain = NULL; } if(monodomain) { - // add mono to C hooks - mono_add_internal_call("PureData.Core::Post",(const void *)PD_Post); - mono_add_internal_call("PureData.Core::PostError",(const void *)PD_PostError); - mono_add_internal_call("PureData.Core::PostBug",(const void *)PD_PostBug); - mono_add_internal_call("PureData.Core::PostVerbose",(const void *)PD_PostVerbose); - - mono_add_internal_call("PureData.Core::SymGen", (const void *)PD_SymGen); - mono_add_internal_call("PureData.Core::SymEval", (const void *)PD_SymEval); - + // try to find PureData.dll in the PD path + char dirbuf[MAXPDSTRING],*nameptr; + // search for classname.dll in the PD path + int fd; + if ((fd = open_via_path("",CORELIB,"." DLLEXT,dirbuf,&nameptr,MAXPDSTRING,1)) >= 0) { + strcat(dirbuf,"/" CORELIB "." DLLEXT); + close(fd); + } + else + strcpy(dirbuf,CORELIB "." DLLEXT); - MonoAssembly *assembly = mono_domain_assembly_open (monodomain, "PureData.dll"); + // look for PureData.dll + MonoAssembly *assembly = mono_domain_assembly_open (monodomain,dirbuf); if(!assembly) { - error("clr: assembly PureData.dll not found!"); + error("clr: assembly " CORELIB "." DLLEXT " not found!"); return; } MonoImage *image = mono_assembly_get_image(assembly); assert(image); + // add mono to C hooks + + mono_add_internal_call("PureData.Internal::SymGen(string)", (const void *)PD_SymGen); + mono_add_internal_call("PureData.Internal::SymEval(void*)", (const void *)PD_SymEval); + + mono_add_internal_call("PureData.External::Post(string)",(const void *)PD_Post); + mono_add_internal_call("PureData.External::PostError(string)",(const void *)PD_PostError); + mono_add_internal_call("PureData.External::PostBug(string)",(const void *)PD_PostBug); + mono_add_internal_call("PureData.External::PostVerbose(string)",(const void *)PD_PostVerbose); + + mono_add_internal_call("PureData.External::Add(PureData.External/MethodBang)", (const void *)PD_AddBang); + mono_add_internal_call("PureData.External::Add(PureData.External/MethodFloat)", (const void *)PD_AddFloat); + mono_add_internal_call("PureData.External::Add(PureData.External/MethodSymbol)", (const void *)PD_AddSymbol); + mono_add_internal_call("PureData.External::Add(PureData.External/MethodPointer)", (const void *)PD_AddPointer); + mono_add_internal_call("PureData.External::Add(PureData.External/MethodList)", (const void *)PD_AddList); + mono_add_internal_call("PureData.External::Add(PureData.External/MethodAnything)", (const void *)PD_AddAnything); + // load important classes clr_symbol = mono_class_from_name(image,"PureData","Symbol"); assert(clr_symbol); @@ -540,8 +610,8 @@ void clr_setup(void) clr_external = mono_class_from_name(image,"PureData","External"); assert(clr_external); - clr_desc_main = mono_method_desc_new("::Main()",FALSE); - assert(clr_desc_main); + clr_desc_tostring = mono_method_desc_new("::ToString()",FALSE); + assert(clr_desc_tostring); clr_desc_ctor = mono_method_desc_new("::.ctor(AtomList)",FALSE); assert(clr_desc_ctor); @@ -570,8 +640,8 @@ void clr_setup(void) sys_loader(classloader); // ready! - post("CLR - (c)2006 Davide Morelli, Thomas Grill"); + post("CLR extension - (c)2006 Davide Morelli, Thomas Grill"); } else - error("clr: mono domain couldn't be initialized!"); + error("clr: mono domain couldn't be initialized!"); } diff --git a/external/AssemblyInfo.cs b/external/AssemblyInfo.cs deleted file mode 100755 index f341568..0000000 --- a/external/AssemblyInfo.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -// -// Le informazioni generali relative a un assembly sono controllate dal seguente -// insieme di attributi. Per modificare le informazioni associate a un assembly -// occorre quindi modificare i valori di questi attributi. -// -[assembly: AssemblyTitle("")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// -// Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: -// -// Numero di versione principale -// Numero di versione secondario -// Numero revisione -// Numero build -// -// È possibile specificare tutti i valori o impostare come predefiniti i valori Numero revisione e Numero build -// utilizzando l'asterisco (*) come illustrato di seguito: - -[assembly: AssemblyVersion("1.0.*")] - -// -// Per firmare l'assembly è necessario specificare una chiave da utilizzare. -// Fare riferimento alla documentazione di Microsoft .NET Framework per ulteriori informazioni sulla firma degli assembly. -// -// Utilizzare gli attributi elencati di seguito per verificare la chiave utilizzata per la firma. -// -// Note: -// (*) Se non è specificata alcuna chiave, non sarà possibile firmare l'assembly. -// (*) KeyName fa riferimento a una chiave installata nel provider di servizi di -// crittografia (CSP) sul computer in uso. KeyFile fa riferimento a un file che contiene -// una chiave. -// (*) Se entrambi i valori KeyFile e KeyName sono specificati, si -// verificherà il seguente processo: -// (1) Se KeyName è presente in CSP, verrà utilizzata tale chiave. -// (2) Se KeyName non esiste e KeyFile esiste, la chiave -// di KeyFile verrà installata nel CSP e utilizzata. -// (*) Per creare un KeyFile, è possibile utilizzare l'utilità sn.exe (Strong Name). -// Quando si specifica il KeyFile, il percorso dovrà essere -// relativo alla directory di output del progetto, ovvero -// %Project Directory%\obj\. Se ad esempio il KeyFile si -// trova nella directory del progetto, occorre specificare l'attributo AssemblyKeyFile -// come [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] -// (*) La firma ritardata è un'opzione avanzata. Vedere la documentazione di Microsoft -// .NET Framework per ulteriori informazioni. -// -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/external/Counter.cs b/external/Counter.cs deleted file mode 100755 index da2b814..0000000 --- a/external/Counter.cs +++ /dev/null @@ -1,72 +0,0 @@ -using System; - -/// -/// Descrizione di riepilogo per Counter. -/// -public class Counter: - PureData.External -{ - public Counter(PureData.AtomList args) - { - Post("Count.ctor "+args.ToString()); - -// pd.AddInlet(x, "init", ParametersType.Float); -// pd.AddOutlet(x, ParametersType.Float); - } - - // this function MUST exist - public static void Main() - { - Post("Count.Main"); - } - -/* - public void MyBang() - { - Post("Count-BANG"); - } - - public void MyFloat(float f) - { - Post(String.Format("Count-FLOAT {0}",f)); - } -*/ - protected override void MethodBang() - { - Post("Count-BANG"); - } - - protected override void MethodFloat(float f) - { - Post("Count-FLOAT "+f.ToString()); - } - - protected override void MethodSymbol(PureData.Symbol s) - { - Post("Count-SYMBOL "+s.ToString()); - } - - protected override void MethodList(PureData.AtomList l) - { - Post("Count-LIST "+l.ToString()); - } - - /* - public void Init(float f) - { - curr = (int) f; - } - - public void SendOut() - { - pd.SendToOutlet(x, 0, new Atom(curr)); - } - - public void Sum(float f) - { - curr += (int) f; - pd.SendToOutlet(x, 0, new Atom(curr)); - } - -*/ -} diff --git a/external/README.txt b/external/README.txt deleted file mode 100755 index dd2d745..0000000 --- a/external/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -to compile External.dll put PureData.dll in this folder then execute this command: - -mcs External.cs Counter.cs -out:External.dll -target:library -r:PureData.dll \ No newline at end of file diff --git a/external/external.csproj b/external/external.csproj deleted file mode 100755 index 3848266..0000000 --- a/external/external.csproj +++ /dev/null @@ -1,106 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/external/external.sln b/external/external.sln deleted file mode 100755 index 092ddee..0000000 --- a/external/external.sln +++ /dev/null @@ -1,21 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "external", "external.csproj", "{FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}.Debug.ActiveCfg = Debug|.NET - {FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}.Debug.Build.0 = Debug|.NET - {FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}.Release.ActiveCfg = Release|.NET - {FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}.Release.Build.0 = Release|.NET - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal diff --git a/pd/AssemblyInfo.cs b/pd/AssemblyInfo.cs deleted file mode 100755 index 93484d8..0000000 --- a/pd/AssemblyInfo.cs +++ /dev/null @@ -1,58 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; - -// -// Le informazioni generali relative a un assembly sono controllate dal seguente -// insieme di attributi. Per modificare le informazioni associate a un assembly -// occorre quindi modificare i valori di questi attributi. -// -[assembly: AssemblyTitle("PureData")] -[assembly: AssemblyDescription("bridge between C sharp externals and pd")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("")] -[assembly: AssemblyCopyright("Davide Morelli, Thomas Grill")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// -// Le informazioni sulla versione di un assembly sono costituite dai seguenti quattro valori: -// -// Numero di versione principale -// Numero di versione secondario -// Numero revisione -// Numero build -// -// È possibile specificare tutti i valori o impostare come predefiniti i valori Numero revisione e Numero build -// utilizzando l'asterisco (*) come illustrato di seguito: - -[assembly: AssemblyVersion("1.0.*")] - -// -// Per firmare l'assembly è necessario specificare una chiave da utilizzare. -// Fare riferimento alla documentazione di Microsoft .NET Framework per ulteriori informazioni sulla firma degli assembly. -// -// Utilizzare gli attributi elencati di seguito per verificare la chiave utilizzata per la firma. -// -// Note: -// (*) Se non è specificata alcuna chiave, non sarà possibile firmare l'assembly. -// (*) KeyName fa riferimento a una chiave installata nel provider di servizi di -// crittografia (CSP) sul computer in uso. KeyFile fa riferimento a un file che contiene -// una chiave. -// (*) Se entrambi i valori KeyFile e KeyName sono specificati, si -// verificherà il seguente processo: -// (1) Se KeyName è presente in CSP, verrà utilizzata tale chiave. -// (2) Se KeyName non esiste e KeyFile esiste, la chiave -// di KeyFile verrà installata nel CSP e utilizzata. -// (*) Per creare un KeyFile, è possibile utilizzare l'utilità sn.exe (Strong Name). -// Quando si specifica il KeyFile, il percorso dovrà essere -// relativo alla directory di output del progetto, ovvero -// %Project Directory%\obj\. Se ad esempio il KeyFile si -// trova nella directory del progetto, occorre specificare l'attributo AssemblyKeyFile -// come [assembly: AssemblyKeyFile("..\\..\\mykey.snk")] -// (*) La firma ritardata è un'opzione avanzata. Vedere la documentazione di Microsoft -// .NET Framework per ulteriori informazioni. -// -[assembly: AssemblyDelaySign(false)] -[assembly: AssemblyKeyFile("")] -[assembly: AssemblyKeyName("")] diff --git a/pd/Atom.cs b/pd/Atom.cs deleted file mode 100755 index d872961..0000000 --- a/pd/Atom.cs +++ /dev/null @@ -1,270 +0,0 @@ -using System; -using System.Runtime.InteropServices; // for structures -using System.Collections; -#if NET_2_0 -using System.Collections.Generic; -#endif - -namespace PureData -{ - [StructLayout (LayoutKind.Sequential)] - public unsafe struct Symbol - { - // this should NOT be public (or at least read only) - private readonly void *sym; - - public Symbol(string s) - { - sym = Core.SymGen(s); - } - - public override string ToString() - { - return Core.SymEval(sym); - } - } - - [StructLayout (LayoutKind.Sequential)] - public unsafe struct Pointer - { - private readonly void *ptr; - - public override string ToString() - { - if(sizeof(void *) == 4) - return ((int)ptr).ToString(); - else - return ((long)ptr).ToString(); - } - } - - [StructLayout (LayoutKind.Sequential)] - public unsafe struct Atom - { - private enum AtomType {Null = 0, Float = 1, Symbol = 2, Pointer = 3}; - - [StructLayout (LayoutKind.Explicit)] - private struct Word - { - [FieldOffset(0)] public float w_float; - [FieldOffset(0)] public Symbol w_sym; - [FieldOffset(0)] public Pointer w_ptr; - } - - private AtomType type; - private Word word; - - public Atom(float f) - { - type = AtomType.Float; - word = new Word(); - word.w_float = f; - } - - public Atom(int i) - { - type = AtomType.Float; - word = new Word(); - word.w_float = (float)i; - } - - public Atom(Symbol s) - { - type = AtomType.Symbol; - word = new Word(); - word.w_sym = s; - } - - public Atom(string s) - { - type = AtomType.Symbol; - word = new Word(); - word.w_sym = new Symbol(s); - } - - public Atom(Pointer p) - { - type = AtomType.Pointer; - word = new Word(); - word.w_ptr = p; - } - - public bool IsFloat { get { return type == AtomType.Float; } } - public bool IsSymbol { get { return type == AtomType.Symbol; } } - public bool IsPointer { get { return type == AtomType.Pointer; } } - - public float ToFloat() - { - if(IsFloat) - return word.w_float; - else - throw new System.InvalidCastException("Can't be cast to float."); - } - - public Symbol ToSymbol() - { - if(IsSymbol) - return word.w_sym; - else - throw new System.InvalidCastException("Can't be cast to Symbol."); - } - - public Pointer ToPointer() - { - if(IsPointer) - return word.w_ptr; - else - throw new System.InvalidCastException("Can't be cast to Pointer."); - } - - override public string ToString() - { - if(IsFloat) - return word.w_float.ToString(); - else if(IsSymbol) - return word.w_sym.ToString(); - else if(IsPointer) - return word.w_ptr.ToString(); - else - // should never happen - throw new System.InvalidProgramException("Internal error."); - } - - public static explicit operator float(Atom a) - { - return a.ToFloat(); - } - - public static explicit operator Symbol(Atom a) - { - return a.ToSymbol(); - } - - public static explicit operator Pointer(Atom a) - { - return a.ToPointer(); - } - } - - public class AtomListEnum - : IEnumerator - { - public AtomList list; - - // Enumerators are positioned before the first element - // until the first MoveNext() call. - int position = -1; - - public AtomListEnum(AtomList l) - { - list = l; - } - - public bool MoveNext() - { - return ++position < list.Count; - } - - public void Reset() - { - position = -1; - } - - public object Current - { - get - { - try - { - return list[position]; - } - catch (IndexOutOfRangeException) - { - throw new InvalidOperationException(); - } - } - } - } - - - // attention: this is dangerous, because we could do the following - // AtomList l2 = l; - // with l also being an AtomList... the two private memebers will get copied, although atoms is only a temporary reference - - [StructLayout (LayoutKind.Sequential)] - unsafe public struct AtomList -#if NET_2_0 - : ICollection -#else - : ICollection -#endif - { - private readonly int len; - private readonly Atom *atoms; - - public int Count { get { return len; } } -#if NET_2_0 - public bool IsReadOnly { get { return false; } } // member of generic.ICollection (C# 2.0) -#endif - public bool IsSynchronized { get { return false; } } - public Object SyncRoot { get { return null; } } - - // protect this from being used - private AtomList(AtomList a) { len = 0; atoms = null; } - -#if NET_2_0 - public void CopyTo(Atom[] array,int start) -#else - public void CopyTo(Array array,int start) -#endif - { - if(len > array.GetUpperBound(0)+1-start) - throw new System.ArgumentException("Destination array is not long enough."); - int i; - for(i = 0; i < len-start; ++i) - array.SetValue(atoms[start+i],i); - } - - public IEnumerator GetEnumerator() - { - return new AtomListEnum(this); - } - - public Atom this[int i] - { - get - { - if(i < 0 || i >= len) - throw new System.IndexOutOfRangeException("Index outside array bounds."); - return atoms[i]; - } - set - { - if(i < 0 || i >= len) - throw new System.IndexOutOfRangeException("Index outside array bounds."); - atoms[i] = value; - } - } - -#if !NET_2_0 - public static explicit operator Atom[](AtomList l) - { - Atom[] ret = new Atom[l.Count]; - int i; - for(i = 0; i < l.Count; ++i) ret[i] = l.atoms[i]; - return ret; - } -#endif - - override public string ToString() - { - string n = "{"; - if(len > 0) { - int i; - for(i = 0; i < len-1; ++i) n += atoms[i].ToString()+","; - n += atoms[i].ToString(); - } - return n+"}"; - } - } -} diff --git a/pd/PureData.cs b/pd/PureData.cs deleted file mode 100644 index d6ad3d9..0000000 --- a/pd/PureData.cs +++ /dev/null @@ -1,48 +0,0 @@ -using System; -using System.Runtime.CompilerServices; // for extern import -using System.Runtime.InteropServices; // for structures - -namespace PureData -{ - // PD core functions - public unsafe class Core - { - [MethodImplAttribute (MethodImplOptions.InternalCall)] - public extern static void Post(string message); - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - public extern static void PostError(string message); - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - public extern static void PostBug(string message); - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - public extern static void PostVerbose(string message); - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static void *SymGen(string sym); - - [MethodImplAttribute (MethodImplOptions.InternalCall)] - internal extern static string SymEval(void *sym); - } - - // This is the base class for a PD/CLR external - public unsafe class External - : Core - { - // PD object pointer - private readonly void *ptr; - - protected virtual void MethodBang() { throw new System.NotImplementedException("Bang handler not defined"); } - - protected virtual void MethodFloat(float f) { throw new System.NotImplementedException("Float handler not defined"); } - - protected virtual void MethodSymbol(Symbol s) { throw new System.NotImplementedException("Symbol handler not defined"); } - - protected virtual void MethodPointer(Pointer p) { throw new System.NotImplementedException("Pointer handler not defined"); } - - protected virtual void MethodList(AtomList lst) { throw new System.NotImplementedException("List handler not defined"); } - - protected virtual void MethodAnything(Symbol tag,AtomList lst) { throw new System.NotImplementedException("Anything handler not defined"); } - } -} diff --git a/pd/README.txt b/pd/README.txt deleted file mode 100755 index 323f00c..0000000 --- a/pd/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -to compile PureData.dll execute this command: - -mcs Atom.cs pd.cs -out:PureData.dll -target:library \ No newline at end of file diff --git a/pd/pd.csproj b/pd/pd.csproj deleted file mode 100755 index 8dd510d..0000000 --- a/pd/pd.csproj +++ /dev/null @@ -1,105 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/pd/pd.sln b/pd/pd.sln deleted file mode 100755 index 2d4a44b..0000000 --- a/pd/pd.sln +++ /dev/null @@ -1,21 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 8.00 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "pd", "pd.csproj", "{FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}" - ProjectSection(ProjectDependencies) = postProject - EndProjectSection -EndProject -Global - GlobalSection(SolutionConfiguration) = preSolution - Debug = Debug - Release = Release - EndGlobalSection - GlobalSection(ProjectConfiguration) = postSolution - {FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}.Debug.ActiveCfg = Debug|.NET - {FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}.Debug.Build.0 = Debug|.NET - {FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}.Release.ActiveCfg = Release|.NET - {FFBC9D2E-1FB7-4E82-B5DC-46B31F8A58A2}.Release.Build.0 = Release|.NET - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - EndGlobalSection - GlobalSection(ExtensibilityAddIns) = postSolution - EndGlobalSection -EndGlobal -- cgit v1.2.1