背景
C#调用C++的dll接口来实现一些算法的功能,我以前使用的方式就是在vs中,在项目属性中的常规——>配置类型中设置为动态库(dll),然后在高级——>目标文件扩展名中设置成.dll,然后导出,将我的dll和依赖dll拷贝到C#的依赖路径中即可。这对于非托管式的调用是可以的,但是当我们的C#软件使用托管式的方式来调用的话,我们需要使用另外一种导出dll的方式,即我接下去要演示的托管式。
项目属性设置


其他的依赖还是一样的设置方式。
代码写法
用了托管式的方式的话和非托管式调用c++内置函数 __declspec(dllexport)的方式不太一样,这里我们回顾一下非托管式的写法:
#ifndef CPPDLL_EXPORTS
#define CPPDLL_API __declspec(dllexport)
#else
#define CPPDLL_API __declspec(dllimport)
#endif
extern "C" CPPDLL_API int xxx();
CPPDLL_API int xxx()
{
函数申明
}
托管式的写法:
/* 首先我们需要写一个类来封装我们的算法 */
/* 假设我们的类封装在 method.h */
/* method.h */
class method{
...
}
/* method.cpp */
假设实现了method类中的各个方法
比如
method::a();
method::b();
method::c();
...
/* 写一个dll包的头文件 */
/* DLL_MANAGER.h */
#ifdef MANAGE
#include "method.h"
#include <msclr/marshal_cppstd.h> // 这个是用来将std::string 和 System::String^ 互转的头文件
namespace My_Method{
public ref class Method{
/* 这里我们可以使用我们刚才写的外部类来实例化一个对象 */
private:
method* mm;
public:
Method(){ mm = new method(); } // dll类中的构造函数
~Method() { delete mm; }
/* 比如我们这里实现的是一个尺度的测量算法,返回的是字符串 */
/* 由于我们使用的是托管式的导出,因此这里我们不能直接返回string或者char* */
System::String^ measure();
}
}
#endif
/* 实现DLL_MANAGER.h中的方法 */
/* DLL_MANAGER.cpp */
#ifdef MANAGE
#include "method.h"
#include "DLL_MANAGER.h"
namespace My_Method
{
System::String^ Method::measure()
{
/* 有可能包含了method类中的abc三个算法的组合 */
/* 举个例子 不代表实际情况 */
mm->a();
mm->b();
mm->c();
...
return ...
}
}
这里的 #ifdef MANAGE可以在预处理器中设置:

当我们不需要导出DLL_MANAGER.h 和cpp时, 我们可以在这里把MANAGE删除,然后这两个文件中的代码都会变成灰色,不再启用,当需要导出时,我们可以预处理器中添加上MANAGE。
总结
这中托管式的好处就是,我们可以在我们的项目中写上很多种我们想导出的dll的实现,而不需要修改我们的基础类中的方法,我们可以根据需要写好一个个这样的DLL_MANAGER1, DLL_MANAGER2, …等等,然后在开始写上 #ifdef xxx,我们就可以根据需要导出对应的dll包,只需要在预处理器定义那边删减即可。

2157

被折叠的 条评论
为什么被折叠?



