zoukankan      html  css  js  c++  java
  • C# 调用C++生成的dll

      现在非常的流行使用C++来完成底层的算法或是需要高运行速度的程序快。然后使用 C# 来调用。用C#来写界面和逻辑层。 这样即用到了 C++ 的运行速度又用到了C# 快速的开发优势。

    下面讲一下如何在C#中调用 C++生成的dll :

    // cppdll.cpp  因为这个DLL的目的就是为了让 C#去调用。所以这里不用
    // 再去写个头文件了,写头文件主要是为了让 C++的程序去调。我们这里
    // 是把函数的声明与定义都写在一起。
    
    #include <iostream>
    using namespace std;
    
    // 把固定要使用的 “extern "C" __declspec(dllexport)”,放在函数、// 头,这是生成DLL函数所必须的,所以给他起个别名,简洁一些。
    #define DLLEXPORT extern "C" __declspec(dllexport)
    
    // 写一个简单的 加法函数 add ,增加两个整数值,反加一个整数
    DLLEXPORT int add(int i,int j){
        return i + j;
    }
    // 再写一个无返回值的Print方法,他传入的是一个字符串
    // 注意 这时字符串最好使用 char* 而不是 string. 不然可能会
    // 报 “尝试访问受保护内存” 的错误。
    DLLEXPORT void Print(char* str,int i) {
        cout << "Input the " << str << " and " << i << endl;
    }

    上面的C++程序使用的是 全局的静态方法,这样比较方法调用。当然你也可以写一个类,让C#去调用的。

    这是如何在C# 中,调用 上面写的那两个 C++ 函数 :

    using System.Text;
    using System.Net;
    using System.Net.Sockets;
    using System.Runtime.InteropServices;
    
    namespace Test
    {
        class Program
        {
            // CalingConvention 意思是“调用协定",主要是规定一下参数如
            // 何进去栈,及是由调用方还是被调用方来释放资源。
            [DllImport("cppdll.dll", CallingConvention = CallingConvention.Cdecl)]
            public static extern int add(int i, int j);
    
            // 如果参数中有 字符串的情况下,还需要设置一下这个函数所使
            // 用的字符集 CharSet = CharSet.Ansi
            [DllImport("cppdll.dll", CallingConvention = CallingConvention.Cdecl,CharSet = CharSet.Ansi)]
            public static extern void Print(string s,int i);
    
            static void Main(string[] args) {
                // C++ add Method
                Console.WriteLine(add(45, 567));
                // C++ Print Method
                Print("May_H",757);
    
                Console.ReadKey();
            }
        }
    }

    参考 : http://www.soaspx.com/dotnet/csharp/csharp_20110406_7469.html

    ------------------------------------------ 2013/10/26 一些补充------------------------------------------

        之前研究的是使用 C# 去调用 C++ 的函数,那么如何来调用C++的类呢. 如果按一般的解决方法,将类在C#中重声明一下,如果其中再有结构体,枚举等会是一个相当麻烦的过程,所以,我们还是使用 调用函数的方法.写一个接口方法,在接口方法中去创建类的指针, 将调用 C++类的操作写在这个接口函数中. 再用C#去调用. 就方便很多. 避开了很多的麻烦.

    例如: 在 C++ 中写一个简单的 Person类,只有name ,age.

    class Person {
    public:
     char* name;
     int age;
     // 构造函数
     Person(char* name,int age);
     ~Person();
     // 方法
     void SayHi();
    };

      1. 创建一个 DLLInterface.cpp 文件,写一个 生成 Person 指针的方法:

    #define EXPORTDLL extern "C" _declspec(dllexport)

    EXPORTDLL void* PersonInit(char* name,int age) {
           Person* per = new Person(name,age);
           return per;
    }

    这样在 C# 中调用这个文件 ,就可以得到这个类的指针(int).

      2. 根据我们的需要, 可以再写一些接口方法,比如调用它的SayHi 方法

      EXPORTDLL void InvokeSayHi(Person* p) {
         p->SayHi();
      }

    再与一个清理 这个生Person指针的方法.

      EXPORTDLL void FreePerson(Person* p) {
         delete p;
         cout << "Free Over" << endl;
      }

    这些方法.都接收一个 Person 指针.

    3.在C#中.. 引入这个 DLL 及声明接口方法:

      // 这里使用 [MarshalAs(UnmanagedType.LPArray)]byte[] name,来传递字符串,(中文还不行.. 还得研究)

      // 经过看网上的资料, 发现所有的指针都可以使用 IntPtr 在C# 中使用,包括Char*. 在C#向C++传字符串的时候使用 Marshal.StringToHGlobalAnsi("字符串"). 的方法传

      // 递, 方便好用 所以指针都用 IntPtr就行了. Marshel 就是用到托管与非托管之间进行参数传递或转换的一个方法类.

      [DllImport("cpp01.dll", EntryPoint = "PersonInit", CallingConvention = CallingConvention.Cdecl)]
          extern static IntPtr PersonInit([MarshalAs(UnmanagedType.LPArray)]byte[] name, int age);

      // 写成 IntPtr的形式: extern static IntPtr PersonInit(IntPtr name, int age);

      
          [DllImport("cpp01.dll", EntryPoint = "InvokeSayHi", CallingConvention = CallingConvention.Cdecl)]
          extern static void InvokeSayHi(IntPtr personPoint);

    4.OK.. 现在我们就可以在C#中调用这个C++类了!

      static void Main(string[] args) {
                // 得到Person 的指针,由Int存储
                int pp = PersonInit(System.Text.Encoding.ASCII.GetBytes("Mick"), 3456); 
                // 使用这个地址调用Person->SayHi 方法
                InvokeSayHi(pp);
                // 清理Person用到的内存
                FreePerson(pp);
            }

      

  • 相关阅读:
    实验 3:Mininet 实验——测量路径的损耗率
    福州大学软件工程实践个人编程作业
    软件定义网络实验 2:Mininet 实验——拓扑的命令脚本生成
    软件定义网络实验 1:Mininet 源码安装和可视化拓扑工具
    第一组冲刺收尾作业——团队总结
    第十天alpha冲刺(11月29日)
    alpha汇总博客
    第九天alpha冲刺(11月26日)
    第八天alpha冲刺(11月25日)
    第七天alpha冲刺(11月23日)
  • 原文地址:https://www.cnblogs.com/easyfrog/p/2767517.html
Copyright © 2011-2022 走看看