Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions src/Core/Silk.NET.Core/Loader/UnmanagedLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ public class UnmanagedLibrary : IDisposable
private static readonly LibraryLoader SPlatformDefaultLoader = LibraryLoader.GetPlatformDefaultLoader();
private readonly LibraryLoader _loader;

private nint _handle;

/// <summary>
/// Constructs a new NativeLibrary using the platform's default library loader.
/// </summary>
Expand Down Expand Up @@ -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;
}

/// <summary>
Expand All @@ -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);
}

/// <summary>
Expand All @@ -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);
}

/// <summary>
/// The operating system handle of the loaded library.
/// </summary>
public nint Handle { get; }
public nint Handle => _handle;

/// <summary>
/// Frees the native library. Function pointers retrieved from this library will be void.
/// </summary>
public void Dispose()
{
if (_handle == 0)
{
return;
}

_loader.FreeNativeLibrary(Handle);
_handle = 0;
}

/// <summary>
Expand Down
7 changes: 7 additions & 0 deletions src/Core/Silk.NET.Core/Native/NativeAPI.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ public NativeAPI(INativeContext ctx)
Context = ctx;
}

public override void Dispose()
{
Context.Dispose();

base.Dispose();
}

/// <summary>
/// Whether or not an extension is present. This function might not be valid for some APIs.
/// </summary>
Expand Down
3 changes: 1 addition & 2 deletions src/Core/Silk.NET.Core/Native/NativeApiContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,8 @@ public NativeApiContainer(INativeContext ctx)

public IVTable CurrentVTable => _vTable;

public void Dispose()
public virtual void Dispose()
{
_ctx.Dispose();
CurrentVTable.Dispose();
}

Expand Down
43 changes: 43 additions & 0 deletions src/OpenAL/Silk.NET.OpenAL.Tests/ExtensionsDisposalTests.cs
Original file line number Diff line number Diff line change
@@ -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<Enumeration>(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<Enumeration>(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);
}
}