Skip to content

Commit a0f5fb2

Browse files
Add DllMap sample (#668)
Add DllMap sample Add a sample to demonstrate the use of NativeLibrary APIs to map library names during resolution.
1 parent 5a7f8ee commit a0f5fb2

File tree

6 files changed

+127
-0
lines changed

6 files changed

+127
-0
lines changed

core/extensions/DllMapDemo/Demo.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
using System.IO;
3+
using System.Reflection;
4+
using System.Runtime.InteropServices;
5+
6+
public class DllMapDemo
7+
{
8+
public static void Main()
9+
{
10+
try
11+
{
12+
DllMap.Register(Assembly.GetExecutingAssembly());
13+
int thirty = NativeSum(10, 20);
14+
Console.WriteLine($"OldLib.NativeSum(10,20) = {thirty}");
15+
}
16+
catch (Exception e)
17+
{
18+
Console.WriteLine($"Error: {e.Message} Line: {e.Source}");
19+
}
20+
}
21+
22+
[DllImport("OldLib")]
23+
static extern int NativeSum(int arg1, int arg2);
24+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>Exe</OutputType>
4+
<TargetFramework>netcoreapp3.0</TargetFramework>
5+
</PropertyGroup>
6+
<ItemGroup>
7+
<None Include="Demo.xml">
8+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
9+
</None>
10+
</ItemGroup>
11+
</Project>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<configuration>
2+
<dllmap dll="OldLib" target="NewLib"/>
3+
</configuration>

core/extensions/DllMapDemo/Map.cs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using System;
2+
using System.Collections;
3+
using System.IO;
4+
using System.Linq;
5+
using System.Reflection;
6+
using System.Runtime.InteropServices;
7+
using System.Xml.Linq;
8+
9+
public static class DllMap
10+
{
11+
// Register a call-back for native library resolution.
12+
public static void Register(Assembly assembly)
13+
{
14+
NativeLibrary.SetDllImportResolver(assembly, MapAndLoad);
15+
}
16+
17+
// The callback: which loads the mapped libray in place of the original
18+
private static IntPtr MapAndLoad(string libraryName, Assembly assembly, DllImportSearchPath? dllImportSearchPath)
19+
{
20+
string mappedName = null;
21+
mappedName = MapLibraryName(assembly.Location, libraryName, out mappedName) ? mappedName : libraryName;
22+
return NativeLibrary.Load(mappedName, assembly, dllImportSearchPath);
23+
}
24+
25+
// Parse the assembly.xml file, and map the old name to the new name of a library.
26+
private static bool MapLibraryName(string assemblyLocation, string originalLibName, out string mappedLibName)
27+
{
28+
string xmlPath = Path.Combine(Path.GetDirectoryName(assemblyLocation),
29+
Path.GetFileNameWithoutExtension(assemblyLocation) + ".xml");
30+
mappedLibName = null;
31+
32+
if (!File.Exists(xmlPath))
33+
return false;
34+
35+
XElement root = XElement.Load(xmlPath);
36+
var map =
37+
(from el in root.Elements("dllmap")
38+
where (string)el.Attribute("dll") == originalLibName
39+
select el).SingleOrDefault();
40+
41+
if (map != null)
42+
mappedLibName = map.Attribute("target").Value;
43+
44+
return (mappedLibName != null);
45+
}
46+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdio.h>
2+
3+
#if defined(__GNUC__)
4+
#define EXPORT extern "C" __attribute__((visibility("default")))
5+
#elif defined(_MSC_VER)
6+
#define EXPORT extern "C" __declspec(dllexport)
7+
#endif
8+
9+
extern "C" EXPORT int NativeSum(int a, int b)
10+
{
11+
return a + b;
12+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# DllMap Demo
2+
3+
This sample illustrates the use of NativeLibrary APIs to implement library name mappings similar to the [Mono](https://www.mono-project.com/) [Dllmap](http://www.mono-project.com/docs/advanced/pinvoke/dllmap/) feature.
4+
5+
## NativeLibrary APIs
6+
7+
.Net Core 3.0 provides a rich set of APIs to manage native libraries:
8+
9+
- [NativeLibrary APIs](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary?view=netcore-3.0): Perform operations on native libraries (such as `Load()`, `Free()`, get the address of an exported symbol, etc.) in a platform-independent way from managed code.
10+
- [DllImport Resolver callback](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.nativelibrary.setdllimportresolver?view=netcore-3.0): Gets a callback for first-chance native library resolution using custom logic.
11+
- [Native Library Resolve event](https://docs.microsoft.com/en-us/dotnet/api/system.runtime.loader.assemblyloadcontext.resolvingunmanageddll?view=netcore-3.0): Get an event for last-chance native library resolution using custom logic.
12+
13+
## Library Mapping
14+
15+
These APIs can be used to implement custom native library resolution logic, including DllMap, as illustrated in this example. The sample demonstrates:
16+
17+
- An [app](Demo.cs) that pInvokes a method in `OldLib`, but runs in an environment where only [`NewLib`](NewLib.cpp) is available.
18+
- The [XML file](Demo.xml) that maps the library name from `OldLib` to `NewLib`.
19+
- The [Map](Map.cs) implementation, which parses the above mapping and uses `NativeLibrary` APIs to load the correct library.
20+
21+
## Build and Run
22+
23+
1. Install .NET Core 3.0 Preview 3 or newer.
24+
25+
2. Use the .NET Core SDK to build the project via `dotnet build`.
26+
27+
3. Build the native component `NewLib.cpp` as a dynamic library, using the platform's native toolset.
28+
29+
Place the generated native library (`NewLib.dll` / `libNewLib.so` / `libNewLib.dylib`) in the `dotnet build` output directory.
30+
31+
4. Run the app with `dotnet run`

0 commit comments

Comments
 (0)