C#调用非托管DLL--[1]基本步骤

托管DLL和非托管DLL的区别
狭义解释讲,托管DLL就在Dotnet环境生成的DLL文件。非托管DLL不是在Dotnet环境生成的DLL文件。

托管DLL文件,可以在Dotnet环境通过 “添加引用” 的方式,直接把托管DLL文件添加到项目中。然后通过 Using DLL命名空间,来调用相应的DLL对象 。
非托管DLL文件,在Dotnet环境应用时,通过引入 using system.Runtime.InteropServices;再在代码中通过DllImport 调用。

 

功能:通过c#调用c++编写的DLL。

实现:用delegate申明函数委托进行调用,可进行回调并应用指针.

遇到的问题点:

1、getProcAddress返回的值是0,无法获得NATIVE DLL中的导出函数
检查调用的函数名和c++项目中的是否一致;

2、查看c++ dll的函数名
VIEWDLL可以查看导出dll函数的名称

3、托管调试助手 "PInvokeStackImbalance":“对 PInvoke 函数“**.**+_DLL_Test::Invoke”的调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配。请检查 PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配。”

程序可以执行以及返回正确结果,但仍然报错。

解决方案在我的另一篇博客 https://blog.csdn.net/u012482453/article/details/102894850

 

4、exception 值不能为 null。\r\n参数名: ptr System.ArgumentNullException
首先查看c++生成的DLL路径是否正确,以及调用的函数名是否正确
其次dll需要是c++项目生成的才可以,一开始我用c#项目生成了dll,无法用该方式调用


5、System.RuntimeType typeof DeclaringMethod 引发了类型 System.InvalidOperation
一开始觉得是typeof()报错,觉得是委托类型或传进的参数不对,后来发现是因为dll是c#生成导致的。

 

 

C#中,先定义将DLL函数地址转换成委托的类,方法以及封装参考: https://www.cnblogs.com/zeroone/p/3681379.html

C#调用C++的函数还有一种方法是用delegate申明函数委托进行调用,这种方法略显麻烦,但是可以进行回调并应用指针.

在C#中,定义一个类,用来把DLL中函数地址转换成委托:

public class DLLWrapper
    {
    ///<summary>
    /// API LoadLibrary
    ///</summary>
    [DllImport("Kernel32")]
    public static extern int LoadLibrary(String funcname);
     
    ///<summary>
    /// API GetProcAddress
    ///</summary>
    [DllImport("Kernel32")]
    public static extern int GetProcAddress(int handle, String funcname);
     
    ///<summary>
    /// API FreeLibrary
    ///</summary>
    [DllImport("Kernel32")]
    public static extern int FreeLibrary(int handle);
     
    ///<summary>
    ///通过非托管函数名转换为对应的委托, by jingzhongrong
    ///</summary>
    ///<param name="dllModule">Get DLL handle by LoadLibrary</param>
    ///<param name="functionName">Unmanaged function name</param>
    ///<param name="t">ManageR type对应的委托类型</param>
    ///<returns>委托实例,可强制转换为适当的委托类型</returns>
    public static Delegate GetFunctionAddress(int dllModule, string functionName, Type t)
    {
    int address = GetProcAddress(dllModule, functionName);
    if (address == 0)
    return null;
    else
    return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
    }
     
    ///<summary>
    ///将表示函数地址的IntPtr实例转换成对应的委托, by jingzhongrong
    ///</summary>
    public static Delegate GetDelegateFromIntPtr(IntPtr address, Type t)
    {
    if (address == IntPtr.Zero)
    return null;
    else
    return Marshal.GetDelegateForFunctionPointer(address, t);
    }
     
    ///<summary>
    ///将表示函数地址的int转换成对应的委托,by jingzhongrong
    ///</summary>
    public static Delegate GetDelegateFromIntPtr(int address, Type t)
    {
    if (address == 0)
    return null;
    else
    return Marshal.GetDelegateForFunctionPointer(new IntPtr(address), t);
    }
    }

 

//函数封装DLL中的函数, hModule()函数的作用是取得DLL的地址,用在多个输出函数中

    private int hModule()
    {
    int _hModule = DLLWrapper.LoadLibrary(DLLPATH);
    if (_hModule == 0)
    {
    return 0;
    }
    return _hModule;
    }
     
    //用delegate声明函数
    delegate void _amDBRInitialize (int mid, ref int errid);


    private void amDBRInitialize()
    {
    try
    {
    _amDBRInitialize amf = (_amDBRInitialize)DLLWrapper.GetFunctionAddress(hModule(), "amDBRInitialize", typeof(_amDBRInitialize));
    amf();
    }
    catch (Exception e)
    {
    throw e;
    }
    }

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值