diff --git a/src/Core/ReflectionUtility.cs b/src/Core/ReflectionUtility.cs index c56d589..03af37e 100644 --- a/src/Core/ReflectionUtility.cs +++ b/src/Core/ReflectionUtility.cs @@ -105,14 +105,7 @@ namespace UnityExplorer /// /// The object to cast /// The object, cast to the underlying Type if possible, otherwise the original object. - public static object TryCast(this object obj) - { - var type = GetActualType(obj); - - if (type.IsValueType) - return obj; - return ReflectionProvider.Instance.Cast(obj, type); - } + public static object TryCast(this object obj) => ReflectionProvider.Instance.Cast(obj, GetActualType(obj)); /// /// Cast an object to a Type, if possible. @@ -120,20 +113,10 @@ namespace UnityExplorer /// The object to cast /// The Type to cast to /// The object, cast to the Type provided if possible, otherwise the original object. - public static object TryCast(this object obj, Type castTo) - { - if (castTo.IsValueType) - return obj; - return ReflectionProvider.Instance.Cast(obj, castTo); - } + public static object TryCast(this object obj, Type castTo) => ReflectionProvider.Instance.Cast(obj, castTo); - public static T TryCast(this object obj) - { - var type = typeof(T); - if (type.IsValueType) - return (T)obj; - return ReflectionProvider.Instance.TryCast(obj); - } + /// Try to cast the object to the type. + public static T TryCast(this object obj) => ReflectionProvider.Instance.TryCast(obj); /// /// Check if the provided Type is assignable to IEnumerable. diff --git a/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs b/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs index 614b857..4af0405 100644 --- a/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs +++ b/src/Core/Runtime/Il2Cpp/Il2CppReflection.cs @@ -53,67 +53,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp } } - public override bool IsString(object obj) - { - return obj is string || obj is Il2CppSystem.String; - } - - public override void BoxStringToType(ref object value, Type castTo) - { - if (castTo == typeof(Il2CppSystem.String)) - value = (Il2CppSystem.String)(value as string); - else - value = (Il2CppSystem.Object)(value as string); - } - - public override string UnboxString(object value) - { - if (value is string s) - return s; - - s = null; - // strings boxed as Il2CppSystem.Objects can behave weirdly. - // GetActualType will find they are a string, but if its boxed - // then we need to unbox it like this... - if (value is Il2CppSystem.Object cppObject) - s = cppObject.ToString(); - else if (value is Il2CppSystem.String cppString) - s = cppString; - - return s; - } - - public override Type GetDeobfuscatedType(Type type) - { - try - { - if (Il2CppToMonoType.ContainsKey(type.AssemblyQualifiedName)) - return Il2CppToMonoType[type.AssemblyQualifiedName]; - //var cppType = Il2CppType.From(type); - //var monoType = GetMonoType(cppType); - //if (monoType != null) - // return monoType; - } - catch { } - - return type; - } - - public override string ProcessTypeFullNameInString(Type type, string theString, ref string typeName) - { - if (!Il2CppTypeNotNull(type)) - return theString; - - var cppType = Il2CppType.From(type); - if (cppType != null && s_deobfuscatedTypeNames.ContainsKey(cppType.FullName)) - { - typeName = s_deobfuscatedTypeNames[cppType.FullName]; - theString = theString.Replace(cppType.FullName, typeName); - } - - return theString; - } - public override Type GetActualType(object obj) { if (obj == null) @@ -125,13 +64,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp { if (obj is Il2CppSystem.Object cppObject) { - // weird specific case - if the object is an Il2CppSystem.Type, then return so manually. - if (cppObject is CppType) - return typeof(CppType); - - if (type.FullName.StartsWith("System.") || type.FullName.StartsWith("Il2CppSystem.")) - return type; - var cppType = cppObject.GetIl2CppType(); // check if type is injected @@ -141,15 +73,10 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp // Note: This will fail on injected subclasses. // - {Namespace}.{Class}.{Subclass} would be {Namespace}.{Subclass} when injected. // Not sure on solution yet. - var typeByName = ReflectionUtility.GetTypeByName(cppType.FullName); - if (typeByName != null) - return typeByName; + return ReflectionUtility.GetTypeByName(cppType.FullName) ?? type; } - // this should be fine for all other il2cpp objects - var getType = GetMonoType(cppType); - if (getType != null) - return getType; + return GetMonoType(cppType) ?? type; } } catch //(Exception ex) @@ -160,58 +87,17 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp return type; } - // caching for GetMonoType - private static readonly Dictionary Il2CppToMonoType = new Dictionary(); - - // keep deobfuscated type name cache, used to display proper name. - internal static Dictionary s_deobfuscatedTypeNames = new Dictionary(); - - private static void BuildDeobfuscationCache() - { - foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) - { - foreach (var type in asm.TryGetTypes()) - TryCacheDeobfuscatedType(type); - } - - if (s_deobfuscatedTypeNames.Count > 0) - ExplorerCore.Log($"Built deobfuscation cache, count: {s_deobfuscatedTypeNames.Count}"); - } - - private static void TryCacheDeobfuscatedType(Type type) - { - try - { - if (type.CustomAttributes.Any(it => it.AttributeType.Name == "ObfuscatedNameAttribute")) - { - var cppType = Il2CppType.From(type); - - if (!Il2CppToMonoType.ContainsKey(cppType.AssemblyQualifiedName)) - { - Il2CppToMonoType.Add(cppType.AssemblyQualifiedName, type); - s_deobfuscatedTypeNames.Add(cppType.FullName, type.FullName); - } - } - } - catch { } - } - - /// - /// Try to get the Mono (Unhollowed) Type representation of the provided . - /// - /// The Cpp Type you want to convert to Mono. - /// The Mono Type if found, otherwise null. public static Type GetMonoType(CppType cppType) { - string name = cppType.AssemblyQualifiedName; + if (DeobfuscatedTypes.TryGetValue(cppType.AssemblyQualifiedName, out Type deob)) + return deob; - if (Il2CppToMonoType.ContainsKey(name)) - return Il2CppToMonoType[name]; + var fullname = cppType.FullName; + if (fullname.StartsWith("System.")) + fullname = $"Il2Cpp{fullname}"; - Type ret = Type.GetType(name); - Il2CppToMonoType.Add(name, ret); - - return ret; + ReflectionUtility.AllTypes.TryGetValue(fullname, out Type monoType); + return monoType; } // cached class pointers for Il2CppCast @@ -232,9 +118,24 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp /// The object, as the type (or a normal C# object) if successful or the input value if not. public static object Il2CppCast(object obj, Type castTo) { + if (obj == null) + return null; + + var type = obj.GetType(); + + if (type.IsValueType && typeof(Il2CppSystem.Object).IsAssignableFrom(castTo)) + return BoxIl2CppObject(obj); + if (!(obj is Il2CppSystem.Object cppObj)) return obj; + if (castTo.IsValueType) + { + if (castTo.FullName.StartsWith("Il2CppSystem.")) + ReflectionUtility.AllTypes.TryGetValue(cppObj.GetIl2CppType().FullName, out castTo); + return Unbox(cppObj, castTo); + } + if (!Il2CppTypeNotNull(castTo, out IntPtr castToPtr)) return obj; @@ -249,9 +150,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp return injectedObj ?? obj; } - if (castTo == typeof(string)) - return cppObj.ToString(); - try { return Activator.CreateInstance(castTo, cppObj.Pointer); @@ -262,6 +160,129 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp } } + // struct boxing + + // cached il2cpp unbox methods + internal static readonly Dictionary s_unboxMethods = new Dictionary(); + + /// + /// Attempt to unbox the object to the underlying struct type. + /// + /// The object which is a struct underneath. + /// The struct if successful, otherwise null. + public static object Unbox(object obj) => Unbox(obj, Instance.GetActualType(obj)); + + /// + /// Attempt to unbox the object to the struct type. + /// + /// The object which is a struct underneath. + /// The type of the struct you want to unbox to. + /// The struct if successful, otherwise null. + public static object Unbox(object obj, Type type) + { + if (!type.IsValueType) + return null; + + if (!(obj is Il2CppSystem.Object)) + return obj; + + var name = type.AssemblyQualifiedName; + + if (!s_unboxMethods.ContainsKey(name)) + { + s_unboxMethods.Add(name, typeof(Il2CppObjectBase) + .GetMethod("Unbox") + .MakeGenericMethod(type)); + } + + return s_unboxMethods[name].Invoke(obj, new object[0]); + } + + //internal static Dictionary monoToIl2CppType = new Dictionary(); + internal static Dictionary structBoxMethods = new Dictionary(); + internal static Dictionary structValueFields = new Dictionary(); + + /// + /// Try to box a value to Il2CppSystem.Object using the Il2CppSystem representation of the value type. + /// + /// The value, eg 5 (System.Int32) + /// The boxed Il2CppSystem.Object for the value, eg for '5' it would be a boxed Il2CppSytem.Int32. + public static Il2CppSystem.Object BoxIl2CppObject(object value) + { + string key = $"Il2Cpp{value.GetType().FullName}"; + + if (ReflectionUtility.AllTypes.TryGetValue(key, out Type type) && type.IsValueType) + { + var cppStruct = Activator.CreateInstance(type); + + if (!structValueFields.ContainsKey(type)) + structValueFields.Add(type, type.GetField("m_value")); + + structValueFields[type].SetValue(cppStruct, value); + + if (!structBoxMethods.ContainsKey(type)) + structBoxMethods.Add(type, type.GetMethod("BoxIl2CppObject")); + + return structBoxMethods[type].Invoke(cppStruct, null) as Il2CppSystem.Object; + } + else + { + ExplorerCore.LogWarning("Couldn't get type to box to"); + return null; + } + } + + // deobfuscation + + private static readonly Dictionary DeobfuscatedTypes = new Dictionary(); + internal static Dictionary s_deobfuscatedTypeNames = new Dictionary(); + + private static void BuildDeobfuscationCache() + { + foreach (var asm in AppDomain.CurrentDomain.GetAssemblies()) + { + foreach (var type in asm.TryGetTypes()) + TryCacheDeobfuscatedType(type); + } + + if (s_deobfuscatedTypeNames.Count > 0) + ExplorerCore.Log($"Built deobfuscation cache, count: {s_deobfuscatedTypeNames.Count}"); + } + + private static void TryCacheDeobfuscatedType(Type type) + { + try + { + // Thanks to Slaynash for this + + if (type.CustomAttributes.Any(it => it.AttributeType.Name == "ObfuscatedNameAttribute")) + { + var cppType = Il2CppType.From(type); + + if (!DeobfuscatedTypes.ContainsKey(cppType.AssemblyQualifiedName)) + { + DeobfuscatedTypes.Add(cppType.AssemblyQualifiedName, type); + s_deobfuscatedTypeNames.Add(cppType.FullName, type.FullName); + } + } + } + catch { } + } + + public override Type GetDeobfuscatedType(Type type) + { + try + { + if (DeobfuscatedTypes.ContainsKey(type.AssemblyQualifiedName)) + return DeobfuscatedTypes[type.AssemblyQualifiedName]; + } + catch { } + + return type; + } + + // misc helpers + /// /// Get the Il2Cpp Class Pointer for the provided Mono (Unhollowed) Type. /// @@ -297,6 +318,132 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp [DllImport("GameAssembly", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] public static extern IntPtr il2cpp_object_get_class(IntPtr obj); + public override bool IsString(object obj) + { + return obj is string || obj is Il2CppSystem.String; + } + + public override void BoxStringToType(ref object value, Type castTo) + { + if (castTo == typeof(Il2CppSystem.String)) + value = (Il2CppSystem.String)(value as string); + else + value = (Il2CppSystem.Object)(value as string); + } + + public override string UnboxString(object value) + { + if (value is string s) + return s; + + s = null; + // strings boxed as Il2CppSystem.Objects can behave weirdly. + // GetActualType will find they are a string, but if its boxed + // then we need to unbox it like this... + if (value is Il2CppSystem.Object cppObject) + s = cppObject.ToString(); + else if (value is Il2CppSystem.String cppString) + s = cppString; + + return s; + } + + public override string ProcessTypeFullNameInString(Type type, string theString, ref string typeName) + { + if (!Il2CppTypeNotNull(type)) + return theString; + + var cppType = Il2CppType.From(type); + if (cppType != null && s_deobfuscatedTypeNames.ContainsKey(cppType.FullName)) + { + typeName = s_deobfuscatedTypeNames[cppType.FullName]; + theString = theString.Replace(cppType.FullName, typeName); + } + + return theString; + } + + + //// Not currently using, not sure if its necessary anymore, was necessary to prevent crashes at one point. + //public override bool IsReflectionSupported(Type type) + //{ + // try + // { + // var gArgs = type.GetGenericArguments(); + // if (!gArgs.Any()) + // return true; + // + // foreach (var gType in gArgs) + // { + // if (!Supported(gType)) + // return false; + // } + // + // return true; + // + // bool Supported(Type t) + // { + // if (!typeof(Il2CppSystem.Object).IsAssignableFrom(t)) + // return true; + // + // if (!Il2CppTypeNotNull(t, out IntPtr ptr)) + // return false; + // + // return CppType.internal_from_handle(IL2CPP.il2cpp_class_get_type(ptr)) is CppType; + // } + // } + // catch + // { + // return false; + // } + //} + + + + #region FORCE LOADING GAME MODULES + + // Helper for IL2CPP to try to make sure the Unhollowed game assemblies are actually loaded. + + internal static void TryLoadGameModules() + { + Instance.LoadModule("Assembly-CSharp"); + Instance.LoadModule("Assembly-CSharp-firstpass"); + } + + public override bool LoadModule(string module) + { +#if ML + var path = Path.Combine("MelonLoader", "Managed", $"{module}.dll"); +#else + var path = Path.Combine("BepInEx", "unhollowed", $"{module}.dll"); +#endif + return LoadModuleInternal(path); + } + + internal static bool LoadModuleInternal(string fullPath) + { + if (!File.Exists(fullPath)) + return false; + + try + { + Assembly.Load(File.ReadAllBytes(fullPath)); + return true; + } + catch (Exception e) + { + Console.WriteLine(e.GetType() + ", " + e.Message); + } + + return false; + } + + #endregion + + #region IL2CPP IENUMERABLE / IDICTIONARY + + // dictionary and enumerable cast helpers (until unhollower rewrite) + internal static IntPtr s_cppEnumerableClassPtr; internal static IntPtr s_cppDictionaryClassPtr; @@ -341,76 +488,6 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp return false; } - // Not currently using, not sure if its necessary anymore, was necessary to prevent crashes at one point. - public override bool IsReflectionSupported(Type type) - { - try - { - var gArgs = type.GetGenericArguments(); - if (!gArgs.Any()) - return true; - - foreach (var gType in gArgs) - { - if (!Supported(gType)) - return false; - } - - return true; - - bool Supported(Type t) - { - if (!typeof(Il2CppSystem.Object).IsAssignableFrom(t)) - return true; - - if (!Il2CppTypeNotNull(t, out IntPtr ptr)) - return false; - - return CppType.internal_from_handle(IL2CPP.il2cpp_class_get_type(ptr)) is CppType; - } - } - catch - { - return false; - } - } - - // Helper for IL2CPP to try to make sure the Unhollowed game assemblies are actually loaded. - - internal static void TryLoadGameModules() - { - Instance.LoadModule("Assembly-CSharp"); - Instance.LoadModule("Assembly-CSharp-firstpass"); - } - - public override bool LoadModule(string module) - { -#if ML - var path = Path.Combine("MelonLoader", "Managed", $"{module}.dll"); -#else - var path = Path.Combine("BepInEx", "unhollowed", $"{module}.dll"); -#endif - return LoadModuleInternal(path); - } - - internal static bool LoadModuleInternal(string fullPath) - { - if (!File.Exists(fullPath)) - return false; - - try - { - Assembly.Load(File.ReadAllBytes(fullPath)); - return true; - } - catch (Exception e) - { - Console.WriteLine(e.GetType() + ", " + e.Message); - } - - return false; - } - internal static readonly Dictionary s_getEnumeratorMethods = new Dictionary(); internal static readonly Dictionary s_enumeratorInfos = new Dictionary(); @@ -536,43 +613,7 @@ namespace UnityExplorer.Core.Runtime.Il2Cpp base.FindSingleton(possibleNames, type, flags, instances); } - // ~~~~~~~~~~ not used ~~~~~~~~~~~~ - - // cached il2cpp unbox methods - internal static readonly Dictionary s_unboxMethods = new Dictionary(); - - /// - /// Attempt to unbox the object to the underlying struct type. - /// - /// The object which is a struct underneath. - /// The struct if successful, otherwise null. - public static object Unbox(object obj) => Unbox(obj, Instance.GetActualType(obj)); - - /// - /// Attempt to unbox the object to the struct type. - /// - /// The object which is a struct underneath. - /// The type of the struct you want to unbox to. - /// The struct if successful, otherwise null. - public static object Unbox(object obj, Type type) - { - if (!type.IsValueType) - return null; - - if (!(obj is Il2CppSystem.Object)) - return obj; - - var name = type.AssemblyQualifiedName; - - if (!s_unboxMethods.ContainsKey(name)) - { - s_unboxMethods.Add(name, typeof(Il2CppObjectBase) - .GetMethod("Unbox") - .MakeGenericMethod(type)); - } - - return s_unboxMethods[name].Invoke(obj, new object[0]); - } + #endregion } } diff --git a/src/Core/Runtime/Mono/MonoReflection.cs b/src/Core/Runtime/Mono/MonoReflection.cs index 5620e1b..5ac3db3 100644 --- a/src/Core/Runtime/Mono/MonoReflection.cs +++ b/src/Core/Runtime/Mono/MonoReflection.cs @@ -31,9 +31,6 @@ namespace UnityExplorer.Core.Runtime.Mono public override bool IsAssignableFrom(Type toAssignTo, Type toAssignFrom) => toAssignTo.IsAssignableFrom(toAssignFrom); - public override bool IsReflectionSupported(Type type) - => true; - public override bool LoadModule(string module) => true; diff --git a/src/Core/Runtime/ReflectionProvider.cs b/src/Core/Runtime/ReflectionProvider.cs index 80fca0f..2d63b5c 100644 --- a/src/Core/Runtime/ReflectionProvider.cs +++ b/src/Core/Runtime/ReflectionProvider.cs @@ -26,7 +26,7 @@ namespace UnityExplorer.Core.Runtime public abstract bool IsAssignableFrom(Type toAssignTo, Type toAssignFrom); - public abstract bool IsReflectionSupported(Type type); + //public abstract bool IsReflectionSupported(Type type); public abstract string ProcessTypeFullNameInString(Type type, string theString, ref string typeName); diff --git a/src/Core/Tests/TestClass.cs b/src/Core/Tests/TestClass.cs index 10964cd..3227552 100644 --- a/src/Core/Tests/TestClass.cs +++ b/src/Core/Tests/TestClass.cs @@ -126,10 +126,14 @@ namespace UnityExplorer.Tests public static Il2CppSystem.String testStringThree = "string boxed as cpp string"; public static string nullString = null; + public static List boxedList; + + public static Il2CppSystem.Object boxedInt; + public static Il2CppSystem.Int32 cppint; + public static Il2CppSystem.Collections.Hashtable testHashset; public static Il2CppSystem.Collections.Generic.List testList; - //public static Il2CppSystem.Nullable NullableQuaternion; //public static Il2CppSystem.Nullable NullableInt = new Il2CppSystem.Nullable(5); //public static Il2CppSystem.Nullable NullableBool = new Il2CppSystem.Nullable(false); @@ -144,6 +148,12 @@ namespace UnityExplorer.Tests //NullableQuaternion = new Il2CppSystem.Nullable(); //NullableQuaternion.value = Quaternion.identity; + boxedInt = new Il2CppSystem.Int32() { m_value = 5 }.BoxIl2CppObject(); + boxedList = new List(); + boxedList.Add((Il2CppSystem.String)"boxedString"); + boxedList.Add(new Il2CppSystem.Int32 { m_value = 5 }.BoxIl2CppObject()); + cppint = new Il2CppSystem.Int32 { m_value = 420 }; + testHashset = new Il2CppSystem.Collections.Hashtable(); testHashset.Add("key1", "itemOne"); testHashset.Add("key2", "itemTwo"); diff --git a/src/UI/CacheObject/CacheField.cs b/src/UI/CacheObject/CacheField.cs index c3ad47f..6a7375e 100644 --- a/src/UI/CacheObject/CacheField.cs +++ b/src/UI/CacheObject/CacheField.cs @@ -43,7 +43,7 @@ namespace UnityExplorer.UI.CacheObject { try { - FieldInfo.SetValue(FieldInfo.IsStatic ? null : Owner.Target.TryCast(this.DeclaringType), value); + FieldInfo.SetValue(DeclaringInstance, value); } catch (Exception ex) { diff --git a/src/UI/CacheObject/CacheKeyValuePair.cs b/src/UI/CacheObject/CacheKeyValuePair.cs index 880ef22..38e4eb4 100644 --- a/src/UI/CacheObject/CacheKeyValuePair.cs +++ b/src/UI/CacheObject/CacheKeyValuePair.cs @@ -82,7 +82,7 @@ namespace UnityExplorer.UI.CacheObject } } - public override void SetUserValue(object value) + public override void TrySetUserValue(object value) { throw new NotImplementedException("TODO"); } diff --git a/src/UI/CacheObject/CacheListEntry.cs b/src/UI/CacheObject/CacheListEntry.cs index d1b9b97..c24d414 100644 --- a/src/UI/CacheObject/CacheListEntry.cs +++ b/src/UI/CacheObject/CacheListEntry.cs @@ -31,7 +31,7 @@ namespace UnityExplorer.UI.CacheObject listCell.Image.color = ListIndex % 2 == 0 ? CacheListEntryCell.EvenColor : CacheListEntryCell.OddColor; } - public override void SetUserValue(object value) + public override void TrySetUserValue(object value) { throw new NotImplementedException("TODO"); } diff --git a/src/UI/CacheObject/CacheMember.cs b/src/UI/CacheObject/CacheMember.cs index e9ae5dc..5fb203d 100644 --- a/src/UI/CacheObject/CacheMember.cs +++ b/src/UI/CacheObject/CacheMember.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Reflection; using System.Text; using UnityEngine; +using UnityExplorer.Core.Runtime; using UnityExplorer.UI.CacheObject.Views; using UnityExplorer.UI.Inspectors; using UnityExplorer.UI.ObjectPool; @@ -74,10 +75,11 @@ namespace UnityExplorer.UI.CacheObject SetValueFromSource(TryEvaluate()); } - public override void SetUserValue(object value) + public override void TrySetUserValue(object value) { - // TODO unbox string, cast, etc - + if (State == ValueState.String) + ReflectionProvider.Instance.BoxStringToType(ref value, FallbackType); + TrySetValue(value); Evaluate(); diff --git a/src/UI/CacheObject/CacheObjectBase.cs b/src/UI/CacheObject/CacheObjectBase.cs index 67ec399..23aa9c1 100644 --- a/src/UI/CacheObject/CacheObjectBase.cs +++ b/src/UI/CacheObject/CacheObjectBase.cs @@ -95,7 +95,13 @@ namespace UnityExplorer.UI.CacheObject // Updating and applying values - public abstract void SetUserValue(object value); + public void SetUserValue(object value) + { + value = value.TryCast(FallbackType); + TrySetUserValue(value); + } + + public abstract void TrySetUserValue(object value); public virtual void SetValueFromSource(object value) { diff --git a/src/UI/CacheObject/CacheProperty.cs b/src/UI/CacheObject/CacheProperty.cs index e932927..6dfdeee 100644 --- a/src/UI/CacheObject/CacheProperty.cs +++ b/src/UI/CacheObject/CacheProperty.cs @@ -52,12 +52,11 @@ namespace UnityExplorer.UI.CacheObject try { bool _static = PropertyInfo.GetAccessors(true)[0].IsStatic; - var target = _static ? null : Owner.Target.TryCast(DeclaringType); if (HasArguments) - PropertyInfo.SetValue(target, value, Evaluator.TryParseArguments()); + PropertyInfo.SetValue(DeclaringInstance, value, Evaluator.TryParseArguments()); else - PropertyInfo.SetValue(target, value, null); + PropertyInfo.SetValue(DeclaringInstance, value, null); } catch (Exception ex) {