C#使用过程中经常会遇到和C++联合开发的过程,通过C++编写动态库,封装成dll后再C#中调用,在此做个记录,并供后期查看
一、新建C#控制台项目
打开VisualStudio,新建一个C#控制台项目,项目名称HelloWorldTest
点击下一步,一个空的默认c#项目创建完成
二、创建C++库
在解决方案上右键--添加--新建项目,建一个C++动态链接库工程,输入项目名称TestDll
创建完成后如下,在源文件--右键--新建项--添加C++(.CPP文件),文件内容如下:
#include "pch.h"
#include "HelloDll.h"
#include<iostream>
void HelloWorld(char* name)
{
std::cout << "Hello World " << name << std::endl;
}
int Test()
{
return 123456;
}
int Add(int a, int b)
{
return a + b;
}
C++库导出有两种方式,但是最好两种方式同时使用,据说第二种是为了防止名字错乱,
1、以C语言接口的方式导出
在头文件--右键--新建项,然后新建HelloDll.h头文件,如下图
这种方法就是在函数前面加上 extern "C" __declspec(dllexport)
加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。
extern "C" __declspec(dllexport) void HelloWorld(char* name);
extern "C" __declspec(dllexport) int Test();
extern "C" __declspec(dllexport) int Add(int a,int b);
2、以模块定义文件的方式导出
在源文件上点击右键,选择添加-》新建项
然后选择代码-》模块定义文件
在HelloDll.def中输入
LIBRARY "HelloDll"
EXPORTS
HelloWorld @ 1
Test @ 2
Add @ 3
EXPORTS下面就是要导出的函数,这里不需要添加分号隔开,直接换行就行。
在C#项目中添加引用:同时把C#代码修改为:
因为要用到DllImport,所以先导入命名空间using System.Runtime.InteropServices;
注意:在DllImport导入C/C++编写的动态库时函数,可以加上一些约定参数,例如:
[DllImport(@"HelloDll.dll", EntryPoint = "Test", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false, CallingConvention = CallingConvention.StdCall)]
CallingConvention = CallingConvention.Cdecl,来指定入口点的调用约定,否则有可能会 报错
因为C/C++编写的动态库默认的入口点约定为_cdecl,而VS默认调用动态库时的约定为_winapi
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace DllTest
{
internal class Program
{
[DllImport("HelloDll.dll")]
public static extern void HelloWorld(string name);
[DllImport("HelloDll.dll")]
public static extern int Test();
[DllImport("HelloDll.dll")]
public static extern int Add(int a, int b);
static void Main(string[] args)
{
Console.WriteLine(Test().ToString());
Console.WriteLine(Add(2, 5));
HelloWorld("LiLi");
Console.ReadKey();
}
}
}
运行程序,结果如下:
这样就成功实现了C#调用的C++库