Skip to content

Commit a9b7c25

Browse files
committed
Added support for more [DllImport] properties
New properties are: BestFitMapping, CallingConvention, CharSet, SetLastError, ThrowOnUnmappableChar. Removed unused parameter modifiers, becouse they are currently not implemented in .NET (ParameterInfo has bunch of empty array returns and NotImplementedException throws).
1 parent 0982a99 commit a9b7c25

3 files changed

Lines changed: 52 additions & 101 deletions

File tree

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ Doing so involves mocking original native method calls with these made to manual
88
- Api Compatibility Level >= .NET 4.x
99

1010
## Limitations
11-
- All `[DllImport]` properties except for `dllName` and `EntryPoint` are not supported
1211
- All marshaling attributes such as `[MarshalAs]` or `[In]` are not supported
12+
- `[DllImport]` properties `ExactSpelling` and `PreserveSig` are not supported
1313
- Multithreading is not supported (native calls from any but Unity main thread)
1414

1515
## Preformance
@@ -126,3 +126,4 @@ class AllInOne : MonoBehaviour
126126
- Thread safety
127127
- Mac support
128128
- Possibly break depencency on Harmony
129+
- Better names

src/DllManipulator.cs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class DllManipulator : MonoBehaviour
1717
public const string DLL_PATH_PATTERN_ASSETS_MACRO = "{assets}";
1818
public const string DLL_PATH_PATTERN_PROJECT_MACRO = "{proj}";
1919
private static readonly Type[] DELEGATE_CTOR_PARAMETERS = new[] { typeof(object), typeof(IntPtr) };
20+
private static readonly Type[] UNMANAGED_FUNCTION_POINTER_ATTRIBUTE_CTOR_PARAMETERS = new[] { typeof(CallingConvention) };
2021

2122
public DllManipulatorOptions Options = new DllManipulatorOptions()
2223
{
@@ -251,10 +252,11 @@ private static DynamicMethod CreateNewNativeFunctionMock(MethodInfo nativeMethod
251252

252253
var parameters = nativeMethod.GetParameters();
253254
var parametersTypes = parameters.Select(x => x.ParameterType).ToArray();
254-
var nativeMethodSignature = new NativeFunctionSignature(nativeMethod, dllImportAttr.CallingConvention);
255+
var nativeMethodSignature = new NativeFunctionSignature(nativeMethod, dllImportAttr.CallingConvention,
256+
dllImportAttr.BestFitMapping, dllImportAttr.CharSet, dllImportAttr.SetLastError, dllImportAttr.ThrowOnUnmappableChar);
255257
if (!_delegateTypesForNativeFunctionSignatures.TryGetValue(nativeMethodSignature, out nativeFunction.delegateType))
256258
{
257-
nativeFunction.delegateType = CreateDelegateTypeForMethodSignature(nativeMethodSignature);
259+
nativeFunction.delegateType = CreateDelegateTypeForNativeFunctionSignature(nativeMethodSignature);
258260
_delegateTypesForNativeFunctionSignatures.Add(nativeMethodSignature, nativeFunction.delegateType);
259261
}
260262
var targetDelegateInvokeMethod = nativeFunction.delegateType.GetMethod("Invoke", BindingFlags.Instance | BindingFlags.Public);
@@ -331,7 +333,7 @@ private static void AddNativeFunction(NativeFunction nativeFunction)
331333
_nativeFunctions[_nativeFunctionsCount++] = nativeFunction;
332334
}
333335

334-
private static Type CreateDelegateTypeForMethodSignature(NativeFunctionSignature methodSignature)
336+
private static Type CreateDelegateTypeForNativeFunctionSignature(NativeFunctionSignature funcionSignature)
335337
{
336338
if (_customDelegateTypesModule == null)
337339
{
@@ -343,19 +345,34 @@ private static Type CreateDelegateTypeForMethodSignature(NativeFunctionSignature
343345
var delBuilder = _customDelegateTypesModule.DefineType("HelperNativeDelegate" + _createdDelegateTypes.ToString(),
344346
TypeAttributes.Class | TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.AutoClass, typeof(MulticastDelegate));
345347

348+
//ufp = UnmanagedFunctionPointer
349+
var ufpAttrType = typeof(UnmanagedFunctionPointerAttribute);
350+
var ufpAttrCtor = ufpAttrType.GetConstructor(UNMANAGED_FUNCTION_POINTER_ATTRIBUTE_CTOR_PARAMETERS);
351+
var ufpAttrCtorArgValues = new object[] { funcionSignature.callingConvention };
352+
var ufpAttrNamedFields = new [] {
353+
ufpAttrType.GetField(nameof(UnmanagedFunctionPointerAttribute.BestFitMapping), BindingFlags.Public | BindingFlags.Instance),
354+
ufpAttrType.GetField(nameof(UnmanagedFunctionPointerAttribute.CharSet), BindingFlags.Public | BindingFlags.Instance),
355+
ufpAttrType.GetField(nameof(UnmanagedFunctionPointerAttribute.SetLastError), BindingFlags.Public | BindingFlags.Instance),
356+
ufpAttrType.GetField(nameof(UnmanagedFunctionPointerAttribute.ThrowOnUnmappableChar), BindingFlags.Public | BindingFlags.Instance),
357+
};
358+
var ufpAttrFieldValues = new object[] { funcionSignature.bestFitMapping, funcionSignature.charSet, funcionSignature.setLastError, funcionSignature.throwOnUnmappableChar };
359+
var ufpAttrBuilder = new CustomAttributeBuilder(ufpAttrCtor, ufpAttrCtorArgValues, ufpAttrNamedFields, ufpAttrFieldValues);
360+
delBuilder.SetCustomAttribute(ufpAttrBuilder);
361+
362+
346363
var ctorBuilder = delBuilder.DefineConstructor(MethodAttributes.RTSpecialName | MethodAttributes.HideBySig | MethodAttributes.Public,
347364
CallingConventions.Standard, DELEGATE_CTOR_PARAMETERS);
348365
ctorBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
349366

350367
var invokeBuilder = delBuilder.DefineMethod("Invoke", MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.NewSlot,
351-
CallingConventions.Standard | CallingConventions.HasThis, methodSignature.returnParameterType, methodSignature.returnParameterRequiredModifiers,
352-
methodSignature.retunrParameterOptionalModifiers, methodSignature.parameterTypes, methodSignature.parameterRequiredModifiers, methodSignature.parameterOptionalModifiers);
368+
CallingConventions.Standard | CallingConventions.HasThis, funcionSignature.returnParameterType, funcionSignature.parameterTypes);
353369
invokeBuilder.SetImplementationFlags(MethodImplAttributes.Runtime | MethodImplAttributes.Managed);
354370

355371
_createdDelegateTypes++;
356372
return delBuilder.CreateType();
357373
}
358374

375+
359376
private static string GetDllPath(string dllName)
360377
{
361378
return _options.dllPathPattern
@@ -445,4 +462,4 @@ public enum LinuxDlopenFlags : int
445462
Lazy_Global = 0x00100 | Lazy,
446463
Now_Global = 0x00100 | Now
447464
}
448-
}
465+
}

src/NativeFunction.cs

Lines changed: 27 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections.Generic;
33
using System.Linq;
44
using System.Reflection;
5+
using System.Runtime.InteropServices;
56

67
namespace DllManipulator.Internal
78
{
@@ -52,115 +53,47 @@ public NativeFunction(NativeFunctionIdentity identity, NativeDll containingDll)
5253

5354
internal class NativeFunctionSignature
5455
{
55-
public readonly Type returnParameterType;
56-
public readonly Type[] returnParameterRequiredModifiers;
57-
public readonly Type[] retunrParameterOptionalModifiers;
56+
public readonly Type returnParameterType;
5857
public readonly Type[] parameterTypes;
59-
public readonly Type[][] parameterRequiredModifiers;
60-
public readonly Type[][] parameterOptionalModifiers;
61-
public readonly System.Runtime.InteropServices.CallingConvention callingConvention;
58+
public readonly CallingConvention callingConvention;
59+
public readonly bool bestFitMapping;
60+
public readonly CharSet charSet;
61+
public readonly bool setLastError;
62+
public readonly bool throwOnUnmappableChar;
6263

63-
public NativeFunctionSignature(MethodInfo methodInfo, System.Runtime.InteropServices.CallingConvention callingConvention)
64+
public NativeFunctionSignature(MethodInfo methodInfo, CallingConvention callingConvention, bool bestFitMapping, CharSet charSet, bool setLastError, bool throwOnUnmappableChar)
6465
{
65-
var returnParameter = methodInfo.ReturnParameter;
66-
returnParameterType = returnParameter.ParameterType;
67-
returnParameterRequiredModifiers = returnParameter.GetRequiredCustomModifiers();
68-
retunrParameterOptionalModifiers = returnParameter.GetOptionalCustomModifiers();
69-
var parameters = methodInfo.GetParameters();
70-
parameterTypes = parameters.Select(p => p.ParameterType).ToArray();
71-
parameterRequiredModifiers = new Type[parameters.Length][];
72-
parameterOptionalModifiers = new Type[parameters.Length][];
73-
for (int i = 0; i < parameters.Length; i++)
74-
{
75-
parameterRequiredModifiers[i] = parameters[i].GetRequiredCustomModifiers();
76-
parameterOptionalModifiers[i] = parameters[i].GetOptionalCustomModifiers();
77-
}
78-
66+
this.returnParameterType = methodInfo.ReturnType;
67+
this.parameterTypes = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
7968
this.callingConvention = callingConvention;
69+
this.bestFitMapping = bestFitMapping;
70+
this.charSet = charSet;
71+
this.setLastError = setLastError;
72+
this.throwOnUnmappableChar = throwOnUnmappableChar;
8073
}
8174

8275
public override bool Equals(object obj)
8376
{
84-
if (obj == null)
85-
{
86-
return false;
87-
}
88-
89-
if (obj is NativeFunctionSignature other)
90-
{
91-
return Equals(other);
92-
}
93-
94-
return false;
95-
}
96-
97-
public bool Equals(NativeFunctionSignature other)
98-
{
99-
//Ordered by probability in being different
100-
if (returnParameterType != other.returnParameterType)
101-
{
102-
return false;
103-
}
104-
105-
if (!parameterTypes.SequenceEqual(other.parameterTypes))
106-
{
107-
return false;
108-
}
109-
110-
if (parameterRequiredModifiers.Length != other.parameterRequiredModifiers.Length)
111-
{
112-
return false;
113-
}
114-
115-
for (int i = 0; i < parameterRequiredModifiers.Length; i++)
116-
{
117-
if (!parameterRequiredModifiers[i].SequenceEqual(other.parameterRequiredModifiers[i]))
118-
{
119-
return false;
120-
}
121-
}
122-
123-
if (!returnParameterRequiredModifiers.SequenceEqual(other.returnParameterRequiredModifiers))
124-
{
125-
return false;
126-
}
127-
128-
if (callingConvention != other.callingConvention)
129-
{
130-
return false;
131-
}
132-
133-
if (parameterOptionalModifiers.Length != other.parameterOptionalModifiers.Length)
134-
{
135-
return false;
136-
}
137-
138-
for (int i = 0; i < parameterOptionalModifiers.Length; i++)
139-
{
140-
if (!parameterOptionalModifiers[i].SequenceEqual(other.parameterOptionalModifiers[i]))
141-
{
142-
return false;
143-
}
144-
}
145-
146-
if (!retunrParameterOptionalModifiers.SequenceEqual(other.retunrParameterOptionalModifiers))
147-
{
148-
return false;
149-
}
150-
151-
return true;
77+
return obj is NativeFunctionSignature other &&
78+
EqualityComparer<Type>.Default.Equals(returnParameterType, other.returnParameterType) &&
79+
EqualityComparer<Type[]>.Default.Equals(parameterTypes, other.parameterTypes) &&
80+
callingConvention == other.callingConvention &&
81+
bestFitMapping == other.bestFitMapping &&
82+
charSet == other.charSet &&
83+
setLastError == other.setLastError &&
84+
throwOnUnmappableChar == other.throwOnUnmappableChar;
15285
}
15386

15487
public override int GetHashCode()
15588
{
156-
var hashCode = 1660825957;
89+
var hashCode = 763644728;
15790
hashCode = hashCode * -1521134295 + EqualityComparer<Type>.Default.GetHashCode(returnParameterType);
158-
hashCode = hashCode * -1521134295 + EqualityComparer<Type[]>.Default.GetHashCode(returnParameterRequiredModifiers);
159-
hashCode = hashCode * -1521134295 + EqualityComparer<Type[]>.Default.GetHashCode(retunrParameterOptionalModifiers);
16091
hashCode = hashCode * -1521134295 + EqualityComparer<Type[]>.Default.GetHashCode(parameterTypes);
161-
hashCode = hashCode * -1521134295 + EqualityComparer<Type[][]>.Default.GetHashCode(parameterRequiredModifiers);
162-
hashCode = hashCode * -1521134295 + EqualityComparer<Type[][]>.Default.GetHashCode(parameterOptionalModifiers);
16392
hashCode = hashCode * -1521134295 + callingConvention.GetHashCode();
93+
hashCode = hashCode * -1521134295 + bestFitMapping.GetHashCode();
94+
hashCode = hashCode * -1521134295 + charSet.GetHashCode();
95+
hashCode = hashCode * -1521134295 + setLastError.GetHashCode();
96+
hashCode = hashCode * -1521134295 + throwOnUnmappableChar.GetHashCode();
16497
return hashCode;
16598
}
16699
}

0 commit comments

Comments
 (0)