Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Custom Symbol/Library loading logic #84

Merged
merged 13 commits into from
Jun 30, 2019
51 changes: 51 additions & 0 deletions AdvancedDLSupport.Tests/Data/Classes/LibraryLoadingOverride.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// LibraryLoadingOverride.cs
//
// Copyright (c) 2018 Firwood Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

using System;
using AdvancedDLSupport.Loaders;
using JetBrains.Annotations;

#pragma warning disable SA1600, CS1591

namespace AdvancedDLSupport.Tests.Data.Classes
{
internal class LibraryLoadingOverride : ILibraryLoader
{
private readonly ILibraryLoader _defaultLoader;

public bool LoadLibraryCalled { get; private set; }

public LibraryLoadingOverride(ILibraryLoader @default)
{
_defaultLoader = @default;
}

public IntPtr LoadLibrary([CanBeNull] string path)
{
LoadLibraryCalled = true;

return _defaultLoader.LoadLibrary(path);
}

public bool CloseLibrary(IntPtr library)
{
return _defaultLoader.CloseLibrary(library);
}
}
}
46 changes: 46 additions & 0 deletions AdvancedDLSupport.Tests/Data/Classes/SymbolLoadingOverride.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//
// SymbolLoadingOverride.cs
//
// Copyright (c) 2018 Firwood Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

using System;
using AdvancedDLSupport.Loaders;
using JetBrains.Annotations;

#pragma warning disable SA1600, CS1591

namespace AdvancedDLSupport.Tests.Data.Classes
{
internal class SymbolLoadingOverride : ISymbolLoader
{
private readonly ISymbolLoader _defaultLoader;

public bool LoadSymbolCalled { get; private set; }

public SymbolLoadingOverride(ISymbolLoader @default)
{
_defaultLoader = @default;
}

public IntPtr LoadSymbol(IntPtr library, [NotNull] string symbolName)
{
LoadSymbolCalled = true;

return _defaultLoader.LoadSymbol(library, symbolName == "GetString" ? "GetNullString" : symbolName);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// ICustomLoadingLogicTests.cs
//
// Copyright (c) 2018 Firwood Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

#pragma warning disable SA1600, CS1591

namespace AdvancedDLSupport.Tests.Data
{
public interface ICustomLoadingLogicTests
{
int ReturnsOne();

int ReturnsTwo();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// CustomLoadingLogicTests.cs
//
// Copyright (c) 2018 Firwood Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

using AdvancedDLSupport.Tests.Data;
using AdvancedDLSupport.Tests.Data.Classes;
using AdvancedDLSupport.Tests.TestBases;
using Xunit;

#pragma warning disable SA1600, CS1591

namespace AdvancedDLSupport.Tests.Integration
{
public class CustomLoadingLogicTests : LibraryTestBase<IStringLibrary>
{
private const string LibraryName = "StringTests";

private LibraryLoadingOverride _libraryLogicOverride;
private SymbolLoadingOverride _symbolLogicOverride;

public CustomLoadingLogicTests()
: base(LibraryName)
{
}

protected override ImplementationOptions GetImplementationOptions()
{
return base.GetImplementationOptions() | ImplementationOptions.UseLazyBinding;
}

protected override NativeLibraryBuilder GetImplementationBuilder()
{
return base.GetImplementationBuilder().WithLibraryLoader(@default =>
{
_libraryLogicOverride = new LibraryLoadingOverride(@default);
return _libraryLogicOverride;
}).WithSymbolLoader(@default =>
{
_symbolLogicOverride = new SymbolLoadingOverride(@default);
return _symbolLogicOverride;
});
}

[Fact]
public void CustomLogicCalled()
{
Library.GetString();
Assert.True(_libraryLogicOverride.LoadLibraryCalled);
Assert.True(_symbolLogicOverride.LoadSymbolCalled);
}

[Fact]
public void CustomLogicSuccessful()
{
Assert.Equal(Library.GetString(), Library.GetNullString());
}
}
}
11 changes: 11 additions & 0 deletions AdvancedDLSupport.Tests/c/src/CustomLoadingLogicTests.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#include <stdint.h>

__declspec(dllexport) int32_t ReturnsOne()
{
return 1;
}

__declspec(dllexport) int32_t ReturnsTwo()
{
return 2;
}
48 changes: 48 additions & 0 deletions AdvancedDLSupport/Loaders/ILibraryLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
//
// ILibraryLoader.cs
//
// Copyright (c) 2018 Firwood Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

using System;
using JetBrains.Annotations;

namespace AdvancedDLSupport.Loaders
{
/// <summary>
/// Represents a class which can load libraries on a specific platform.
/// </summary>
public interface ILibraryLoader
{
/// <summary>
/// Load the given library. A null path signifies intent to load the main executable instead of an external
/// library.
/// </summary>
/// <param name="path">The path to the library.</param>
/// <returns>A handle to the library. This value carries no intrinsic meaning.</returns>
/// <exception cref="LibraryLoadingException">Thrown if the library could not be loaded.</exception>
[PublicAPI]
IntPtr LoadLibrary([CanBeNull] string path);

/// <summary>
/// Closes the open handle to the given library.
/// </summary>
/// <param name="library">The handle to the library to close.</param>
/// <returns>true if the library was closed successfully; otherwise, false.</returns>
[PublicAPI]
bool CloseLibrary(IntPtr library);
}
}
40 changes: 1 addition & 39 deletions AdvancedDLSupport/Loaders/IPlatformLoader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

using System;
using JetBrains.Annotations;

namespace AdvancedDLSupport.Loaders
Expand All @@ -26,44 +25,7 @@ namespace AdvancedDLSupport.Loaders
/// Represents a class which can load libraries and symbols on a specific platform.
/// </summary>
[PublicAPI]
public interface IPlatformLoader
public interface IPlatformLoader : ISymbolLoader, ILibraryLoader
{
/// <summary>
/// Loads the given symbol name and marshals it into a function delegate.
/// </summary>
/// <param name="library">The library handle.</param>
/// <param name="symbolName">The name of the symbol.</param>
/// <typeparam name="T">The delegate type to marshal.</typeparam>
/// <returns>A marshalled delegate.</returns>
[PublicAPI, NotNull, Pure]
T LoadFunction<T>(IntPtr library, [NotNull] string symbolName);

/// <summary>
/// Load the given library. A null path signifies intent to load the main executable instead of an external
/// library.
/// </summary>
/// <param name="path">The path to the library.</param>
/// <returns>A handle to the library. This value carries no intrinsic meaning.</returns>
/// <exception cref="LibraryLoadingException">Thrown if the library could not be loaded.</exception>
[PublicAPI]
IntPtr LoadLibrary([CanBeNull] string path);

/// <summary>
/// Load the given symbol.
/// </summary>
/// <param name="library">The handle to the library in which the symbol exists.</param>
/// <param name="symbolName">The name of the symbol to load.</param>
/// <exception cref="SymbolLoadingException">Thrown if the symbol could not be loaded.</exception>
/// <returns>A handle to the symbol.</returns>
[PublicAPI, Pure]
IntPtr LoadSymbol(IntPtr library, [NotNull] string symbolName);

/// <summary>
/// Closes the open handle to the given library.
/// </summary>
/// <param name="library">The handle to the library to close.</param>
/// <returns>true if the library was closed successfully; otherwise, false.</returns>
[PublicAPI]
bool CloseLibrary(IntPtr library);
}
}
40 changes: 40 additions & 0 deletions AdvancedDLSupport/Loaders/ISymbolLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//
// ISymbolLoader.cs
//
// Copyright (c) 2018 Firwood Software
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//

using System;
using JetBrains.Annotations;

namespace AdvancedDLSupport.Loaders
{
/// <summary>
/// Represents a class which can load symbols on a specific platform.
/// </summary>
public interface ISymbolLoader
{
/// <summary>
/// Load the given symbol.
/// </summary>
/// <param name="library">The handle to the library in which the symbol exists.</param>
/// <param name="symbolName">The name of the symbol to load.</param>
/// <exception cref="SymbolLoadingException">Thrown if the symbol could not be loaded.</exception>
/// <returns>A handle to the symbol.</returns>
[PublicAPI, Pure]
IntPtr LoadSymbol(IntPtr library, [NotNull] string symbolName);
}
}
9 changes: 5 additions & 4 deletions AdvancedDLSupport/Loaders/PlatformLoaderBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ namespace AdvancedDLSupport.Loaders
[PublicAPI]
public abstract class PlatformLoaderBase : IPlatformLoader
{
/// <inheritdoc />
public T LoadFunction<T>(IntPtr library, string symbolName) =>
Marshal.GetDelegateForFunctionPointer<T>(LoadSymbol(library, symbolName));
/// <summary>
/// Gets a cached instance of the current platform's default loader.
/// </summary>
public static IPlatformLoader PlatformLoader { get; } = SelectPlatformLoader();

/// <inheritdoc />
public IntPtr LoadLibrary(string path) => LoadLibraryInternal(path);
Expand All @@ -57,7 +58,7 @@ public T LoadFunction<T>(IntPtr library, string symbolName) =>
/// <returns>A platform loader for the current platform..</returns>
/// <exception cref="PlatformNotSupportedException">Thrown if the current platform is not supported.</exception>
[PublicAPI, NotNull, Pure]
public static IPlatformLoader SelectPlatformLoader()
private static IPlatformLoader SelectPlatformLoader()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note to self: run an attribute cleanup sometime in the future.

{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Expand Down
Loading