internal HostItem GetOrCreateHostItem(HostTarget target, HostItemFlags flags, Func <ScriptEngine, HostTarget, HostItemFlags, HostItem> createHostItem) { var hostObject = target as HostObject; if (hostObject != null) { return(GetOrCreateHostItemForHostTarget(hostObject, flags, createHostItem)); } var hostType = target as HostType; if (hostType != null) { return(GetOrCreateHostItemForHostType(hostType, flags, createHostItem)); } var hostMethod = target as HostMethod; if (hostMethod != null) { return(GetOrCreateHostItemForHostTarget(hostMethod, flags, createHostItem)); } var hostIndexedProperty = target as HostIndexedProperty; if (hostIndexedProperty != null) { return(GetOrCreateHostItemForHostTarget(hostIndexedProperty, flags, createHostItem)); } return(createHostItem(this, target, flags)); }
internal override void AddHostItem(string itemName, HostItemFlags flags, object item) { VerifyNotDisposed(); var globalMembers = flags.HasFlag(HostItemFlags.GlobalMembers); if (globalMembers && engineFlags.HasFlag(V8ScriptEngineFlags.DisableGlobalMembers)) { throw new InvalidOperationException("GlobalMembers support is disabled in this script engine"); } MiscHelpers.VerifyNonNullArgument(itemName, "itemName"); Debug.Assert(item != null); ScriptInvoke(() => { var marshaledItem = MarshalToScript(item, flags); if (!(marshaledItem is HostItem)) { throw new InvalidOperationException("Invalid host item"); } proxy.AddGlobalItem(itemName, marshaledItem, globalMembers); }); }
internal override object MarshalToScript(object obj, HostItemFlags flags) { if (obj == null) { return(DBNull.Value); } if (obj is Undefined) { return(null); } if (obj is Nonexistent) { return(obj); } if (obj is Nothing) { return(null); } if (engineFlags.HasFlag(V8ScriptEngineFlags.EnableDateTimeConversion) && (obj is DateTime)) { return(obj); } var hostItem = obj as HostItem; if (hostItem != null) { if ((hostItem.Engine == this) && (hostItem.Flags == flags)) { return(obj); } obj = hostItem.Target; } var hostTarget = obj as HostTarget; if ((hostTarget != null) && !(hostTarget is IHostVariable)) { obj = hostTarget.Target; } var scriptItem = obj as ScriptItem; if (scriptItem != null) { if (scriptItem.Engine == this) { return(scriptItem.Unwrap()); } } return(HostItem.Wrap(this, hostTarget ?? obj, flags)); }
private static HostItem Create(ScriptEngine engine, HostTarget target, HostItemFlags flags) { if (!MiscHelpers.PlatformIsWindows()) { return(new HostItem(engine, target, flags)); } return(TargetSupportsExpandoMembers(target, flags) ? new DispatchExHostItem(engine, target, flags) : new HostItem(engine, target, flags)); }
private HostItem GetOrCreateHostItemForHostType(HostType hostType, HostItemFlags flags, Func <ScriptEngine, HostTarget, HostItemFlags, HostItem> createHostItem) { if (hostType.Types.Length != 1) { return(createHostItem(this, hostType, flags)); } var cacheEntry = hostTypeHostItemCache.GetOrCreateValue(hostType.Types[0]); List <WeakReference> activeWeakRefs = null; var staleWeakRefCount = 0; foreach (var weakRef in cacheEntry) { var hostItem = weakRef.Target as HostItem; if (hostItem == null) { staleWeakRefCount++; } else { if (hostItem.Flags == flags) { return(hostItem); } if (activeWeakRefs == null) { activeWeakRefs = new List <WeakReference>(cacheEntry.Count); } activeWeakRefs.Add(weakRef); } } if (staleWeakRefCount > 4) { cacheEntry.Clear(); if (activeWeakRefs != null) { cacheEntry.Capacity = activeWeakRefs.Count + 1; cacheEntry.AddRange(activeWeakRefs); } } var newHostItem = createHostItem(this, hostType, flags); cacheEntry.Add(new WeakReference(newHostItem)); return(newHostItem); }
internal override object MarshalToScript(object obj, HostItemFlags flags) { if (obj == null) { return(DBNull.Value); } if (obj is Undefined) { return(null); } if (obj is Nonexistent) { return(null); } var hostItem = obj as HostItem; if (hostItem != null) { if ((hostItem.Engine == this) && (hostItem.Flags == flags)) { return(obj); } obj = hostItem.Target; } var hostTarget = obj as HostTarget; if (hostTarget != null) { obj = hostTarget.Target; } var scriptItem = obj as ScriptItem; if (scriptItem != null) { if (scriptItem.Engine == this) { return(scriptItem.Unwrap()); } } return(HostItem.Wrap(this, hostTarget ?? obj, flags)); }
internal override void AddHostItem(string itemName, HostItemFlags flags, object item) { VerifyNotDisposed(); MiscHelpers.VerifyNonNullArgument(itemName, "itemName"); Debug.Assert(item != null); ScriptInvoke(() => { object marshaledItem; if (!flags.HasFlag(HostItemFlags.DirectAccess) || !GetDirectAccessItem(item, out marshaledItem)) { marshaledItem = MarshalToScript(item, flags); if (!(marshaledItem is HostItem)) { throw new InvalidOperationException("Invalid host item"); } } var oldItem = ((IDictionary)hostItemMap)[itemName]; hostItemMap[itemName] = marshaledItem; var nativeFlags = ScriptItemFlags.IsVisible; if (flags.HasFlag(HostItemFlags.GlobalMembers)) { nativeFlags |= ScriptItemFlags.GlobalMembers; } try { activeScript.AddNamedItem(itemName, nativeFlags); } catch (Exception) { if (oldItem != null) { hostItemMap[itemName] = oldItem; } else { hostItemMap.Remove(itemName); } throw; } }); }
private static bool TargetSupportsExpandoMembers(HostTarget target, HostItemFlags flags) { if (!TargetSupportsSpecialTargets(target)) { return(false); } if (typeof(IDynamic).IsAssignableFrom(target.Type)) { return(true); } if (target is IHostVariable) { if (target.Type.IsImport) { return(true); } } else { if ((target.InvokeTarget is IDispatchEx dispatchEx) && dispatchEx.GetType().IsCOMObject) { return(true); } } if (typeof(IPropertyBag).IsAssignableFrom(target.Type)) { return(true); } if (!flags.HasFlag(HostItemFlags.HideDynamicMembers) && typeof(IDynamicMetaObjectProvider).IsAssignableFrom(target.Type)) { return(true); } return(false); }
/// <summary> /// Exposes a host object to script code with the specified options. /// </summary> /// <param name="itemName">A name for the new global script item that will represent the object.</param> /// <param name="flags">A value that selects options for the operation.</param> /// <param name="target">The object to expose.</param> /// <remarks> /// Once a host object is exposed to script code, its members are accessible via the script /// language's native syntax for member access. The following table provides details about /// the mapping between host members and script-accessible properties and methods. /// <para> /// <list type="table"> /// <listheader> /// <term>Member Type</term> /// <term>Exposed As</term> /// <description>Remarks</description> /// </listheader> /// <item> /// <term><b>Constructor</b></term> /// <term>N/A</term> /// <description> /// To invoke a constructor from script code, call /// <see cref="HostFunctions.newObj{T}">HostFunctions.newObj(T)</see>. /// </description> /// </item> /// <item> /// <term><b>Property/Field</b></term> /// <term><b>Property</b></term> /// <description>N/A</description> /// </item> /// <item> /// <term><b>Method</b></term> /// <term><b>Method</b></term> /// <description> /// Overloaded host methods are merged into a single script-callable method. At /// runtime the correct host method is selected based on the argument types. /// </description> /// </item> /// <item> /// <term><b>Generic Method</b></term> /// <term><b>Method</b></term> /// <description> /// The ClearScript library supports dynamic C#-like type inference when invoking /// generic methods. However, some methods require explicit type arguments. To call /// such a method from script code, you must place the required number of /// <see cref="AddHostType(string, HostItemFlags, Type)">host type objects</see> /// at the beginning of the argument list. Doing so for methods that do not require /// explicit type arguments is optional. /// </description> /// </item> /// <item> /// <term><b>Extension Method</b></term> /// <term><b>Method</b></term> /// <description> /// Extension methods are available if the type that implements them has been /// exposed in the current script engine. /// </description> /// </item> /// <item> /// <term><b>Indexer</b></term> /// <term><b>Property</b></term> /// <description> /// Indexers appear as properties named "Item" that accept one or more index values /// as arguments. In addition, objects that implement <see cref="IList"/> expose /// properties with numeric names that match their valid indices. This includes /// one-dimensional host arrays and other collections. Multidimensional host arrays /// do not expose functional indexers; you must use /// <see href="http://msdn.microsoft.com/en-us/library/system.array.getvalue.aspx">Array.GetValue</see> /// and /// <see href="http://msdn.microsoft.com/en-us/library/system.array.setvalue.aspx">Array.SetValue</see> /// instead. /// </description> /// </item> /// <item> /// <term><b>Event</b></term> /// <term><b>Property</b></term> /// <description> /// Events are exposed as read-only properties of type <see cref="EventSource{T}"/>. /// </description> /// </item> /// </list> /// </para> /// </remarks> public void AddHostObject(string itemName, HostItemFlags flags, object target) { MiscHelpers.VerifyNonNullArgument(target, "target"); AddHostItem(itemName, flags, target); }
private static HostItem Create(ScriptEngine engine, HostTarget target, HostItemFlags flags) { return(new HostItem(engine, target, flags)); }
internal abstract object MarshalToScript(object obj, HostItemFlags flags);
internal abstract void AddHostItem(string itemName, HostItemFlags flags, object item);
/// <summary> /// Exposes a host type to script code with the specified options. The type is specified by /// type name and assembly name. /// </summary> /// <param name="itemName">A name for the new global script item that will represent the type.</param> /// <param name="flags">A value that selects options for the operation.</param> /// <param name="typeName">The fully qualified name of the type to expose.</param> /// <param name="assemblyName">The name of the assembly that contains the type to expose.</param> /// <param name="typeArgs">Optional generic type arguments.</param> /// <remarks> /// Host types are exposed to script code in the form of objects whose properties and /// methods are bound to the type's static members and nested types. If the type has /// generic parameters, the corresponding object will be invocable with type arguments to /// yield a specific type. /// <para> /// For more information about the mapping between host members and script-callable /// properties and methods, see <see cref="AddHostObject(string, HostItemFlags, object)"/>. /// </para> /// </remarks> public void AddHostType(string itemName, HostItemFlags flags, string typeName, string assemblyName, params Type[] typeArgs) { AddHostItem(itemName, flags, TypeHelpers.ImportType(typeName, assemblyName, true, typeArgs)); }
internal override object MarshalToScript(object obj, HostItemFlags flags) { throw new PlatformNotSupportedException(); }
private static HostItem Create(ScriptEngine engine, HostTarget target, HostItemFlags flags) { return(TargetSupportsExpandoMembers(target, flags) ? new DispatchExHostItem(engine, target, flags) : new HostItem(engine, target, flags)); }
internal override object MarshalToScript(object obj, HostItemFlags flags) { return(MarshalToScriptInternal(obj, flags, null)); }
public DispatchExHostItem(ScriptEngine engine, HostTarget target, HostItemFlags flags) : base(engine, target, flags) { EnsurePatched(); }
private object MarshalToScriptInternal(object obj, HostItemFlags flags, HashSet <Array> marshaledArraySet) { if (obj == null) { if (engineFlags.HasFlag(WindowsScriptEngineFlags.MarshalNullAsDispatch)) { return(nullDispatch); } return(DBNull.Value); } if (obj is Undefined) { return(null); } if (obj is Nonexistent) { return(null); } if (engineFlags.HasFlag(WindowsScriptEngineFlags.MarshalDecimalAsCurrency) && (obj is decimal)) { return(new CurrencyWrapper(obj)); } var hostItem = obj as HostItem; if (hostItem != null) { if ((hostItem.Engine == this) && (hostItem.Flags == flags)) { return(obj); } obj = hostItem.Target; } var hostTarget = obj as HostTarget; if ((hostTarget != null) && !(hostTarget is IHostVariable)) { obj = hostTarget.Target; } var scriptItem = obj as ScriptItem; if (scriptItem != null) { if (scriptItem.Engine == this) { return(scriptItem.Unwrap()); } } if (engineFlags.HasFlag(WindowsScriptEngineFlags.MarshalArraysByValue)) { var array = obj as Array; if ((array != null) && ((hostTarget == null) || (typeof(Array).IsAssignableFrom(hostTarget.Type)))) { bool alreadyMarshaled; if (marshaledArraySet != null) { alreadyMarshaled = marshaledArraySet.Contains(array); } else { marshaledArraySet = new HashSet <Array>(); alreadyMarshaled = false; } if (!alreadyMarshaled) { marshaledArraySet.Add(array); var dimensions = Enumerable.Range(0, array.Rank).ToArray(); var marshaledArray = Array.CreateInstance(typeof(object), dimensions.Select(array.GetLength).ToArray(), dimensions.Select(array.GetLowerBound).ToArray()); array.Iterate(indices => marshaledArray.SetValue(MarshalToScriptInternal(array.GetValue(indices), flags, marshaledArraySet), indices)); return(marshaledArray); } // COM interop can't handle circularly referenced arrays return(MarshalToScriptInternal(null, flags, marshaledArraySet)); } } return(HostItem.Wrap(this, hostTarget ?? obj, flags)); }
/// <summary> /// Exposes a host object to script code with the specified type restriction and options. /// </summary> /// <typeparam name="T">The type whose members are to be made accessible from script code.</typeparam> /// <param name="itemName">A name for the new global script item that will represent the object.</param> /// <param name="flags">A value that selects options for the operation.</param> /// <param name="target">The object to expose.</param> /// <remarks> /// This method can be used to restrict script access to the members of a particular /// interface or base class. /// <para> /// For information about the mapping between host members and script-callable properties /// and methods, see <see cref="AddHostObject(string, HostItemFlags, object)"/>. /// </para> /// </remarks> public void AddRestrictedHostObject <T>(string itemName, HostItemFlags flags, T target) { AddHostItem(itemName, flags, HostItem.Wrap(this, target, typeof(T))); }
internal override void AddHostItem(string itemName, HostItemFlags flags, object item) { throw new PlatformNotSupportedException(); }
/// <summary> /// Exposes a host type to script code with the specified options. /// </summary> /// <param name="itemName">A name for the new global script item that will represent the type.</param> /// <param name="flags">A value that selects options for the operation.</param> /// <param name="type">The type to expose.</param> /// <remarks> /// Host types are exposed to script code in the form of objects whose properties and /// methods are bound to the type's static members and nested types. If the type has /// generic parameters, the corresponding object will be invocable with type arguments to /// yield a specific type. /// <para> /// For more information about the mapping between host members and script-callable /// properties and methods, see <see cref="AddHostObject(string, HostItemFlags, object)"/>. /// </para> /// </remarks> public void AddHostType(string itemName, HostItemFlags flags, Type type) { MiscHelpers.VerifyNonNullArgument(type, "type"); AddHostItem(itemName, flags, HostType.Wrap(type)); }
/// <summary> /// Exposes a host type to script code with the specified options. The type is specified by name. /// </summary> /// <param name="itemName">A name for the new global script item that will represent the type.</param> /// <param name="flags">A value that selects options for the operation.</param> /// <param name="typeName">The fully qualified name of the type to expose.</param> /// <param name="typeArgs">Optional generic type arguments.</param> /// <remarks> /// Host types are exposed to script code in the form of objects whose properties and /// methods are bound to the type's static members and nested types. If the type has /// generic parameters, the corresponding object will be invocable with type arguments to /// yield a specific type. /// <para> /// For more information about the mapping between host members and script-callable /// properties and methods, see <see cref="AddHostObject(string, HostItemFlags, object)"/>. /// </para> /// </remarks> public void AddHostType(string itemName, HostItemFlags flags, string typeName, params Type[] typeArgs) { AddHostItem(itemName, flags, TypeHelpers.ImportType(typeName, null, false, typeArgs)); }
// ReSharper disable MemberCanBeProtected.Local public ExpandoHostItem(ScriptEngine engine, HostTarget target, HostItemFlags flags) : base(engine, target, flags) { }