1 新建工程
(1)首先新建C#控制台工程,文件—新建—项目,选择控制台应用,如下图所示:
(2)在此工程中添加C++的动态链接库项目,右键解决方案(注意这里是解决方案,不是C#工程),选择添加,选择新建项目,如下图:
(3)在添加新建项目的界面,选择VC++下面的Win32,然后选Win32项目,修改对应文件名称,如下图:
(4)点击确定后进入设置向导,在应用程序类型中选择DLL,在附加选项中勾选导出符号和预编译头,点击确定即可(若熟练流程后,可自行添加文件,不勾选该选项)。
(5)开始编写代码。打开刚才添加的文件的,打开cpp和h文件如下图,这里是模板生成的文件,可根据需要删除,此处删除该模板生成的代码。
cpp文件 | h文件 |
---|---|
在CPPDLL.cpp文件写测试代码如下:
//cpp文件
int num = 0;
CPPDLL_API int getnum(void)
{
return num;
}
CPPDLL_API void setnum(int n)
{
num = n;
}
CPPDLL_API int intadd(int a, int b)
{
int tmp = a + b;
return tmp;
}
在CPPDLL.h文件写测试代码如下:
#ifdef CPPDLL_EXPORTS
#define CPPDLL_API __declspec(dllexport)
#else
#define CPPDLL_API __declspec(dllimport)
#endif
CPPDLL_API int intadd(int a, int b);
CPPDLL_API int getnum(void);
CPPDLL_API void setnum(int n);
点击生成解决方案,即可生成dll。使用Dependency Walker打开该dll文件,查看生成的dll中的函数
2 联合调试
在上一步中将dll完成后,现在来写Csharp的测试程序,程序如下:
在命名空间中加入下面这句话,表示调用外部dll,使用DllImport
using System.Runtime.InteropServices;
主程序如下:
class Program
{
[DllImport("CPPDLL.dll", EntryPoint = "intadd", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false)]
public extern static int intadd(int a, int b);
[DllImport("CPPDLL.dll", EntryPoint = "setnum", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false)]
public extern static void setnum(int n);
[DllImport("CPPDLL.dll", EntryPoint = "getnum", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = false)]
public extern static int getnum();
static void Main(string[] args)
{
int aa = 1, bb = 2;
int cc = 5;
Console.WriteLine(aa);
Console.WriteLine(bb);
Console.WriteLine(cc);
var sum = intadd(aa, bb);
Console.WriteLine(sum);
cc = getnum();
Console.WriteLine(cc);
setnum(10);
cc = getnum();
Console.WriteLine(cc);
Console.ReadLine();
}
}
联合调试前的准备:
-
首先选择dll项目,右键–属性–常规,设置如下(注意标记的地方):
这里设置输出目录的原因是:在DllImport(“CPPDLL.dll”)时设置的是相对路径,即exe文件与dll文件在同一个文件夹下,也可以改为绝对路径,如DllImport(“E:\desktop\Csharp_demo\Csharp_demo\bin\Debug\CPPDLL.dll”),但不建议这么做,因为当生成的exe在其他电脑上运行时,这种情况下exe一般与dll在一个文件夹,使用相对路径更好,使用绝对路径可能会报错。 -
然后选择C#控制台项目,右键–属性–调试,设置如下:
-
接着就可以开始进入调试模式,先在需要调试的地方添加断点,然后点击生成解决方案(注意每次修改dll中的函数后,最好选择重新生成解决方案,以便更新生成的dll),然后点击启动即可进行调试。
设置断点 | 调试断点 |
---|---|
最后的调试结果如下:
3 相关问题的总结
3.1 运行编译平台问题
关于dll版本与C#控制台版本的问题。x86的dll在x86的C#控制台上肯定是可以运行的,x64同理。下面主要讨论,x86的dll在x64的C#控制台上是否可以运行以及x64的dll在x32的C#控制台上是否可以运行。
首先测试dll为x64版本,将dll设置x64版本,然后选择C#工程,右键–属性–生成,找到目标平台,选择x86。测试对比,如下表所示:
平台 | x64dll+x86C# | x86dll+x64C# |
---|---|---|
设置 | ||
结果 | 报错 | 运行正常 |
报错(其他信息:试图加载格式不正确的程序,异常来自HRESULT:0x8007000B)具体情况如下图:
结论:x64的exe可以运行x86和x64的dll,但x86的exe只能运行x86的dll。因此使用动态链接的时候应特别注意版本,在发布的时候应用realease版本的dll。
3.2 运行环境问题
当将本地生成的exe与dll在其他电脑上运行时,会出现如下错误:
找不到dll,错误代码0x8007007e
错误原因:该电脑未安装Visual C ++ 2015 Redistributable Packages(dll由VS2015编译,其他的找对应版本即可)
解决办法:
方法1、安装Visual C ++ 2105 Redistributable Packages组件
方法2、在编译dll之前,“项目属性–C/C+±-代码生成”,“运行库改”为“多线程(/MD)”;
“项目属性–链接器–系统”, “所需的最低版本”,修改为“5.01”。
踩过了许多坑,发现CSDN上面写的方法,好多都没效果,最后是google找到的。。。。