diff --git a/RGB.NET.Core/Devices/AbstractRGBDevice.cs b/RGB.NET.Core/Devices/AbstractRGBDevice.cs index 6ac90da..596625c 100644 --- a/RGB.NET.Core/Devices/AbstractRGBDevice.cs +++ b/RGB.NET.Core/Devices/AbstractRGBDevice.cs @@ -85,6 +85,8 @@ public abstract class AbstractRGBDevice : Placeable, IRGBDevice : Placeable, IRGBDevice public virtual void Dispose() { - try { UpdateQueue.Dispose(); } catch { /* :( */ } + try + { + UpdateQueue.RemoveReferencingObject(this); + if (!UpdateQueue.HasActiveReferences()) + UpdateQueue.Dispose(); + } + catch { /* :( */ } try { LedMapping.Clear(); } catch { /* this really shouldn't happen */ } IdGenerator.ResetCounter(GetType().Assembly); diff --git a/RGB.NET.Core/Extensions/ReferenceCountingExtension.cs b/RGB.NET.Core/Extensions/ReferenceCountingExtension.cs new file mode 100644 index 0000000..58039eb --- /dev/null +++ b/RGB.NET.Core/Extensions/ReferenceCountingExtension.cs @@ -0,0 +1,6 @@ +namespace RGB.NET.Core; + +public static class ReferenceCountingExtension +{ + public static bool HasActiveReferences(this IReferenceCounting target) => target.ActiveReferenceCount > 0; +} \ No newline at end of file diff --git a/RGB.NET.Core/Misc/AbstractReferenceCounting.cs b/RGB.NET.Core/Misc/AbstractReferenceCounting.cs new file mode 100644 index 0000000..070138a --- /dev/null +++ b/RGB.NET.Core/Misc/AbstractReferenceCounting.cs @@ -0,0 +1,41 @@ +using System.Collections.Generic; + +namespace RGB.NET.Core; + +public abstract class AbstractReferenceCounting : IReferenceCounting +{ + #region Properties & Fields + + private readonly HashSet _referencingObjects = new(); + + /// + public int ActiveReferenceCount + { + get + { + lock (_referencingObjects) + return _referencingObjects.Count; + } + } + + #endregion + + #region Methods + + /// + public void AddReferencingObject(object obj) + { + lock (_referencingObjects) + if (!_referencingObjects.Contains(obj)) + _referencingObjects.Add(obj); + } + + /// + public void RemoveReferencingObject(object obj) + { + lock (_referencingObjects) + _referencingObjects.Remove(obj); + } + + #endregion +} \ No newline at end of file diff --git a/RGB.NET.Core/Misc/IReferenceCounting.cs b/RGB.NET.Core/Misc/IReferenceCounting.cs new file mode 100644 index 0000000..d8bcb28 --- /dev/null +++ b/RGB.NET.Core/Misc/IReferenceCounting.cs @@ -0,0 +1,21 @@ +namespace RGB.NET.Core; + +public interface IReferenceCounting +{ + /// + /// Gets the amount of currently registered referencing objects. + /// + public int ActiveReferenceCount { get; } + + /// + /// Adds the given object to the list of referencing objects. + /// + /// The object to add. + public void AddReferencingObject(object obj); + + /// + /// Removes the given object from the list of referencing objects. + /// + /// The object to remove. + public void RemoveReferencingObject(object obj); +} \ No newline at end of file diff --git a/RGB.NET.Core/RGB.NET.Core.csproj.DotSettings b/RGB.NET.Core/RGB.NET.Core.csproj.DotSettings index bf7655f..7f9a6e2 100644 --- a/RGB.NET.Core/RGB.NET.Core.csproj.DotSettings +++ b/RGB.NET.Core/RGB.NET.Core.csproj.DotSettings @@ -16,6 +16,7 @@ True True True + True True True True diff --git a/RGB.NET.Core/Update/Devices/IUpdateQueue.cs b/RGB.NET.Core/Update/Devices/IUpdateQueue.cs index 348c16e..bf4011c 100644 --- a/RGB.NET.Core/Update/Devices/IUpdateQueue.cs +++ b/RGB.NET.Core/Update/Devices/IUpdateQueue.cs @@ -8,7 +8,7 @@ namespace RGB.NET.Core; /// /// The identifier used to identify the data processed by this queue. /// The type of the data processed by this queue. -public interface IUpdateQueue : IDisposable +public interface IUpdateQueue : IReferenceCounting, IDisposable where TIdentifier : notnull { /// diff --git a/RGB.NET.Core/Update/Devices/UpdateQueue.cs b/RGB.NET.Core/Update/Devices/UpdateQueue.cs index 1cc5eca..72cec7e 100644 --- a/RGB.NET.Core/Update/Devices/UpdateQueue.cs +++ b/RGB.NET.Core/Update/Devices/UpdateQueue.cs @@ -10,7 +10,7 @@ namespace RGB.NET.Core; /// /// The type of the key used to identify some data. /// The type of the data. -public abstract class UpdateQueue : IUpdateQueue +public abstract class UpdateQueue : AbstractReferenceCounting, IUpdateQueue where TIdentifier : notnull { #region Properties & Fields diff --git a/RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs b/RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs index fa743e8..8bea2eb 100644 --- a/RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs +++ b/RGB.NET.Devices.Corsair/Generic/CorsairDeviceUpdateQueue.cs @@ -13,6 +13,8 @@ public class CorsairDeviceUpdateQueue : UpdateQueue { #region Properties & Fields + private bool _isDisposed = false; + private readonly _CorsairDeviceInfo _device; private readonly nint _colorPtr; @@ -42,6 +44,7 @@ public class CorsairDeviceUpdateQueue : UpdateQueue { try { + if (_isDisposed) throw new ObjectDisposedException(nameof(CorsairDeviceUpdateQueue)); if (!_CUESDK.IsConnected) return false; Span<_CorsairLedColor> colors = new((void*)_colorPtr, dataSet.Length); @@ -71,6 +74,7 @@ public class CorsairDeviceUpdateQueue : UpdateQueue { base.Dispose(); + _isDisposed = true; Marshal.FreeHGlobal(_colorPtr); GC.SuppressFinalize(this); diff --git a/RGB.NET.Devices.Razer/RazerDeviceProvider.cs b/RGB.NET.Devices.Razer/RazerDeviceProvider.cs index f31174e..04edecc 100644 --- a/RGB.NET.Devices.Razer/RazerDeviceProvider.cs +++ b/RGB.NET.Devices.Razer/RazerDeviceProvider.cs @@ -108,6 +108,7 @@ public class RazerDeviceProvider : AbstractRGBDeviceProvider { 0x0266, RGBDeviceType.Keyboard, "Huntsman V2", LedMappings.Keyboard, RazerEndpointType.Keyboard }, { 0x026C, RGBDeviceType.Keyboard, "Huntsman V2", LedMappings.Keyboard, RazerEndpointType.Keyboard }, { 0x028D, RGBDeviceType.Keyboard, "BlackWidow V4", LedMappings.Keyboard, RazerEndpointType.Keyboard }, + { 0x02A1, RGBDeviceType.Keyboard, "Ornata V3", LedMappings.Keyboard, RazerEndpointType.Keyboard }, // Mice { 0x0013, RGBDeviceType.Mouse, "Orochi 2011", LedMappings.Mouse, RazerEndpointType.Mouse },