diff --git a/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs b/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs index e76554e..2d1f2eb 100644 --- a/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs +++ b/RGB.NET.Core/Devices/AbstractRGBDeviceProvider.cs @@ -12,6 +12,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider { #region Properties & Fields + private bool _isDisposed = false; + private readonly double _defaultUpdateRateHardLimit; /// @@ -60,6 +62,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider this._defaultUpdateRateHardLimit = defaultUpdateRateHardLimit; } + ~AbstractRGBDeviceProvider() => Dispose(false); + #endregion #region Methods @@ -67,6 +71,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider /// public bool Initialize(RGBDeviceType loadFilter = RGBDeviceType.All, bool throwExceptions = false) { + if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); + ThrowsExceptions = throwExceptions; try @@ -108,6 +114,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider /// The filtered collection of loaded devices. protected virtual IEnumerable GetLoadedDevices(RGBDeviceType loadFilter) { + if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); + List devices = new(); foreach (IRGBDevice device in LoadDevices()) { @@ -152,6 +160,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider /// The update trigger mapped to the specified id. protected virtual IDeviceUpdateTrigger GetUpdateTrigger(int id = -1, double? updateRateHardLimit = null) { + if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); + if (!UpdateTriggerMapping.TryGetValue(id, out IDeviceUpdateTrigger? updaeTrigger)) UpdateTriggerMapping[id] = (updaeTrigger = CreateUpdateTrigger(id, updateRateHardLimit ?? _defaultUpdateRateHardLimit)); @@ -171,6 +181,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider /// protected virtual void Reset() { + if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); + foreach (IDeviceUpdateTrigger updateTrigger in UpdateTriggerMapping.Values) updateTrigger.Dispose(); @@ -192,6 +204,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider /// true if the device was added successfully; otherwise false. protected virtual bool AddDevice(IRGBDevice device) { + if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); + if (InternalDevices.Contains(device)) return false; InternalDevices.Add(device); @@ -207,6 +221,8 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider /// true if the device was removed successfully; otherwise false. protected virtual bool RemoveDevice(IRGBDevice device) { + if (_isDisposed) throw new ObjectDisposedException(GetType().FullName); + if (!InternalDevices.Remove(device)) return false; try { OnDevicesChanged(DevicesChangedEventArgs.CreateDevicesRemovedArgs(device)); } catch { /* we don't want to throw due to bad event handlers */ } @@ -241,12 +257,26 @@ public abstract class AbstractRGBDeviceProvider : IRGBDeviceProvider protected virtual void OnDevicesChanged(DevicesChangedEventArgs args) => DevicesChanged?.Invoke(this, args); /// - public virtual void Dispose() + public void Dispose() { - Reset(); + if (_isDisposed) return; + + try + { + Dispose(true); + } + catch { /* don't throw in dispose! */ } GC.SuppressFinalize(this); + + _isDisposed = true; } + /// + /// Disposes the object and frees all resources. + /// + /// true if explicitely called through the Dispose-Method, false if called by the destructor. + protected virtual void Dispose(bool disposing) => Reset(); + #endregion } \ No newline at end of file diff --git a/RGB.NET.Devices.Asus/AsusDeviceProvider.cs b/RGB.NET.Devices.Asus/AsusDeviceProvider.cs index e3b093c..1558f6d 100644 --- a/RGB.NET.Devices.Asus/AsusDeviceProvider.cs +++ b/RGB.NET.Devices.Asus/AsusDeviceProvider.cs @@ -80,15 +80,16 @@ public sealed class AsusDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); try { _sdk?.ReleaseControl(0); } catch { /* at least we tried */ } _devices = null; _sdk = null; + _instance = null; } #endregion diff --git a/RGB.NET.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs b/RGB.NET.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs index ab16a45..be075df 100644 --- a/RGB.NET.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs +++ b/RGB.NET.Devices.CoolerMaster/CoolerMasterDeviceProvider.cs @@ -94,12 +94,14 @@ public sealed class CoolerMasterDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); try { _CoolerMasterSDK.Reload(); } catch { /* Unlucky.. */ } + + _instance = null; } #endregion diff --git a/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs b/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs index 87ab725..88f4509 100644 --- a/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs +++ b/RGB.NET.Devices.Corsair/CorsairDeviceProvider.cs @@ -300,12 +300,14 @@ public sealed class CorsairDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); try { _CUESDK.CorsairDisconnect(); } catch { /* at least we tried */ } try { _CUESDK.UnloadCUESDK(); } catch { /* at least we tried */ } + + _instance = null; } #endregion diff --git a/RGB.NET.Devices.DMX/DMXDeviceProvider.cs b/RGB.NET.Devices.DMX/DMXDeviceProvider.cs index 2d85a44..0baad66 100644 --- a/RGB.NET.Devices.DMX/DMXDeviceProvider.cs +++ b/RGB.NET.Devices.DMX/DMXDeviceProvider.cs @@ -86,5 +86,13 @@ public sealed class DMXDeviceProvider : AbstractRGBDeviceProvider return updateTrigger; } + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _instance = null; + } + #endregion } \ No newline at end of file diff --git a/RGB.NET.Devices.Debug/DebugDeviceProvider.cs b/RGB.NET.Devices.Debug/DebugDeviceProvider.cs index f88ad50..f37e4e9 100644 --- a/RGB.NET.Devices.Debug/DebugDeviceProvider.cs +++ b/RGB.NET.Devices.Debug/DebugDeviceProvider.cs @@ -66,11 +66,13 @@ public sealed class DebugDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); _fakeDeviceDefinitions.Clear(); + + _instance = null; } #endregion diff --git a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs index 4ebd163..f6a8862 100644 --- a/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs +++ b/RGB.NET.Devices.Logitech/LogitechDeviceProvider.cs @@ -254,9 +254,9 @@ public class LogitechDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); try { _LogitechGSDK.LogiLedRestoreLighting(); } catch { /* at least we tried */ } @@ -264,7 +264,7 @@ public class LogitechDeviceProvider : AbstractRGBDeviceProvider try { _LogitechGSDK.UnloadLogitechGSDK(); } catch { /* at least we tried */ } - GC.SuppressFinalize(this); + _instance = null; } #endregion diff --git a/RGB.NET.Devices.Msi/MsiDeviceProvider.cs b/RGB.NET.Devices.Msi/MsiDeviceProvider.cs index fb18827..c45a2df 100644 --- a/RGB.NET.Devices.Msi/MsiDeviceProvider.cs +++ b/RGB.NET.Devices.Msi/MsiDeviceProvider.cs @@ -98,14 +98,14 @@ public class MsiDeviceProvider : AbstractRGBDeviceProvider private void ThrowMsiError(int errorCode, bool isCritical = false) => Throw(new MysticLightException(errorCode, _MsiSDK.GetErrorMessage(errorCode)), isCritical); /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); try { _MsiSDK.UnloadMsiSDK(); } catch { /* at least we tried */ } - - GC.SuppressFinalize(this); + + _instance = null; } #endregion diff --git a/RGB.NET.Devices.Novation/NovationDeviceProvider.cs b/RGB.NET.Devices.Novation/NovationDeviceProvider.cs index 837a82c..9c9555b 100644 --- a/RGB.NET.Devices.Novation/NovationDeviceProvider.cs +++ b/RGB.NET.Devices.Novation/NovationDeviceProvider.cs @@ -67,5 +67,13 @@ public sealed class NovationDeviceProvider : AbstractRGBDeviceProvider } } + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _instance = null; + } + #endregion } \ No newline at end of file diff --git a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs index 4d19484..50647a1 100644 --- a/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs +++ b/RGB.NET.Devices.OpenRGB/OpenRGBDeviceProvider.cs @@ -107,22 +107,22 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider continue; } - if (device.Zones.Length == 0) + if (device.Zones.Length == 0) continue; - if (device.Zones.All(z => z.LedCount == 0)) + if (device.Zones.All(z => z.LedCount == 0)) continue; OpenRGBUpdateQueue updateQueue = new(GetUpdateTrigger(), i, openRgb, device); - + bool anyZoneHasSegments = device.Zones.Any(z => z.Segments.Length > 0); - bool splitDeviceByZones = anyZoneHasSegments || PerZoneDeviceFlag.HasFlag(Helper.GetRgbNetDeviceType(device.Type)); + bool splitDeviceByZones = anyZoneHasSegments || PerZoneDeviceFlag.HasFlag(Helper.GetRgbNetDeviceType(device.Type)); if (!splitDeviceByZones) { yield return new OpenRGBGenericDevice(new OpenRGBDeviceInfo(device), updateQueue); continue; } - + int totalLedCount = 0; foreach (Zone zone in device.Zones) @@ -149,9 +149,9 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); foreach (OpenRgbClient client in _clients) { @@ -161,6 +161,8 @@ public sealed class OpenRGBDeviceProvider : AbstractRGBDeviceProvider _clients.Clear(); DeviceDefinitions.Clear(); + + _instance = null; } #endregion diff --git a/RGB.NET.Devices.PicoPi/PicoPiDeviceProvider.cs b/RGB.NET.Devices.PicoPi/PicoPiDeviceProvider.cs index f18116f..debdc39 100644 --- a/RGB.NET.Devices.PicoPi/PicoPiDeviceProvider.cs +++ b/RGB.NET.Devices.PicoPi/PicoPiDeviceProvider.cs @@ -126,5 +126,13 @@ public sealed class PicoPiDeviceProvider : AbstractRGBDeviceProvider _sdks.Clear(); } + /// + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _instance = null; + } + #endregion } \ No newline at end of file diff --git a/RGB.NET.Devices.Razer/RazerDeviceProvider.cs b/RGB.NET.Devices.Razer/RazerDeviceProvider.cs index 344f96e..05c18c1 100644 --- a/RGB.NET.Devices.Razer/RazerDeviceProvider.cs +++ b/RGB.NET.Devices.Razer/RazerDeviceProvider.cs @@ -342,15 +342,17 @@ public sealed class RazerDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); TryUnInit(); // DarthAffe 03.03.2020: Fails with an access-violation - verify if an unload is already triggered by uninit //try { _RazerSDK.UnloadRazerSDK(); } //catch { /* at least we tried */ } + + _instance = null; } #endregion diff --git a/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs b/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs index 61f3254..eeeff1c 100644 --- a/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs +++ b/RGB.NET.Devices.SteelSeries/SteelSeriesDeviceProvider.cs @@ -133,12 +133,14 @@ public sealed class SteelSeriesDeviceProvider : AbstractRGBDeviceProvider protected override IDeviceUpdateTrigger CreateUpdateTrigger(int id, double updateRateHardLimit) => new DeviceUpdateTrigger(updateRateHardLimit) { HeartbeatTimer = HEARTBEAT_TIMER }; /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); try { SteelSeriesSDK.Dispose(); } catch { /* shit happens */ } + + _instance = null; } #endregion diff --git a/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs b/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs index 4d2e047..43077c8 100644 --- a/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs +++ b/RGB.NET.Devices.WS281X/WS281XDeviceProvider.cs @@ -70,11 +70,13 @@ public sealed class WS281XDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); DeviceDefinitions.Clear(); + + _instance = null; } #endregion diff --git a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs index 484bbaf..079ffb1 100644 --- a/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs +++ b/RGB.NET.Devices.Wooting/WootingDeviceProvider.cs @@ -94,15 +94,17 @@ public sealed class WootingDeviceProvider : AbstractRGBDeviceProvider } /// - public override void Dispose() + protected override void Dispose(bool disposing) { - base.Dispose(); + base.Dispose(disposing); lock (_WootingSDK.SdkLock) { try { _WootingSDK.UnloadWootingSDK(); } catch { /* at least we tried */ } } + + _instance = null; } #endregion