C# 调用C++的dll 那些事

       之前从来没搞过C++,最近被安排的任务需要调用C++的接口,对于一个没用过 Dependency 的小白来说,原本以为像平时的Http接口那样,协议,端口一定义,方法参数一写就没事,结果踩了无数的坑。现在从0基础开始记录。A发了一个SDK文件夹过来,先不管cpp、h、lib五花八门的后缀文件,直接看文档说明,表明需要调哪些方法。网上简单的查阅下资料,发现直接引用动态库Dll 的方式是通过 DllImport去实现,命名空间为 using System.Runtime.InteropServices; 

按照文档中方法名、参数类型的说明,对应写下代码

        [DllImport("ConX.dll", EntryPoint = "add")]
        public static extern int add(byte[] cfg_dir_name);
        
        public void Test1() 
        {
            int a=0;
            try
            {
                string str = "123";
                byte[] bts = Encoding.Default.GetBytes(str);
                a = add(bts);
            }
            catch (Exception ex)
            {

                string strEx = ex.Message;
            }
            Console.WriteLine(a);
            Console.ReadLine();
          
        }

一运行,提示 " 试图加载格式不正确的程序。 (异常来自 HRESULT:0x8007000B)" ,这一般是版本不匹配的原因,确定dll 版本为64位后,将Debug中设置为 X64 即可,然后运行提示 " 找不到Dll的入口点 "

用 DepenDency 查看下该Dll ,发现所谓的函数名变化了,并不是add,变成了下图一长串的字符(CallingConvention.Cdecl 编码)

相关资料显示,在导出C++程序是,可以选择C方式,和C++方式,C方式不会变更函数名,C++则会,   项目右键--属性--配置属性--C/C++--高级--编译为--①C ②C++ ,当然还可以在原函数中的前面加上Extern C来限定导出后函数名不变,目前没有源码,只有dll,所以对于这种情况,只需要将变更的函数名作为入口点 赋值给 EntryPoint 即可 

      [DllImport("ConX.dll", EntryPoint = "?add@@YAHABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z")]

接着运行,这个时候 又会提示 " 请检查PInvoke 签名的调用约定和参数与非托管的目标签名是否匹配 " , 资料显示,使用默认调用平台的约定 为Winapi ,这种变更方法后的格式 " ?方法名@@YA-----------@Z " 为Cdecl 约定,于是再次更改导入dll的代码

      [DllImport("ConX.dll", EntryPoint = "?add@@YAHABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z",CallingConvention=CallingConvention.Cdecl)]

如此折腾了一番,运行后, 如果报 " 无法加载 DLL“face_export.dll”: 找不到指定的程序 " 那就是路径有问题,一般处理方法如下

①直接把Dll 拷贝到 执行文件exe所在的目录下,记住通过Dependency 查看dll时,看下有没有缺失的dll ,如果没有,在将所依赖的非系统的dll 一并拷贝到 执行文件exe所在的目录下,

②使用 Dll 的绝对路径  

③将 Dll 拷贝至系统的文件下,64位系统 对应的32位Dll则为SysWOW ,64为Dll 则为System32

      正常情况下,到这里就没有什么大问题,如果报参数问题,那就需要查阅 C++ 对应的 C# 数据类型。匹配正确即可,关键就在于我这里仍然报错,外部组件异常,外部组件异常,外部组件异常,查阅资料显示,网上没什么好的解决方案,因为这种问题的原因五花八门,是一个很笼统的错误,可是偏偏就被我遇到了,我这边按接口中函数的申明,照葫芦画瓢写了一个C++ 的Dll,用C#调用自己写的Dll 是OK 。同事用C++调用 第三方的 Dll 也没问题(说明别人提供的Dll没问题)。这样一来就尴尬了,思路不能沉寂在这里。网上有人说是Net 版本可能不兼容,我挨个尝试一遍从3.5 切换到 4.6.1 仍是外部组件异常的错误。 最后我用VS2017 打开,调试程序,仍然是外部组件异常。现在可以排除的是 不是依赖问题(报找不到Dll),不是没加载指定Dll问题, 因为不会报入口点找不到的错误,也不是参数的问题,版本的问题已经用VS2017尝试过。还会有什么方面的原因呢?希望哪位仁兄能提供一个好的思路...

未完待续...

猜你喜欢

转载自www.cnblogs.com/Sientuo/p/9361729.html