Skip to content

Commit 6356007

Browse files
committed
fix failure to load with "Ambiguous match found" exception in Mono 5
1 parent 62501de commit 6356007

File tree

2 files changed

+37
-33
lines changed

2 files changed

+37
-33
lines changed

RocksDbSharp/AutoNativeImport.cs

Lines changed: 36 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -46,13 +46,34 @@ public interface INativeLibImporter
4646
IntPtr GetProcAddress(IntPtr lib, string entryPoint);
4747
void FreeLibrary(IntPtr lib);
4848
string Translate(string name);
49+
object GetDelegate(IntPtr lib, string entryPoint, Type delegateType);
4950
}
5051

5152
public static class Importers
5253
{
5354
public static INativeLibImporter Windows = new WindowsImporter();
5455
public static INativeLibImporter Posix = new PosixImporter();
5556

57+
static object GetDelegate(INativeLibImporter importer, IntPtr lib, string entryPoint, Type delegateType)
58+
{
59+
IntPtr procAddress = importer.GetProcAddress(lib, entryPoint);
60+
if (procAddress == IntPtr.Zero)
61+
{
62+
var invokeMethod = delegateType.GetTypeInfo().GetMethod("Invoke");
63+
var parameters = invokeMethod.GetParameters().Select(p => Expression.Parameter(p.ParameterType)).ToArray();
64+
var returnType = invokeMethod.ReturnType;
65+
var errorMessage = string.Format("Unable to get address of {0} ({1})", entryPoint, delegateType);
66+
Action throwAction = () => throw new NativeLoadException(errorMessage, null);
67+
var callThrowExpr = Expression.Constant(throwAction, typeof(Action));
68+
var defaultExpr = Expression.Default(returnType);
69+
var block = Expression.Block(returnType, Expression.Invoke(callThrowExpr), defaultExpr);
70+
var lambda = Expression.Lambda(delegateType, block, parameters);
71+
return lambda.Compile();
72+
}
73+
var method = typeof(CurrentFramework).GetTypeInfo().GetMethod(nameof(CurrentFramework.GetDelegateForFunctionPointer)).MakeGenericMethod(delegateType);
74+
return method.Invoke(null, new object[] { procAddress });
75+
}
76+
5677
private class WindowsImporter : INativeLibImporter
5778
{
5879
[DllImport("kernel32.dll", EntryPoint = "LoadLibrary", SetLastError = true)]
@@ -78,6 +99,9 @@ public IntPtr GetProcAddress(IntPtr lib, string entryPoint)
7899
return address;
79100
}
80101

102+
public object GetDelegate(IntPtr lib, string entryPoint, Type delegateType)
103+
=> Importers.GetDelegate(this, lib, entryPoint, delegateType);
104+
81105
public void FreeLibrary(IntPtr lib)
82106
{
83107
WinFreeLibrary(lib);
@@ -161,6 +185,9 @@ public IntPtr GetProcAddress(IntPtr lib, string entryPoint)
161185
return address;
162186
}
163187

188+
public object GetDelegate(IntPtr lib, string entryPoint, Type delegateType)
189+
=> Importers.GetDelegate(this, lib, entryPoint, delegateType);
190+
164191
public void FreeLibrary(IntPtr lib)
165192
{
166193
dlclose(lib);
@@ -172,31 +199,6 @@ public string Translate(string name)
172199
}
173200
}
174201

175-
public static class U
176-
{
177-
public static T LoadFunc<T>(INativeLibImporter importer, IntPtr libraryHandle, string entryPoint)
178-
{
179-
IntPtr procAddress = importer.GetProcAddress(libraryHandle, entryPoint);
180-
if (procAddress == IntPtr.Zero)
181-
{
182-
throw new Exception($"Cannot get proc address of {entryPoint}");
183-
/*
184-
var invokeMethod = typeof(T).GetTypeInfo().GetMethod("Invoke");
185-
var parameters = invokeMethod.GetParameters().Select(p => Expression.Parameter(p.ParameterType)).ToArray();
186-
var returnType = invokeMethod.ReturnType;
187-
var errorMessage = string.Format("Unable to get address of {0} ({1})", entryPoint, typeof(T));
188-
Action throwAction = () => throw new NativeLoadException(errorMessage, null);
189-
var callThrowExpr = Expression.Constant(throwAction, typeof(Action));
190-
var defaultExpr = Expression.Default(returnType);
191-
var block = Expression.Block(returnType, Expression.Invoke(callThrowExpr), defaultExpr);
192-
var lambda = Expression.Lambda<T>(block, parameters);
193-
return lambda.Compile();
194-
*/
195-
}
196-
return CurrentFramework.GetDelegateForFunctionPointer<T>(procAddress);
197-
}
198-
}
199-
200202
public static string GetArchName(Architecture arch)
201203
{
202204
switch (arch)
@@ -241,8 +243,7 @@ public static T Import<T>(INativeLibImporter importer, string libName, string ve
241243
MethodInfo = m,
242244
DelegateType = delegateMap[GetMethodSig(m)],
243245
}).ToArray();
244-
var fields = delegates.Select(d => typeBuilder.DefineField(d.MethodInfo.Name + "_func", d.DelegateType, FieldAttributes.Private)).ToArray();
245-
246+
var fields = delegates.Select((d, i) => typeBuilder.DefineField($"{d.MethodInfo.Name}_func_{i}", d.DelegateType, FieldAttributes.Private)).ToArray();
246247

247248
// Create the constructor which will initialize the importer and library handle
248249
// and also use the importer to populate each of the delegate fields
@@ -266,19 +267,22 @@ public static T Import<T>(INativeLibImporter importer, string libName, string ve
266267
il.Emit(OpCodes.Ldarg_2); // library handle
267268
il.Emit(OpCodes.Stfld, field_libraryHandle);
268269

270+
var getDelegateMethod = typeof(INativeLibImporter).GetTypeInfo().GetMethod("GetDelegate");
269271
// Initialize each delegate field
270272
for (int i = 0; i < fields.Length; i++)
271273
{
274+
var delegateType = delegates[i].DelegateType;
275+
272276
il.Emit(OpCodes.Ldarg_0); // this
277+
273278
il.Emit(OpCodes.Ldarg_1); // importer
274279
il.Emit(OpCodes.Ldarg_0); // this
275280
il.Emit(OpCodes.Ldfld, field_libraryHandle);
276281
il.Emit(OpCodes.Ldstr, delegates[i].MethodInfo.Name); // use method name from original class as entry point
277-
var delegateType = delegates[i].DelegateType;
278-
//il.Emit(OpCodes.Ldtoken, delegateType); // the delegate type
279-
//il.Emit(OpCodes.Call, typeof(System.Type).GetTypeInfo().GetMethod("GetTypeFromHandle")); // typeof()
280-
il.Emit(OpCodes.Call, typeof(U).GetTypeInfo().GetMethod("LoadFunc").MakeGenericMethod(delegateType)); // U.LoadFunc<delegate type>()
281-
//il.Emit(OpCodes.Isinst, delegates[i].DelegateType); // as <delegate type>
282+
il.Emit(OpCodes.Ldtoken, delegateType); // the delegate type
283+
il.Emit(OpCodes.Call, typeof(System.Type).GetTypeInfo().GetMethod("GetTypeFromHandle")); // typeof()
284+
il.Emit(OpCodes.Callvirt, getDelegateMethod); // importer.GetDelegate()
285+
il.Emit(OpCodes.Isinst, delegateType); // as <delegate type>
282286
il.Emit(OpCodes.Stfld, fields[i]);
283287
}
284288

RocksDbSharp/Transitional.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public static unsafe string CreateString(sbyte* value, int startIndex, int lengt
6868
=> new string(value, startIndex, length, enc);
6969
#endif
7070

71-
internal static T GetDelegateForFunctionPointer<T>(IntPtr ptr)
71+
public static T GetDelegateForFunctionPointer<T>(IntPtr ptr)
7272
#if NETSTANDARD1_6
7373
=> Marshal.GetDelegateForFunctionPointer<T>(ptr);
7474
#else

0 commit comments

Comments
 (0)