C#语言个人人为比较全面的一门语言,不仅继承了C++的有点,而且对底层开发也相对友好,为什么这么说主要是因为它不仅可以面向C语言以及C++程序而且可以直接接触底层指针,相对而言是功能比较全面的一门语言,本片文章主要介绍一下C#使用P-Invoke调用C/C++动态链接库.
打开VS2017专业版,新建面向桌面的C++链接库文件项目如,以加减乘除为例在stdafx.cpp文件中,填写以下代码:
#include "stdafx.h"
extern "C" __declspec(dllexport) int __stdcall Add(int m, int n)
{
return m + n;
}
extern "C" __declspec(dllexport) int __stdcall Subtract(int m, int n)
{
return m - n;
}
extern "C" __declspec(dllexport) int __stdcall Multiply(int m, int n)
{
return m * n;
}
extern "C" __declspec(dllexport) int __stdcall Divide(int m, int n)
{
return m / n;
}
在这说明一下 extern "C"__declspec(dllexport) 与 __stdcall,extern "C"标准的C++声明用法,意思就说当前函数在其他地方定义时使用C语言调用约定,_declspec(dllexport)主要用途是从C#或者C++DLL文件中导出数据,函数以及类与类函数所用的关键字,_stdcall作用是告诉编译器这个函数由调用者来清理堆栈,调用者约定的函数名称以及参数需要相同,具体来说就是假如C#调用C++dll中的函数,需要在声明时C++dll中存在相应参数的函数(这里需要特别注意一下两者编译器架构需要相同,32位对应32位,64位对应64位,不然会报如下图二错误,或者其他未知错误),想要了解详情的同学可以点进去查看微软官方说明文档,更专业详细。
图二与图三是正确设置,C#调用时需要将C++生成的DLL文件放在对应程序运行目录下,(或者相同环境变量Path中所在的所有目录都可以就是如图四下的系统环境变量表),调用调用代码:
[DllImport("CLanguageDLL.dll", EntryPoint = "Add")]
public extern static int Add(int m,int n);
[DllImport("CLanguageDLL.dll", EntryPoint = "Subtract")]
public extern static int Subtract(int m, int n);
[DllImport("CLanguageDLL.dll", EntryPoint = "Multiply")]
public extern static int Multiply(int m, int n);
[DllImport("CLanguageDLL.dll", EntryPoint = "Divide")]
public extern static int Divide(int m, int n);
运行结果测试如图四:
优化:C++文件中 extern "C" __declspec(dllexport) int __stdcall 需要每次都写,可以使用#define简化,具体使用如下代码:
#define C_int extern "C" __declspec(dllexport) int __stdcall
使用C_int代替,原函数可以简化如下代码(预编译#define可以放在stdafx.h掉头文件中):
#include "stdafx.h"
#define C_int extern "C" __declspec(dllexport) int __stdcall //定义动态输出库标志
C_int Add(int m, int n)
{
return m + n;
}
C_int Subtract(int m, int n)
{
return m - n;
}
C_int Multiply(int m, int n)
{
return m * n;
}
C_int Divide(int m, int n)
{
return m / n;
}
整理:P-InvokeDemo源码 下载完成后重新生成每个项目,平台架构选64位或32位,但三个项目架构必须一致