diff --git a/src/Core/Silk.NET.Core/Loader/UnmanagedLibrary.cs b/src/Core/Silk.NET.Core/Loader/UnmanagedLibrary.cs index 54dc3e96ad..021fd6382f 100644 --- a/src/Core/Silk.NET.Core/Loader/UnmanagedLibrary.cs +++ b/src/Core/Silk.NET.Core/Loader/UnmanagedLibrary.cs @@ -15,6 +15,8 @@ public class UnmanagedLibrary : IDisposable private static readonly LibraryLoader SPlatformDefaultLoader = LibraryLoader.GetPlatformDefaultLoader(); private readonly LibraryLoader _loader; + private nint _handle; + /// /// Constructs a new NativeLibrary using the platform's default library loader. /// @@ -55,7 +57,7 @@ public UnmanagedLibrary(string[] names, LibraryLoader loader) : this(names, load private UnmanagedLibrary(LibraryLoader loader, nint handle) { _loader = loader; - Handle = handle; + _handle = handle; } /// @@ -82,7 +84,7 @@ public static bool TryCreate(string name, LibraryLoader loader, PathResolver pat public UnmanagedLibrary(string name, LibraryLoader loader, PathResolver pathResolver) { _loader = loader; - Handle = _loader.LoadNativeLibrary(name, pathResolver); + _handle = _loader.LoadNativeLibrary(name, pathResolver); } /// @@ -94,20 +96,26 @@ public UnmanagedLibrary(string name, LibraryLoader loader, PathResolver pathReso public UnmanagedLibrary(string[] names, LibraryLoader loader, PathResolver pathResolver) { _loader = loader; - Handle = _loader.LoadNativeLibrary(names, pathResolver); + _handle = _loader.LoadNativeLibrary(names, pathResolver); } /// /// The operating system handle of the loaded library. /// - public nint Handle { get; } + public nint Handle => _handle; /// /// Frees the native library. Function pointers retrieved from this library will be void. /// public void Dispose() { + if (_handle == 0) + { + return; + } + _loader.FreeNativeLibrary(Handle); + _handle = 0; } /// diff --git a/src/Core/Silk.NET.Core/Native/NativeAPI.cs b/src/Core/Silk.NET.Core/Native/NativeAPI.cs index 39e86f6d64..bb46c64179 100644 --- a/src/Core/Silk.NET.Core/Native/NativeAPI.cs +++ b/src/Core/Silk.NET.Core/Native/NativeAPI.cs @@ -20,6 +20,13 @@ public NativeAPI(INativeContext ctx) Context = ctx; } + public override void Dispose() + { + Context.Dispose(); + + base.Dispose(); + } + /// /// Whether or not an extension is present. This function might not be valid for some APIs. /// diff --git a/src/Core/Silk.NET.Core/Native/NativeApiContainer.cs b/src/Core/Silk.NET.Core/Native/NativeApiContainer.cs index 17f5ad72d6..78b31fa24a 100644 --- a/src/Core/Silk.NET.Core/Native/NativeApiContainer.cs +++ b/src/Core/Silk.NET.Core/Native/NativeApiContainer.cs @@ -31,9 +31,8 @@ public NativeApiContainer(INativeContext ctx) public IVTable CurrentVTable => _vTable; - public void Dispose() + public virtual void Dispose() { - _ctx.Dispose(); CurrentVTable.Dispose(); } diff --git a/src/OpenAL/Silk.NET.OpenAL.Tests/ExtensionsDisposalTests.cs b/src/OpenAL/Silk.NET.OpenAL.Tests/ExtensionsDisposalTests.cs new file mode 100644 index 0000000000..a9ce80f39a --- /dev/null +++ b/src/OpenAL/Silk.NET.OpenAL.Tests/ExtensionsDisposalTests.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using Silk.NET.OpenAL.Extensions.Enumeration; +using Xunit; + +namespace Silk.NET.OpenAL.Tests; + +public class ExtensionsDisposalTests +{ + private static nint GetProcAddress(ALContext alc) => + alc.Context.GetProcAddress("alcIsExtensionPresent"); + + [Fact] + public unsafe void TestALContextExtensionDispose() + { + var alc = ALContext.GetApi(); + alc.TryGetExtension(null, out var ext); + + // Disposing the same object multiple times should not throw + ext.Dispose(); + alc.Dispose(); + + alc.Dispose(); + ext.Dispose(); + } + + [Fact] + public unsafe void TestALContextExtensionDisposeState() + { + using var alc = ALContext.GetApi(); + alc.TryGetExtension(null, out var ext); + + var address = GetProcAddress(alc); + Assert.NotEqual(0, address); + + ext.Dispose(); + + // Disposing the extension should not affect the parent context + address = GetProcAddress(alc); + Assert.NotEqual(0, address); + } +}