Damien 所写内容的完整示例...请注意,它仅在方法具有所有相同签名时才有效(在此示例中为 void function_X())。此外,探索 dll 以发现导出了哪些方法是“困难的”,因此最好知道 dll 中应该包含哪些方法。
[DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
public static extern IntPtr LoadLibrary(string dllToLoad);
[DllImport("kernel32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
// Set the correct calling convention
[UnmanagedFunctionPointer(CallingConvention.StdCall)]
private delegate void DllMethodDelegate();
IntPtr dll = LoadLibrary(@"PathToYourDll.DLL");
if (dll == IntPtr.Zero)
{
throw new Exception();
}
string methodName = "function_1";
IntPtr method = GetProcAddress(dll, methodName);
if (method == IntPtr.Zero)
{
throw new Exception();
}
DllMethodDelegate method2 = (DllMethodDelegate)Marshal.GetDelegateForFunctionPointer(method, typeof(DllMethodDelegate));
// Now you can do method2();
请注意,您必须在DllMethodDelegate() 定义中设置正确的调用约定。通常dll方法应该是StdCall。
你写的方法的签名是:
[UnmanagedFunctionPointer(CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
private delegate int DllMethodDelegate(char cmd, ref IntPtr out_address);
请注意,“填充”out_address 非常复杂(头痛复杂)。
{
// I case:
IntPtr ret = IntPtr.Zero;
int result = method2('I', ref ret);
}
{
// R case:
IntPtr ptr = IntPtr.Zero;
int result = method2('R', ref ptr);
int value = Marshal.ReadInt32(ptr);
}
{
// W case:
int value = 100;
GCHandle handle = default(GCHandle);
try
{
int[] value2 = new int[] { value };
handle = GCHandle.Alloc(value2, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
int result = method2('W', ref ptr);
}
finally
{
if (handle.IsAllocated)
{
handle.Free();
}
}
}
有可能(但我不确定)对于第三个示例,您可以这样做
object value2 = value;
而不是
int[] value2 = new int[] { value };
boxing 和GCHandle 的交互并没有详细记录,但它似乎有效。 C# 规范 4.3 似乎还可以……但我不相信它,而且这种技术似乎在“.NET 和 COM:完整的互操作性指南”一书中有所描述,在“获取值类型的地址”一章中"(该章节可在 google 中搜索,使用我给出的确切章节标题。示例在 VB.NET 中,但读起来很清楚)