C#调用c++的dll执行带参数的函数时 请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配
C#动态调用DLL
由于Dll路径的限制,使用的不是很方便,C#中我们经常通过配置动态的调用托管Dll,例如常用的一些设计模式:Abstract Factory, Provider, Strategy模式等等,那么是不是也可以这样动态调用C++动态链接呢?只要您还记得在C++中,通过LoadLibrary, GetProcess, FreeLibrary这几个函数是可以动态调用动态链接的(它们包含在kernel32.dll中),那么问题迎刃而解了,下面我们一步一步实验
将kernel32中的几个方法封装成本地调用类NativeMethod
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace InteropDemo { public static class NativeMethod { [DllImport("kernel32.dll", EntryPoint = "LoadLibrary")] public static extern int LoadLibrary( [MarshalAs(UnmanagedType.LPStr)] string lpLibFileName); [DllImport("kernel32.dll", EntryPoint = "GetProcAddress")] public static extern IntPtr GetProcAddress(int hModule, [MarshalAs(UnmanagedType.LPStr)] string lpProcName); [DllImport("kernel32.dll", EntryPoint = "FreeLibrary")] public static extern bool FreeLibrary(int hModule); } }
使用NativeMethod类动态读取C++Dll,获得函数指针,并且将指针封装成C#中的委托。原因很简单,C#中已经不能使用指针了,如下
int hModule = NativeMethod.LoadLibrary(@"c:"CppDemo.dll");
IntPtr intPtr = NativeMethod.GetProcAddress(hModule, "Add");
详细请参见代码
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServices; namespace InteropDemo { class Program { //[DllImport("CppDemo.dll", EntryPoint = "Add", ExactSpelling = false, CallingConvention = CallingConvention.Cdecl)] //public static extern int Add(int a, int b); //DllImport请参照MSDN static void Main(string[] args) { //1. 动态加载C++ Dll int hModule = NativeMethod.LoadLibrary(@"c:\CppDemo.dll"); if (hModule == 0) return; //2. 读取函数指针 IntPtr intPtr = NativeMethod.GetProcAddress(hModule, "Add"); //3. 将函数指针封装成委托 Add addFunction = (Add)Marshal.GetDelegateForFunctionPointer(intPtr, typeof(Add)); //4. 测试 Console.WriteLine(addFunction(1, 2)); Console.Read(); } /// <summary> /// 函数指针 /// </summary> /// <param name="a"></param> /// <param name="b"></param> /// <returns></returns> delegate int Add(int a, int b); } }
报错信息是:托管调试助手“PInvokeStackImbalance”在“E:\WCF\CPP\bin\test.vshost.exe”中检测到问题。
其他信息: 对 PInvoke 函数“test!test.FUNC1::Invoke”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。
解决方法:
C#默认是stdcall调用约定,你可以把委托改成下面写法
[UnmanagedFunctionPointerAttribute(CallingConvention.Cdecl)]
delegate int FUNC1(string xmlSta, StringBuilder fileOut);
- 随机文章
- 热门文章
- 热评文章
- C#获取机器码的方法详解(机器名,CPU编号,硬盘编号,网卡mac等)
- C#图片处理示例(裁剪,缩放,清晰度,水印)
- C# 生成图片缩略图
- 永恒之蓝病毒是什么 怎么防范ONION勒索软件
- ESP8266在Eclipse下设置编译模式(有boot和无boot)
- HTTP请求头详解
- 乐高EV3与单片机蓝牙通讯
- 单片机时钟周期,机器周期,指令周期的区别