diff --git a/src/native/QmlNet/QmlNet/qml/NetValue.cpp b/src/native/QmlNet/QmlNet/qml/NetValue.cpp index 6d45acd1..8169af3b 100644 --- a/src/native/QmlNet/QmlNet/qml/NetValue.cpp +++ b/src/native/QmlNet/QmlNet/qml/NetValue.cpp @@ -5,10 +5,10 @@ NetValue::~NetValue() { - auto hit = netValues.find(instance.data()); - if(hit != netValues.end()) + auto hit = objectIdNetValuesMap.find(instance->getObjectId()); + if(hit != objectIdNetValuesMap.end()) { - netValues.erase(hit); + objectIdNetValuesMap.erase(hit); } qDebug("NetValue deleted: %s", qPrintable(instance->getTypeInfo()->getClassName())); if(instance != nullptr) { @@ -78,9 +78,10 @@ bool NetValue::activateSignal(QString signalName, QSharedPointer NetValue* NetValue::forInstance(QSharedPointer instance, bool autoCreate) { - if(netValues.find(instance.data()) != netValues.end()) + auto objectId = instance->getObjectId(); + if(objectIdNetValuesMap.find(objectId) != objectIdNetValuesMap.end()) { - return netValues.at(instance.data()); + return objectIdNetValuesMap.at(objectId); } if(!autoCreate) { @@ -96,8 +97,8 @@ NetValue::NetValue(QSharedPointer instance, QObject *parent) { valueMeta = new NetValueMetaObject(this, instance); setParent(parent); - netValues[instance.data()] = this; + objectIdNetValuesMap[instance->getObjectId()] = this; qDebug("NetValue created: %s", qPrintable(instance->getTypeInfo()->getClassName())); } -std::map NetValue::netValues = std::map(); +std::map NetValue::objectIdNetValuesMap = std::map(); diff --git a/src/native/QmlNet/QmlNet/qml/NetValue.h b/src/native/QmlNet/QmlNet/qml/NetValue.h index 4c9564d6..65647da8 100644 --- a/src/native/QmlNet/QmlNet/qml/NetValue.h +++ b/src/native/QmlNet/QmlNet/qml/NetValue.h @@ -36,7 +36,7 @@ private: QSharedPointer instance; NetValueMetaObject* valueMeta; - static std::map netValues; + static std::map objectIdNetValuesMap; }; #endif // NETVALUE_H diff --git a/src/native/QmlNet/QmlNet/types/NetReference.cpp b/src/native/QmlNet/QmlNet/types/NetReference.cpp index c87a7472..6be2fc71 100644 --- a/src/native/QmlNet/QmlNet/types/NetReference.cpp +++ b/src/native/QmlNet/QmlNet/types/NetReference.cpp @@ -3,8 +3,9 @@ #include #include -NetReference::NetReference(NetGCHandle* gcHandle, QSharedPointer typeInfo) : +NetReference::NetReference(NetGCHandle* gcHandle, uint64_t objectId, QSharedPointer typeInfo) : gcHandle(gcHandle), + objectId(objectId), typeInfo(typeInfo) { qDebug("NetReference created: %s", qPrintable(typeInfo->getClassName())); @@ -20,6 +21,11 @@ NetGCHandle* NetReference::getGCHandle() return gcHandle; } +uint64_t NetReference::getObjectId() +{ + return objectId; +} + QSharedPointer NetReference::getTypeInfo() { return typeInfo; @@ -38,9 +44,9 @@ void NetReference::release() extern "C" { -Q_DECL_EXPORT NetReferenceContainer* net_instance_create(NetGCHandle* handle, NetTypeInfoContainer* typeContainer) { +Q_DECL_EXPORT NetReferenceContainer* net_instance_create(NetGCHandle* handle, uint64_t objectId, NetTypeInfoContainer* typeContainer) { NetReferenceContainer* result = new NetReferenceContainer(); - result->instance = QSharedPointer(new NetReference(handle, typeContainer->netTypeInfo)); + result->instance = QSharedPointer(new NetReference(handle, objectId, typeContainer->netTypeInfo)); return result; } @@ -57,6 +63,10 @@ Q_DECL_EXPORT NetGCHandle* net_instance_getHandle(NetReferenceContainer* contain return container->instance->getGCHandle(); } +Q_DECL_EXPORT uint64_t net_instance_getObjectId(NetReferenceContainer* container) { + return container->instance->getObjectId(); +} + Q_DECL_EXPORT bool net_instance_activateSignal(NetReferenceContainer* container, LPWSTR signalName, NetVariantListContainer* parametersContainer) { NetValue* existing = NetValue::forInstance(container->instance); if(existing == NULL) { diff --git a/src/native/QmlNet/QmlNet/types/NetReference.h b/src/native/QmlNet/QmlNet/types/NetReference.h index 887e4d07..4af9bcda 100644 --- a/src/native/QmlNet/QmlNet/types/NetReference.h +++ b/src/native/QmlNet/QmlNet/types/NetReference.h @@ -6,14 +6,16 @@ class NetReference { public: - NetReference(NetGCHandle* gcHandle, QSharedPointer typeInfo); + NetReference(NetGCHandle* gcHandle, uint64_t objectId, QSharedPointer typeInfo); ~NetReference(); NetGCHandle* getGCHandle(); + uint64_t getObjectId(); QSharedPointer getTypeInfo(); void release(); private: NetGCHandle* gcHandle; + uint64_t objectId; QSharedPointer typeInfo; }; diff --git a/src/net/Qml.Net.Tests/Qml/NetVariantTests.cs b/src/net/Qml.Net.Tests/Qml/NetVariantTests.cs index f51e4e93..cba2857f 100644 --- a/src/net/Qml.Net.Tests/Qml/NetVariantTests.cs +++ b/src/net/Qml.Net.Tests/Qml/NetVariantTests.cs @@ -26,7 +26,7 @@ namespace Qml.Net.Tests.Qml var testObject = new TestObject(); var variant = new NetVariant(); variant.Instance.Should().BeNull(); - variant.Instance = NetReference.GetForObject(testObject); + variant.Instance = NetReference.CreateForObject(testObject); variant.Instance.Should().NotBeNull(); variant.Instance.Instance.Should().Be(testObject); variant.VariantType.Should().Be(NetVariantType.Object); diff --git a/src/net/Qml.Net.Tests/Types/CallbacksTests.cs b/src/net/Qml.Net.Tests/Types/CallbacksTests.cs index c84f3975..6704932a 100644 --- a/src/net/Qml.Net.Tests/Types/CallbacksTests.cs +++ b/src/net/Qml.Net.Tests/Types/CallbacksTests.cs @@ -35,7 +35,7 @@ namespace Qml.Net.Tests.Types { var o = new TestObject(); reference = new WeakReference(o); - instance = NetReference.GetForObject(o); + instance = NetReference.CreateForObject(o); }).Wait(); // NetReference is still alive, so the weak reference must be alive as well. @@ -67,7 +67,7 @@ namespace Qml.Net.Tests.Types var o = new TestObject(); var type = NetTypeManager.GetTypeInfo(); var method = type.GetMethod(0); - var instance = NetReference.GetForObject(o); + var instance = NetReference.CreateForObject(o); // This will jump to native, to then call the .NET delegate (round trip). // The purpose is to simulate Qml invoking a method, sending .NET instance back. diff --git a/src/net/Qml.Net.Tests/Types/NetReferenceTests.cs b/src/net/Qml.Net.Tests/Types/NetReferenceTests.cs index fab3cfc6..d23c319d 100644 --- a/src/net/Qml.Net.Tests/Types/NetReferenceTests.cs +++ b/src/net/Qml.Net.Tests/Types/NetReferenceTests.cs @@ -15,7 +15,7 @@ namespace Qml.Net.Tests.Types public void Can_create_net_instance() { var o = new TestObject(); - var instance = NetReference.GetForObject(o); + var instance = NetReference.CreateForObject(o); var returnedInstance = instance.Instance; diff --git a/src/net/Qml.Net/Internal/DefaultCallbacks.cs b/src/net/Qml.Net/Internal/DefaultCallbacks.cs index d8794c56..e4d2f4f4 100644 --- a/src/net/Qml.Net/Internal/DefaultCallbacks.cs +++ b/src/net/Qml.Net/Internal/DefaultCallbacks.cs @@ -142,7 +142,7 @@ namespace Qml.Net.Internal var typeCreator = NetReference.TypeCreator; var instance = typeCreator != null ? typeCreator.Create(typeInfo) : Activator.CreateInstance(typeInfo); - var netReference = NetReference.GetForObject(instance); + var netReference = NetReference.CreateForObject(instance); // When .NET collects this NetReference, we don't want it to delete this // handle. Ownership has been passed to the caller. return Interop.NetReference.Clone(netReference.Handle); diff --git a/src/net/Qml.Net/Internal/Helpers.cs b/src/net/Qml.Net/Internal/Helpers.cs index 830ff7bb..42a3bbf3 100644 --- a/src/net/Qml.Net/Internal/Helpers.cs +++ b/src/net/Qml.Net/Internal/Helpers.cs @@ -38,7 +38,7 @@ namespace Qml.Net.Internal destination.DateTime = (DateTime)source; else { - destination.Instance = NetReference.GetForObject(source); + destination.Instance = NetReference.CreateForObject(source); } } } diff --git a/src/net/Qml.Net/Internal/ObjectTagger.cs b/src/net/Qml.Net/Internal/ObjectTagger.cs index ad33e1d9..3470e12d 100644 --- a/src/net/Qml.Net/Internal/ObjectTagger.cs +++ b/src/net/Qml.Net/Internal/ObjectTagger.cs @@ -13,14 +13,14 @@ namespace Qml.Net.Internal { } - private ObjectId(ulong id) + private ObjectId(UInt64 id) { Id = id; } - public ulong Id { get; private set; } + public UInt64 Id { get; private set; } - public static implicit operator ulong(ObjectId oId) + public static implicit operator UInt64(ObjectId oId) { return oId.Id; } @@ -32,23 +32,23 @@ namespace Qml.Net.Internal #region Id management - private static ulong NextId = 1; - private static HashSet UsedIds = new HashSet(); + private static UInt64 NextId = 1; + private static HashSet UsedIds = new HashSet(); - private static ulong TakeNextFreeId() + private static UInt64 TakeNextFreeId() { - ulong nextId = NextId; + UInt64 nextId = NextId; UsedIds.Add(nextId); NextId = CalculateNextFreeId(nextId); return nextId; } - private static ulong CalculateNextFreeId(ulong nextId) + private static UInt64 CalculateNextFreeId(UInt64 nextId) { bool firstPass = true; while (UsedIds.Contains(nextId)) { - if(nextId == ulong.MaxValue) + if(nextId == UInt64.MaxValue) { if(!firstPass) { @@ -65,7 +65,7 @@ namespace Qml.Net.Internal return nextId; } - private static void FreeId(ulong id) + private static void FreeId(UInt64 id) { UsedIds.Remove(id); } @@ -82,7 +82,7 @@ namespace Qml.Net.Internal { private static readonly ConditionalWeakTable ObjectIdRefs = new ConditionalWeakTable(); - public static ulong GetOrCreateTag(this object obj) + public static UInt64 GetOrCreateTag(this object obj) { var result = GetTag(obj); if(result.HasValue) @@ -94,7 +94,7 @@ namespace Qml.Net.Internal return newObjId; } - public static ulong? GetTag(this object obj) + public static UInt64? GetTag(this object obj) { if (ObjectIdRefs.TryGetValue(obj, out var objId)) { diff --git a/src/net/Qml.Net/Signals.cs b/src/net/Qml.Net/Signals.cs index 339d856c..26023309 100644 --- a/src/net/Qml.Net/Signals.cs +++ b/src/net/Qml.Net/Signals.cs @@ -6,7 +6,7 @@ namespace Qml.Net { public static bool ActivateSignal(this object instance, string signalName, params object[] args) { - var existing = NetReference.GetForObject(instance, false /*don't create one if doesn't exist*/); + var existing = NetReference.CreateForObject(instance); return existing != null && existing.ActivateSignal(signalName, args); } } diff --git a/src/net/Qml.Net/Types/NetReference.cs b/src/net/Qml.Net/Types/NetReference.cs index f78a65e4..f3dccc2e 100644 --- a/src/net/Qml.Net/Types/NetReference.cs +++ b/src/net/Qml.Net/Types/NetReference.cs @@ -1,6 +1,7 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Serialization; using AdvancedDLSupport; using Qml.Net.Internal; using Qml.Net.Qml; @@ -9,8 +10,8 @@ namespace Qml.Net.Types { public class NetReference : BaseDisposable { - private NetReference(IntPtr gcHandle, NetTypeInfo type, bool ownsHandle = true) - :base(Interop.NetReference.Create(gcHandle, type.Handle), ownsHandle) + private NetReference(IntPtr gcHandle, UInt64 objectId, NetTypeInfo type, bool ownsHandle = true) + :base(Interop.NetReference.Create(gcHandle, objectId, type.Handle), ownsHandle) { } @@ -29,6 +30,14 @@ namespace Qml.Net.Types } } + public ulong ObjectId + { + get + { + return Interop.NetReference.GetObjectId(Handle); + } + } + public NetReference Clone() { return new NetReference(Interop.NetReference.Clone(Handle)); @@ -74,37 +83,17 @@ namespace Qml.Net.Types return type; } - private static readonly ConditionalWeakTable ObjectNetReferenceConnections = new ConditionalWeakTable(); - - public static bool ExistsForObject(object value) - { - return ObjectNetReferenceConnections.TryGetValue(value, out NetReference NetReference); - } - - public static NetReference GetForObject(object value, bool autoCreate = true) + public static NetReference CreateForObject(object value) { if (value == null) return null; - var alreadyExists = false; - if (ObjectNetReferenceConnections.TryGetValue(value, out var NetReference)) - { - alreadyExists = true; - if (GCHandle.FromIntPtr(NetReference.Handle).IsAllocated) - { - return NetReference; - } - } - if (!autoCreate) return null; - var typeInfo = NetTypeManager.GetTypeInfo(GetUnproxiedType(value.GetType()).AssemblyQualifiedName); if(typeInfo == null) throw new InvalidOperationException($"Couldn't create type info from {value.GetType().AssemblyQualifiedName}"); var handle = GCHandle.Alloc(value); - var newNetReference = new NetReference(GCHandle.ToIntPtr(handle), typeInfo); - if(alreadyExists) - { - ObjectNetReferenceConnections.Remove(value); - } - ObjectNetReferenceConnections.Add(value, newNetReference); + + var objectId = value.GetOrCreateTag(); + var newNetReference = new NetReference(GCHandle.ToIntPtr(handle), objectId, typeInfo); + return newNetReference; } @@ -114,7 +103,7 @@ namespace Qml.Net.Types public interface INetReferenceInterop { [NativeSymbol(Entrypoint = "net_instance_create")] - IntPtr Create(IntPtr handle, IntPtr type); + IntPtr Create(IntPtr handle, UInt64 objectId, IntPtr type); [NativeSymbol(Entrypoint = "net_instance_destroy")] void Destroy(IntPtr instance); [NativeSymbol(Entrypoint = "net_instance_clone")] @@ -122,6 +111,8 @@ namespace Qml.Net.Types [NativeSymbol(Entrypoint = "net_instance_getHandle")] IntPtr GetHandle(IntPtr instance); + [NativeSymbol(Entrypoint = "net_instance_getObjectId")] + UInt64 GetObjectId(IntPtr instance); [NativeSymbol(Entrypoint = "net_instance_activateSignal")] bool ActivateSignal(IntPtr instance, [MarshalAs(UnmanagedType.LPWStr)]string signalName, IntPtr variants); }