C#调用C++的动态库方式有两种:
一种是直接调用:
这种形式可以用一个类来封装从dll文件中提取出来的方法,然后继承或调用此类;
using System.Runtime.InteropServices;//需要引入的命名空间
//前缀必须是static extern
[DllImport("dll文件完整路径", EntryPoint = "dll中封装的函数名"))]
public static extern Int GetInt(int ParameterInt);
//注意数据类型,
// 函数原型返回值为char*时,用IntPtr接受,并调用Marshal.PtrToStringAnsi()转为string
// 函数原型参数为char*时,用string类型传入
[DllImport("dll文件完整路径", EntryPoint = "dll中封装的函数名")]
public static extern IntPtr GetCharPoint(string ParameterCharPoint);
string str = Marshal.PtrToStringAnsi(init);//参数为IntPtr类型
另一种是动态调用:
这种方法更加灵活
首先需要从kernel132.dll中静态调用出以下方法,之后会使用这几个方法来操作dll文件
//加载DLL
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
protected extern static IntPtr LoadLibrary(string path);
//获取函数地址
[DllImport("kernel32.dll", SetLastError = true)]
protected extern static IntPtr GetProcAddress(IntPtr lib, string funcName);
//释放相应的库
[DllImport("kernel32.dll")]
protected extern static bool FreeLibrary(IntPtr lib);
//获取错误信息
[DllImport("Kernel32.dll")]
public extern static int FormatMessage(int flag, ref IntPtr source, int msgid, int langid, ref string buf, int size, ref IntPtr args);
使用这些方法来解析dll文件
//此处的T指代一个函数委托的具体类型
T GetDelegate()
{
//解析dll文件句柄
IntPtr DllHandle = LoadLibrary("dll文件路径");
//_获取函数指针
IntPtr funcPoint = GetProcAddress(DllHandle, "dll中封装的方法名");
//解析函数指针并转化为函数委托,并作为返回值.
return (T)(object)Marshal.GetDelegateForFunctionPointer(funcPoint, typeof(T));
}
然后就可以把dll中的方法作为这个委托函数来使用了
在cpp端参数为一个函数指针时,在c#端以IntPtr类型作为参数;
实例化一个Delegate函数委托作为回调函数,调用Marshal.GetFunctionPointerForDelegate(此参数为该Delegate实例对象)转化为一个IntPtr类型函数指针,即可作为参数传入;
需要传入c++中定义为NULL的参数时,使用default(IntPtr)作为空指针;
cpp端的代码声明:
typedef bool (*FileStdCall)(const char* _FilePath);//_对文件的回调函数指针类型
typedef bool (*DirStdCall)(const char* _Directory);//_对文件夹的回调函数指针类型
extern "C" _declspec(dllexport)
void ErgodicDirAndFile(char* _BeginPath = NULL,
DirStdCall _DirCall = NULL,
FileStdCall _FileCall = NULL,
bool _ifOnlyFirstDeep = false);
c#端的代码调用
public delegate void Api_Ergodic(string path, IntPtr dirCall, IntPtr fileCall, bool ifOneDeep);
public delegate bool Api_FileCall(string FilePath);
//File 回调
Api_FileCall api_FileCall = delegate (string path)
{
Console.WriteLine(path);
return true;
};
//Ergodic函数
//GetFuncAsDelegate是自己写的一个函数,作用是从dll文件中提取函数封装为T类型返回,失败时返回default
Api_Ergodic api_Ergodic = GetFuncAsDelegate("ErgodicDirAndFile");
if(api_Ergodic == default) {
Console.WriteLine("api_Ergodic Failed");
}else
{
api_Ergodic(dirPath,default(IntPtr),Marshal.GetFunctionPointerForDelegate(api_FileCall), false);
}