笔记:C#调用C++动态库

3 篇文章 0 订阅
1 篇文章 0 订阅

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中的方法作为这个委托函数来使用了

关于C#调用C++的参数问题:函数指针和回调函数部分:

在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<T>是自己写的一个函数,作用是从dll文件中提取函数封装为T类型返回,失败时返回default
            Api_Ergodic api_Ergodic = GetFuncAsDelegate<Api_Ergodic>("ErgodicDirAndFile");
            if(api_Ergodic == default) {
                Console.WriteLine("api_Ergodic Failed");
            }else
            {
                api_Ergodic(dirPath,default(IntPtr),Marshal.GetFunctionPointerForDelegate(api_FileCall), false);
            }

  • 1
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值