使用VS2017把C++项目打包成dll,并暴露函数。
1、创建下图类型的项目
默认生成的是这样的,我们在Dll3.cpp中写函数就行。
2、创建、或者从外部引入C++文件。
注意:要在每个cpp文件的头部都加上 #include “stdafx.h”,而且一定要在首行。不然会报错。
注意:若想要以c语言封装,图中标记的一定要存在。这里还是都加上吧。
由于这里使用了strdup,所以生成dll时会报4996错误。
参考 https://blog.csdn.net/heimabuhei/article/details/79976270即可解决,好多函数都会报4996错误,用这个就行。
3、我演示的是传入和返回字符串
C++中代码
#include "stdafx.h"
#include<string>
#include<iostream>
using namespace std;
extern "C" _declspec(dllexport)const char* show_and_return(char* s) {
string str = s;
cout << s << "\n";
//下面的string转const char* 代码很重要。我找了好久,就这种好用
string return_str = "hello word1\nhello word2\n";
const char* return_char;
return_char = strdup(return_str.c_str());
return return_char;
}
为了方便看,提前贴出C#调用与dll交互的代码。我用的时WPF程序。
//部分代码
public partial class MainWindow : Window
{
//为了方便演示,我就直接写了C++生成的dll的绝对路径。
[DllImport("C:\\Users\\Administrator\\source\\repos\\Dll3\\Debug\\Dll3.dll", EntryPoint = "show_and_return", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr show_and_return(string a);
public MainWindow()
{
InitializeComponent();
string s = "传输参数,由C++打印";
IntPtr p = show_and_return(s);
string str_out = Marshal.PtrToStringAnsi(p);
Console.WriteLine(str_out);
}
}
这里有下面几点需要注意:
(1)C++ 函数的参数使用char类型的形参接收外部传入的字符串。
然后C#调用dll时传入的参数类型时string就可以。
(2)C++返回字符串类型为 const char,这里一定要注意。我试过 如果返回值参数为string,C#调用dll时会报错。
下面还需要注意:我们可能在C++用的是string类型,但是由于我们的返回值类型是const char*,所以要把进行转换,经过我的尝试,使用
1、
str.c_str();
2、
str.data();
3、以及这篇文章(https://blog.csdn.net/mpp_king/article/details/88763120)的方法都有问题。
使用前两种方法,C#获得的是空值。使用三种方法,返回的字符串仍有乱码。
通过参考这篇https://blog.csdn.net/weixin_40647819/article/details/108245474文章,使用strdup()函数解决。
然后C#接收时用IntPtr类型接收,然后转化为c#中的string类型。
4、C++代码写完后,根据下图生成dll
C#中调用
我直接创建的是一个WPF项目。这个无所谓,只要是C#项目就可以。下面说下我遇到的问题。
代码如下,和上面一样。
//部分代码
public partial class MainWindow : Window
{
//为了方便演示,我就直接写了C++生成的dll的绝对路径。
[DllImport("C:\\Users\\Administrator\\source\\repos\\Dll3\\Debug\\Dll3.dll", EntryPoint = "show_and_return", CallingConvention = CallingConvention.Cdecl)]
public static extern IntPtr show_and_return(string a);
public MainWindow()
{
InitializeComponent();
string s = "传输参数,由C++打印";
IntPtr p = show_and_return(s);
string str_out = Marshal.PtrToStringAnsi(p);
Console.WriteLine(str_out);
}
}
1、因为我们生成dll的C++项目是x86的,所以C#项目也要是x86的。WPF默认是Anycpu,就会报错。所以需要改成x86。
**此外:**C++代码运行错误也会导致这个错误提示,所以也可以测试下,C++代码运行时,是否会有错误。我后来有一次是因为字符串访问冲突导致的该错误。
2、如果DllImport里不加CallingConvention = CallingConvention.Cdecl,这时会报下面的错误。
3、我发现在C#中直接用string类型也可以接收到字符串。
public partial class MainWindow : Window
{
[DllImport("C:\\Users\\Administrator\\source\\repos\\Dll3\\Debug\\Dll3.dll", EntryPoint = "show_and_return", CallingConvention = CallingConvention.Cdecl)]
public static extern string show_and_return(string a);
public MainWindow()
{
InitializeComponent();
string s = "传输参数,由C++打印";
string str = show_and_return(s);
Console.WriteLine(str);
}
}
4、最后可以通过“输出”栏可以看见结果。
其中C++代码打印的那块,在关闭WPF窗体后,才会打印出来。
以上是我自己的总结,因为C++还是很久以前用过,有不对的地方请指出。
参考:
重要:https://blog.csdn.net/weixin_40647819/article/details/108245474
https://www.cnblogs.com/cyberarmy/p/10102350.html