internal static extern void ResultSetJsValue(IntPtr callingArgsPtr, JsValue jsvalue);
internal static extern JsValue jscontext_invoke(HandleRef engine, IntPtr funcPtr, IntPtr thisPtr, JsValue args);
public object FromJsValue(JsValue v) { switch (v.Type) { case JsValueType.Null: return null; case JsValueType.Boolean: return v.I32 != 0; case JsValueType.Integer: return v.I32; case JsValueType.Number: return v.Num; case JsValueType.String: return Marshal.PtrToStringUni(v.Ptr); case JsValueType.Date: // The formula (v.num * 10000) + 621355968000000000L was taken from a StackOverflow // question and should be OK. Then why do we need to compensate by -26748000000000L // (a value determined from the failing tests)?! return new DateTime((long)(v.Num * 10000) + 621355968000000000L - 26748000000000L); case JsValueType.Array: { var r = new object[v.Length]; for (int i=0 ; i < v.Length ; i++) { var vi =(JsValue)Marshal.PtrToStructure((v.Ptr + 16*i), typeof(JsValue)); r[i] = FromJsValue(vi); } return r; } case JsValueType.UnknownError: if (v.Ptr != IntPtr.Zero) return new JsException(Marshal.PtrToStringUni(v.Ptr)); return new JsInteropException("unknown error without reason"); case JsValueType.Error: return new JsException(Marshal.PtrToStringUni(v.Ptr)); case JsValueType.Managed: return _engine.KeepAliveGet(v.Index); case JsValueType.ManagedError: string msg = null; if (v.Ptr != IntPtr.Zero) msg = Marshal.PtrToStringUni(v.Ptr); return new JsException(msg, _engine.KeepAliveGet(v.Index) as Exception); case JsValueType.Wrapped: return new JsObject(_engine, v.Ptr); case JsValueType.WrappedError: return new JsException(new JsObject(_engine, v.Ptr)); default: throw new InvalidOperationException("unknown type code: " + v.Type); } }
static extern JsValue jscontext_set_property_value(IntPtr engine, IntPtr ptr, [MarshalAs(UnmanagedType.LPWStr)] string name, JsValue value);
private JsObject JsDictionaryObject(JsValue v) { JsObject obj = new JsObject(this._context, v.Ptr); int len = v.Length * 2; for (int i = 0; i < len; i += 2) { var key = (JsValue)Marshal.PtrToStructure(new IntPtr(v.Ptr.ToInt64() + (16 * i)), typeof(JsValue)); var value = (JsValue)Marshal.PtrToStructure(new IntPtr(v.Ptr.ToInt64() + (16 * (i + 1))), typeof(JsValue)); obj[(string)FromJsValue(key)] = FromJsValue(value); } return obj; }
static extern JsValue jsengine_set_property_value(HandleRef engine, IntPtr ptr, [MarshalAs(UnmanagedType.LPWStr)] string name, JsValue value);
JsValue KeepAliveInvoke(int slot, JsValue args) { // TODO: This is pretty slow: use a cache of generated code to make it faster. Console.WriteLine(args); var obj = KeepAliveGet(slot) as WeakDelegate; if (obj != null) { Type type = obj.Target.GetType(); object[] a = (object[])_convert.FromJsValue(args); try { const BindingFlags flags = BindingFlags.Instance|BindingFlags.Public |BindingFlags.InvokeMethod|BindingFlags.FlattenHierarchy; return _convert.ToJsValue(type.InvokeMember(obj.MethodName, flags, null, obj.Target, a)); } catch (Exception e) { return JsValue.Error(KeepAliveAdd(e)); } } return JsValue.Error(KeepAliveAdd(new IndexOutOfRangeException("invalid keepalive slot: " + slot))); }
internal JsValue KeepAliveSetPropertyValue(int slot, string name, JsValue value) { #if DEBUG_TRACE_API Console.WriteLine("setting prop " + name); #endif // TODO: This is pretty slow: use a cache of generated code to make it faster. var obj = KeepAliveGet(slot); if (obj != null) { Type type; if (obj is Type) { type = (Type)obj; } else { type = obj.GetType(); } #if DEBUG_TRACE_API Console.WriteLine("setting prop " + name + " type " + type); #endif try { if (!string.IsNullOrEmpty(name)) { var upperCamelCase = Char.ToUpper(name[0]) + name.Substring(1); if (TrySetMemberValue(type, obj, upperCamelCase, value)) { return JsValue.Null; } if (TrySetMemberValue(type, obj, name, value)) { return JsValue.Null; } } return JsValue.Error(KeepAliveAdd( new InvalidOperationException(String.Format("property not found on {0}: {1} ", type, name)))); } catch (Exception e) { return JsValue.Error(KeepAliveAdd(e)); } } return JsValue.Error(KeepAliveAdd(new IndexOutOfRangeException("invalid keepalive slot: " + slot))); }
internal bool TryGetMemberValue(Type type, object obj, string name, out JsValue value) { object result; // dictionaries. if (typeof(IDictionary).IsAssignableFrom(type)) { IDictionary dictionary = (IDictionary)obj; if (dictionary.Contains(name)) { result = dictionary[name]; value = _convert.ToJsValue(result); } else { value = JsValue.Null; } return true; } BindingFlags flags; if (type == obj) { flags = BindingFlags.Public | BindingFlags.Static; } else { flags = BindingFlags.Public | BindingFlags.Instance; } // First of all try with a public property (the most common case). PropertyInfo pi = type.GetProperty(name, flags); if (pi != null) { result = pi.GetValue(obj, null); value = _convert.ToJsValue(result); return true; } // try field. FieldInfo fi = type.GetField(name, flags); if (fi != null) { result = fi.GetValue(obj); value = _convert.ToJsValue(result); return true; } // Then with an instance method: the problem is that we don't have a list of // parameter types so we just check if any method with the given name exists // and then keep alive a "weak delegate", i.e., just a name and the target. // The real method will be resolved during the invokation itself. BindingFlags mFlags = flags | BindingFlags.FlattenHierarchy; // TODO: This is probably slooow. if (type.GetMethods(mFlags).Any(x => x.Name == name)) { if (type == obj) { result = new WeakDelegate(type, name); } else { result = new WeakDelegate(obj, name); } value = _convert.ToJsValue(result); return true; } value = JsValue.Null; return false; }
private JsValue KeepAliveSetPropertyValue(int contextId, int slot, string name, JsValue value) { #if DEBUG_TRACE_API Console.WriteLine("set prop " + contextId + " " + slot); #endif JsContext context; if (!_aliveContexts.TryGetValue(contextId, out context)) { throw new Exception("fail"); } return context.KeepAliveSetPropertyValue(slot, name, value); }
internal JsValue KeepAliveInvoke(int slot, JsValue args) { // TODO: This is pretty slow: use a cache of generated code to make it faster. #if DEBUG_TRACE_API Console.WriteLine("invoking"); #endif // Console.WriteLine(args); var obj = KeepAliveGet(slot); if (obj != null) { Type constructorType = obj as Type; if (constructorType != null) { #if DEBUG_TRACE_API Console.WriteLine("constructing " + constructorType.Name); #endif object[] constructorArgs = (object[])_convert.FromJsValue(args); return _convert.ToJsValue(Activator.CreateInstance(constructorType, constructorArgs)); } WeakDelegate func = obj as WeakDelegate; if (func == null) { throw new Exception("not a function."); } Type type = func.Target != null ? func.Target.GetType() : func.Type; #if DEBUG_TRACE_API Console.WriteLine("invoking " + obj.Target + " method " + obj.MethodName); #endif object[] a = (object[])_convert.FromJsValue(args); BindingFlags flags = BindingFlags.Public | BindingFlags.FlattenHierarchy; if (func.Target != null) { flags |= BindingFlags.Instance; } else { flags |= BindingFlags.Static; } if (obj is BoundWeakDelegate) { flags |= BindingFlags.NonPublic; } // need to convert methods from JsFunction's into delegates? if (a.Any(z => z != null && z.GetType() == typeof(JsFunction))) { CheckAndResolveJsFunctions(type, func.MethodName, flags, a); } try { object result = type.GetMethod(func.MethodName, flags).Invoke(func.Target, a); return _convert.ToJsValue(result); } catch (TargetInvocationException e) { return JsValue.Error(KeepAliveAdd(e.InnerException)); } catch (Exception e) { return JsValue.Error(KeepAliveAdd(e)); } } return JsValue.Error(KeepAliveAdd(new IndexOutOfRangeException("invalid keepalive slot: " + slot))); }
private JsValue KeepAliveInvoke(int contextId, int slot, JsValue args) { JsContext context; if (!_aliveContexts.TryGetValue(contextId, out context)) { throw new Exception("fail"); } return context.KeepAliveInvoke(slot, args); }
public object FromJsValue(JsValue v) { #if DEBUG_TRACE_API Console.WriteLine("Converting Js value to .net"); #endif switch (v.Type) { case JsValueType.Empty: case JsValueType.Null: return(null); case JsValueType.Boolean: return(v.I32 != 0); case JsValueType.Integer: return(v.I32); case JsValueType.Index: return((UInt32)v.I64); case JsValueType.Number: return(v.Num); case JsValueType.String: return(Marshal.PtrToStringUni(v.Ptr)); case JsValueType.Date: /* * // The formula (v.num * 10000) + 621355968000000000L was taken from a StackOverflow * // question and should be OK. Then why do we need to compensate by -26748000000000L * // (a value determined from the failing tests)?! * return new DateTime((long)(v.Num * 10000) + 621355968000000000L - 26748000000000L); */ //var msFromJsTime = v.I64 % 1000; return(EPOCH_LocalTime.AddMilliseconds(v.I64)); // + new TimeSpan(7, 0, 0); //return EPOCH_LocalTime.AddMilliseconds(v.I64);// + new TimeSpan(7, 0, 0); //return EPOCH.AddMilliseconds(v.I64); //return EPOCH.AddMilliseconds(v.Num); //return new DateTime((long)(v.Num * 10000) + 621355968000000000L - 26748000000000L); case JsValueType.Array: { int len = v.Length; var r = new object[len]; for (int i = 0; i < len; i++) { var vi = (JsValue)Marshal.PtrToStructure(new IntPtr(v.Ptr.ToInt64() + (16 * i)), typeof(JsValue)); r[i] = FromJsValue(vi); } return(r); } case JsValueType.UnknownError: if (v.Ptr != IntPtr.Zero) { return(new JsException(Marshal.PtrToStringUni(v.Ptr))); } return(new JsInteropException("unknown error without reason")); case JsValueType.StringError: return(new JsException(Marshal.PtrToStringUni(v.Ptr))); case JsValueType.Managed: return(_context.KeepAliveGet(v.Index)); case JsValueType.JsTypeWrap: //auto unwrap return(this._context.GetObjectProxy(v.Index).WrapObject); case JsValueType.ManagedError: Exception inner = _context.KeepAliveGet(v.Index) as Exception; string msg = null; if (v.Ptr != IntPtr.Zero) { msg = Marshal.PtrToStringUni(v.Ptr); } else { if (inner != null) { msg = inner.Message; } } return(new JsException(msg, inner)); #if NET40 case JsValueType.Wrapped: return(new JsObject(_context, v.Ptr)); #else case JsValueType.Dictionary: return(JsDictionaryObject(v)); #endif case JsValueType.Wrapped: return(new JsObject(_context, v.Ptr)); case JsValueType.Error: return(JsException.Create(this, (JsError)Marshal.PtrToStructure(v.Ptr, typeof(JsError)))); case JsValueType.Function: var fa = new JsValue[2]; for (int i = 0; i < 2; i++) { fa[i] = (JsValue)Marshal.PtrToStructure(new IntPtr(v.Ptr.ToInt64() + (16 * i)), typeof(JsValue)); } return(new JsFunction(_context, fa[0].Ptr, fa[1].Ptr)); default: throw new InvalidOperationException("unknown type code: " + v.Type); } }
public JsValue AnyToJsValue(object obj) { if (obj == null) { return new JsValue { Type = JsValueType.Null } } ; if (obj is INativeRef) { //extension INativeRef prox = (INativeRef)obj; int keepAliveId = _context.KeepAliveAdd(obj); return(new JsValue { Type = JsValueType.JsTypeWrap, Ptr = prox.UnmanagedPtr, Index = keepAliveId }); } Type type = obj.GetType(); // Check for nullable types (we will cast the value out of the box later). if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable <>)) { type = type.GetGenericArguments()[0]; } if (type == typeof(Boolean)) { return new JsValue { Type = JsValueType.Boolean, I32 = (bool)obj ? 1 : 0 } } ; if (type == typeof(String) || type == typeof(Char)) { // We need to allocate some memory on the other side; will be free'd by unmanaged code. return(JsContext.jsvalue_alloc_string(obj.ToString())); } if (type == typeof(Byte)) { return new JsValue { Type = JsValueType.Integer, I32 = (int)(Byte)obj } } ; if (type == typeof(Int16)) { return new JsValue { Type = JsValueType.Integer, I32 = (int)(Int16)obj } } ; if (type == typeof(UInt16)) { return new JsValue { Type = JsValueType.Integer, I32 = (int)(UInt16)obj } } ; if (type == typeof(Int32)) { return new JsValue { Type = JsValueType.Integer, I32 = (int)obj } } ; if (type == typeof(UInt32)) { return new JsValue { Type = JsValueType.Integer, I32 = (int)(UInt32)obj } } ; if (type == typeof(Int64)) { return new JsValue { Type = JsValueType.Number, Num = (double)(Int64)obj } } ; if (type == typeof(UInt64)) { return new JsValue { Type = JsValueType.Number, Num = (double)(UInt64)obj } } ; if (type == typeof(Single)) { return new JsValue { Type = JsValueType.Number, Num = (double)(Single)obj } } ; if (type == typeof(Double)) { return new JsValue { Type = JsValueType.Number, Num = (double)obj } } ; if (type == typeof(Decimal)) { return new JsValue { Type = JsValueType.Number, Num = (double)(Decimal)obj } } ; if (type == typeof(DateTime)) { return new JsValue { Type = JsValueType.Date, Num = Convert.ToInt64(((DateTime)obj).Subtract(EPOCH).TotalMilliseconds) /*(((DateTime)obj).Ticks - 621355968000000000.0 + 26748000000000.0)/10000.0*/ } } ; // Arrays of anything that can be cast to object[] are recursively convertef after // allocating an appropriate jsvalue on the unmanaged side. var array = obj as object[]; if (array != null) { JsValue v = JsContext.jsvalue_alloc_array(array.Length); if (v.Length != array.Length) { throw new JsInteropException("can't allocate memory on the unmanaged side"); } for (int i = 0; i < array.Length; i++) { Marshal.StructureToPtr(AnyToJsValue(array[i]), new IntPtr(v.Ptr.ToInt64() + (16 * i)), false); } return(v); } // Every object explicitly converted to a value becomes an entry of the // _keepalives list, to make sure the GC won't collect it while still in // use by the unmanaged Javascript engine. We don't try to track duplicates // because adding the same object more than one time acts more or less as // reference counting. //check var jsTypeDefinition = _context.GetJsTypeDefinition2(type); INativeRef prox2 = _context.CreateWrapper(obj, jsTypeDefinition); //int keepAliveId2 = _context.KeepAliveAdd(prox2); return(new JsValue { Type = JsValueType.JsTypeWrap, Ptr = prox2.UnmanagedPtr, Index = prox2.ManagedIndex }); //return new JsValue { Type = JsValueType.JsTypeWrap, Ptr = prox2.UnmanagedPtr, Index = keepAliveId2 }; //return new JsValue { Type = JsValueType.Managed, Index = _context.KeepAliveAdd(obj) }; } } }
internal static extern void jsvalue_dispose(JsValue value);
internal bool TrySetMemberValue(Type type, object obj, string name, JsValue value) { // dictionaries. if (typeof(IDictionary).IsAssignableFrom(type)) { IDictionary dictionary = (IDictionary)obj; dictionary[name] = _convert.FromJsValue(value); return true; } BindingFlags flags; if (type == obj) { flags = BindingFlags.Public | BindingFlags.Static; } else { flags = BindingFlags.Public | BindingFlags.Instance; } PropertyInfo pi = type.GetProperty(name, flags); if (pi != null) { pi.SetValue(obj, _convert.FromJsValue(value), null); return true; } return false; }
static extern JsValue jsengine_invoke_property(HandleRef engine, IntPtr ptr, [MarshalAs(UnmanagedType.LPWStr)] string name, JsValue args);
static extern JsValue jscontext_set_variable(IntPtr engine, [MarshalAs(UnmanagedType.LPWStr)] string name, JsValue value);
static extern JsValue jsengine_set_variable(HandleRef engine, [MarshalAs(UnmanagedType.LPWStr)] string name, JsValue value);
public object FromJsValue(JsValue v) { #if DEBUG_TRACE_API Console.WriteLine("Converting Js value to .net"); #endif switch (v.Type) { case JsValueType.Empty: case JsValueType.Null: return null; case JsValueType.Boolean: return v.I32 != 0; case JsValueType.Integer: return v.I32; case JsValueType.Index: return (UInt32)v.I64; case JsValueType.Number: return v.Num; case JsValueType.String: return Marshal.PtrToStringUni(v.Ptr); case JsValueType.Date: /* // The formula (v.num * 10000) + 621355968000000000L was taken from a StackOverflow // question and should be OK. Then why do we need to compensate by -26748000000000L // (a value determined from the failing tests)?! return new DateTime((long)(v.Num * 10000) + 621355968000000000L - 26748000000000L); */ //var msFromJsTime = v.I64 % 1000; return EPOCH_LocalTime.AddMilliseconds(v.I64);// + new TimeSpan(7, 0, 0); //return EPOCH_LocalTime.AddMilliseconds(v.I64);// + new TimeSpan(7, 0, 0); //return EPOCH.AddMilliseconds(v.I64); //return EPOCH.AddMilliseconds(v.Num); //return new DateTime((long)(v.Num * 10000) + 621355968000000000L - 26748000000000L); case JsValueType.Array: { int len = v.Length; var r = new object[len]; for (int i = 0; i < len; i++) { var vi = (JsValue)Marshal.PtrToStructure(new IntPtr(v.Ptr.ToInt64() + (16 * i)), typeof(JsValue)); r[i] = FromJsValue(vi); } return r; } case JsValueType.UnknownError: if (v.Ptr != IntPtr.Zero) return new JsException(Marshal.PtrToStringUni(v.Ptr)); return new JsInteropException("unknown error without reason"); case JsValueType.StringError: return new JsException(Marshal.PtrToStringUni(v.Ptr)); case JsValueType.Managed: return _context.KeepAliveGet(v.Index); case JsValueType.JsTypeWrap: //auto unwrap return this._context.GetObjectProxy(v.Index).WrapObject; case JsValueType.ManagedError: Exception inner = _context.KeepAliveGet(v.Index) as Exception; string msg = null; if (v.Ptr != IntPtr.Zero) { msg = Marshal.PtrToStringUni(v.Ptr); } else { if (inner != null) { msg = inner.Message; } } return new JsException(msg, inner); #if NET40 case JsValueType.Wrapped: return new JsObject(_context, v.Ptr); #else case JsValueType.Dictionary: return JsDictionaryObject(v); #endif case JsValueType.Wrapped: return new JsObject(_context, v.Ptr); case JsValueType.Error: return JsException.Create(this, (JsError)Marshal.PtrToStructure(v.Ptr, typeof(JsError))); case JsValueType.Function: var fa = new JsValue[2]; for (int i = 0; i < 2; i++) { fa[i] = (JsValue)Marshal.PtrToStructure(new IntPtr(v.Ptr.ToInt64() + (16 * i)), typeof(JsValue)); } return new JsFunction(_context, fa[0].Ptr, fa[1].Ptr); default: throw new InvalidOperationException("unknown type code: " + v.Type); } }
JsValue KeepAliveSetPropertyValue(int slot, [MarshalAs(UnmanagedType.LPWStr)] string name, JsValue value) { // TODO: This is pretty slow: use a cache of generated code to make it faster. var obj = KeepAliveGet(slot); if (obj != null) { Type type = obj.GetType(); // We can only set properties; everything else is an error. try { PropertyInfo pi = type.GetProperty(name, BindingFlags.Instance|BindingFlags.Public|BindingFlags.SetProperty); if (pi != null) { pi.SetValue(obj, _convert.FromJsValue(value), null); return JsValue.Null; } return JsValue.Error(KeepAliveAdd( new InvalidOperationException(String.Format("property not found on {0}: {1} ", type, name)))); } catch (Exception e) { return JsValue.Error(KeepAliveAdd(e)); } } return JsValue.Error(KeepAliveAdd(new IndexOutOfRangeException("invalid keepalive slot: " + slot))); }
static extern JsValue jscontext_invoke_property(IntPtr engine, IntPtr ptr, [MarshalAs(UnmanagedType.LPWStr)] string name, JsValue args);