您的位置:首页 > 编程语言 > C语言/C++

C# 调用C++生成的dll

2012-11-13 10:08 274 查看
  现在非常的流行使用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);
}

  
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: