zoukankan      html  css  js  c++  java
  • 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);
            //VS2017中 方法名首字母需要大写为 Add
            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 即可 (32位则设置为x86),接着运行 ,会提示 " 找不到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尝试过。还会有什么方面的原因呢?

    未完待续...

          最后经过翻来覆去的测试,发现问题出在 c++ 的dll上,最后重新封装了一边dll,再次调用就没问题了,看来还是自己学习的不够... 

  • 相关阅读:
    SoapUI 使用笔记
    git 使用笔记(二)
    git 使用笔记(一)
    jquery 拓展
    hdu 1024 Max Sum Plus Plus (DP)
    hdu 2602 Bone Collector (01背包)
    hdu 1688 Sightseeing (最短路径)
    hdu 3191 How Many Paths Are There (次短路径数)
    hdu 2722 Here We Go(relians) Again (最短路径)
    hdu 1596 find the safest road (最短路径)
  • 原文地址:https://www.cnblogs.com/Sientuo/p/9361729.html
Copyright © 2011-2022 走看看