-
-
Save decay88/64ebb8ada827269e2e0db6582597959c to your computer and use it in GitHub Desktop.
関数ポインタと呼ばれし者たちの墓
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.IO; | |
using System.Reflection; | |
using System.Reflection.Emit; | |
using System.Runtime.CompilerServices; | |
using System.Runtime.InteropServices; | |
namespace ConsoleApp60 | |
{ | |
class Program | |
{ | |
[DllImport(@"Python37.dll", EntryPoint = "Py_Initialize", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] | |
public static extern void Initialize(); | |
[DllImport("kernel32", CharSet = CharSet.Ansi, BestFitMapping = false, SetLastError = true)] | |
public static extern IntPtr LoadLibrary(string fileName); | |
[DllImport("kernel32", CharSet = CharSet.Ansi)] | |
public static extern IntPtr GetProcAddress(IntPtr hModule, string procname); | |
[DllImport(@"Python3.dll", EntryPoint = "PyLong_FromLong", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] | |
public static extern IntPtr PyLongFromLong(long v); | |
[DllImport(@"Python3.dll", EntryPoint = "PyLong_Type", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] | |
public static extern IntPtr PyLong_Type(); | |
[DllImport(@"Python3.dll", EntryPoint = "PyObject_IsInstance", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)] | |
public static extern int IsInstance(IntPtr inst, IntPtr cls); | |
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)] | |
public delegate IntPtr TypeDelegate(); | |
static void Main(string[] args) | |
{ | |
if (File.Exists(@"C:\Program Files\Python37\Python3.dll")) | |
{ | |
Initialize(); | |
var lib = LoadLibrary(@"C:\Program Files\Python37\Python3.dll"); | |
var loadLibPtr = GetProcAddress(lib, "PyLong_Type"); // Marshal.GetDelegateForFunctionPointer 使用可 | |
var mi = GenerateInvoke(); | |
IntPtr propertyPtr = mi.MethodHandle.Value; // Marshal.GetDelegateForFunctionPointer不可 | |
IntPtr unsafePtr = GetMethodAddress(mi); // Marshal.GetDelegateForFunctionPointer不可 | |
IntPtr myInvokePtr = GetFuncPtr(mi); //Marshal.GetDelegateForFunctionPointer 使用可 | |
IntPtr pinvokePtr = GetFuncPtr(PyLong_Type); //delegateParamPtrと同値 Marshal.GetDelegateForFunctionPointer 使用可 | |
IntPtr delegateParamPtr = GetDelegateParam((Func<IntPtr>)PyLong_Type); //pinvokeと同値 Marshal.GetDelegateForFunctionPointer 使用可 | |
TypeDelegate typeDelegate = PyLong_Type; | |
IntPtr marshalPtr = Marshal.GetFunctionPointerForDelegate(typeDelegate); //Marshal.GetDelegateForFunctionPointer 使用可 | |
//IntPtr marshalPtr = Marshal.GetFunctionPointerForDelegate((Func<IntPtr>)PyLong_Type); //直接は不可能 | |
IntPtr pyLong = PyLongFromLong(10); | |
IsInstance(pyLong, loadLibPtr); //OK | |
//IsInstance(pyLong, propertyPtr); // 場所 0x00000000000000A8 の読み取り中にアクセス違反が発生しました | |
//IsInstance(pyLong, unsafePtr); // 場所 0x00000000000000A8 の読み取り中にアクセス違反が発生しました | |
//IsInstance(pyLong, myInvokePtr); //場所 0x000011B0E94000A8 の読み取り中にアクセス違反が発生しました(unsafeの実行をなくすと0xFFFFFFFFFFFFFFFF) | |
//IsInstance(pyLong, pinvokePtr); // 場所 0xFFFFFFFFFFFFFFFF の読み取り中にアクセス違反が発生しました | |
//IsInstance(pyLong, delegateParamPtr); // 場所 0xFFFFFFFFFFFFFFFF の読み取り中にアクセス違反が発生しました | |
//IsInstance(pyLong, marshalPtr); // 場所 0xFFFFFFFFFFFFFFFF の読み取り中にアクセス違反が発生しました | |
} | |
} | |
public static MethodInfo GenerateInvoke() | |
{ | |
AssemblyName assemblyName = new AssemblyName("InvokeTest"); | |
AssemblyBuilder assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run); | |
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name); | |
TypeBuilder typeBld = moduleBuilder.DefineType( | |
"Test.PInvoke", | |
TypeAttributes.Public | TypeAttributes.Sealed | TypeAttributes.AnsiClass | TypeAttributes.BeforeFieldInit | |
); | |
MethodBuilder methodBuilder = typeBld.DefinePInvokeMethod( | |
"PyLong_Type", @"C:\Program Files\Python37\Python3.dll", | |
MethodAttributes.Static | MethodAttributes.HideBySig | MethodAttributes.PinvokeImpl | MethodAttributes.Public, | |
CallingConventions.Standard, | |
null, | |
new[] { typeof(long) }, | |
CallingConvention.Cdecl, | |
CharSet.Ansi | |
); | |
methodBuilder.SetImplementationFlags( | |
methodBuilder.GetMethodImplementationFlags() | MethodImplAttributes.PreserveSig | |
); | |
Type type = typeBld.CreateType(); | |
return type.GetMethod("PyLong_Type"); | |
} | |
static IntPtr GetFuncPtr(MethodInfo methodInfo) | |
{ | |
DynamicMethod dm = new DynamicMethod("", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(IntPtr), new Type[] { }, typeof(Delegate), true); | |
ILGenerator ilgen = dm.GetILGenerator(); | |
ilgen.Emit(OpCodes.Ldftn, methodInfo); | |
ilgen.Emit(OpCodes.Ret); | |
return ((Func<IntPtr>)dm.CreateDelegate(typeof(Func<IntPtr>)))(); | |
} | |
static IntPtr GetFuncPtr(Func<IntPtr> func) | |
{ | |
return GetFuncPtr(func.GetMethodInfo()); | |
} | |
static IntPtr GetDelegateParam(Delegate input) | |
{ | |
DynamicMethod method = new DynamicMethod("", MethodAttributes.Public | MethodAttributes.Static, CallingConventions.Standard, typeof(IntPtr), new Type[] { typeof(Delegate) }, typeof(Delegate), true); | |
ILGenerator ilgen = method.GetILGenerator(); | |
ilgen.Emit(OpCodes.Ldarg_0); | |
ilgen.Emit(OpCodes.Ldfld, typeof(Delegate).GetField("_methodPtrAux", BindingFlags.NonPublic | BindingFlags.Instance)); | |
ilgen.Emit(OpCodes.Ret); | |
return ((Func<Delegate, IntPtr>)method.CreateDelegate(typeof(Func<Delegate, IntPtr>)))(input); | |
} | |
public static IntPtr GetMethodAddress(MethodBase method) | |
{ | |
RuntimeHelpers.PrepareMethod(method.MethodHandle); | |
unsafe | |
{ | |
int skip = 10; | |
UInt64* location = (UInt64*)(method.MethodHandle.Value.ToPointer()); | |
int index = (int)(((*location) >> 32) & 0xFF); | |
if (IntPtr.Size == 8) | |
{ | |
ulong* classStart = (ulong*)method.DeclaringType.TypeHandle.Value.ToPointer(); | |
ulong* address = classStart + index + skip; | |
return new IntPtr(address); | |
} | |
else | |
{ | |
uint* classStart = (uint*)method.DeclaringType.TypeHandle.Value.ToPointer(); | |
uint* address = classStart + index + skip; | |
return new IntPtr(address); | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment